HDFS-15820. Ensure snapshot root trash provisioning happens only post safe mode exit (#2682)

This commit is contained in:
bshashikant 2021-02-06 21:56:12 +05:30 committed by GitHub
parent c4918fb298
commit 19ae0faacc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 30 deletions

View File

@ -425,7 +425,7 @@ class BlockManagerSafeMode {
BlockManagerSafeMode.STEP_AWAITING_REPORTED_BLOCKS); BlockManagerSafeMode.STEP_AWAITING_REPORTED_BLOCKS);
prog.endPhase(Phase.SAFEMODE); prog.endPhase(Phase.SAFEMODE);
} }
namesystem.checkAndProvisionSnapshotTrashRoots();
return true; return true;
} }

View File

@ -124,7 +124,8 @@ import org.apache.hadoop.hdfs.server.common.ECTopologyVerifier;
import org.apache.hadoop.hdfs.server.namenode.metrics.ReplicatedBlocksMBean; import org.apache.hadoop.hdfs.server.namenode.metrics.ReplicatedBlocksMBean;
import org.apache.hadoop.hdfs.server.protocol.SlowDiskReports; import org.apache.hadoop.hdfs.server.protocol.SlowDiskReports;
import org.apache.hadoop.ipc.ObserverRetryOnActiveException; import org.apache.hadoop.ipc.ObserverRetryOnActiveException;
import org.apache.hadoop.util.Time; import org.apache.hadoop.util.*;
import static org.apache.hadoop.util.Time.now; import static org.apache.hadoop.util.Time.now;
import static org.apache.hadoop.util.Time.monotonicNow; import static org.apache.hadoop.util.Time.monotonicNow;
import static org.apache.hadoop.hdfs.server.namenode.top.metrics.TopMetrics.TOPMETRICS_METRICS_SOURCE_NAME; import static org.apache.hadoop.hdfs.server.namenode.top.metrics.TopMetrics.TOPMETRICS_METRICS_SOURCE_NAME;
@ -329,11 +330,6 @@ import org.apache.hadoop.security.token.SecretManager.InvalidToken;
import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.security.token.delegation.DelegationKey; import org.apache.hadoop.security.token.delegation.DelegationKey;
import org.apache.hadoop.util.Daemon;
import org.apache.hadoop.util.DataChecksum;
import org.apache.hadoop.util.ReflectionUtils;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.VersionInfo;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.log4j.Appender; import org.apache.log4j.Appender;
import org.apache.log4j.AsyncAppender; import org.apache.log4j.AsyncAppender;
@ -8531,25 +8527,37 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
* Check if snapshot roots are created for all existing snapshottable * Check if snapshot roots are created for all existing snapshottable
* directories. Create them if not. * directories. Create them if not.
*/ */
void checkAndProvisionSnapshotTrashRoots() throws IOException { @Override
SnapshottableDirectoryStatus[] dirStatusList = getSnapshottableDirListing(); public void checkAndProvisionSnapshotTrashRoots() {
if (dirStatusList == null) { if (isSnapshotTrashRootEnabled) {
return; try {
} SnapshottableDirectoryStatus[] dirStatusList =
for (SnapshottableDirectoryStatus dirStatus : dirStatusList) { getSnapshottableDirListing();
String currDir = dirStatus.getFullPath().toString(); if (dirStatusList == null) {
if (!currDir.endsWith(Path.SEPARATOR)) { return;
currDir += Path.SEPARATOR; }
} for (SnapshottableDirectoryStatus dirStatus : dirStatusList) {
String trashPath = currDir + FileSystem.TRASH_PREFIX; String currDir = dirStatus.getFullPath().toString();
HdfsFileStatus fileStatus = getFileInfo(trashPath, false, false, false); if (!currDir.endsWith(Path.SEPARATOR)) {
if (fileStatus == null) { currDir += Path.SEPARATOR;
LOG.info("Trash doesn't exist for snapshottable directory {}. " }
+ "Creating trash at {}", currDir, trashPath); String trashPath = currDir + FileSystem.TRASH_PREFIX;
PermissionStatus permissionStatus = new PermissionStatus(getRemoteUser() HdfsFileStatus fileStatus = getFileInfo(trashPath, false, false, false);
.getShortUserName(), null, SHARED_TRASH_PERMISSION); if (fileStatus == null) {
mkdirs(trashPath, permissionStatus, false); 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);
}
}
} catch (IOException e) {
final String msg =
"Could not provision Trash directory for existing "
+ "snapshottable directories. Exiting Namenode.";
ExitUtil.terminate(1, msg);
} }
} }
} }

