This is an automated email from the ASF dual-hosted git repository.

siyao pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/trunk by this push:
     new a308a1e  HDFS-15614. Initialize snapshot trash root during NameNode 
startup if enabled (#2370)
a308a1e is described below

commit a308a1ec22befa919ad8b6509f1b8c888c80f350
Author: Siyao Meng <[email protected]>
AuthorDate: Tue Oct 13 10:59:42 2020 -0700

    HDFS-15614. Initialize snapshot trash root during NameNode startup if 
enabled (#2370)
---
 .../hadoop/hdfs/server/namenode/FSNamesystem.java  | 28 +++++++++++++++
 .../hadoop/hdfs/server/namenode/NameNode.java      |  3 ++
 .../org/apache/hadoop/hdfs/MiniDFSCluster.java     | 15 ++++++++
 .../hadoop/hdfs/TestDistributedFileSystem.java     | 42 +++++++++++++++++++++-
 4 files changed, 87 insertions(+), 1 deletion(-)

diff --git 
a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
 
b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
index badf237..13ad4c4 100644
--- 
a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
+++ 
b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
@@ -388,6 +388,8 @@ public class FSNamesystem implements Namesystem, 
FSNamesystemMBean,
       "dfs.namenode.snapshot.trashroot.enabled";
   public static final boolean DFS_NAMENODE_SNAPSHOT_TRASHROOT_ENABLED_DEFAULT
       = false;
+  private static final FsPermission SHARED_TRASH_PERMISSION =
+      new FsPermission(FsAction.ALL, FsAction.ALL, FsAction.ALL, true);
 
   private final MetricsRegistry registry = new MetricsRegistry("FSNamesystem");
   @Metric final MutableRatesWithAggregation detailedLockHoldTimeMetrics =
@@ -8524,6 +8526,32 @@ public class FSNamesystem implements Namesystem, 
FSNamesystemMBean,
     logAuditEvent(true, operationName, src);
   }
 
+  /**
+   * Check if snapshot roots are created for all existing snapshottable
+   * directories. Create them if not.
+   */
+  void checkAndProvisionSnapshotTrashRoots() throws IOException {
+    SnapshottableDirectoryStatus[] dirStatusList = 
getSnapshottableDirListing();
+    if (dirStatusList == null) {
+      return;
+    }
+    for (SnapshottableDirectoryStatus dirStatus : dirStatusList) {
+      String currDir = dirStatus.getFullPath().toString();
+      if (!currDir.endsWith(Path.SEPARATOR)) {
+        currDir += Path.SEPARATOR;
+      }
+      String trashPath = currDir + FileSystem.TRASH_PREFIX;
+      HdfsFileStatus fileStatus = getFileInfo(trashPath, false, false, false);
+      if (fileStatus == null) {
+        LOG.info("Trash doesn't exist for snapshottable directory {}. "
+            + "Creating trash at {}", currDir, trashPath);
+        PermissionStatus permissionStatus = new 
PermissionStatus(getRemoteUser()
+            .getShortUserName(), null, SHARED_TRASH_PERMISSION);
+        mkdirs(trashPath, permissionStatus, false);
+      }
+    }
+  }
+
   private Supplier<String> getLockReportInfoSupplier(String src) {
     return getLockReportInfoSupplier(src, null);
   }
diff --git 
a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
 
b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
index 461f676..6dca05d 100644
--- 
a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
+++ 
b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
@@ -2018,6 +2018,9 @@ public class NameNode extends ReconfigurableBase 
implements
     public void startActiveServices() throws IOException {
       try {
         namesystem.startActiveServices();
+        if (namesystem.isSnapshotTrashRootEnabled()) {
+          namesystem.checkAndProvisionSnapshotTrashRoots();
+        }
         startTrashEmptier(getConf());
       } catch (Throwable t) {
         doImmediateShutdown(t);
diff --git 
a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/MiniDFSCluster.java
 
b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/MiniDFSCluster.java
index a2a9066..9e4bd5e 100644
--- 
a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/MiniDFSCluster.java
+++ 
b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/MiniDFSCluster.java
@@ -623,6 +623,10 @@ public class MiniDFSCluster implements AutoCloseable {
       this.startOpt = startOpt;
       this.conf = conf;
     }
+
+    public void setConf(Configuration conf) {
+      this.conf = conf;
+    }
     
     public void setStartOpt(StartupOption startOpt) {
       this.startOpt = startOpt;
@@ -2186,6 +2190,17 @@ public class MiniDFSCluster implements AutoCloseable {
   }
 
   /**
+   * Update an existing NameNode's configuration.
+   */
+  public void setNameNodeConf(int nnIndex, Configuration nnConf) {
+    NameNodeInfo info = getNN(nnIndex);
+    if (info == null) {
+      throw new RuntimeException("Invalid nnIndex!");
+    }
+    info.setConf(nnConf);
+  }
+
+  /**
    * Restart the namenode at a given index. Optionally wait for the cluster
    * to become active.
    */
diff --git 
a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDistributedFileSystem.java
 
b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDistributedFileSystem.java
index 3f22da3..e0d1f92 100644
--- 
a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDistributedFileSystem.java
+++ 
b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDistributedFileSystem.java
@@ -24,6 +24,7 @@ import static 
org.apache.hadoop.hdfs.client.HdfsAdmin.TRASH_PERMISSION;
 import static 
org.apache.hadoop.hdfs.client.HdfsClientConfigKeys.DFS_CLIENT_CONTEXT;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -1620,7 +1621,7 @@ public class TestDistributedFileSystem {
       cluster.waitActive();
       DistributedFileSystem dfs = cluster.getFileSystem();
       FsServerDefaults fsServerDefaults = dfs.getServerDefaults();
-      Assert.assertNotNull(fsServerDefaults);
+      assertNotNull(fsServerDefaults);
     } finally {
       cluster.shutdown();
     }
@@ -2513,4 +2514,43 @@ public class TestDistributedFileSystem {
           () -> FileUtil.copy(dfs, fstatus, dfs, filePath, false, true, conf));
     }
   }
+
+  @Test
+  public void testNameNodeCreateSnapshotTrashRootOnStartup()
+      throws Exception {
+    // Start NN with dfs.namenode.snapshot.trashroot.enabled=false
+    Configuration conf = getTestConfiguration();
+    conf.setBoolean("dfs.namenode.snapshot.trashroot.enabled", false);
+    MiniDFSCluster cluster =
+        new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
+    try {
+      final DistributedFileSystem dfs = cluster.getFileSystem();
+      final Path testDir = new Path("/disallowss/test2/");
+      final Path file0path = new Path(testDir, "file-0");
+      dfs.create(file0path).close();
+      dfs.allowSnapshot(testDir);
+      // .Trash won't be created right now since snapshot trash is disabled
+      final Path trashRoot = new Path(testDir, FileSystem.TRASH_PREFIX);
+      assertFalse(dfs.exists(trashRoot));
+      // Set dfs.namenode.snapshot.trashroot.enabled=true
+      conf.setBoolean("dfs.namenode.snapshot.trashroot.enabled", true);
+      cluster.setNameNodeConf(0, conf);
+      cluster.restartNameNode(0);
+      // Check .Trash existence, should be created now
+      assertTrue(dfs.exists(trashRoot));
+      // Check permission
+      FileStatus trashRootStatus = dfs.getFileStatus(trashRoot);
+      assertNotNull(trashRootStatus);
+      assertEquals(TRASH_PERMISSION, trashRootStatus.getPermission());
+
+      // Cleanup
+      dfs.delete(trashRoot, true);
+      dfs.disallowSnapshot(testDir);
+      dfs.delete(testDir, true);
+    } finally {
+      if (cluster != null) {
+        cluster.shutdown();
+      }
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to