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:
parent
08a9ac7098
commit
3425ae5d7e
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue