Skip to content

Commit

Permalink
HDFS-7728. Avoid updating quota usage while loading edits. Contribute…
Browse files Browse the repository at this point in the history
…d by Jing Zhao.
  • Loading branch information
Haohui Mai committed May 14, 2015
1 parent 54fa9b4 commit b2c85db
Show file tree
Hide file tree
Showing 27 changed files with 465 additions and 417 deletions.
3 changes: 3 additions & 0 deletions hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt
Expand Up @@ -755,6 +755,9 @@ Release 2.8.0 - UNRELEASED
HDFS-8243. Files written by TestHostsFiles and TestNameNodeMXBean are HDFS-8243. Files written by TestHostsFiles and TestNameNodeMXBean are
causing Release Audit Warnings. (Ruth Wisniewski via Arpit Agarwal) causing Release Audit Warnings. (Ruth Wisniewski via Arpit Agarwal)


HDFS-7728. Avoid updating quota usage while loading edits.
(Jing Zhao via wheat9)

Release 2.7.1 - UNRELEASED Release 2.7.1 - UNRELEASED


INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES
Expand Down
Expand Up @@ -20,6 +20,7 @@
import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException;
import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsAction;
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.ReclaimContext;
import org.apache.hadoop.util.ChunkedArrayList; import org.apache.hadoop.util.ChunkedArrayList;


