HDFS-4727. Update inodeMap after deleting files/directories/snapshots. Contributed by Jing Zhao

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-2802@1470756 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Tsz-wo Sze 2013-04-23 00:00:47 +00:00
parent 43bdc22e92
commit 92e0416ced
18 changed files with 182 additions and 112 deletions

View File

@ -263,3 +263,6 @@ Branch-2802 Snapshot (Unreleased)
HDFS-4726. Fix test failures after merging the INodeId-INode mapping HDFS-4726. Fix test failures after merging the INodeId-INode mapping
from trunk. (Jing Zhao via szetszwo) from trunk. (Jing Zhao via szetszwo)
HDFS-4727. Update inodeMap after deleting files/directories/snapshots.
(Jing Zhao via szetszwo)

View File

@ -928,9 +928,12 @@ boolean unprotectedRenameTo(String src, String dst, long timestamp,
if (removedDst != null) { if (removedDst != null) {
undoRemoveDst = false; undoRemoveDst = false;
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ArrayList<INode>();
filesDeleted = removedDst.cleanSubtree(null, filesDeleted = removedDst.cleanSubtree(null,
dstIIP.getLatestSnapshot(), collectedBlocks).get(Quota.NAMESPACE); dstIIP.getLatestSnapshot(), collectedBlocks, removedINodes).get(
getFSNamesystem().removePathAndBlocks(src, collectedBlocks); Quota.NAMESPACE);
getFSNamesystem().removePathAndBlocks(src, collectedBlocks,
removedINodes);
} }
if (snapshottableDirs.size() > 0) { if (snapshottableDirs.size() > 0) {
@ -1210,10 +1213,11 @@ void unprotectedConcat(String target, String [] srcs, long timestamp)
* *
* @param src Path of a directory to delete * @param src Path of a directory to delete
* @param collectedBlocks Blocks under the deleted directory * @param collectedBlocks Blocks under the deleted directory
* @param removedINodes INodes that should be removed from {@link #inodeMap}
* @return true on successful deletion; else false * @return true on successful deletion; else false
*/ */
boolean delete(String src, BlocksMapUpdateInfo collectedBlocks) boolean delete(String src, BlocksMapUpdateInfo collectedBlocks,
throws IOException { List<INode> removedINodes) throws IOException {
if (NameNode.stateChangeLog.isDebugEnabled()) { if (NameNode.stateChangeLog.isDebugEnabled()) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: " + src); NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: " + src);
} }
@ -1234,7 +1238,8 @@ boolean delete(String src, BlocksMapUpdateInfo collectedBlocks)
List<INodeDirectorySnapshottable> snapshottableDirs = List<INodeDirectorySnapshottable> snapshottableDirs =
new ArrayList<INodeDirectorySnapshottable>(); new ArrayList<INodeDirectorySnapshottable>();
checkSnapshot(targetNode, snapshottableDirs); checkSnapshot(targetNode, snapshottableDirs);
filesRemoved = unprotectedDelete(inodesInPath, collectedBlocks, now); filesRemoved = unprotectedDelete(inodesInPath, collectedBlocks,
removedINodes, now);
if (snapshottableDirs.size() > 0) { if (snapshottableDirs.size() > 0) {
// There are some snapshottable directories without snapshots to be // There are some snapshottable directories without snapshots to be
// deleted. Need to update the SnapshotManager. // deleted. Need to update the SnapshotManager.
@ -1249,8 +1254,8 @@ boolean delete(String src, BlocksMapUpdateInfo collectedBlocks)
} }
fsImage.getEditLog().logDelete(src, now); fsImage.getEditLog().logDelete(src, now);
incrDeletedFileCount(filesRemoved); incrDeletedFileCount(filesRemoved);
// Blocks will be deleted later by the caller of this method // Blocks/INodes will be handled later by the caller of this method
getFSNamesystem().removePathAndBlocks(src, null); getFSNamesystem().removePathAndBlocks(src, null, null);
return true; return true;
} }
@ -1306,13 +1311,16 @@ void unprotectedDelete(String src, long mtime) throws UnresolvedLinkException,
QuotaExceededException, SnapshotAccessControlException { QuotaExceededException, SnapshotAccessControlException {
assert hasWriteLock(); assert hasWriteLock();
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ArrayList<INode>();
final INodesInPath inodesInPath = rootDir.getINodesInPath4Write( final INodesInPath inodesInPath = rootDir.getINodesInPath4Write(
normalizePath(src), false); normalizePath(src), false);
final long filesRemoved = deleteAllowed(inodesInPath, src)? final long filesRemoved = deleteAllowed(inodesInPath, src) ?
unprotectedDelete(inodesInPath, collectedBlocks, mtime): -1; unprotectedDelete(inodesInPath, collectedBlocks,
removedINodes, mtime) : -1;
if (filesRemoved >= 0) { if (filesRemoved >= 0) {
getFSNamesystem().removePathAndBlocks(src, collectedBlocks); getFSNamesystem().removePathAndBlocks(src, collectedBlocks,
removedINodes);
} }
} }
@ -1321,11 +1329,12 @@ void unprotectedDelete(String src, long mtime) throws UnresolvedLinkException,
* Update the count at each ancestor directory with quota * Update the count at each ancestor directory with quota
* @param iip the inodes resolved from the path * @param iip the inodes resolved from the path
* @param collectedBlocks blocks collected from the deleted path * @param collectedBlocks blocks collected from the deleted path
* @param removedINodes inodes that should be removed from {@link #inodeMap}
* @param mtime the time the inode is removed * @param mtime the time the inode is removed
* @return the number of inodes deleted; 0 if no inodes are deleted. * @return the number of inodes deleted; 0 if no inodes are deleted.
*/ */
long unprotectedDelete(INodesInPath iip, BlocksMapUpdateInfo collectedBlocks, long unprotectedDelete(INodesInPath iip, BlocksMapUpdateInfo collectedBlocks,
long mtime) throws QuotaExceededException { List<INode> removedINodes, long mtime) throws QuotaExceededException {
assert hasWriteLock(); assert hasWriteLock();
// check if target node exists // check if target node exists
@ -1354,11 +1363,10 @@ long unprotectedDelete(INodesInPath iip, BlocksMapUpdateInfo collectedBlocks,
// collect block // collect block
if (!targetNode.isInLatestSnapshot(latestSnapshot)) { if (!targetNode.isInLatestSnapshot(latestSnapshot)) {
targetNode.destroyAndCollectBlocks(collectedBlocks); targetNode.destroyAndCollectBlocks(collectedBlocks, removedINodes);
remvoedAllFromInodesFromMap(targetNode);
} else { } else {
Quota.Counts counts = targetNode.cleanSubtree(null, latestSnapshot, Quota.Counts counts = targetNode.cleanSubtree(null, latestSnapshot,
collectedBlocks); collectedBlocks, removedINodes);
parent.addSpaceConsumed(-counts.get(Quota.NAMESPACE), parent.addSpaceConsumed(-counts.get(Quota.NAMESPACE),
-counts.get(Quota.DISKSPACE), true); -counts.get(Quota.DISKSPACE), true);
removed = counts.get(Quota.NAMESPACE); removed = counts.get(Quota.NAMESPACE);
@ -2184,7 +2192,6 @@ private long removeLastINode(final INodesInPath iip)
if (!parent.removeChild(last, latestSnapshot)) { if (!parent.removeChild(last, latestSnapshot)) {
return -1; return -1;
} }
inodeMap.remove(last);
if (parent != last.getParent()) { if (parent != last.getParent()) {
// parent is changed // parent is changed
inodeMap.put(last.getParent()); inodeMap.put(last.getParent());
@ -2237,21 +2244,12 @@ final void addToInodeMapUnprotected(INode inode) {
} }
/* This method is always called with writeLock held */ /* This method is always called with writeLock held */
private final void removeFromInodeMap(INode inode) { final void removeFromInodeMap(List<INode> inodes) {
inodeMap.remove(inode); if (inodes != null) {
} for (INode inode : inodes) {
inodeMap.remove(inode);
/** Remove all the inodes under given inode from the map */ }
private void remvoedAllFromInodesFromMap(INode inode) {
removeFromInodeMap(inode);
if (!inode.isDirectory()) {
return;
} }
INodeDirectory dir = (INodeDirectory) inode;
for (INode child : dir.getChildrenList(null)) {
remvoedAllFromInodesFromMap(child);
}
dir.clearChildren();
} }
/** /**
@ -2584,7 +2582,8 @@ INode recordModification(Snapshot latest) throws QuotaExceededException {
} }
@Override @Override
public void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks) { public void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks,
List<INode> removedINodes) {
// Nothing to do // Nothing to do
} }
@ -2605,7 +2604,8 @@ public CountsMap computeContentSummary(CountsMap countsMap) {
@Override @Override
public Counts cleanSubtree(Snapshot snapshot, Snapshot prior, public Counts cleanSubtree(Snapshot snapshot, Snapshot prior,
BlocksMapUpdateInfo collectedBlocks) throws QuotaExceededException { BlocksMapUpdateInfo collectedBlocks, List<INode> removedINodes)
throws QuotaExceededException {
return null; return null;
} }
}; };

View File

@ -22,8 +22,10 @@
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -520,11 +522,14 @@ private long applyEditLogOp(FSEditLogOp op, FSDirectory fsDir,
case OP_DELETE_SNAPSHOT: { case OP_DELETE_SNAPSHOT: {
DeleteSnapshotOp deleteSnapshotOp = (DeleteSnapshotOp) op; DeleteSnapshotOp deleteSnapshotOp = (DeleteSnapshotOp) op;
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ArrayList<INode>();
fsNamesys.getSnapshotManager().deleteSnapshot( fsNamesys.getSnapshotManager().deleteSnapshot(
deleteSnapshotOp.snapshotRoot, deleteSnapshotOp.snapshotName, deleteSnapshotOp.snapshotRoot, deleteSnapshotOp.snapshotName,
collectedBlocks); collectedBlocks, removedINodes);
fsNamesys.removeBlocks(collectedBlocks); fsNamesys.removeBlocks(collectedBlocks);
collectedBlocks.clear(); collectedBlocks.clear();
fsNamesys.dir.removeFromInodeMap(removedINodes);
removedINodes.clear();
break; break;
} }
case OP_RENAME_SNAPSHOT: { case OP_RENAME_SNAPSHOT: {

View File

@ -561,7 +561,11 @@ public FSDirectory getFSDirectoryInLoading() {
public INode loadINodeWithLocalName(boolean isSnapshotINode, public INode loadINodeWithLocalName(boolean isSnapshotINode,
DataInput in) throws IOException { DataInput in) throws IOException {
final byte[] localName = FSImageSerialization.readLocalName(in); final byte[] localName = FSImageSerialization.readLocalName(in);
return loadINode(localName, isSnapshotINode, in); INode inode = loadINode(localName, isSnapshotINode, in);
if (LayoutVersion.supports(Feature.ADD_INODE_ID, getLayoutVersion())) {
namesystem.dir.addToInodeMapUnprotected(inode);
}
return inode;
} }
/** /**

View File

@ -2878,6 +2878,7 @@ private boolean deleteInternal(String src, boolean recursive,
throws AccessControlException, SafeModeException, UnresolvedLinkException, throws AccessControlException, SafeModeException, UnresolvedLinkException,
IOException { IOException {
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ArrayList<INode>();
FSPermissionChecker pc = getPermissionChecker(); FSPermissionChecker pc = getPermissionChecker();
checkOperation(OperationCategory.WRITE); checkOperation(OperationCategory.WRITE);
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src); byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
@ -2895,7 +2896,7 @@ private boolean deleteInternal(String src, boolean recursive,
checkPermission(pc, src, false, null, FsAction.WRITE, null, FsAction.ALL); checkPermission(pc, src, false, null, FsAction.WRITE, null, FsAction.ALL);
} }
// Unlink the target directory from directory tree // Unlink the target directory from directory tree
if (!dir.delete(src, collectedBlocks)) { if (!dir.delete(src, collectedBlocks, removedINodes)) {
return false; return false;
} }
} finally { } finally {
@ -2904,6 +2905,8 @@ private boolean deleteInternal(String src, boolean recursive,
getEditLog().logSync(); getEditLog().logSync();
removeBlocks(collectedBlocks); // Incremental deletion of blocks removeBlocks(collectedBlocks); // Incremental deletion of blocks
collectedBlocks.clear(); collectedBlocks.clear();
dir.removeFromInodeMap(removedINodes);
removedINodes.clear();
if (NameNode.stateChangeLog.isDebugEnabled()) { if (NameNode.stateChangeLog.isDebugEnabled()) {
NameNode.stateChangeLog.debug("DIR* Namesystem.delete: " NameNode.stateChangeLog.debug("DIR* Namesystem.delete: "
+ src +" is removed"); + src +" is removed");
@ -2940,13 +2943,21 @@ void removeBlocks(BlocksMapUpdateInfo blocks) {
} }
/** /**
* Remove leases and blocks related to a given path * Remove leases, inodes and blocks related to a given path
* @param src The given path * @param src The given path
* @param blocks Containing the list of blocks to be deleted from blocksMap * @param blocks Containing the list of blocks to be deleted from blocksMap
* @param removedINodes Containing the list of inodes to be removed from
* inodesMap
*/ */
void removePathAndBlocks(String src, BlocksMapUpdateInfo blocks) { void removePathAndBlocks(String src, BlocksMapUpdateInfo blocks,
List<INode> removedINodes) {
assert hasWriteLock(); assert hasWriteLock();
leaseManager.removeLeaseWithPrefixPath(src); leaseManager.removeLeaseWithPrefixPath(src);
// remove inodes from inodesMap
if (removedINodes != null) {
dir.removeFromInodeMap(removedINodes);
removedINodes.clear();
}
if (blocks == null) { if (blocks == null) {
return; return;
} }
@ -6007,13 +6018,16 @@ void deleteSnapshot(String snapshotRoot, String snapshotName)
checkOwner(pc, snapshotRoot); checkOwner(pc, snapshotRoot);
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ArrayList<INode>();
dir.writeLock(); dir.writeLock();
try { try {
snapshotManager.deleteSnapshot(snapshotRoot, snapshotName, snapshotManager.deleteSnapshot(snapshotRoot, snapshotName,
collectedBlocks); collectedBlocks, removedINodes);
dir.removeFromInodeMap(removedINodes);
} finally { } finally {
dir.writeUnlock(); dir.writeUnlock();
} }
removedINodes.clear();
this.removeBlocks(collectedBlocks); this.removeBlocks(collectedBlocks);
collectedBlocks.clear(); collectedBlocks.clear();
getEditLog().logDeleteSnapshot(snapshotRoot, snapshotName); getEditLog().logDeleteSnapshot(snapshotRoot, snapshotName);

View File

@ -329,24 +329,31 @@ public INodeSymlink asSymlink() {
* @param collectedBlocks * @param collectedBlocks
* blocks collected from the descents for further block * blocks collected from the descents for further block
* deletion/update will be added to the given map. * deletion/update will be added to the given map.
* @param removedINodes
* INodes collected from the descents for further cleaning up of
* inodeMap
* @return quota usage delta when deleting a snapshot * @return quota usage delta when deleting a snapshot
*/ */
public abstract Quota.Counts cleanSubtree(final Snapshot snapshot, public abstract Quota.Counts cleanSubtree(final Snapshot snapshot,
Snapshot prior, BlocksMapUpdateInfo collectedBlocks) Snapshot prior, BlocksMapUpdateInfo collectedBlocks,
throws QuotaExceededException; List<INode> removedINodes) throws QuotaExceededException;
/** /**
* Destroy self and clear everything! If the INode is a file, this method * Destroy self and clear everything! If the INode is a file, this method
* collects its blocks for further block deletion. If the INode is a * collects its blocks for further block deletion. If the INode is a
* directory, the method goes down the subtree and collects blocks from the * directory, the method goes down the subtree and collects blocks from the
* descents, and clears its parent/children references as well. The method * descents, and clears its parent/children references as well. The method
* also clears the diff list if the INode contains snapshot diff list. * also clears the diff list if the INode contains snapshot diff list.
* *
* @param collectedBlocks blocks collected from the descents for further block * @param collectedBlocks
* deletion/update will be added to this map. * blocks collected from the descents for further block
* deletion/update will be added to this map.
* @param removedINodes
* INodes collected from the descents for further cleaning up of
* inodeMap
*/ */
public abstract void destroyAndCollectBlocks( public abstract void destroyAndCollectBlocks(
BlocksMapUpdateInfo collectedBlocks); BlocksMapUpdateInfo collectedBlocks, List<INode> removedINodes);
/** Compute {@link ContentSummary}. */ /** Compute {@link ContentSummary}. */
public final ContentSummary computeContentSummary() { public final ContentSummary computeContentSummary() {

View File

@ -488,8 +488,8 @@ public void clear() {
* recursively down the subtree. * recursively down the subtree.
*/ */
public Quota.Counts cleanSubtreeRecursively(final Snapshot snapshot, public Quota.Counts cleanSubtreeRecursively(final Snapshot snapshot,
Snapshot prior, final BlocksMapUpdateInfo collectedBlocks) Snapshot prior, final BlocksMapUpdateInfo collectedBlocks,
throws QuotaExceededException { final List<INode> removedINodes) throws QuotaExceededException {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
// in case of deletion snapshot, since this call happens after we modify // in case of deletion snapshot, since this call happens after we modify
// the diff list, the snapshot to be deleted has been combined or renamed // the diff list, the snapshot to be deleted has been combined or renamed
@ -499,36 +499,36 @@ public Quota.Counts cleanSubtreeRecursively(final Snapshot snapshot,
Snapshot s = snapshot != null && prior != null ? prior : snapshot; Snapshot s = snapshot != null && prior != null ? prior : snapshot;
for (INode child : getChildrenList(s)) { for (INode child : getChildrenList(s)) {
Quota.Counts childCounts = child.cleanSubtree(snapshot, prior, Quota.Counts childCounts = child.cleanSubtree(snapshot, prior,
collectedBlocks); collectedBlocks, removedINodes);
counts.add(childCounts); counts.add(childCounts);
} }
return counts; return counts;
} }
@Override @Override
public void destroyAndCollectBlocks( public void destroyAndCollectBlocks(final BlocksMapUpdateInfo collectedBlocks,
final BlocksMapUpdateInfo collectedBlocks) { final List<INode> removedINodes) {
for (INode child : getChildrenList(null)) { for (INode child : getChildrenList(null)) {
child.destroyAndCollectBlocks(collectedBlocks); child.destroyAndCollectBlocks(collectedBlocks, removedINodes);
} }
// TODO: Need to update the cleanSubtree/destroy methods to clean inode map
clear(); clear();
removedINodes.add(this);
} }
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) final BlocksMapUpdateInfo collectedBlocks,
throws QuotaExceededException { final List<INode> removedINodes) throws QuotaExceededException {
if (prior == null && snapshot == null) { if (prior == null && snapshot == null) {
// destroy the whole subtree and collect blocks that should be deleted // destroy the whole subtree and collect blocks that should be deleted
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
this.computeQuotaUsage(counts, true); this.computeQuotaUsage(counts, true);
destroyAndCollectBlocks(collectedBlocks); destroyAndCollectBlocks(collectedBlocks, removedINodes);
return counts; return counts;
} else { } else {
// process recursively down the subtree // process recursively down the subtree
Quota.Counts counts = cleanSubtreeRecursively(snapshot, prior, Quota.Counts counts = cleanSubtreeRecursively(snapshot, prior,
collectedBlocks); collectedBlocks, removedINodes);
if (isQuotaSet()) { if (isQuotaSet()) {
((INodeDirectoryWithQuota) this).addSpaceConsumed2Cache( ((INodeDirectoryWithQuota) this).addSpaceConsumed2Cache(
-counts.get(Quota.NAMESPACE), -counts.get(Quota.DISKSPACE)); -counts.get(Quota.NAMESPACE), -counts.get(Quota.DISKSPACE));

View File

@ -20,6 +20,7 @@
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsAction;
@ -291,19 +292,20 @@ public void setBlocks(BlockInfo[] blocks) {
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
throws QuotaExceededException { throws QuotaExceededException {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
if (snapshot == null && prior == null) { if (snapshot == null && prior == null) {
// this only happens when deleting the current file // this only happens when deleting the current file
computeQuotaUsage(counts, false); computeQuotaUsage(counts, false);
destroyAndCollectBlocks(collectedBlocks); destroyAndCollectBlocks(collectedBlocks, removedINodes);
} }
return counts; return counts;
} }
@Override @Override
public void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks) { public void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
if (blocks != null && collectedBlocks != null) { if (blocks != null && collectedBlocks != null) {
for (BlockInfo blk : blocks) { for (BlockInfo blk : blocks) {
collectedBlocks.addDeleteBlock(blk); collectedBlocks.addDeleteBlock(blk);
@ -312,6 +314,7 @@ public void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks) {
} }
setBlocks(null); setBlocks(null);
clear(); clear();
removedINodes.add(this);
if (this instanceof FileWithSnapshot) { if (this instanceof FileWithSnapshot) {
((FileWithSnapshot) this).getDiffs().clear(); ((FileWithSnapshot) this).getDiffs().clear();

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hdfs.server.namenode; package org.apache.hadoop.hdfs.server.namenode;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List;
import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.PermissionStatus; import org.apache.hadoop.fs.permission.PermissionStatus;
@ -222,14 +223,17 @@ final INode recordModification(Snapshot latest) throws QuotaExceededException {
@Override @Override
public final Quota.Counts cleanSubtree(Snapshot snapshot, Snapshot prior, public final Quota.Counts cleanSubtree(Snapshot snapshot, Snapshot prior,
BlocksMapUpdateInfo collectedBlocks) throws QuotaExceededException { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
return referred.cleanSubtree(snapshot, prior, collectedBlocks); throws QuotaExceededException {
return referred.cleanSubtree(snapshot, prior, collectedBlocks,
removedINodes);
} }
@Override @Override
public final void destroyAndCollectBlocks(BlocksMapUpdateInfo collectedBlocks) { public final void destroyAndCollectBlocks(
BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
if (removeReference(this) <= 0) { if (removeReference(this) <= 0) {
referred.destroyAndCollectBlocks(collectedBlocks); referred.destroyAndCollectBlocks(collectedBlocks, removedINodes);
} }
} }

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hdfs.server.namenode; package org.apache.hadoop.hdfs.server.namenode;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.fs.permission.PermissionStatus; import org.apache.hadoop.fs.permission.PermissionStatus;
@ -73,14 +74,17 @@ public byte[] getSymlink() {
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) { final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
if (snapshot == null && prior == null) {
destroyAndCollectBlocks(collectedBlocks, removedINodes);
}
return Quota.Counts.newInstance(1, 0); return Quota.Counts.newInstance(1, 0);
} }
@Override @Override
public void destroyAndCollectBlocks( public void destroyAndCollectBlocks(final BlocksMapUpdateInfo collectedBlocks,
final BlocksMapUpdateInfo collectedBlocks) { final List<INode> removedINodes) {
// do nothing removedINodes.add(this);
} }
@Override @Override

View File

@ -19,6 +19,7 @@
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.apache.hadoop.hdfs.server.namenode.INode; import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo; import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
@ -128,7 +129,8 @@ N getSnapshotINode() {
/** Combine the posterior diff and collect blocks for deletion. */ /** Combine the posterior diff and collect blocks for deletion. */
abstract Quota.Counts combinePosteriorAndCollectBlocks(final N currentINode, abstract Quota.Counts combinePosteriorAndCollectBlocks(final N currentINode,
final D posterior, final BlocksMapUpdateInfo collectedBlocks); final D posterior, final BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes);
/** /**
* Delete and clear self. * Delete and clear self.
@ -137,7 +139,7 @@ abstract Quota.Counts combinePosteriorAndCollectBlocks(final N currentINode,
* @return quota usage delta * @return quota usage delta
*/ */
abstract Quota.Counts destroyDiffAndCollectBlocks(final N currentINode, abstract Quota.Counts destroyDiffAndCollectBlocks(final N currentINode,
final BlocksMapUpdateInfo collectedBlocks); final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes);
@Override @Override
public String toString() { public String toString() {

View File

@ -68,7 +68,7 @@ public void clear() {
*/ */
final Quota.Counts deleteSnapshotDiff(final Snapshot snapshot, final Quota.Counts deleteSnapshotDiff(final Snapshot snapshot,
Snapshot prior, final N currentINode, Snapshot prior, final N currentINode,
final BlocksMapUpdateInfo collectedBlocks) { final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
int snapshotIndex = Collections.binarySearch(diffs, snapshot); int snapshotIndex = Collections.binarySearch(diffs, snapshot);
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
@ -81,7 +81,7 @@ final Quota.Counts deleteSnapshotDiff(final Snapshot snapshot,
removed = diffs.remove(0); removed = diffs.remove(0);
counts.add(Quota.NAMESPACE, 1); counts.add(Quota.NAMESPACE, 1);
counts.add(removed.destroyDiffAndCollectBlocks(currentINode, counts.add(removed.destroyDiffAndCollectBlocks(currentINode,
collectedBlocks)); collectedBlocks, removedINodes));
} }
} else if (snapshotIndex > 0) { } else if (snapshotIndex > 0) {
final AbstractINodeDiff<N, D> previous = diffs.get(snapshotIndex - 1); final AbstractINodeDiff<N, D> previous = diffs.get(snapshotIndex - 1);
@ -97,7 +97,7 @@ final Quota.Counts deleteSnapshotDiff(final Snapshot snapshot,
removed.snapshotINode.clear(); removed.snapshotINode.clear();
} }
counts.add(previous.combinePosteriorAndCollectBlocks( counts.add(previous.combinePosteriorAndCollectBlocks(
currentINode, removed, collectedBlocks)); currentINode, removed, collectedBlocks, removedINodes));
previous.setPosterior(removed.getPosterior()); previous.setPosterior(removed.getPosterior());
removed.setPosterior(null); removed.setPosterior(null);
} }

View File

@ -19,11 +19,13 @@
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo; import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization; import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization;
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo; import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INodeFile; import org.apache.hadoop.hdfs.server.namenode.INodeFile;
import org.apache.hadoop.hdfs.server.namenode.Quota; import org.apache.hadoop.hdfs.server.namenode.Quota;
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap; import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap;
@ -61,7 +63,7 @@ public long getFileSize() {
private static Quota.Counts updateQuotaAndCollectBlocks( private static Quota.Counts updateQuotaAndCollectBlocks(
INodeFile currentINode, FileDiff removed, INodeFile currentINode, FileDiff removed,
BlocksMapUpdateInfo collectedBlocks) { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
FileWithSnapshot sFile = (FileWithSnapshot) currentINode; FileWithSnapshot sFile = (FileWithSnapshot) currentINode;
long oldDiskspace = currentINode.diskspaceConsumed(); long oldDiskspace = currentINode.diskspaceConsumed();
if (removed.snapshotINode != null) { if (removed.snapshotINode != null) {
@ -72,7 +74,7 @@ private static Quota.Counts updateQuotaAndCollectBlocks(
} }
} }
Util.collectBlocksAndClear(sFile, collectedBlocks); Util.collectBlocksAndClear(sFile, collectedBlocks, removedINodes);
long dsDelta = oldDiskspace - currentINode.diskspaceConsumed(); long dsDelta = oldDiskspace - currentINode.diskspaceConsumed();
return Quota.Counts.newInstance(0, dsDelta); return Quota.Counts.newInstance(0, dsDelta);
@ -80,9 +82,10 @@ private static Quota.Counts updateQuotaAndCollectBlocks(
@Override @Override
Quota.Counts combinePosteriorAndCollectBlocks(INodeFile currentINode, Quota.Counts combinePosteriorAndCollectBlocks(INodeFile currentINode,
FileDiff posterior, BlocksMapUpdateInfo collectedBlocks) { FileDiff posterior, BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
return updateQuotaAndCollectBlocks(currentINode, posterior, return updateQuotaAndCollectBlocks(currentINode, posterior,
collectedBlocks); collectedBlocks, removedINodes);
} }
@Override @Override
@ -107,9 +110,9 @@ void write(DataOutput out, ReferenceMap referenceMap) throws IOException {
@Override @Override
Quota.Counts destroyDiffAndCollectBlocks(INodeFile currentINode, Quota.Counts destroyDiffAndCollectBlocks(INodeFile currentINode,
BlocksMapUpdateInfo collectedBlocks) { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
return updateQuotaAndCollectBlocks(currentINode, this, return updateQuotaAndCollectBlocks(currentINode, this,
collectedBlocks); collectedBlocks, removedINodes);
} }
} }
@ -171,11 +174,11 @@ public static short getBlockReplication(final FileWithSnapshot file) {
* any inode, collect them and update the block list. * any inode, collect them and update the block list.
*/ */
static void collectBlocksAndClear(final FileWithSnapshot file, static void collectBlocksAndClear(final FileWithSnapshot file,
final BlocksMapUpdateInfo info) { final BlocksMapUpdateInfo info, final List<INode> removedINodes) {
// check if everything is deleted. // check if everything is deleted.
if (file.isCurrentFileDeleted() if (file.isCurrentFileDeleted()
&& file.getDiffs().asList().isEmpty()) { && file.getDiffs().asList().isEmpty()) {
file.asINodeFile().destroyAndCollectBlocks(info); file.asINodeFile().destroyAndCollectBlocks(info, removedINodes);
return; return;
} }

View File

@ -311,7 +311,8 @@ Snapshot addSnapshot(int id, String name)
* exists. * exists.
*/ */
Snapshot removeSnapshot(String snapshotName, Snapshot removeSnapshot(String snapshotName,
BlocksMapUpdateInfo collectedBlocks) throws SnapshotException { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
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
@ -321,7 +322,8 @@ Snapshot removeSnapshot(String snapshotName,
final Snapshot snapshot = snapshotsByNames.remove(i); final Snapshot snapshot = snapshotsByNames.remove(i);
Snapshot prior = Snapshot.findLatestSnapshot(this, snapshot); Snapshot prior = Snapshot.findLatestSnapshot(this, snapshot);
try { try {
Quota.Counts counts = cleanSubtree(snapshot, prior, collectedBlocks); Quota.Counts counts = cleanSubtree(snapshot, prior, collectedBlocks,
removedINodes);
INodeDirectory parent = getParent(); INodeDirectory parent = getParent();
if (parent != null) { if (parent != null) {
parent.addSpaceConsumed(-counts.get(Quota.NAMESPACE), parent.addSpaceConsumed(-counts.get(Quota.NAMESPACE),

View File

@ -94,12 +94,13 @@ private final boolean removeChild(ListType type, final INode child) {
/** clear the created list */ /** clear the created list */
private Quota.Counts destroyCreatedList( private Quota.Counts destroyCreatedList(
final INodeDirectoryWithSnapshot currentINode, final INodeDirectoryWithSnapshot currentINode,
final BlocksMapUpdateInfo collectedBlocks) { final BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
final List<INode> createdList = getList(ListType.CREATED); final List<INode> createdList = getList(ListType.CREATED);
for (INode c : createdList) { for (INode c : createdList) {
c.computeQuotaUsage(counts, true); c.computeQuotaUsage(counts, true);
c.destroyAndCollectBlocks(collectedBlocks); c.destroyAndCollectBlocks(collectedBlocks, removedINodes);
// c should be contained in the children list, remove it // c should be contained in the children list, remove it
currentINode.removeChild(c); currentINode.removeChild(c);
} }
@ -110,13 +111,13 @@ private Quota.Counts destroyCreatedList(
/** clear the deleted list */ /** clear the deleted list */
private Quota.Counts destroyDeletedList( private Quota.Counts destroyDeletedList(
final BlocksMapUpdateInfo collectedBlocks, final BlocksMapUpdateInfo collectedBlocks,
final List<INodeReference> refNodes) { final List<INode> removedINodes, final List<INodeReference> refNodes) {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
final List<INode> deletedList = getList(ListType.DELETED); final List<INode> deletedList = getList(ListType.DELETED);
for (INode d : deletedList) { for (INode d : deletedList) {
if (INodeReference.tryRemoveReference(d) <= 0) { if (INodeReference.tryRemoveReference(d) <= 0) {
d.computeQuotaUsage(counts, false); d.computeQuotaUsage(counts, false);
d.destroyAndCollectBlocks(collectedBlocks); d.destroyAndCollectBlocks(collectedBlocks, removedINodes);
} else { } else {
refNodes.add(d.asReference()); refNodes.add(d.asReference());
} }
@ -262,7 +263,8 @@ boolean isSnapshotRoot() {
@Override @Override
Quota.Counts combinePosteriorAndCollectBlocks( Quota.Counts combinePosteriorAndCollectBlocks(
final INodeDirectory currentDir, final DirectoryDiff posterior, final INodeDirectory currentDir, final DirectoryDiff posterior,
final BlocksMapUpdateInfo collectedBlocks) { final BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
final Quota.Counts counts = Quota.Counts.newInstance(); final Quota.Counts counts = Quota.Counts.newInstance();
diff.combinePosterior(posterior.diff, new Diff.Processor<INode>() { diff.combinePosterior(posterior.diff, new Diff.Processor<INode>() {
/** Collect blocks for deleted files. */ /** Collect blocks for deleted files. */
@ -271,7 +273,7 @@ public void process(INode inode) {
if (inode != null) { if (inode != null) {
if (INodeReference.tryRemoveReference(inode) <= 0) { if (INodeReference.tryRemoveReference(inode) <= 0) {
inode.computeQuotaUsage(counts, false); inode.computeQuotaUsage(counts, false);
inode.destroyAndCollectBlocks(collectedBlocks); inode.destroyAndCollectBlocks(collectedBlocks, removedINodes);
} else { } else {
// if the node is a reference node, we should continue the // if the node is a reference node, we should continue the
// snapshot deletion process // snapshot deletion process
@ -284,7 +286,7 @@ public void process(INode inode) {
// and it can be identified by the cleanSubtree since we call // and it can be identified by the cleanSubtree since we call
// recordModification before the rename. // recordModification before the rename.
counts.add(inode.cleanSubtree(posterior.snapshot, null, counts.add(inode.cleanSubtree(posterior.snapshot, null,
collectedBlocks)); collectedBlocks, removedINodes));
} catch (QuotaExceededException e) { } catch (QuotaExceededException e) {
String error = "should not have QuotaExceededException while deleting snapshot"; String error = "should not have QuotaExceededException while deleting snapshot";
LOG.error(error, e); LOG.error(error, e);
@ -384,11 +386,12 @@ void write(DataOutput out, ReferenceMap referenceMap) throws IOException {
@Override @Override
Quota.Counts destroyDiffAndCollectBlocks(INodeDirectory currentINode, Quota.Counts destroyDiffAndCollectBlocks(INodeDirectory currentINode,
BlocksMapUpdateInfo collectedBlocks) { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
// this diff has been deleted // this diff has been deleted
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
List<INodeReference> refNodes = new ArrayList<INodeReference>(); List<INodeReference> refNodes = new ArrayList<INodeReference>();
counts.add(diff.destroyDeletedList(collectedBlocks, refNodes)); counts.add(diff.destroyDeletedList(collectedBlocks, removedINodes,
refNodes));
for (INodeReference ref : refNodes) { for (INodeReference ref : refNodes) {
// if the node is a reference node, we should continue the // if the node is a reference node, we should continue the
// snapshot deletion process // snapshot deletion process
@ -401,7 +404,8 @@ Quota.Counts destroyDiffAndCollectBlocks(INodeDirectory currentINode,
// snapshot to be deleted. If the ref node presents the dst node of a // snapshot to be deleted. If the ref node presents the dst node of a
// rename operation, we can identify the corresponding prior snapshot // rename operation, we can identify the corresponding prior snapshot
// when we come into the subtree of the ref node. // when we come into the subtree of the ref node.
counts.add(ref.cleanSubtree(this.snapshot, null, collectedBlocks)); counts.add(ref.cleanSubtree(this.snapshot, null, collectedBlocks,
removedINodes));
} catch (QuotaExceededException e) { } catch (QuotaExceededException e) {
String error = String error =
"should not have QuotaExceededException while deleting snapshot " "should not have QuotaExceededException while deleting snapshot "
@ -755,7 +759,7 @@ public int getSnapshotDirectory(
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
throws QuotaExceededException { throws QuotaExceededException {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
if (snapshot == null) { // delete the current directory if (snapshot == null) { // delete the current directory
@ -763,13 +767,14 @@ public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
// delete everything in created list // delete everything in created list
DirectoryDiff lastDiff = diffs.getLast(); DirectoryDiff lastDiff = diffs.getLast();
if (lastDiff != null) { if (lastDiff != null) {
counts.add(lastDiff.diff.destroyCreatedList(this, collectedBlocks)); counts.add(lastDiff.diff.destroyCreatedList(this, collectedBlocks,
removedINodes));
} }
} else { } else {
// update prior // update prior
prior = getDiffs().updatePrior(snapshot, prior); prior = getDiffs().updatePrior(snapshot, prior);
counts.add(getDiffs().deleteSnapshotDiff(snapshot, prior, this, counts.add(getDiffs().deleteSnapshotDiff(snapshot, prior, this,
collectedBlocks)); collectedBlocks, removedINodes));
if (prior != null) { if (prior != null) {
DirectoryDiff priorDiff = this.getDiffs().getDiff(prior); DirectoryDiff priorDiff = this.getDiffs().getDiff(prior);
if (priorDiff != null) { if (priorDiff != null) {
@ -780,7 +785,8 @@ public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
// cleanSubtreeRecursively call. // cleanSubtreeRecursively call.
for (INode cNode : priorDiff.getChildrenDiff().getList( for (INode cNode : priorDiff.getChildrenDiff().getList(
ListType.CREATED)) { ListType.CREATED)) {
counts.add(cNode.cleanSubtree(snapshot, null, collectedBlocks)); counts.add(cNode.cleanSubtree(snapshot, null, collectedBlocks,
removedINodes));
} }
// When a directory is moved from the deleted list of the posterior // When a directory is moved from the deleted list of the posterior
// diff to the deleted list of this diff, we need to destroy its // diff to the deleted list of this diff, we need to destroy its
@ -792,12 +798,13 @@ public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
for (INode dNode : priorDiff.getChildrenDiff().getList( for (INode dNode : priorDiff.getChildrenDiff().getList(
ListType.DELETED)) { ListType.DELETED)) {
counts.add(cleanDeletedINode(dNode, snapshot, prior, counts.add(cleanDeletedINode(dNode, snapshot, prior,
collectedBlocks)); collectedBlocks, removedINodes));
} }
} }
} }
} }
counts.add(cleanSubtreeRecursively(snapshot, prior, collectedBlocks)); counts.add(cleanSubtreeRecursively(snapshot, prior, collectedBlocks,
removedINodes));
if (isQuotaSet()) { if (isQuotaSet()) {
this.addSpaceConsumed2Cache(-counts.get(Quota.NAMESPACE), this.addSpaceConsumed2Cache(-counts.get(Quota.NAMESPACE),
@ -816,7 +823,8 @@ public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
* @return Quota usage update. * @return Quota usage update.
*/ */
private Quota.Counts cleanDeletedINode(INode inode, Snapshot post, private Quota.Counts cleanDeletedINode(INode inode, Snapshot post,
Snapshot prior, final BlocksMapUpdateInfo collectedBlocks) { Snapshot prior, final BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
Quota.Counts counts = Quota.Counts.newInstance(); Quota.Counts counts = Quota.Counts.newInstance();
Deque<INode> queue = new ArrayDeque<INode>(); Deque<INode> queue = new ArrayDeque<INode>();
queue.addLast(inode); queue.addLast(inode);
@ -825,7 +833,7 @@ private Quota.Counts cleanDeletedINode(INode inode, Snapshot post,
if (topNode instanceof FileWithSnapshot) { if (topNode instanceof FileWithSnapshot) {
FileWithSnapshot fs = (FileWithSnapshot) topNode; FileWithSnapshot fs = (FileWithSnapshot) topNode;
counts.add(fs.getDiffs().deleteSnapshotDiff(post, prior, counts.add(fs.getDiffs().deleteSnapshotDiff(post, prior,
topNode.asFile(), collectedBlocks)); topNode.asFile(), collectedBlocks, removedINodes));
} else if (topNode.isDirectory()) { } else if (topNode.isDirectory()) {
INodeDirectory dir = topNode.asDirectory(); INodeDirectory dir = topNode.asDirectory();
if (dir instanceof INodeDirectoryWithSnapshot) { if (dir instanceof INodeDirectoryWithSnapshot) {
@ -835,7 +843,7 @@ private Quota.Counts cleanDeletedINode(INode inode, Snapshot post,
DirectoryDiff priorDiff = sdir.getDiffs().getDiff(prior); DirectoryDiff priorDiff = sdir.getDiffs().getDiff(prior);
if (priorDiff != null) { if (priorDiff != null) {
counts.add(priorDiff.diff.destroyCreatedList(sdir, counts.add(priorDiff.diff.destroyCreatedList(sdir,
collectedBlocks)); collectedBlocks, removedINodes));
} }
} }
for (INode child : dir.getChildrenList(prior)) { for (INode child : dir.getChildrenList(prior)) {
@ -848,13 +856,14 @@ private Quota.Counts cleanDeletedINode(INode inode, Snapshot post,
@Override @Override
public void destroyAndCollectBlocks( public void destroyAndCollectBlocks(
final BlocksMapUpdateInfo collectedBlocks) { final BlocksMapUpdateInfo collectedBlocks,
final List<INode> removedINodes) {
// destroy its diff list // destroy its diff list
for (DirectoryDiff diff : diffs) { for (DirectoryDiff diff : diffs) {
diff.destroyDiffAndCollectBlocks(this, collectedBlocks); diff.destroyDiffAndCollectBlocks(this, collectedBlocks, removedINodes);
} }
diffs.clear(); diffs.clear();
super.destroyAndCollectBlocks(collectedBlocks); super.destroyAndCollectBlocks(collectedBlocks, removedINodes);
} }
@Override @Override

View File

@ -17,9 +17,12 @@
*/ */
package org.apache.hadoop.hdfs.server.namenode.snapshot; package org.apache.hadoop.hdfs.server.namenode.snapshot;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.protocol.QuotaExceededException; import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor; import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INodeFile; import org.apache.hadoop.hdfs.server.namenode.INodeFile;
import org.apache.hadoop.hdfs.server.namenode.INodeFileUnderConstruction; import org.apache.hadoop.hdfs.server.namenode.INodeFileUnderConstruction;
import org.apache.hadoop.hdfs.server.namenode.Quota; import org.apache.hadoop.hdfs.server.namenode.Quota;
@ -113,16 +116,17 @@ public FileDiffList getDiffs() {
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
throws QuotaExceededException { throws QuotaExceededException {
if (snapshot == null) { // delete the current file if (snapshot == null) { // delete the current file
recordModification(prior); recordModification(prior);
isCurrentFileDeleted = true; isCurrentFileDeleted = true;
Util.collectBlocksAndClear(this, collectedBlocks); Util.collectBlocksAndClear(this, collectedBlocks, removedINodes);
return Quota.Counts.newInstance(); return Quota.Counts.newInstance();
} else { // delete a snapshot } else { // delete a snapshot
prior = getDiffs().updatePrior(snapshot, prior); prior = getDiffs().updatePrior(snapshot, prior);
return diffs.deleteSnapshotDiff(snapshot, prior, this, collectedBlocks); return diffs.deleteSnapshotDiff(snapshot, prior, this, collectedBlocks,
removedINodes);
} }
} }

View File

@ -17,9 +17,12 @@
*/ */
package org.apache.hadoop.hdfs.server.namenode.snapshot; package org.apache.hadoop.hdfs.server.namenode.snapshot;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.protocol.QuotaExceededException; import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor; import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INodeFile; import org.apache.hadoop.hdfs.server.namenode.INodeFile;
import org.apache.hadoop.hdfs.server.namenode.Quota; import org.apache.hadoop.hdfs.server.namenode.Quota;
@ -84,16 +87,17 @@ public FileDiffList getDiffs() {
@Override @Override
public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior, public Quota.Counts cleanSubtree(final Snapshot snapshot, Snapshot prior,
final BlocksMapUpdateInfo collectedBlocks) final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
throws QuotaExceededException { throws QuotaExceededException {
if (snapshot == null) { // delete the current file if (snapshot == null) { // delete the current file
recordModification(prior); recordModification(prior);
isCurrentFileDeleted = true; isCurrentFileDeleted = true;
Util.collectBlocksAndClear(this, collectedBlocks); Util.collectBlocksAndClear(this, collectedBlocks, removedINodes);
return Quota.Counts.newInstance(); return Quota.Counts.newInstance();
} else { // delete a snapshot } else { // delete a snapshot
prior = getDiffs().updatePrior(snapshot, prior); prior = getDiffs().updatePrior(snapshot, prior);
return diffs.deleteSnapshotDiff(snapshot, prior, this, collectedBlocks); return diffs.deleteSnapshotDiff(snapshot, prior, this, collectedBlocks,
removedINodes);
} }
} }

View File

@ -32,6 +32,7 @@
import org.apache.hadoop.hdfs.server.namenode.FSDirectory; import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
import org.apache.hadoop.hdfs.server.namenode.FSImageFormat; import org.apache.hadoop.hdfs.server.namenode.FSImageFormat;
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo; import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory; import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
import org.apache.hadoop.hdfs.server.namenode.INodesInPath; import org.apache.hadoop.hdfs.server.namenode.INodesInPath;
@ -162,7 +163,8 @@ public String createSnapshot(final String path, String snapshotName
* @throws IOException * @throws IOException
*/ */
public void deleteSnapshot(final String path, final String snapshotName, public void deleteSnapshot(final String path, final String snapshotName,
BlocksMapUpdateInfo collectedBlocks) throws IOException { BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
throws IOException {
// parse the path, and check if the path is a snapshot path // parse the path, and check if the path is a snapshot path
INodesInPath inodesInPath = fsdir.getINodesInPath4Write(path.toString()); INodesInPath inodesInPath = fsdir.getINodesInPath4Write(path.toString());
// transfer the inode for path to an INodeDirectorySnapshottable. // transfer the inode for path to an INodeDirectorySnapshottable.
@ -171,7 +173,7 @@ public void deleteSnapshot(final String path, final String snapshotName,
INodeDirectorySnapshottable dir = INodeDirectorySnapshottable.valueOf( INodeDirectorySnapshottable dir = INodeDirectorySnapshottable.valueOf(
inodesInPath.getLastINode(), path.toString()); inodesInPath.getLastINode(), path.toString());
dir.removeSnapshot(snapshotName, collectedBlocks); dir.removeSnapshot(snapshotName, collectedBlocks, removedINodes);
numSnapshots.getAndDecrement(); numSnapshots.getAndDecrement();
} }