From b65e43fe386c9e9cf056f1c460b6c4a2605aeebe Mon Sep 17 00:00:00 2001 From: Siyao Meng <50227127+smengcl@users.noreply.github.com> Date: Tue, 18 Aug 2020 03:28:19 -0700 Subject: [PATCH] HDFS-15525. Make trash root inside each snapshottable directory for WebHDFS (#2220) --- .../web/resources/NamenodeWebHdfsMethods.java | 48 ++++++++++++++++--- .../apache/hadoop/hdfs/web/TestWebHDFS.java | 28 +++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java index 2423a037c8f..9baed4f0673 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java @@ -1345,19 +1345,55 @@ public class NamenodeWebHdfsMethods { } } + /** + * Get the snapshot root of a given file or directory if it exists. + * e.g. if /snapdir1 is a snapshottable directory and path given is + * /snapdir1/path/to/file, this method would return /snapdir1 + * @param pathStr String of path to a file or a directory. + * @return Not null if found in a snapshot root directory. + * @throws IOException + */ + String getSnapshotRoot(String pathStr) throws IOException { + SnapshottableDirectoryStatus[] dirStatusList = + getRpcClientProtocol().getSnapshottableDirListing(); + if (dirStatusList == null) { + return null; + } + for (SnapshottableDirectoryStatus dirStatus : dirStatusList) { + String currDir = dirStatus.getFullPath().toString(); + if (pathStr.startsWith(currDir)) { + return currDir; + } + } + return null; + } + private String getTrashRoot(Configuration conf, String fullPath) throws IOException { - UserGroupInformation ugi= UserGroupInformation.getCurrentUser(); + UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); String parentSrc = getParent(fullPath); + String ssTrashRoot = ""; + boolean isSnapshotTrashRootEnabled = getRpcClientProtocol() + .getServerDefaults().getSnapshotTrashRootEnabled(); + if (isSnapshotTrashRootEnabled) { + String ssRoot = getSnapshotRoot(fullPath); + if (ssRoot != null) { + ssTrashRoot = DFSUtilClient.getSnapshotTrashRoot(ssRoot, ugi); + } + } EncryptionZone ez = getRpcClientProtocol().getEZForPath( parentSrc != null ? parentSrc : fullPath); - String trashRoot; + String ezTrashRoot = ""; if (ez != null) { - trashRoot = DFSUtilClient.getEZTrashRoot(ez, ugi); - } else { - trashRoot = DFSUtilClient.getTrashRoot(conf, ugi); + ezTrashRoot = DFSUtilClient.getEZTrashRoot(ez, ugi); + } + // Choose the longest path + if (ssTrashRoot.isEmpty() && ezTrashRoot.isEmpty()) { + return DFSUtilClient.getTrashRoot(conf, ugi); + } else { + return ssTrashRoot.length() > ezTrashRoot.length() ? + ssTrashRoot : ezTrashRoot; } - return trashRoot; } /** diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFS.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFS.java index 69a0e600ffb..3c8a92eee12 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFS.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFS.java @@ -1569,6 +1569,34 @@ public class TestWebHDFS { assertEquals(expectedPath.toUri().getPath(), trashPath.toUri().getPath()); } + @Test + public void testGetSnapshotTrashRoot() throws Exception { + final Configuration conf = WebHdfsTestUtil.createConf(); + conf.setBoolean("dfs.namenode.snapshot.trashroot.enabled", true); + final String currentUser = + UserGroupInformation.getCurrentUser().getShortUserName(); + cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); + final WebHdfsFileSystem webFS = WebHdfsTestUtil.getWebHdfsFileSystem(conf, + WebHdfsConstants.WEBHDFS_SCHEME); + Path ssDir1 = new Path("/ssDir1"); + assertTrue(webFS.mkdirs(ssDir1)); + + Path trashPath = webFS.getTrashRoot(ssDir1); + Path expectedPath = new Path(FileSystem.USER_HOME_PREFIX, + new Path(currentUser, FileSystem.TRASH_PREFIX)); + assertEquals(expectedPath.toUri().getPath(), trashPath.toUri().getPath()); + // Enable snapshot + webFS.allowSnapshot(ssDir1); + Path trashPathAfter = webFS.getTrashRoot(ssDir1); + Path expectedPathAfter = new Path(ssDir1, + new Path(FileSystem.TRASH_PREFIX, currentUser)); + assertEquals(expectedPathAfter.toUri().getPath(), + trashPathAfter.toUri().getPath()); + // Cleanup + webFS.disallowSnapshot(ssDir1); + webFS.delete(ssDir1, true); + } + @Test public void testGetEZTrashRoot() throws Exception { final Configuration conf = WebHdfsTestUtil.createConf();