HDFS-2975. Rename with overwrite flag true can make NameNode to stuck in safemode on NN (crash + restart). (Yi Liu via umamahesh)

This commit is contained in:
Uma Maheswara Rao G 2014-09-03 18:53:51 +05:30
parent 08a9ac7098
commit 3425ae5d7e
4 changed files with 53 additions and 12 deletions

View File

@ -680,6 +680,9 @@ Release 2.6.0 - UNRELEASED
HDFS-6954. With crypto, no native lib systems are too verbose. (clamb via wang) HDFS-6954. With crypto, no native lib systems are too verbose. (clamb via wang)
HDFS-2975. Rename with overwrite flag true can make NameNode to stuck in safemode
on NN (crash + restart). (Yi Liu via umamahesh)
Release 2.5.1 - UNRELEASED Release 2.5.1 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -452,7 +452,7 @@ public class FSDirectory implements Closeable {
* @see #unprotectedRenameTo(String, String, long, Options.Rename...) * @see #unprotectedRenameTo(String, String, long, Options.Rename...)
*/ */
void renameTo(String src, String dst, long mtime, void renameTo(String src, String dst, long mtime,
Options.Rename... options) BlocksMapUpdateInfo collectedBlocks, Options.Rename... options)
throws FileAlreadyExistsException, FileNotFoundException, throws FileAlreadyExistsException, FileNotFoundException,
ParentNotDirectoryException, QuotaExceededException, ParentNotDirectoryException, QuotaExceededException,
UnresolvedLinkException, IOException { UnresolvedLinkException, IOException {
@ -462,7 +462,7 @@ public class FSDirectory implements Closeable {
} }
writeLock(); writeLock();
try { try {
if (unprotectedRenameTo(src, dst, mtime, options)) { if (unprotectedRenameTo(src, dst, mtime, collectedBlocks, options)) {
namesystem.incrDeletedFileCount(1); namesystem.incrDeletedFileCount(1);
} }
} finally { } finally {
@ -569,8 +569,9 @@ public class FSDirectory implements Closeable {
/** /**
* Rename src to dst. * Rename src to dst.
* See {@link DistributedFileSystem#rename(Path, Path, Options.Rename...)} * <br>
* for details related to rename semantics and exceptions. * Note: This is to be used by {@link FSEditLog} only.
* <br>
* *
* @param src source path * @param src source path
* @param dst destination path * @param dst destination path
@ -578,9 +579,34 @@ public class FSDirectory implements Closeable {
* @param options Rename options * @param options Rename options
*/ */
boolean unprotectedRenameTo(String src, String dst, long timestamp, boolean unprotectedRenameTo(String src, String dst, long timestamp,
Options.Rename... options) throws FileAlreadyExistsException, Options.Rename... options) throws FileAlreadyExistsException,
FileNotFoundException, ParentNotDirectoryException, FileNotFoundException, ParentNotDirectoryException,
QuotaExceededException, UnresolvedLinkException, IOException { QuotaExceededException, UnresolvedLinkException, IOException {
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
boolean ret = unprotectedRenameTo(src, dst, timestamp,
collectedBlocks, options);
if (!collectedBlocks.getToDeleteList().isEmpty()) {
getFSNamesystem().removeBlocksAndUpdateSafemodeTotal(collectedBlocks);
}
return ret;
}
/**
* Rename src to dst.
* See {@link DistributedFileSystem#rename(Path, Path, Options.Rename...)}
* for details related to rename semantics and exceptions.
*
* @param src source path
* @param dst destination path
* @param timestamp modification time
* @param collectedBlocks blocks to be removed
* @param options Rename options
*/
boolean unprotectedRenameTo(String src, String dst, long timestamp,
BlocksMapUpdateInfo collectedBlocks, Options.Rename... options)
throws FileAlreadyExistsException, FileNotFoundException,
ParentNotDirectoryException, QuotaExceededException,
UnresolvedLinkException, IOException {
assert hasWriteLock(); assert hasWriteLock();
boolean overwrite = options != null && Arrays.asList(options).contains boolean overwrite = options != null && Arrays.asList(options).contains
(Rename.OVERWRITE); (Rename.OVERWRITE);
@ -670,7 +696,6 @@ public class FSDirectory implements Closeable {
if (removedDst != null) { if (removedDst != null) {
undoRemoveDst = false; undoRemoveDst = false;
if (removedNum > 0) { if (removedNum > 0) {
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
List<INode> removedINodes = new ChunkedArrayList<INode>(); List<INode> removedINodes = new ChunkedArrayList<INode>();
if (!removedDst.isInLatestSnapshot(dstIIP.getLatestSnapshotId())) { if (!removedDst.isInLatestSnapshot(dstIIP.getLatestSnapshotId())) {
removedDst.destroyAndCollectBlocks(collectedBlocks, removedINodes); removedDst.destroyAndCollectBlocks(collectedBlocks, removedINodes);
@ -680,7 +705,7 @@ public class FSDirectory implements Closeable {
dstIIP.getLatestSnapshotId(), collectedBlocks, removedINodes, dstIIP.getLatestSnapshotId(), collectedBlocks, removedINodes,
true).get(Quota.NAMESPACE) >= 0; true).get(Quota.NAMESPACE) >= 0;
} }
getFSNamesystem().removePathAndBlocks(src, collectedBlocks, getFSNamesystem().removePathAndBlocks(src, null,
removedINodes, false); removedINodes, false);
} }
} }

View File

@ -3627,12 +3627,14 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
HdfsFileStatus resultingStat = null; HdfsFileStatus resultingStat = null;
boolean success = false; boolean success = false;
writeLock(); writeLock();
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
try { try {
checkOperation(OperationCategory.WRITE); checkOperation(OperationCategory.WRITE);
checkNameNodeSafeMode("Cannot rename " + src); checkNameNodeSafeMode("Cannot rename " + src);
src = resolvePath(src, srcComponents); src = resolvePath(src, srcComponents);
dst = resolvePath(dst, dstComponents); dst = resolvePath(dst, dstComponents);
renameToInternal(pc, src, dst, cacheEntry != null, options); renameToInternal(pc, src, dst, cacheEntry != null,
collectedBlocks, options);
resultingStat = getAuditFileInfo(dst, false); resultingStat = getAuditFileInfo(dst, false);
success = true; success = true;
} finally { } finally {
@ -3640,6 +3642,10 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
RetryCache.setState(cacheEntry, success); RetryCache.setState(cacheEntry, success);
} }
getEditLog().logSync(); getEditLog().logSync();
if (!collectedBlocks.getToDeleteList().isEmpty()) {
removeBlocks(collectedBlocks);
collectedBlocks.clear();
}
if (resultingStat != null) { if (resultingStat != null) {
StringBuilder cmd = new StringBuilder("rename options="); StringBuilder cmd = new StringBuilder("rename options=");
for (Rename option : options) { for (Rename option : options) {
@ -3649,8 +3655,9 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
} }
} }
private void renameToInternal(FSPermissionChecker pc, String src, String dst, private void renameToInternal(FSPermissionChecker pc, String src,
boolean logRetryCache, Options.Rename... options) throws IOException { String dst, boolean logRetryCache, BlocksMapUpdateInfo collectedBlocks,
Options.Rename... options) throws IOException {
assert hasWriteLock(); assert hasWriteLock();
if (isPermissionEnabled) { if (isPermissionEnabled) {
// Rename does not operates on link targets // Rename does not operates on link targets
@ -3665,7 +3672,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
waitForLoadingFSImage(); waitForLoadingFSImage();
long mtime = now(); long mtime = now();
dir.renameTo(src, dst, mtime, options); dir.renameTo(src, dst, mtime, collectedBlocks, options);
getEditLog().logRename(src, dst, mtime, logRetryCache, options); getEditLog().logRename(src, dst, mtime, logRetryCache, options);
} }

View File

@ -131,6 +131,7 @@ public class TestDFSRename {
/** /**
* Check the blocks of dst file are cleaned after rename with overwrite * Check the blocks of dst file are cleaned after rename with overwrite
* Restart NN to check the rename successfully
*/ */
@Test(timeout = 120000) @Test(timeout = 120000)
public void testRenameWithOverwrite() throws Exception { public void testRenameWithOverwrite() throws Exception {
@ -160,6 +161,11 @@ public class TestDFSRename {
dfs.rename(srcPath, dstPath, Rename.OVERWRITE); dfs.rename(srcPath, dstPath, Rename.OVERWRITE);
assertTrue(bm.getStoredBlock(lbs.getLocatedBlocks().get(0).getBlock(). assertTrue(bm.getStoredBlock(lbs.getLocatedBlocks().get(0).getBlock().
getLocalBlock()) == null); getLocalBlock()) == null);
// Restart NN and check the rename successfully
cluster.restartNameNodes();
assertFalse(dfs.exists(srcPath));
assertTrue(dfs.exists(dstPath));
} finally { } finally {
if (dfs != null) { if (dfs != null) {
dfs.close(); dfs.close();