|
@@ -143,8 +143,8 @@ class FSDirRenameOp {
|
|
* Change a path name
|
|
* Change a path name
|
|
*
|
|
*
|
|
* @param fsd FSDirectory
|
|
* @param fsd FSDirectory
|
|
- * @param src source path
|
|
|
|
- * @param dst destination path
|
|
|
|
|
|
+ * @param srcIIP source path
|
|
|
|
+ * @param dstIIP destination path
|
|
* @return true INodesInPath if rename succeeds; null otherwise
|
|
* @return true INodesInPath if rename succeeds; null otherwise
|
|
* @deprecated See {@link #renameToInt(FSDirectory, String, String,
|
|
* @deprecated See {@link #renameToInt(FSDirectory, String, String,
|
|
* boolean, Options.Rename...)}
|
|
* boolean, Options.Rename...)}
|
|
@@ -155,8 +155,9 @@ class FSDirRenameOp {
|
|
throws IOException {
|
|
throws IOException {
|
|
assert fsd.hasWriteLock();
|
|
assert fsd.hasWriteLock();
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
|
|
+ List<INodeDirectory> snapshottableDirs = new ArrayList<>();
|
|
try {
|
|
try {
|
|
- validateRenameSource(fsd, srcIIP);
|
|
|
|
|
|
+ validateRenameSource(fsd, srcIIP, snapshottableDirs);
|
|
} catch (SnapshotException e) {
|
|
} catch (SnapshotException e) {
|
|
throw e;
|
|
throw e;
|
|
} catch (IOException ignored) {
|
|
} catch (IOException ignored) {
|
|
@@ -190,6 +191,8 @@ class FSDirRenameOp {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ validateNestSnapshot(fsd, src, dstParent.asDirectory(), snapshottableDirs);
|
|
|
|
+
|
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP);
|
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP);
|
|
// Ensure dst has quota to accommodate rename
|
|
// Ensure dst has quota to accommodate rename
|
|
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
|
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
|
@@ -342,8 +345,8 @@ class FSDirRenameOp {
|
|
* for details related to rename semantics and exceptions.
|
|
* for details related to rename semantics and exceptions.
|
|
*
|
|
*
|
|
* @param fsd FSDirectory
|
|
* @param fsd FSDirectory
|
|
- * @param src source path
|
|
|
|
- * @param dst destination path
|
|
|
|
|
|
+ * @param srcIIP source path
|
|
|
|
+ * @param dstIIP destination path
|
|
* @param timestamp modification time
|
|
* @param timestamp modification time
|
|
* @param collectedBlocks blocks to be removed
|
|
* @param collectedBlocks blocks to be removed
|
|
* @param options Rename options
|
|
* @param options Rename options
|
|
@@ -361,7 +364,8 @@ class FSDirRenameOp {
|
|
final String dst = dstIIP.getPath();
|
|
final String dst = dstIIP.getPath();
|
|
final String error;
|
|
final String error;
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
- validateRenameSource(fsd, srcIIP);
|
|
|
|
|
|
+ List<INodeDirectory> srcSnapshottableDirs = new ArrayList<>();
|
|
|
|
+ validateRenameSource(fsd, srcIIP, srcSnapshottableDirs);
|
|
|
|
|
|
// validate the destination
|
|
// validate the destination
|
|
if (dst.equals(src)) {
|
|
if (dst.equals(src)) {
|
|
@@ -380,10 +384,10 @@ class FSDirRenameOp {
|
|
BlockStoragePolicySuite bsps = fsd.getBlockStoragePolicySuite();
|
|
BlockStoragePolicySuite bsps = fsd.getBlockStoragePolicySuite();
|
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP);
|
|
fsd.ezManager.checkMoveValidity(srcIIP, dstIIP);
|
|
final INode dstInode = dstIIP.getLastINode();
|
|
final INode dstInode = dstIIP.getLastINode();
|
|
- List<INodeDirectory> snapshottableDirs = new ArrayList<>();
|
|
|
|
|
|
+ List<INodeDirectory> dstSnapshottableDirs = new ArrayList<>();
|
|
if (dstInode != null) { // Destination exists
|
|
if (dstInode != null) { // Destination exists
|
|
validateOverwrite(src, dst, overwrite, srcInode, dstInode);
|
|
validateOverwrite(src, dst, overwrite, srcInode, dstInode);
|
|
- FSDirSnapshotOp.checkSnapshot(fsd, dstIIP, snapshottableDirs);
|
|
|
|
|
|
+ FSDirSnapshotOp.checkSnapshot(fsd, dstIIP, dstSnapshottableDirs);
|
|
}
|
|
}
|
|
|
|
|
|
INode dstParent = dstIIP.getINode(-2);
|
|
INode dstParent = dstIIP.getINode(-2);
|
|
@@ -400,6 +404,9 @@ class FSDirRenameOp {
|
|
throw new ParentNotDirectoryException(error);
|
|
throw new ParentNotDirectoryException(error);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ validateNestSnapshot(fsd, src,
|
|
|
|
+ dstParent.asDirectory(), srcSnapshottableDirs);
|
|
|
|
+
|
|
// Ensure dst has quota to accommodate rename
|
|
// Ensure dst has quota to accommodate rename
|
|
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
|
verifyFsLimitsForRename(fsd, srcIIP, dstIIP);
|
|
verifyQuotaForRename(fsd, srcIIP, dstIIP);
|
|
verifyQuotaForRename(fsd, srcIIP, dstIIP);
|
|
@@ -439,10 +446,10 @@ class FSDirRenameOp {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (snapshottableDirs.size() > 0) {
|
|
|
|
|
|
+ if (dstSnapshottableDirs.size() > 0) {
|
|
// There are snapshottable directories (without snapshots) to be
|
|
// There are snapshottable directories (without snapshots) to be
|
|
// deleted. Need to update the SnapshotManager.
|
|
// deleted. Need to update the SnapshotManager.
|
|
- fsd.getFSNamesystem().removeSnapshottableDirs(snapshottableDirs);
|
|
|
|
|
|
+ fsd.getFSNamesystem().removeSnapshottableDirs(dstSnapshottableDirs);
|
|
}
|
|
}
|
|
|
|
|
|
tx.updateQuotasInSourceTree(bsps);
|
|
tx.updateQuotasInSourceTree(bsps);
|
|
@@ -556,7 +563,8 @@ class FSDirRenameOp {
|
|
}
|
|
}
|
|
|
|
|
|
private static void validateRenameSource(FSDirectory fsd,
|
|
private static void validateRenameSource(FSDirectory fsd,
|
|
- INodesInPath srcIIP) throws IOException {
|
|
|
|
|
|
+ INodesInPath srcIIP, List<INodeDirectory> snapshottableDirs)
|
|
|
|
+ throws IOException {
|
|
String error;
|
|
String error;
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
final INode srcInode = srcIIP.getLastINode();
|
|
// validate source
|
|
// validate source
|
|
@@ -574,7 +582,32 @@ class FSDirRenameOp {
|
|
}
|
|
}
|
|
// srcInode and its subtree cannot contain snapshottable directories with
|
|
// srcInode and its subtree cannot contain snapshottable directories with
|
|
// snapshots
|
|
// snapshots
|
|
- FSDirSnapshotOp.checkSnapshot(fsd, srcIIP, null);
|
|
|
|
|
|
+ FSDirSnapshotOp.checkSnapshot(fsd, srcIIP, snapshottableDirs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void validateNestSnapshot(FSDirectory fsd, String srcPath,
|
|
|
|
+ INodeDirectory dstParent, List<INodeDirectory> snapshottableDirs)
|
|
|
|
+ throws SnapshotException {
|
|
|
|
+
|
|
|
|
+ if (fsd.getFSNamesystem().getSnapshotManager().isAllowNestedSnapshots()) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * snapshottableDirs is a list of snapshottable directory (child of rename
|
|
|
|
+ * src) which do not have snapshots yet. If this list is not empty, that
|
|
|
|
+ * means rename src has snapshottable descendant directories.
|
|
|
|
+ */
|
|
|
|
+ if (snapshottableDirs != null && snapshottableDirs.size() > 0) {
|
|
|
|
+ if (fsd.getFSNamesystem().getSnapshotManager()
|
|
|
|
+ .isDescendantOfSnapshotRoot(dstParent)) {
|
|
|
|
+ String dstPath = dstParent.getFullPathName();
|
|
|
|
+ throw new SnapshotException("Unable to rename because " + srcPath
|
|
|
|
+ + " has snapshottable descendant directories and " + dstPath
|
|
|
|
+ + " is a descent of a snapshottable directory, and HDFS does"
|
|
|
|
+ + " not support nested snapshottable directory.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
private static class RenameOperation {
|
|
private static class RenameOperation {
|