You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by su...@apache.org on 2012/11/07 23:50:03 UTC
svn commit: r1406850 - in /hadoop/common/branches/branch-1.1: ./
src/hdfs/org/apache/hadoop/hdfs/server/namenode/
src/test/org/apache/hadoop/hdfs/server/namenode/
Author: suresh
Date: Wed Nov 7 22:50:02 2012
New Revision: 1406850
URL: http://svn.apache.org/viewvc?rev=1406850&view=rev
Log:
HDFS-3791. Merging change r1378241 from branch-1
Added:
hadoop/common/branches/branch-1.1/src/test/org/apache/hadoop/hdfs/server/namenode/TestLargeDirectoryDelete.java
- copied unchanged from r1378241, hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestLargeDirectoryDelete.java
Modified:
hadoop/common/branches/branch-1.1/CHANGES.txt
hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/BlocksMap.java
hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/INodeFile.java
Modified: hadoop/common/branches/branch-1.1/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1.1/CHANGES.txt?rev=1406850&r1=1406849&r2=1406850&view=diff
==============================================================================
--- hadoop/common/branches/branch-1.1/CHANGES.txt (original)
+++ hadoop/common/branches/branch-1.1/CHANGES.txt Wed Nov 7 22:50:02 2012
@@ -12,6 +12,10 @@ Release 1.1.1 - Unreleased
BUG FIXES
+ HDFS-3791. HDFS-173 Backport - Namenode will not block until a large
+ directory deletion completes. It allows other operations when the
+ deletion is in progress. (umamahesh via suresh)
+
Release 1.1.0 - 2012.09.28
INCOMPATIBLE CHANGES
Modified: hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/BlocksMap.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/BlocksMap.java?rev=1406850&r1=1406849&r2=1406850&view=diff
==============================================================================
--- hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/BlocksMap.java (original)
+++ hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/BlocksMap.java Wed Nov 7 22:50:02 2012
@@ -58,6 +58,10 @@ class BlocksMap {
INodeFile getINode() {
return inode;
}
+
+ void setINode(INodeFile inode) {
+ this.inode = inode;
+ }
DatanodeDescriptor getDatanode(int index) {
assert this.triplets != null : "BlockInfo is not initialized";
Modified: hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java?rev=1406850&r1=1406849&r2=1406850&view=diff
==============================================================================
--- hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java (original)
+++ hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java Wed Nov 7 22:50:02 2012
@@ -587,19 +587,27 @@ class FSDirectory implements FSConstants
}
/**
- * Remove the file from management, return blocks
+ * Delete the target directory and collect the blocks under it
+ *
+ * @param src
+ * Path of a directory to delete
+ * @param collectedBlocks
+ * Blocks under the deleted directory
+ * @return true on successful deletion; else false
*/
- boolean delete(String src) {
+ boolean delete(String src, List<Block>collectedBlocks) {
if (NameNode.stateChangeLog.isDebugEnabled()) {
- NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: "+src);
+ NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: " + src);
}
waitForReady();
long now = FSNamesystem.now();
- int filesRemoved = unprotectedDelete(src, now);
+ int filesRemoved = unprotectedDelete(src, collectedBlocks, now);
if (filesRemoved <= 0) {
return false;
}
incrDeletedFileCount(filesRemoved);
+ // Blocks will be deleted later by the caller of this method
+ FSNamesystem.getFSNamesystem().removePathAndBlocks(src, null);
fsImage.getEditLog().logDelete(src, now);
return true;
}
@@ -621,14 +629,36 @@ class FSDirectory implements FSConstants
}
/**
- * Delete a path from the name space
- * Update the count at each ancestor directory with quota
- * @param src a string representation of a path to an inode
- * @param modificationTime the time the inode is removed
- * @param deletedBlocks the place holder for the blocks to be removed
+ * Delete a path from the name space Update the count at each ancestor
+ * directory with quota
+ *
+ * @param src
+ * a string representation of a path to an inode
+ *
+ * @param mTime
+ * the time the inode is removed
+ */
+ void unprotectedDelete(String src, long mTime) {
+ List<Block> collectedBlocks = new ArrayList<Block>();
+ int filesRemoved = unprotectedDelete(src, collectedBlocks, mTime);
+ if (filesRemoved > 0) {
+ namesystem.removePathAndBlocks(src, collectedBlocks);
+ }
+ }
+
+ /**
+ * Delete a path from the name space Update the count at each ancestor
+ * directory with quota
+ *
+ * @param src
+ * a string representation of a path to an inode
+ * @param collectedBlocks
+ * blocks collected from the deleted path
+ * @param mtime
+ * the time the inode is removed
* @return the number of inodes deleted; 0 if no inodes are deleted.
- */
- int unprotectedDelete(String src, long modificationTime) {
+ */
+ int unprotectedDelete(String src, List<Block> collectedBlocks, long mtime) {
src = normalizePath(src);
synchronized (rootDir) {
@@ -639,32 +669,27 @@ class FSDirectory implements FSConstants
NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: "
+"failed to remove "+src+" because it does not exist");
return 0;
- } else if (inodes.length == 1) { // src is the root
+ }
+ if (inodes.length == 1) { // src is the root
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedDelete: " +
"failed to remove " + src +
" because the root is not allowed to be deleted");
return 0;
- } else {
- try {
- // Remove the node from the namespace
- removeChild(inodes, inodes.length-1);
- // set the parent's modification time
- inodes[inodes.length-2].setModificationTime(modificationTime);
- // GC all the blocks underneath the node.
- ArrayList<Block> v = new ArrayList<Block>();
- int filesRemoved = targetNode.collectSubtreeBlocksAndClear(v);
- namesystem.removePathAndBlocks(src, v);
- if (NameNode.stateChangeLog.isDebugEnabled()) {
- NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: "
- +src+" is removed");
- }
- return filesRemoved;
- } catch (IOException e) {
- NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedDelete: " +
- "failed to remove " + src + " because " + e.getMessage());
- return 0;
- }
+ }
+ int pos = inodes.length - 1;
+ targetNode = removeChild(inodes, pos);
+ if (targetNode == null) {
+ return 0;
+ }
+ // set the parent's modification time
+ inodes[pos - 1].setModificationTime(mtime);
+ int filesRemoved = targetNode
+ .collectSubtreeBlocksAndClear(collectedBlocks);
+ if (NameNode.stateChangeLog.isDebugEnabled()) {
+ NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: "
+ + src + " is removed");
}
+ return filesRemoved;
}
}
Modified: hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java?rev=1406850&r1=1406849&r2=1406850&view=diff
==============================================================================
--- hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java (original)
+++ hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java Wed Nov 7 22:50:02 2012
@@ -178,6 +178,7 @@ public class FSNamesystem implements FSC
// Default initial capacity and load factor of map
public static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
public static final float DEFAULT_MAP_LOAD_FACTOR = 0.75f;
+ static int BLOCK_DELETION_INCREMENT = 1000;
private float blocksInvalidateWorkPct;
private int blocksReplWorkMultiplier;
@@ -1843,17 +1844,33 @@ public class FSNamesystem implements FSC
/**
* Adds block to list of blocks which will be invalidated on
- * specified datanode and log the move
+ * specified datanode
* @param b block
* @param n datanode
+ * @param log true to create an entry in the log
*/
- void addToInvalidates(Block b, DatanodeInfo n) {
- addToInvalidatesNoLog(b, n);
- NameNode.stateChangeLog.info("BLOCK* NameSystem.addToInvalidates: "
- + b.getBlockName() + " is added to invalidSet of " + n.getName());
+ void addToInvalidates(Block b, DatanodeInfo dn, boolean log) {
+ addToInvalidatesNoLog(b, dn);
+ if (log) {
+ NameNode.stateChangeLog.info("BLOCK* NameSystem.addToInvalidates: "
+ + b.getBlockName() + " to " + dn.getName());
+ }
}
/**
+ * Adds block to list of blocks which will be invalidated on specified
+ * datanode and log the operation
+ *
+ * @param b
+ * block
+ * @param dn
+ * datanode
+ */
+ void addToInvalidates(Block b, DatanodeInfo dn) {
+ addToInvalidates(b, dn, true);
+ }
+
+ /**
* Adds block to list of blocks which will be invalidated on
* specified datanode
* @param b block
@@ -1875,10 +1892,16 @@ public class FSNamesystem implements FSC
* all its datanodes.
*/
private void addToInvalidates(Block b) {
+ StringBuilder datanodes = new StringBuilder();
for (Iterator<DatanodeDescriptor> it =
blocksMap.nodeIterator(b); it.hasNext();) {
DatanodeDescriptor node = it.next();
- addToInvalidates(b, node);
+ addToInvalidates(b, node, false);
+ datanodes.append(node.getName()).append(" ");
+ }
+ if (datanodes.length() != 0) {
+ NameNode.stateChangeLog.info("BLOCK* NameSystem.addToInvalidates: "
+ + b.getBlockName() + " to " + datanodes.toString());
}
}
@@ -2035,8 +2058,10 @@ public class FSNamesystem implements FSC
if ((!recursive) && (!dir.isDirEmpty(src))) {
throw new IOException(src + " is non empty");
}
+ if (NameNode.stateChangeLog.isDebugEnabled()) {
+ NameNode.stateChangeLog.debug("DIR* NameSystem.delete: " + src);
+ }
boolean status = deleteInternal(src, true);
- getEditLog().logSync();
if (status && auditLog.isInfoEnabled() && isExternalInvocation()) {
logAuditEvent(UserGroupInformation.getCurrentUser(),
Server.getRemoteIp(),
@@ -2046,30 +2071,73 @@ public class FSNamesystem implements FSC
}
/**
- * Remove the indicated filename from the namespace. This may
- * invalidate some blocks that make up the file.
+ * Remove a file/directory from the namespace.
+ * <p>
+ * For large directories, deletion is incremental. The blocks under the
+ * directory are collected and deleted a small number at a time holding the
+ * {@link FSNamesystem} lock.
+ * <p>
+ * For small directory or file the deletion is done in one shot.
*/
- synchronized boolean deleteInternal(String src,
+ private boolean deleteInternal(String src,
boolean enforcePermission) throws IOException {
+ boolean deleteNow = false;
+ ArrayList<Block> collectedBlocks = new ArrayList<Block>();
+ synchronized (this) {
+ if (isInSafeMode()) {
+ throw new SafeModeException("Cannot delete " + src, safeMode);
+ }
+ if (enforcePermission && isPermissionEnabled) {
+ checkPermission(src, false, null, FsAction.WRITE, null, FsAction.ALL);
+ }
+ // Unlink the target directory from directory tree
+ if (!dir.delete(src, collectedBlocks)) {
+ return false;
+ }
+ deleteNow = collectedBlocks.size() <= BLOCK_DELETION_INCREMENT;
+ if (deleteNow) { // Perform small deletes right away
+ removeBlocks(collectedBlocks);
+ }
+ }
+
+ // Log directory deletion to editlog
+ getEditLog().logSync();
+ if (!deleteNow) {
+ removeBlocks(collectedBlocks); // Incremental deletion of blocks
+ }
+ collectedBlocks.clear();
if (NameNode.stateChangeLog.isDebugEnabled()) {
- NameNode.stateChangeLog.debug("DIR* NameSystem.delete: " + src);
+ NameNode.stateChangeLog.debug("DIR* Namesystem.delete: " + src
+ + " is removed");
}
- if (isInSafeMode())
- throw new SafeModeException("Cannot delete " + src, safeMode);
- if (enforcePermission && isPermissionEnabled) {
- checkPermission(src, false, null, FsAction.WRITE, null, FsAction.ALL);
+ return true;
+ }
+
+ /** From the given list, incrementally remove the blocks from blockManager */
+ private void removeBlocks(List<Block> blocks) {
+ int start = 0;
+ int end = 0;
+ while (start < blocks.size()) {
+ end = BLOCK_DELETION_INCREMENT + start;
+ end = end > blocks.size() ? blocks.size() : end;
+ synchronized (this) {
+ for (int i = start; i < end; i++) {
+ Block b = blocks.get(i);
+ blocksMap.removeINode(b);
+ corruptReplicas.removeFromCorruptReplicasMap(b);
+ addToInvalidates(b);
+ }
+ }
+ start = end;
}
-
- return dir.delete(src);
}
- void removePathAndBlocks(String src, List<Block> blocks) throws IOException {
+ void removePathAndBlocks(String src, List<Block> blocks) {
leaseManager.removeLeaseWithPrefixPath(src);
- for(Block b : blocks) {
- blocksMap.removeINode(b);
- corruptReplicas.removeFromCorruptReplicasMap(b);
- addToInvalidates(b);
+ if (blocks == null) {
+ return;
}
+ removeBlocks(blocks);
}
/** Get the file info for a specific file.
Modified: hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/INodeFile.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/INodeFile.java?rev=1406850&r1=1406849&r2=1406850&view=diff
==============================================================================
--- hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/INodeFile.java (original)
+++ hadoop/common/branches/branch-1.1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/INodeFile.java Wed Nov 7 22:50:02 2012
@@ -136,8 +136,9 @@ class INodeFile extends INode {
int collectSubtreeBlocksAndClear(List<Block> v) {
parent = null;
- for (Block blk : blocks) {
+ for (BlockInfo blk : blocks) {
v.add(blk);
+ blk.setINode(null);
}
blocks = null;
return 1;