Skip to content

Commit 05b3337

Browse files
authored
HDFS-15481. Ordered snapshot deletion: garbage collect deleted snapshots (#2165)
1 parent e0c9653 commit 05b3337

File tree

15 files changed

+517
-53
lines changed

15 files changed

+517
-53
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSConfigKeys.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,11 +502,6 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
502502
"dfs.namenode.snapshot.max.limit";
503503
public static final int DFS_NAMENODE_SNAPSHOT_MAX_LIMIT_DEFAULT = 65536;
504504

505-
public static final String DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED =
506-
"dfs.namenode.snapshot.deletion.ordered";
507-
public static final boolean DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED_DEFAULT
508-
= false;
509-
510505
public static final String DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL =
511506
"dfs.namenode.snapshot.skiplist.interval";
512507
public static final int DFS_NAMENODE_SNAPSHOT_SKIPLIST_SKIP_INTERVAL_DEFAULT =

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/HdfsServerConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ enum BlockUCState {
366366
"security.hdfs.unreadable.by.superuser";
367367
String XATTR_ERASURECODING_POLICY =
368368
"system.hdfs.erasurecoding.policy";
369-
String SNAPSHOT_XATTR_NAME = "system.hdfs.snapshot.deleted";
369+
String XATTR_SNAPSHOT_DELETED = "system.hdfs.snapshot.deleted";
370370

371371
String XATTR_SATISFY_STORAGE_POLICY = "user.hdfs.sps";
372372

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.SECURITY_XATTR_UNREADABLE_BY_SUPERUSER;
4545
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SATISFY_STORAGE_POLICY;
4646
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.CRYPTO_XATTR_FILE_ENCRYPTION_INFO;
47-
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.SNAPSHOT_XATTR_NAME;
47+
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SNAPSHOT_DELETED;
4848
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.CRYPTO_XATTR_ENCRYPTION_ZONE;
4949

5050
public class FSDirXAttrOp {
@@ -328,10 +328,10 @@ public static INode unprotectedSetXAttrs(
328328
SECURITY_XATTR_UNREADABLE_BY_SUPERUSER + "' on a file.");
329329
}
330330

331-
if (xaName.equals(SNAPSHOT_XATTR_NAME) && !(inode.isDirectory() &&
331+
if (xaName.equals(XATTR_SNAPSHOT_DELETED) && !(inode.isDirectory() &&
332332
inode.getParent().isSnapshottable())) {
333333
throw new IOException("Can only set '" +
334-
SNAPSHOT_XATTR_NAME + "' on a snapshot root.");
334+
XATTR_SNAPSHOT_DELETED + "' on a snapshot root.");
335335
}
336336
}
337337

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

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ private static INodeDirectory createRoot(FSNamesystem namesystem) {
187187
private boolean posixAclInheritanceEnabled;
188188
private final boolean xattrsEnabled;
189189
private final int xattrMaxSize;
190-
private final boolean snapshotDeletionOrdered;
191190

192191
// precision of access times.
193192
private final long accessTimePrecision;
@@ -354,12 +353,6 @@ public enum DirOp {
354353
+ " hard limit " + DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_HARD_LIMIT
355354
+ ": (%s).", DFSConfigKeys.DFS_NAMENODE_MAX_XATTR_SIZE_KEY);
356355

357-
this.snapshotDeletionOrdered =
358-
conf.getBoolean(DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED,
359-
DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED_DEFAULT);
360-
LOG.info("{} = {}", DFSConfigKeys.DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED,
361-
snapshotDeletionOrdered);
362-
363356
this.accessTimePrecision = conf.getLong(
364357
DFS_NAMENODE_ACCESSTIME_PRECISION_KEY,
365358
DFS_NAMENODE_ACCESSTIME_PRECISION_DEFAULT);
@@ -618,10 +611,6 @@ boolean isXattrsEnabled() {
618611
}
619612
int getXattrMaxSize() { return xattrMaxSize; }
620613

621-
public boolean isSnapshotDeletionOrdered() {
622-
return snapshotDeletionOrdered;
623-
}
624-
625614
boolean isAccessTimeSupported() {
626615
return accessTimePrecision > 0;
627616
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicyInfo;
110110

111111
import com.google.common.collect.Maps;
112+
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotDeletionGc;
112113
import org.apache.hadoop.thirdparty.protobuf.ByteString;
113114
import org.apache.hadoop.hdfs.protocol.BatchedDirectoryListing;
114115
import org.apache.hadoop.hdfs.protocol.HdfsPartialListing;
@@ -493,6 +494,7 @@ private void logAuditEvent(boolean succeeded,
493494
FSDirectory dir;
494495
private BlockManager blockManager;
495496
private final SnapshotManager snapshotManager;
497+
private final SnapshotDeletionGc snapshotDeletionGc;
496498
private final CacheManager cacheManager;
497499
private final DatanodeStatistics datanodeStatistics;
498500

@@ -974,6 +976,9 @@ static FSNamesystem loadFromDisk(Configuration conf) throws IOException {
974976
this.dtSecretManager = createDelegationTokenSecretManager(conf);
975977
this.dir = new FSDirectory(this, conf);
976978
this.snapshotManager = new SnapshotManager(conf, dir);
979+
this.snapshotDeletionGc = snapshotManager.isSnapshotDeletionOrdered()?
980+
new SnapshotDeletionGc(this, conf): null;
981+
977982
this.cacheManager = new CacheManager(this, conf, blockManager);
978983
// Init ErasureCodingPolicyManager instance.
979984
ErasureCodingPolicyManager.getInstance().init(conf);
@@ -1360,6 +1365,10 @@ void startActiveServices() throws IOException {
13601365
dir.enableQuotaChecks();
13611366
dir.ezManager.startReencryptThreads();
13621367

1368+
if (snapshotDeletionGc != null) {
1369+
snapshotDeletionGc.schedule();
1370+
}
1371+
13631372
if (haEnabled) {
13641373
// Renew all of the leases before becoming active.
13651374
// This is because, while we were in standby mode,
@@ -5480,6 +5489,9 @@ private void registerMBean() {
54805489
* Shutdown FSNamesystem.
54815490
*/
54825491
void shutdown() {
5492+
if (snapshotDeletionGc != null) {
5493+
snapshotDeletionGc.cancel();
5494+
}
54835495
if (snapshotManager != null) {
54845496
snapshotManager.shutdown();
54855497
}
@@ -7198,6 +7210,30 @@ void deleteSnapshot(String snapshotRoot, String snapshotName,
71987210
logAuditEvent(true, operationName, rootPath, null, null);
71997211
}
72007212

7213+
public void gcDeletedSnapshot(String snapshotRoot, String snapshotName)
7214+
throws IOException {
7215+
final String operationName = "gcDeletedSnapshot";
7216+
String rootPath = null;
7217+
final INode.BlocksMapUpdateInfo blocksToBeDeleted;
7218+
7219+
checkOperation(OperationCategory.WRITE);
7220+
writeLock();
7221+
try {
7222+
checkOperation(OperationCategory.WRITE);
7223+
rootPath = Snapshot.getSnapshotPath(snapshotRoot, snapshotName);
7224+
checkNameNodeSafeMode("Cannot gcDeletedSnapshot for " + rootPath);
7225+
7226+
final long now = Time.now();
7227+
final INodesInPath iip = dir.resolvePath(null, snapshotRoot, DirOp.WRITE);
7228+
snapshotManager.assertMarkedAsDeleted(iip, snapshotName);
7229+
blocksToBeDeleted = FSDirSnapshotOp.deleteSnapshot(
7230+
dir, snapshotManager, iip, snapshotName, now);
7231+
} finally {
7232+
writeUnlock(operationName, getLockReportInfoSupplier(rootPath));
7233+
}
7234+
removeBlocks(blocksToBeDeleted);
7235+
}
7236+
72017237
/**
72027238
* Remove a list of INodeDirectorySnapshottable from the SnapshotManager
72037239
* @param toRemove the list of INodeDirectorySnapshottable to be removed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectoryWithSnapshotFeature;
3939
import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectoryWithSnapshotFeature.DirectoryDiffList;
4040
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
41+
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager;
4142
import org.apache.hadoop.hdfs.util.ReadOnlyList;
4243

4344
import com.google.common.annotations.VisibleForTesting;
@@ -294,11 +295,11 @@ public Snapshot addSnapshot(int id, String name,
294295
* @param snapshotName Name of the snapshot.
295296
* @param mtime The snapshot deletion time set by Time.now().
296297
*/
297-
public Snapshot removeSnapshot(
298-
ReclaimContext reclaimContext, String snapshotName, long mtime)
298+
public Snapshot removeSnapshot(ReclaimContext reclaimContext,
299+
String snapshotName, long mtime, SnapshotManager snapshotManager)
299300
throws SnapshotException {
300301
return getDirectorySnapshottableFeature().removeSnapshot(
301-
reclaimContext, this, snapshotName, mtime);
302+
reclaimContext, this, snapshotName, mtime, snapshotManager);
302303
}
303304

304305
/**

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ final void addFirst(D diff) {
133133
diff.setPosterior(first);
134134
}
135135

136+
/** @return the first diff. */
137+
final D getFirst() {
138+
return diffs == null || diffs.isEmpty()? null: diffs.get(0);
139+
}
140+
141+
/** @return the first snapshot INode. */
142+
final A getFirstSnapshotINode() {
143+
final D first = getFirst();
144+
return first == null? null: first.getSnapshotINode();
145+
}
146+
136147
/** @return the last diff. */
137148
public final D getLast() {
138149
if (diffs == null) {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ public Snapshot addSnapshot(INodeDirectory snapshotRoot, int id, String name,
239239
*/
240240
public Snapshot removeSnapshot(
241241
INode.ReclaimContext reclaimContext, INodeDirectory snapshotRoot,
242-
String snapshotName, long now) throws SnapshotException {
242+
String snapshotName, long now, SnapshotManager snapshotManager)
243+
throws SnapshotException {
243244
final int i = searchSnapshot(DFSUtil.string2Bytes(snapshotName));
244245
if (i < 0) {
245246
throw new SnapshotException("Cannot delete snapshot " + snapshotName
@@ -248,6 +249,7 @@ public Snapshot removeSnapshot(
248249
} else {
249250
final Snapshot snapshot = snapshotsByNames.get(i);
250251
int prior = Snapshot.findLatestSnapshot(snapshotRoot, snapshot.getId());
252+
snapshotManager.assertPrior(snapshotRoot, snapshotName, prior);
251253
snapshotRoot.cleanSubtree(reclaimContext, snapshot.getId(), prior);
252254
// remove from snapshotsByNames after successfully cleaning the subtree
253255
snapshotsByNames.remove(i);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ public void serializeSnapshotSection(OutputStream out) throws IOException {
438438
.setSnapshotCounter(sm.getSnapshotCounter())
439439
.setNumSnapshots(sm.getNumSnapshots());
440440

441-
INodeDirectory[] snapshottables = sm.getSnapshottableDirs();
441+
final List<INodeDirectory> snapshottables = sm.getSnapshottableDirs();
442442
for (INodeDirectory sdir : snapshottables) {
443443
b.addSnapshottableDir(sdir.getId());
444444
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040

4141
import org.apache.hadoop.security.AccessControlException;
4242

43+
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SNAPSHOT_DELETED;
44+
4345
/** Snapshot of a sub-tree in the namesystem. */
4446
@InterfaceAudience.Private
4547
public class Snapshot implements Comparable<byte[]> {
@@ -156,6 +158,11 @@ static public class Root extends INodeDirectory {
156158
}).collect(Collectors.toList()).toArray(new Feature[0]));
157159
}
158160

161+
boolean isMarkedAsDeleted() {
162+
final XAttrFeature f = getXAttrFeature();
163+
return f != null && f.getXAttr(XATTR_SNAPSHOT_DELETED) != null;
164+
}
165+
159166
@Override
160167
public ReadOnlyList<INode> getChildrenList(int snapshotId) {
161168
return getParent().getChildrenList(snapshotId);

0 commit comments

Comments
 (0)