@@ -143,8 +143,8 @@ private static INodesInPath dstForRenameTo(
143143 * Change a path name
144144 *
145145 * @param fsd FSDirectory
146- * @param src source path
147- * @param dst destination path
146+ * @param srcIIP source path
147+ * @param dstIIP destination path
148148 * @return true INodesInPath if rename succeeds; null otherwise
149149 * @deprecated See {@link #renameToInt(FSDirectory, String, String,
150150 * boolean, Options.Rename...)}
@@ -155,8 +155,9 @@ static INodesInPath unprotectedRenameTo(FSDirectory fsd,
155155 throws IOException {
156156 assert fsd .hasWriteLock ();
157157 final INode srcInode = srcIIP .getLastINode ();
158+ List <INodeDirectory > snapshottableDirs = new ArrayList <>();
158159 try {
159- validateRenameSource (fsd , srcIIP );
160+ validateRenameSource (fsd , srcIIP , snapshottableDirs );
160161 } catch (SnapshotException e ) {
161162 throw e ;
162163 } catch (IOException ignored ) {
@@ -190,6 +191,8 @@ static INodesInPath unprotectedRenameTo(FSDirectory fsd,
190191 return null ;
191192 }
192193
194+ validateNestSnapshot (fsd , src , dstParent .asDirectory (), snapshottableDirs );
195+
193196 fsd .ezManager .checkMoveValidity (srcIIP , dstIIP );
194197 // Ensure dst has quota to accommodate rename
195198 verifyFsLimitsForRename (fsd , srcIIP , dstIIP );
@@ -342,8 +345,8 @@ static void renameForEditLog(
342345 * for details related to rename semantics and exceptions.
343346 *
344347 * @param fsd FSDirectory
345- * @param src source path
346- * @param dst destination path
348+ * @param srcIIP source path
349+ * @param dstIIP destination path
347350 * @param timestamp modification time
348351 * @param collectedBlocks blocks to be removed
349352 * @param options Rename options
@@ -361,7 +364,8 @@ static RenameResult unprotectedRenameTo(FSDirectory fsd,
361364 final String dst = dstIIP .getPath ();
362365 final String error ;
363366 final INode srcInode = srcIIP .getLastINode ();
364- validateRenameSource (fsd , srcIIP );
367+ List <INodeDirectory > srcSnapshottableDirs = new ArrayList <>();
368+ validateRenameSource (fsd , srcIIP , srcSnapshottableDirs );
365369
366370 // validate the destination
367371 if (dst .equals (src )) {
@@ -380,10 +384,10 @@ static RenameResult unprotectedRenameTo(FSDirectory fsd,
380384 BlockStoragePolicySuite bsps = fsd .getBlockStoragePolicySuite ();
381385 fsd .ezManager .checkMoveValidity (srcIIP , dstIIP );
382386 final INode dstInode = dstIIP .getLastINode ();
383- List <INodeDirectory > snapshottableDirs = new ArrayList <>();
387+ List <INodeDirectory > dstSnapshottableDirs = new ArrayList <>();
384388 if (dstInode != null ) { // Destination exists
385389 validateOverwrite (src , dst , overwrite , srcInode , dstInode );
386- FSDirSnapshotOp .checkSnapshot (fsd , dstIIP , snapshottableDirs );
390+ FSDirSnapshotOp .checkSnapshot (fsd , dstIIP , dstSnapshottableDirs );
387391 }
388392
389393 INode dstParent = dstIIP .getINode (-2 );
@@ -400,6 +404,9 @@ static RenameResult unprotectedRenameTo(FSDirectory fsd,
400404 throw new ParentNotDirectoryException (error );
401405 }
402406
407+ validateNestSnapshot (fsd , src ,
408+ dstParent .asDirectory (), srcSnapshottableDirs );
409+
403410 // Ensure dst has quota to accommodate rename
404411 verifyFsLimitsForRename (fsd , srcIIP , dstIIP );
405412 verifyQuotaForRename (fsd , srcIIP , dstIIP );
@@ -439,10 +446,10 @@ static RenameResult unprotectedRenameTo(FSDirectory fsd,
439446 }
440447 }
441448
442- if (snapshottableDirs .size () > 0 ) {
449+ if (dstSnapshottableDirs .size () > 0 ) {
443450 // There are snapshottable directories (without snapshots) to be
444451 // deleted. Need to update the SnapshotManager.
445- fsd .getFSNamesystem ().removeSnapshottableDirs (snapshottableDirs );
452+ fsd .getFSNamesystem ().removeSnapshottableDirs (dstSnapshottableDirs );
446453 }
447454
448455 tx .updateQuotasInSourceTree (bsps );
@@ -556,7 +563,8 @@ private static void validateOverwrite(
556563 }
557564
558565 private static void validateRenameSource (FSDirectory fsd ,
559- INodesInPath srcIIP ) throws IOException {
566+ INodesInPath srcIIP , List <INodeDirectory > snapshottableDirs )
567+ throws IOException {
560568 String error ;
561569 final INode srcInode = srcIIP .getLastINode ();
562570 // validate source
@@ -574,7 +582,32 @@ private static void validateRenameSource(FSDirectory fsd,
574582 }
575583 // srcInode and its subtree cannot contain snapshottable directories with
576584 // snapshots
577- FSDirSnapshotOp .checkSnapshot (fsd , srcIIP , null );
585+ FSDirSnapshotOp .checkSnapshot (fsd , srcIIP , snapshottableDirs );
586+ }
587+
588+ private static void validateNestSnapshot (FSDirectory fsd , String srcPath ,
589+ INodeDirectory dstParent , List <INodeDirectory > snapshottableDirs )
590+ throws SnapshotException {
591+
592+ if (fsd .getFSNamesystem ().getSnapshotManager ().isAllowNestedSnapshots ()) {
593+ return ;
594+ }
595+
596+ /*
597+ * snapshottableDirs is a list of snapshottable directory (child of rename
598+ * src) which do not have snapshots yet. If this list is not empty, that
599+ * means rename src has snapshottable descendant directories.
600+ */
601+ if (snapshottableDirs != null && snapshottableDirs .size () > 0 ) {
602+ if (fsd .getFSNamesystem ().getSnapshotManager ()
603+ .isDescendantOfSnapshotRoot (dstParent )) {
604+ String dstPath = dstParent .getFullPathName ();
605+ throw new SnapshotException ("Unable to rename because " + srcPath
606+ + " has snapshottable descendant directories and " + dstPath
607+ + " is a descent of a snapshottable directory, and HDFS does"
608+ + " not support nested snapshottable directory." );
609+ }
610+ }
578611 }
579612
580613 private static class RenameOperation {
0 commit comments