View File

@ -2011,9 +2011,6 @@ public class NameNode extends ReconfigurableBase implements
public void startActiveServices() throws IOException { public void startActiveServices() throws IOException {
try { try {
namesystem.startActiveServices(); namesystem.startActiveServices();
if (namesystem.isSnapshotTrashRootEnabled()) {
namesystem.checkAndProvisionSnapshotTrashRoots();
}
startTrashEmptier(getConf()); startTrashEmptier(getConf());
} catch (Throwable t) { } catch (Throwable t) {
doImmediateShutdown(t); doImmediateShutdown(t);

View File

@ -27,7 +27,9 @@ import org.apache.hadoop.hdfs.util.RwLock;
/** Namesystem operations. */ /** Namesystem operations. */
@InterfaceAudience.Private @InterfaceAudience.Private
public interface Namesystem extends RwLock, SafeMode { public interface Namesystem extends RwLock, SafeMode {
/** Is this name system running? */ /**
* Is this name system running?
*/
boolean isRunning(); boolean isRunning();
BlockCollection getBlockCollection(long id); BlockCollection getBlockCollection(long id);
@ -55,4 +57,10 @@ public interface Namesystem extends RwLock, SafeMode {
* @throws IOException * @throws IOException
*/ */
void removeXattr(long id, String xattrName) throws IOException; void removeXattr(long id, String xattrName) throws IOException;
/**
* Check if snapshot roots are created for all existing snapshottable
* directories. Create them if not.
*/
void checkAndProvisionSnapshotTrashRoots();
} }

View File

@ -2524,7 +2524,7 @@ public class TestDistributedFileSystem {
MiniDFSCluster cluster = MiniDFSCluster cluster =
new MiniDFSCluster.Builder(conf).numDataNodes(1).build(); new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
try { try {
final DistributedFileSystem dfs = cluster.getFileSystem(); DistributedFileSystem dfs = cluster.getFileSystem();
final Path testDir = new Path("/disallowss/test2/"); final Path testDir = new Path("/disallowss/test2/");
final Path file0path = new Path(testDir, "file-0"); final Path file0path = new Path(testDir, "file-0");
dfs.create(file0path).close(); dfs.create(file0path).close();
@ -2535,7 +2535,20 @@ public class TestDistributedFileSystem {
// Set dfs.namenode.snapshot.trashroot.enabled=true // Set dfs.namenode.snapshot.trashroot.enabled=true
conf.setBoolean("dfs.namenode.snapshot.trashroot.enabled", true); conf.setBoolean("dfs.namenode.snapshot.trashroot.enabled", true);
cluster.setNameNodeConf(0, conf); cluster.setNameNodeConf(0, conf);
cluster.shutdown();
conf.setInt(DFSConfigKeys.DFS_NAMENODE_SAFEMODE_EXTENSION_KEY, 0);
conf.setInt(DFSConfigKeys.DFS_NAMENODE_SAFEMODE_MIN_DATANODES_KEY, 1);
cluster.restartNameNode(0); cluster.restartNameNode(0);
dfs = cluster.getFileSystem();
assertTrue(cluster.getNameNode().isInSafeMode());
// Check .Trash existence, won't be created now
assertFalse(dfs.exists(trashRoot));
// Start a datanode
cluster.startDataNodes(conf, 1, true, null, null);
// Wait long enough for safemode check to retire
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {}
// Check .Trash existence, should be created now // Check .Trash existence, should be created now
assertTrue(dfs.exists(trashRoot)); assertTrue(dfs.exists(trashRoot));
// Check permission // Check permission
@ -2553,4 +2566,6 @@ public class TestDistributedFileSystem {
} }
} }
} }
} }