diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-2802.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-2802.txt index ee692149b3..083d972fe5 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-2802.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-2802.txt @@ -329,3 +329,6 @@ Branch-2802 Snapshot (Unreleased) HDFS-4758. Disallow nested snapshottable directories and unwrap RemoteException. (szetszwo) + + HDFS-4781. Fix a NullPointerException when listing .snapshot under + a non-existing directory. (szetszwo) diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java index 0cdad8d68d..4462099be9 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java @@ -1588,7 +1588,8 @@ private HdfsFileStatus getFileInfo4DotSnapshot(String src) src.length() - HdfsConstants.DOT_SNAPSHOT_DIR.length())); final INode node = this.getINode(dirPath); - if (node.isDirectory() + if (node != null + && node.isDirectory() && node.asDirectory() instanceof INodeDirectorySnapshottable) { return new HdfsFileStatus(0, true, 0, 0, 0, 0, null, null, null, null, HdfsFileStatus.EMPTY_NAME, -1L); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INode.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INode.java index 7709fc5a85..541f591113 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INode.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INode.java @@ -313,12 +313,12 @@ public INodeSymlink asSymlink() { * children. * * 1.3 The current inode is a {@link FileWithSnapshot}. - * Call {@link INode#recordModification(Snapshot)} to capture the - * current states. Mark the INode as deleted. + * Call recordModification(..) to capture the current states. + * Mark the INode as deleted. * * 1.4 The current inode is a {@link INodeDirectoryWithSnapshot}. - * Call {@link INode#recordModification(Snapshot)} to capture the - * current states. Destroy files/directories created after the latest snapshot + * Call recordModification(..) to capture the current states. + * Destroy files/directories created after the latest snapshot * (i.e., the inodes stored in the created list of the latest snapshot). * Recursively clean remaining children. * diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeDirectory.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeDirectory.java index afaf98c026..1dc1016498 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeDirectory.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/INodeDirectory.java @@ -111,7 +111,7 @@ private int searchChildren(byte[] name) { * Remove the specified child from this directory. * * @param child the child inode to be removed - * @param latest See {@link INode#recordModification(Snapshot)}. + * @param latest See {@link INode#recordModification(Snapshot, INodeMap)}. */ public boolean removeChild(INode child, Snapshot latest, final INodeMap inodeMap) throws QuotaExceededException { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestSnapshotPathINodes.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestSnapshotPathINodes.java index 612efff125..721a0fd3f6 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestSnapshotPathINodes.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestSnapshotPathINodes.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.FileNotFoundException; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.DFSTestUtil; @@ -238,6 +240,18 @@ public void testSnapshotPathINodes() throws Exception { final INode last = nodesInPath.getLastINode(); assertEquals(last.getFullPathName(), sub1.toString()); assertFalse(last instanceof INodeFileWithSnapshot); + + String[] invalidPathComponent = {"invalidDir", "foo", ".snapshot", "bar"}; + Path invalidPath = new Path(invalidPathComponent[0]); + for(int i = 1; i < invalidPathComponent.length; i++) { + invalidPath = new Path(invalidPath, invalidPathComponent[i]); + try { + hdfs.getFileStatus(invalidPath); + Assert.fail(); + } catch(FileNotFoundException fnfe) { + System.out.println("The exception is expected: " + fnfe); + } + } } /**