HDFS-15054. Delete Snapshot not updating new modification time. Contributed by hemanthboyina.
This commit is contained in:
parent
df622cf4a3
commit
300505c562
@ -253,9 +253,11 @@ static INode.BlocksMapUpdateInfo deleteSnapshot(
|
|||||||
ChunkedArrayList<INode> removedINodes = new ChunkedArrayList<>();
|
ChunkedArrayList<INode> removedINodes = new ChunkedArrayList<>();
|
||||||
INode.ReclaimContext context = new INode.ReclaimContext(
|
INode.ReclaimContext context = new INode.ReclaimContext(
|
||||||
fsd.getBlockStoragePolicySuite(), collectedBlocks, removedINodes, null);
|
fsd.getBlockStoragePolicySuite(), collectedBlocks, removedINodes, null);
|
||||||
|
// time of snapshot deletion
|
||||||
|
final long now = Time.now();
|
||||||
fsd.writeLock();
|
fsd.writeLock();
|
||||||
try {
|
try {
|
||||||
snapshotManager.deleteSnapshot(iip, snapshotName, context);
|
snapshotManager.deleteSnapshot(iip, snapshotName, context, now);
|
||||||
fsd.updateCount(iip, context.quotaDelta(), false);
|
fsd.updateCount(iip, context.quotaDelta(), false);
|
||||||
fsd.removeFromInodeMap(removedINodes);
|
fsd.removeFromInodeMap(removedINodes);
|
||||||
fsd.updateReplicationFactor(context.collectedBlocks()
|
fsd.updateReplicationFactor(context.collectedBlocks()
|
||||||
@ -265,7 +267,7 @@ static INode.BlocksMapUpdateInfo deleteSnapshot(
|
|||||||
}
|
}
|
||||||
removedINodes.clear();
|
removedINodes.clear();
|
||||||
fsd.getEditLog().logDeleteSnapshot(snapshotRoot, snapshotName,
|
fsd.getEditLog().logDeleteSnapshot(snapshotRoot, snapshotName,
|
||||||
logRetryCache);
|
logRetryCache, now);
|
||||||
|
|
||||||
return collectedBlocks;
|
return collectedBlocks;
|
||||||
}
|
}
|
||||||
|
@ -1133,9 +1133,18 @@ void logCreateSnapshot(String snapRoot, String snapName, boolean toLogRpcIds,
|
|||||||
logEdit(op);
|
logEdit(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logDeleteSnapshot(String snapRoot, String snapName, boolean toLogRpcIds) {
|
/**
|
||||||
|
* Log that a snapshot is deleted.
|
||||||
|
* @param snapRoot Root of the snapshot.
|
||||||
|
* @param snapName Name of the snapshot.
|
||||||
|
* @param toLogRpcIds If it is logging RPC ids.
|
||||||
|
* @param mtime The snapshot deletion time set by Time.now().
|
||||||
|
*/
|
||||||
|
void logDeleteSnapshot(String snapRoot, String snapName, boolean toLogRpcIds,
|
||||||
|
long mtime) {
|
||||||
DeleteSnapshotOp op = DeleteSnapshotOp.getInstance(cache.get())
|
DeleteSnapshotOp op = DeleteSnapshotOp.getInstance(cache.get())
|
||||||
.setSnapshotRoot(snapRoot).setSnapshotName(snapName);
|
.setSnapshotRoot(snapRoot).setSnapshotName(snapName)
|
||||||
|
.setSnapshotMTime(mtime);
|
||||||
logRpcIds(op, toLogRpcIds);
|
logRpcIds(op, toLogRpcIds);
|
||||||
logEdit(op);
|
logEdit(op);
|
||||||
}
|
}
|
||||||
|
@ -820,7 +820,7 @@ private long applyEditLogOp(FSEditLogOp op, FSDirectory fsDir,
|
|||||||
fsNamesys.getSnapshotManager().deleteSnapshot(iip,
|
fsNamesys.getSnapshotManager().deleteSnapshot(iip,
|
||||||
deleteSnapshotOp.snapshotName,
|
deleteSnapshotOp.snapshotName,
|
||||||
new INode.ReclaimContext(fsNamesys.dir.getBlockStoragePolicySuite(),
|
new INode.ReclaimContext(fsNamesys.dir.getBlockStoragePolicySuite(),
|
||||||
collectedBlocks, removedINodes, null));
|
collectedBlocks, removedINodes, null), deleteSnapshotOp.mtime);
|
||||||
fsNamesys.getBlockManager().removeBlocksAndUpdateSafemodeTotal(
|
fsNamesys.getBlockManager().removeBlocksAndUpdateSafemodeTotal(
|
||||||
collectedBlocks);
|
collectedBlocks);
|
||||||
collectedBlocks.clear();
|
collectedBlocks.clear();
|
||||||
|
@ -3529,6 +3529,8 @@ public String toString() {
|
|||||||
static class DeleteSnapshotOp extends FSEditLogOp {
|
static class DeleteSnapshotOp extends FSEditLogOp {
|
||||||
String snapshotRoot;
|
String snapshotRoot;
|
||||||
String snapshotName;
|
String snapshotName;
|
||||||
|
/** Modification time of the edit set by Time.now(). */
|
||||||
|
long mtime;
|
||||||
|
|
||||||
DeleteSnapshotOp() {
|
DeleteSnapshotOp() {
|
||||||
super(OP_DELETE_SNAPSHOT);
|
super(OP_DELETE_SNAPSHOT);
|
||||||
@ -3542,22 +3544,32 @@ static DeleteSnapshotOp getInstance(OpInstanceCache cache) {
|
|||||||
void resetSubFields() {
|
void resetSubFields() {
|
||||||
snapshotRoot = null;
|
snapshotRoot = null;
|
||||||
snapshotName = null;
|
snapshotName = null;
|
||||||
|
mtime = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the name of the snapshot. */
|
||||||
DeleteSnapshotOp setSnapshotName(String snapName) {
|
DeleteSnapshotOp setSnapshotName(String snapName) {
|
||||||
this.snapshotName = snapName;
|
this.snapshotName = snapName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the directory path where the snapshot is taken. */
|
||||||
DeleteSnapshotOp setSnapshotRoot(String snapRoot) {
|
DeleteSnapshotOp setSnapshotRoot(String snapRoot) {
|
||||||
snapshotRoot = snapRoot;
|
snapshotRoot = snapRoot;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The snapshot deletion time set by Time.now(). */
|
||||||
|
DeleteSnapshotOp setSnapshotMTime(long mTime) {
|
||||||
|
this.mtime = mTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void readFields(DataInputStream in, int logVersion) throws IOException {
|
void readFields(DataInputStream in, int logVersion) throws IOException {
|
||||||
snapshotRoot = FSImageSerialization.readString(in);
|
snapshotRoot = FSImageSerialization.readString(in);
|
||||||
snapshotName = FSImageSerialization.readString(in);
|
snapshotName = FSImageSerialization.readString(in);
|
||||||
|
mtime = FSImageSerialization.readLong(in);
|
||||||
|
|
||||||
// read RPC ids if necessary
|
// read RPC ids if necessary
|
||||||
readRpcIds(in, logVersion);
|
readRpcIds(in, logVersion);
|
||||||
@ -3567,6 +3579,7 @@ void readFields(DataInputStream in, int logVersion) throws IOException {
|
|||||||
public void writeFields(DataOutputStream out) throws IOException {
|
public void writeFields(DataOutputStream out) throws IOException {
|
||||||
FSImageSerialization.writeString(snapshotRoot, out);
|
FSImageSerialization.writeString(snapshotRoot, out);
|
||||||
FSImageSerialization.writeString(snapshotName, out);
|
FSImageSerialization.writeString(snapshotName, out);
|
||||||
|
FSImageSerialization.writeLong(mtime, out);
|
||||||
writeRpcIds(rpcClientId, rpcCallId, out);
|
writeRpcIds(rpcClientId, rpcCallId, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3574,6 +3587,7 @@ public void writeFields(DataOutputStream out) throws IOException {
|
|||||||
protected void toXml(ContentHandler contentHandler) throws SAXException {
|
protected void toXml(ContentHandler contentHandler) throws SAXException {
|
||||||
XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
|
XMLUtils.addSaxString(contentHandler, "SNAPSHOTROOT", snapshotRoot);
|
||||||
XMLUtils.addSaxString(contentHandler, "SNAPSHOTNAME", snapshotName);
|
XMLUtils.addSaxString(contentHandler, "SNAPSHOTNAME", snapshotName);
|
||||||
|
XMLUtils.addSaxString(contentHandler, "MTIME", Long.toString(mtime));
|
||||||
appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
|
appendRpcIdsToXml(contentHandler, rpcClientId, rpcCallId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3581,6 +3595,7 @@ protected void toXml(ContentHandler contentHandler) throws SAXException {
|
|||||||
void fromXml(Stanza st) throws InvalidXmlException {
|
void fromXml(Stanza st) throws InvalidXmlException {
|
||||||
snapshotRoot = st.getValue("SNAPSHOTROOT");
|
snapshotRoot = st.getValue("SNAPSHOTROOT");
|
||||||
snapshotName = st.getValue("SNAPSHOTNAME");
|
snapshotName = st.getValue("SNAPSHOTNAME");
|
||||||
|
this.mtime = Long.parseLong(st.getValue("MTIME"));
|
||||||
|
|
||||||
readRpcIdsFromXml(st);
|
readRpcIdsFromXml(st);
|
||||||
}
|
}
|
||||||
@ -3591,7 +3606,8 @@ public String toString() {
|
|||||||
builder.append("DeleteSnapshotOp [snapshotRoot=")
|
builder.append("DeleteSnapshotOp [snapshotRoot=")
|
||||||
.append(snapshotRoot)
|
.append(snapshotRoot)
|
||||||
.append(", snapshotName=")
|
.append(", snapshotName=")
|
||||||
.append(snapshotName);
|
.append(snapshotName)
|
||||||
|
.append(", mtime=").append(mtime);
|
||||||
appendRpcIdsToString(builder, rpcClientId, rpcCallId);
|
appendRpcIdsToString(builder, rpcClientId, rpcCallId);
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@ -289,11 +289,16 @@ public Snapshot addSnapshot(int id, String name,
|
|||||||
leaseManager, captureOpenFiles, maxSnapshotLimit, mtime);
|
leaseManager, captureOpenFiles, maxSnapshotLimit, mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a snapshot.
|
||||||
|
* @param snapshotName Name of the snapshot.
|
||||||
|
* @param mtime The snapshot deletion time set by Time.now().
|
||||||
|
*/
|
||||||
public Snapshot removeSnapshot(
|
public Snapshot removeSnapshot(
|
||||||
ReclaimContext reclaimContext, String snapshotName)
|
ReclaimContext reclaimContext, String snapshotName, long mtime)
|
||||||
throws SnapshotException {
|
throws SnapshotException {
|
||||||
return getDirectorySnapshottableFeature().removeSnapshot(
|
return getDirectorySnapshottableFeature().removeSnapshot(
|
||||||
reclaimContext, this, snapshotName);
|
reclaimContext, this, snapshotName, mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,12 +233,13 @@ public Snapshot addSnapshot(INodeDirectory snapshotRoot, int id, String name,
|
|||||||
* @param reclaimContext records blocks and inodes that need to be reclaimed
|
* @param reclaimContext records blocks and inodes that need to be reclaimed
|
||||||
* @param snapshotRoot The directory where we take snapshots
|
* @param snapshotRoot The directory where we take snapshots
|
||||||
* @param snapshotName The name of the snapshot to be removed
|
* @param snapshotName The name of the snapshot to be removed
|
||||||
|
* @param now The snapshot deletion time set by Time.now().
|
||||||
* @return The removed snapshot. Null if no snapshot with the given name
|
* @return The removed snapshot. Null if no snapshot with the given name
|
||||||
* exists.
|
* exists.
|
||||||
*/
|
*/
|
||||||
public Snapshot removeSnapshot(
|
public Snapshot removeSnapshot(
|
||||||
INode.ReclaimContext reclaimContext, INodeDirectory snapshotRoot,
|
INode.ReclaimContext reclaimContext, INodeDirectory snapshotRoot,
|
||||||
String snapshotName) throws SnapshotException {
|
String snapshotName, long now) throws SnapshotException {
|
||||||
final int i = searchSnapshot(DFSUtil.string2Bytes(snapshotName));
|
final int i = searchSnapshot(DFSUtil.string2Bytes(snapshotName));
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
throw new SnapshotException("Cannot delete snapshot " + snapshotName
|
throw new SnapshotException("Cannot delete snapshot " + snapshotName
|
||||||
@ -250,6 +251,7 @@ public Snapshot removeSnapshot(
|
|||||||
snapshotRoot.cleanSubtree(reclaimContext, snapshot.getId(), prior);
|
snapshotRoot.cleanSubtree(reclaimContext, snapshot.getId(), prior);
|
||||||
// remove from snapshotsByNames after successfully cleaning the subtree
|
// remove from snapshotsByNames after successfully cleaning the subtree
|
||||||
snapshotsByNames.remove(i);
|
snapshotsByNames.remove(i);
|
||||||
|
snapshotRoot.updateModificationTime(now, Snapshot.CURRENT_STATE_ID);
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,13 +346,14 @@ public String createSnapshot(final LeaseManager leaseManager,
|
|||||||
/**
|
/**
|
||||||
* Delete a snapshot for a snapshottable directory
|
* Delete a snapshot for a snapshottable directory
|
||||||
* @param snapshotName Name of the snapshot to be deleted
|
* @param snapshotName Name of the snapshot to be deleted
|
||||||
|
* @param now is the snapshot deletion time set by Time.now().
|
||||||
* @param reclaimContext Used to collect information to reclaim blocks
|
* @param reclaimContext Used to collect information to reclaim blocks
|
||||||
* and inodes
|
* and inodes
|
||||||
*/
|
*/
|
||||||
public void deleteSnapshot(final INodesInPath iip, final String snapshotName,
|
public void deleteSnapshot(final INodesInPath iip, final String snapshotName,
|
||||||
INode.ReclaimContext reclaimContext) throws IOException {
|
INode.ReclaimContext reclaimContext, long now) throws IOException {
|
||||||
INodeDirectory srcRoot = getSnapshottableRoot(iip);
|
INodeDirectory srcRoot = getSnapshottableRoot(iip);
|
||||||
srcRoot.removeSnapshot(reclaimContext, snapshotName);
|
srcRoot.removeSnapshot(reclaimContext, snapshotName, now);
|
||||||
numSnapshots.getAndDecrement();
|
numSnapshots.getAndDecrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,6 +490,29 @@ public void testRenameSnapshotMtime() throws Exception {
|
|||||||
newSnapshotStatus.getModificationTime());
|
newSnapshotStatus.getModificationTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test snapshot directory mtime after snapshot deletion.
|
||||||
|
*/
|
||||||
|
@Test(timeout = 60000)
|
||||||
|
public void testDeletionSnapshotMtime() throws Exception {
|
||||||
|
Path dir = new Path("/dir");
|
||||||
|
Path sub = new Path(dir, "sub");
|
||||||
|
Path subFile = new Path(sub, "file");
|
||||||
|
DFSTestUtil.createFile(hdfs, subFile, BLOCKSIZE, REPLICATION, seed);
|
||||||
|
|
||||||
|
hdfs.allowSnapshot(dir);
|
||||||
|
Path snapshotPath = hdfs.createSnapshot(dir, "s1");
|
||||||
|
FileStatus oldSnapshotStatus = hdfs.getFileStatus(snapshotPath);
|
||||||
|
hdfs.deleteSnapshot(dir, "s1");
|
||||||
|
FileStatus dirStatus = hdfs.getFileStatus(dir);
|
||||||
|
assertNotEquals(dirStatus.getModificationTime(),
|
||||||
|
oldSnapshotStatus.getModificationTime());
|
||||||
|
cluster.restartNameNodes();
|
||||||
|
FileStatus newSnapshotStatus = hdfs.getFileStatus(dir);
|
||||||
|
assertEquals(dirStatus.getModificationTime(),
|
||||||
|
newSnapshotStatus.getModificationTime());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a list of modifications. A modification may be a file creation,
|
* Prepare a list of modifications. A modification may be a file creation,
|
||||||
* file deletion, or a modification operation such as appending to an existing
|
* file deletion, or a modification operation such as appending to an existing
|
||||||
|
@ -78,7 +78,7 @@ public void testSnapshotLimits() throws Exception {
|
|||||||
|
|
||||||
// Delete a snapshot to free up a slot.
|
// Delete a snapshot to free up a slot.
|
||||||
//
|
//
|
||||||
sm.deleteSnapshot(iip, "", mock(INode.ReclaimContext.class));
|
sm.deleteSnapshot(iip, "", mock(INode.ReclaimContext.class), Time.now());
|
||||||
|
|
||||||
// Attempt to create a snapshot again. It should still fail due
|
// Attempt to create a snapshot again. It should still fail due
|
||||||
// to snapshot ID rollover.
|
// to snapshot ID rollover.
|
||||||
|
Binary file not shown.
@ -299,6 +299,7 @@
|
|||||||
<TXID>24</TXID>
|
<TXID>24</TXID>
|
||||||
<SNAPSHOTROOT>/directory_mkdir</SNAPSHOTROOT>
|
<SNAPSHOTROOT>/directory_mkdir</SNAPSHOTROOT>
|
||||||
<SNAPSHOTNAME>snapshot2</SNAPSHOTNAME>
|
<SNAPSHOTNAME>snapshot2</SNAPSHOTNAME>
|
||||||
|
<MTIME>1512607197720</MTIME>
|
||||||
<RPC_CLIENTID>cab1aa2d-e08a-4d2f-8216-76e167eccd94</RPC_CLIENTID>
|
<RPC_CLIENTID>cab1aa2d-e08a-4d2f-8216-76e167eccd94</RPC_CLIENTID>
|
||||||
<RPC_CALLID>56</RPC_CALLID>
|
<RPC_CALLID>56</RPC_CALLID>
|
||||||
</DATA>
|
</DATA>
|
||||||
|
Loading…
Reference in New Issue
Block a user