import java.io.IOException; import java.io.IOException;
Expand All @@ -39,24 +40,26 @@ class FSDirDeleteOp {
* @param removedINodes INodes that should be removed from inodeMap * @param removedINodes INodes that should be removed from inodeMap
* @return the number of files that have been removed * @return the number of files that have been removed
*/ */
static long delete( static long delete(FSDirectory fsd, INodesInPath iip,
FSDirectory fsd, INodesInPath iip, BlocksMapUpdateInfo collectedBlocks, BlocksMapUpdateInfo collectedBlocks, List<INode> removedINodes,
List<INode> removedINodes, List<Long> removedUCFiles, List<Long> removedUCFiles, long mtime) throws IOException {
long mtime) throws IOException {
if (NameNode.stateChangeLog.isDebugEnabled()) { if (NameNode.stateChangeLog.isDebugEnabled()) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: " + iip.getPath()); NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: " + iip.getPath());
} }
final long filesRemoved; long filesRemoved = -1;
fsd.writeLock(); fsd.writeLock();
try { try {
if (!deleteAllowed(iip, iip.getPath()) ) { if (deleteAllowed(iip, iip.getPath()) ) {
filesRemoved = -1;
} else {
List<INodeDirectory> snapshottableDirs = new ArrayList<>(); List<INodeDirectory> snapshottableDirs = new ArrayList<>();
FSDirSnapshotOp.checkSnapshot(iip.getLastINode(), snapshottableDirs); FSDirSnapshotOp.checkSnapshot(iip.getLastINode(), snapshottableDirs);
filesRemoved = unprotectedDelete(fsd, iip, collectedBlocks, ReclaimContext context = new ReclaimContext(
removedINodes, removedUCFiles, mtime); fsd.getBlockStoragePolicySuite(), collectedBlocks, removedINodes,
removedUCFiles);
if (unprotectedDelete(fsd, iip, context, mtime)) {
filesRemoved = context.quotaDelta().getNsDelta();
}
fsd.getFSNamesystem().removeSnapshottableDirs(snapshottableDirs); fsd.getFSNamesystem().removeSnapshottableDirs(snapshottableDirs);
fsd.updateCount(iip, context.quotaDelta(), false);
} }
} finally { } finally {
fsd.writeUnlock(); fsd.writeUnlock();
Expand Down Expand Up @@ -128,11 +131,13 @@ static void deleteForEditLog(FSDirectory fsd, String src, long mtime)
} }
List<INodeDirectory> snapshottableDirs = new ArrayList<>(); List<INodeDirectory> snapshottableDirs = new ArrayList<>();
FSDirSnapshotOp.checkSnapshot(iip.getLastINode(), snapshottableDirs); FSDirSnapshotOp.checkSnapshot(iip.getLastINode(), snapshottableDirs);
long filesRemoved = unprotectedDelete( boolean filesRemoved = unprotectedDelete(fsd, iip,
fsd, iip, collectedBlocks, removedINodes, removedUCFiles, mtime); new ReclaimContext(fsd.getBlockStoragePolicySuite(),
collectedBlocks, removedINodes, removedUCFiles),
mtime);
fsn.removeSnapshottableDirs(snapshottableDirs); fsn.removeSnapshottableDirs(snapshottableDirs);


if (filesRemoved >= 0) { if (filesRemoved) {
fsn.removeLeasesAndINodes(removedUCFiles, removedINodes, false); fsn.removeLeasesAndINodes(removedUCFiles, removedINodes, false);
fsn.removeBlocksAndUpdateSafemodeTotal(collectedBlocks); fsn.removeBlocksAndUpdateSafemodeTotal(collectedBlocks);
} }
Expand Down Expand Up @@ -213,21 +218,18 @@ private static boolean deleteAllowed(final INodesInPath iip,
* Update the count at each ancestor directory with quota * Update the count at each ancestor directory with quota
* @param fsd the FSDirectory instance * @param fsd the FSDirectory instance
* @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 reclaimContext used to collect blocks and inodes to be removed
* @param removedINodes inodes that should be removed from inodeMap
* @param removedUCFiles inodes whose leases need to be released
* @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 true if there are inodes deleted
*/ */
private static long unprotectedDelete( private static boolean unprotectedDelete(FSDirectory fsd, INodesInPath iip,
FSDirectory fsd, INodesInPath iip, BlocksMapUpdateInfo collectedBlocks, ReclaimContext reclaimContext, long mtime) {
List<INode> removedINodes, List<Long> removedUCFiles, long mtime) {
assert fsd.hasWriteLock(); assert fsd.hasWriteLock();


// check if target node exists // check if target node exists
INode targetNode = iip.getLastINode(); INode targetNode = iip.getLastINode();
if (targetNode == null) { if (targetNode == null) {
return -1; return false;
} }


// record modification // record modification
Expand All @@ -237,35 +239,24 @@ private static long unprotectedDelete(
// Remove the node from the namespace // Remove the node from the namespace
long removed = fsd.removeLastINode(iip); long removed = fsd.removeLastINode(iip);
if (removed == -1) { if (removed == -1) {
return -1; return false;
} }


// set the parent's modification time // set the parent's modification time
final INodeDirectory parent = targetNode.getParent(); final INodeDirectory parent = targetNode.getParent();
parent.updateModificationTime(mtime, latestSnapshot); parent.updateModificationTime(mtime, latestSnapshot);


fsd.updateCountForDelete(targetNode, iip);
if (removed == 0) {
return 0;
}

// collect block and update quota // collect block and update quota
INode.ReclaimContext reclaimContext = new INode.ReclaimContext(
fsd.getBlockStoragePolicySuite(), collectedBlocks,
removedINodes, removedUCFiles);
if (!targetNode.isInLatestSnapshot(latestSnapshot)) { if (!targetNode.isInLatestSnapshot(latestSnapshot)) {
targetNode.destroyAndCollectBlocks(reclaimContext); targetNode.destroyAndCollectBlocks(reclaimContext);
} else { } else {
QuotaCounts counts = targetNode.cleanSubtree(reclaimContext, targetNode.cleanSubtree(reclaimContext, CURRENT_STATE_ID, latestSnapshot);
CURRENT_STATE_ID, latestSnapshot);
removed = counts.getNameSpace();
fsd.updateCountNoQuotaCheck(iip, iip.length() -1, counts.negation());
} }


if (NameNode.stateChangeLog.isDebugEnabled()) { if (NameNode.stateChangeLog.isDebugEnabled()) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: " NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: "
+ iip.getPath() + " is removed"); + iip.getPath() + " is removed");
} }
return removed; return true;
} }
} }
Expand Up @@ -302,19 +302,18 @@ static void renameTo(FSDirectory fsd, FSPermissionChecker pc, String src,
* @param timestamp modification time * @param timestamp modification time
* @param options Rename options * @param options Rename options
*/ */
static boolean renameForEditLog( static void renameForEditLog(
FSDirectory fsd, String src, String dst, long timestamp, FSDirectory fsd, String src, String dst, long timestamp,
Options.Rename... options) Options.Rename... options)
throws IOException { throws IOException {
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
final INodesInPath srcIIP = fsd.getINodesInPath4Write(src, false); final INodesInPath srcIIP = fsd.getINodesInPath4Write(src, false);
final INodesInPath dstIIP = fsd.getINodesInPath4Write(dst, false); final INodesInPath dstIIP = fsd.getINodesInPath4Write(dst, false);
boolean ret = unprotectedRenameTo(fsd, src, dst, srcIIP, dstIIP, timestamp, unprotectedRenameTo(fsd, src, dst, srcIIP, dstIIP, timestamp,
collectedBlocks, options); collectedBlocks, options);
if (!collectedBlocks.getToDeleteList().isEmpty()) { if (!collectedBlocks.getToDeleteList().isEmpty()) {
fsd.getFSNamesystem().removeBlocksAndUpdateSafemodeTotal(collectedBlocks); fsd.getFSNamesystem().removeBlocksAndUpdateSafemodeTotal(collectedBlocks);
} }
return ret;
} }


/** /**
Expand Down Expand Up @@ -609,7 +608,7 @@ private static class RenameOperation {
this.srcIIP = INodesInPath.replace(srcIIP, srcIIP.length() - 1, this.srcIIP = INodesInPath.replace(srcIIP, srcIIP.length() - 1,
srcChild); srcChild);
// get the counts before rename // get the counts before rename
withCount.getReferredINode().computeQuotaUsage(bsps, oldSrcCounts, true); oldSrcCounts.add(withCount.getReferredINode().computeQuotaUsage(bsps));
} else if (srcChildIsReference) { } else if (srcChildIsReference) {
// srcChild is reference but srcChild is not in latest snapshot // srcChild is reference but srcChild is not in latest snapshot
withCount = (INodeReference.WithCount) srcChild.asReference() withCount = (INodeReference.WithCount) srcChild.asReference()
Expand Down Expand Up @@ -730,18 +729,16 @@ boolean cleanDst(BlockStoragePolicySuite bsps, BlocksMapUpdateInfo collectedBloc
Preconditions.checkState(oldDstChild != null); Preconditions.checkState(oldDstChild != null);
List<INode> removedINodes = new ChunkedArrayList<>(); List<INode> removedINodes = new ChunkedArrayList<>();
List<Long> removedUCFiles = new ChunkedArrayList<>(); List<Long> removedUCFiles = new ChunkedArrayList<>();
INode.ReclaimContext context = new INode.ReclaimContext(bsps,
collectedBlocks, removedINodes, removedUCFiles);
final boolean filesDeleted; final boolean filesDeleted;
if (!oldDstChild.isInLatestSnapshot(dstIIP.getLatestSnapshotId())) { if (!oldDstChild.isInLatestSnapshot(dstIIP.getLatestSnapshotId())) {
oldDstChild.destroyAndCollectBlocks( oldDstChild.destroyAndCollectBlocks(context);
new INode.ReclaimContext(bsps, collectedBlocks, removedINodes, removedUCFiles));
filesDeleted = true; filesDeleted = true;
} else { } else {
filesDeleted = oldDstChild.cleanSubtree( oldDstChild.cleanSubtree(context, Snapshot.CURRENT_STATE_ID,
new INode.ReclaimContext(bsps, collectedBlocks, removedINodes, dstIIP.getLatestSnapshotId());
removedUCFiles), filesDeleted = context.quotaDelta().getNsDelta() >= 0;
Snapshot.CURRENT_STATE_ID,
dstIIP.getLatestSnapshotId())
.getNameSpace() >= 0;
} }
fsd.getFSNamesystem().removeLeasesAndINodes( fsd.getFSNamesystem().removeLeasesAndINodes(
removedUCFiles, removedINodes, false); removedUCFiles, removedINodes, false);
Expand All @@ -752,8 +749,7 @@ void updateQuotasInSourceTree(BlockStoragePolicySuite bsps) throws QuotaExceeded
// update the quota usage in src tree // update the quota usage in src tree
if (isSrcInSnapshot) { if (isSrcInSnapshot) {
// get the counts after rename // get the counts after rename
QuotaCounts newSrcCounts = srcChild.computeQuotaUsage(bsps, QuotaCounts newSrcCounts = srcChild.computeQuotaUsage(bsps, false);
new QuotaCounts.Builder().build(), false);
newSrcCounts.subtract(oldSrcCounts); newSrcCounts.subtract(oldSrcCounts);
srcParent.addSpaceConsumed(newSrcCounts, false); srcParent.addSpaceConsumed(newSrcCounts, false);
} }
Expand Down
Expand Up @@ -176,11 +176,13 @@ static INode.BlocksMapUpdateInfo deleteSnapshot(
} }


INode.BlocksMapUpdateInfo collectedBlocks = new INode.BlocksMapUpdateInfo(); INode.BlocksMapUpdateInfo collectedBlocks = new INode.BlocksMapUpdateInfo();
ChunkedArrayList<INode> removedINodes = new ChunkedArrayList<INode>(); ChunkedArrayList<INode> removedINodes = new ChunkedArrayList<>();
INode.ReclaimContext context = new INode.ReclaimContext(
fsd.getBlockStoragePolicySuite(), collectedBlocks, removedINodes, null);
fsd.writeLock(); fsd.writeLock();
try { try {
snapshotManager.deleteSnapshot(iip, snapshotName, collectedBlocks, snapshotManager.deleteSnapshot(iip, snapshotName, context);
removedINodes); fsd.updateCount(iip, context.quotaDelta(), false);
fsd.removeFromInodeMap(removedINodes); fsd.removeFromInodeMap(removedINodes);
} finally { } finally {
fsd.writeUnlock(); fsd.writeUnlock();
Expand Down
Expand Up @@ -76,6 +76,7 @@
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;


import static org.apache.hadoop.fs.BatchedRemoteIterator.BatchedListEntries; import static org.apache.hadoop.fs.BatchedRemoteIterator.BatchedListEntries;
Expand Down Expand Up @@ -641,6 +642,23 @@ void updateSpaceConsumed(INodesInPath iip, long nsDelta, long ssDelta, short rep
} }
} }


public void updateCount(INodesInPath iip, INode.QuotaDelta quotaDelta,
boolean check) throws QuotaExceededException {
QuotaCounts counts = quotaDelta.getCountsCopy();
updateCount(iip, iip.length() - 1, counts.negation(), check);
Map<INode, QuotaCounts> deltaInOtherPaths = quotaDelta.getUpdateMap();
for (Map.Entry<INode, QuotaCounts> entry : deltaInOtherPaths.entrySet()) {
INodesInPath path = INodesInPath.fromINode(entry.getKey());
updateCount(path, path.length() - 1, entry.getValue().negation(), check);
}
for (Map.Entry<INodeDirectory, QuotaCounts> entry :
quotaDelta.getQuotaDirMap().entrySet()) {
INodeDirectory quotaDir = entry.getKey();
quotaDir.getDirectoryWithQuotaFeature().addSpaceConsumed2Cache(
entry.getValue().negation());
}
}

/** /**
* Update the quota usage after deletion. The quota update is only necessary * Update the quota usage after deletion. The quota update is only necessary
* when image/edits have been loaded and the file/dir to be deleted is not * when image/edits have been loaded and the file/dir to be deleted is not
Expand Down
Expand Up @@ -733,9 +733,10 @@ fsDir, renameReservedPathsOnUpgrade(timesOp.path, logVersion),
renameReservedPathsOnUpgrade(deleteSnapshotOp.snapshotRoot, renameReservedPathsOnUpgrade(deleteSnapshotOp.snapshotRoot,
logVersion); logVersion);
INodesInPath iip = fsDir.getINodesInPath4Write(snapshotRoot); INodesInPath iip = fsDir.getINodesInPath4Write(snapshotRoot);
fsNamesys.getSnapshotManager().deleteSnapshot( fsNamesys.getSnapshotManager().deleteSnapshot(iip,
iip, deleteSnapshotOp.snapshotName, deleteSnapshotOp.snapshotName,
collectedBlocks, removedINodes); new INode.ReclaimContext(fsNamesys.dir.getBlockStoragePolicySuite(),
collectedBlocks, removedINodes, null));
fsNamesys.removeBlocksAndUpdateSafemodeTotal(collectedBlocks); fsNamesys.removeBlocksAndUpdateSafemodeTotal(collectedBlocks);
collectedBlocks.clear(); collectedBlocks.clear();
fsNamesys.dir.removeFromInodeMap(removedINodes); fsNamesys.dir.removeFromInodeMap(removedINodes);
Expand Down
Expand Up @@ -882,8 +882,8 @@ private static void updateCountForQuotaRecursively(BlockStoragePolicySuite bsps,
child.asDirectory(), counts); child.asDirectory(), counts);
} else { } else {
// file or symlink: count here to reduce recursive calls. // file or symlink: count here to reduce recursive calls.
child.computeQuotaUsage(bsps, childPolicyId, counts, false, counts.add(child.computeQuotaUsage(bsps, childPolicyId, false,
Snapshot.CURRENT_STATE_ID); Snapshot.CURRENT_STATE_ID));
} }
} }


Expand Down

0 comments on commit b2c85db

Please sign in to comment.