Skip to content

Commit f86f15c

Browse files
committed
HDFS-15446. CreateSnapshotOp fails during edit log loading for /.reserved/raw/path with error java.io.FileNotFoundException: Directory does not exist: /.reserved/raw/path. Contributed by Stephen O'Donnell.
1 parent 1f2a80b commit f86f15c

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,26 @@ public INodesInPath resolvePath(FSPermissionChecker pc, String src,
734734
return iip;
735735
}
736736

737+
/**
738+
* This method should only be used from internal paths and not those provided
739+
* directly by a user. It resolves a given path into an INodesInPath in a
740+
* similar way to resolvePath(...), only traversal and permissions are not
741+
* checked.
742+
* @param src The path to resolve.
743+
* @return if the path indicates an inode, return path after replacing up to
744+
* {@code <inodeid>} with the corresponding path of the inode, else
745+
* the path in {@code src} as is. If the path refers to a path in
746+
* the "raw" directory, return the non-raw pathname.
747+
* @throws FileNotFoundException
748+
*/
749+
public INodesInPath unprotectedResolvePath(String src)
750+
throws FileNotFoundException {
751+
byte[][] components = INode.getPathComponents(src);
752+
boolean isRaw = isReservedRawName(components);
753+
components = resolveComponents(components, this);
754+
return INodesInPath.resolve(rootDir, components, isRaw);
755+
}
756+
737757
INodesInPath resolvePath(FSPermissionChecker pc, String src, long fileId)
738758
throws UnresolvedLinkException, FileNotFoundException,
739759
AccessControlException, ParentNotDirectoryException {

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogLoader.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ private long applyEditLogOp(FSEditLogOp op, FSDirectory fsDir,
798798
final String snapshotRoot =
799799
renameReservedPathsOnUpgrade(createSnapshotOp.snapshotRoot,
800800
logVersion);
801-
INodesInPath iip = fsDir.getINodesInPath(snapshotRoot, DirOp.WRITE);
801+
INodesInPath iip = fsDir.unprotectedResolvePath(snapshotRoot);
802802
String path = fsNamesys.getSnapshotManager().createSnapshot(
803803
fsDir.getFSNamesystem().getLeaseManager(),
804804
iip, snapshotRoot, createSnapshotOp.snapshotName,
@@ -816,7 +816,7 @@ private long applyEditLogOp(FSEditLogOp op, FSDirectory fsDir,
816816
final String snapshotRoot =
817817
renameReservedPathsOnUpgrade(deleteSnapshotOp.snapshotRoot,
818818
logVersion);
819-
INodesInPath iip = fsDir.getINodesInPath(snapshotRoot, DirOp.WRITE);
819+
INodesInPath iip = fsDir.unprotectedResolvePath(snapshotRoot);
820820
fsNamesys.getSnapshotManager().deleteSnapshot(iip,
821821
deleteSnapshotOp.snapshotName,
822822
new INode.ReclaimContext(fsNamesys.dir.getBlockStoragePolicySuite(),
@@ -838,7 +838,7 @@ private long applyEditLogOp(FSEditLogOp op, FSDirectory fsDir,
838838
final String snapshotRoot =
839839
renameReservedPathsOnUpgrade(renameSnapshotOp.snapshotRoot,
840840
logVersion);
841-
INodesInPath iip = fsDir.getINodesInPath(snapshotRoot, DirOp.WRITE);
841+
INodesInPath iip = fsDir.unprotectedResolvePath(snapshotRoot);
842842
fsNamesys.getSnapshotManager().renameSnapshot(iip,
843843
snapshotRoot, renameSnapshotOp.snapshotOldName,
844844
renameSnapshotOp.snapshotNewName, renameSnapshotOp.mtime);

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestSnapshot.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,59 @@ public void testDeletionSnapshotMtime() throws Exception {
513513
newSnapshotStatus.getModificationTime());
514514
}
515515

516+
/**
517+
* HDFS-15446 - ensure that snapshot operations on /.reserved/raw
518+
* paths work and the NN can load the resulting edits.
519+
*/
520+
@Test(timeout = 60000)
521+
public void testSnapshotOpsOnReservedPath() throws Exception {
522+
Path dir = new Path("/dir");
523+
Path nestedDir = new Path("/nested/dir");
524+
Path sub = new Path(dir, "sub");
525+
Path subFile = new Path(sub, "file");
526+
Path nestedFile = new Path(nestedDir, "file");
527+
DFSTestUtil.createFile(hdfs, subFile, BLOCKSIZE, REPLICATION, seed);
528+
DFSTestUtil.createFile(hdfs, nestedFile, BLOCKSIZE, REPLICATION, seed);
529+
530+
hdfs.allowSnapshot(dir);
531+
hdfs.allowSnapshot(nestedDir);
532+
Path reservedDir = new Path("/.reserved/raw/dir");
533+
Path reservedNestedDir = new Path("/.reserved/raw/nested/dir");
534+
hdfs.createSnapshot(reservedDir, "s1");
535+
hdfs.createSnapshot(reservedNestedDir, "s1");
536+
hdfs.renameSnapshot(reservedDir, "s1", "s2");
537+
hdfs.renameSnapshot(reservedNestedDir, "s1", "s2");
538+
hdfs.deleteSnapshot(reservedDir, "s2");
539+
hdfs.deleteSnapshot(reservedNestedDir, "s2");
540+
// The original problem with reserved path, is that the NN was unable to
541+
// replay the edits, therefore restarting the NN to ensure it starts
542+
// and no exceptions are raised.
543+
cluster.restartNameNode(true);
544+
}
545+
546+
/**
547+
* HDFS-15446 - ensure that snapshot operations on /.reserved/raw
548+
* paths work and the NN can load the resulting edits. This test if for
549+
* snapshots at the root level.
550+
*/
551+
@Test(timeout = 60000)
552+
public void testSnapshotOpsOnRootReservedPath() throws Exception {
553+
Path dir = new Path("/");
554+
Path sub = new Path(dir, "sub");
555+
Path subFile = new Path(sub, "file");
556+
DFSTestUtil.createFile(hdfs, subFile, BLOCKSIZE, REPLICATION, seed);
557+
558+
hdfs.allowSnapshot(dir);
559+
Path reservedDir = new Path("/.reserved/raw");
560+
hdfs.createSnapshot(reservedDir, "s1");
561+
hdfs.renameSnapshot(reservedDir, "s1", "s2");
562+
hdfs.deleteSnapshot(reservedDir, "s2");
563+
// The original problem with reserved path, is that the NN was unable to
564+
// replay the edits, therefore restarting the NN to ensure it starts
565+
// and no exceptions are raised.
566+
cluster.restartNameNode(true);
567+
}
568+
516569
/**
517570
* Prepare a list of modifications. A modification may be a file creation,
518571
* file deletion, or a modification operation such as appending to an existing

0 commit comments

Comments
 (0)