HDFS-6551. Rename with OVERWRITE option may throw NPE when the target file/directory is a reference INode. Contributed by Jing Zhao.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1603612 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jing Zhao 2014-06-18 19:57:00 +00:00
parent 52d18aa217
commit 4cf94aaf80
3 changed files with 56 additions and 11 deletions

View File

@ -656,6 +656,9 @@ Release 2.5.0 - UNRELEASED
HDFS-6552. add DN storage to a BlockInfo will not replace the different HDFS-6552. add DN storage to a BlockInfo will not replace the different
storage from same DN. (Amir Langer via Arpit Agarwal) storage from same DN. (Amir Langer via Arpit Agarwal)
HDFS-6551. Rename with OVERWRITE option may throw NPE when the target
file/directory is a reference INode. (jing9)
BREAKDOWN OF HDFS-2006 SUBTASKS AND RELATED JIRAS BREAKDOWN OF HDFS-2006 SUBTASKS AND RELATED JIRAS
HDFS-6299. Protobuf for XAttr and client-side implementation. (Yi Liu via umamahesh) HDFS-6299. Protobuf for XAttr and client-side implementation. (Yi Liu via umamahesh)

View File

@ -44,7 +44,6 @@ import org.apache.hadoop.fs.XAttr;
import org.apache.hadoop.fs.XAttrSetFlag; import org.apache.hadoop.fs.XAttrSetFlag;
import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.AclStatus;
import org.apache.hadoop.fs.permission.FsAction;
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;
import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSConfigKeys;
@ -891,9 +890,10 @@ public class FSDirectory implements Closeable {
boolean undoRemoveDst = false; boolean undoRemoveDst = false;
INode removedDst = null; INode removedDst = null;
long removedNum = 0;
try { try {
if (dstInode != null) { // dst exists remove it if (dstInode != null) { // dst exists remove it
if (removeLastINode(dstIIP) != -1) { if ((removedNum = removeLastINode(dstIIP)) != -1) {
removedDst = dstIIP.getLastINode(); removedDst = dstIIP.getLastINode();
undoRemoveDst = true; undoRemoveDst = true;
} }
@ -933,13 +933,15 @@ public class FSDirectory implements Closeable {
long filesDeleted = -1; long filesDeleted = -1;
if (removedDst != null) { if (removedDst != null) {
undoRemoveDst = false; undoRemoveDst = false;
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); if (removedNum > 0) {
List<INode> removedINodes = new ChunkedArrayList<INode>(); BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
filesDeleted = removedDst.cleanSubtree(Snapshot.CURRENT_STATE_ID, List<INode> removedINodes = new ChunkedArrayList<INode>();
dstIIP.getLatestSnapshotId(), collectedBlocks, removedINodes, true) filesDeleted = removedDst.cleanSubtree(Snapshot.CURRENT_STATE_ID,
.get(Quota.NAMESPACE); dstIIP.getLatestSnapshotId(), collectedBlocks, removedINodes,
getFSNamesystem().removePathAndBlocks(src, collectedBlocks, true).get(Quota.NAMESPACE);
removedINodes); getFSNamesystem().removePathAndBlocks(src, collectedBlocks,
removedINodes);
}
} }
if (snapshottableDirs.size() > 0) { if (snapshottableDirs.size() > 0) {

View File

@ -171,8 +171,6 @@ public class TestRenameWithSnapshots {
private static boolean existsInDiffReport(List<DiffReportEntry> entries, private static boolean existsInDiffReport(List<DiffReportEntry> entries,
DiffType type, String relativePath) { DiffType type, String relativePath) {
for (DiffReportEntry entry : entries) { for (DiffReportEntry entry : entries) {
System.out.println("DiffEntry is:" + entry.getType() + "\""
+ new String(entry.getRelativePath()) + "\"");
if ((entry.getType() == type) if ((entry.getType() == type)
&& ((new String(entry.getRelativePath())).compareTo(relativePath) == 0)) { && ((new String(entry.getRelativePath())).compareTo(relativePath) == 0)) {
return true; return true;
@ -2374,4 +2372,46 @@ public class TestRenameWithSnapshots {
// save namespace and restart // save namespace and restart
restartClusterAndCheckImage(true); restartClusterAndCheckImage(true);
} }
@Test
public void testRenameWithOverWrite() throws Exception {
final Path root = new Path("/");
final Path foo = new Path(root, "foo");
final Path file1InFoo = new Path(foo, "file1");
final Path file2InFoo = new Path(foo, "file2");
final Path file3InFoo = new Path(foo, "file3");
DFSTestUtil.createFile(hdfs, file1InFoo, 1L, REPL, SEED);
DFSTestUtil.createFile(hdfs, file2InFoo, 1L, REPL, SEED);
DFSTestUtil.createFile(hdfs, file3InFoo, 1L, REPL, SEED);
final Path bar = new Path(root, "bar");
hdfs.mkdirs(bar);
SnapshotTestHelper.createSnapshot(hdfs, root, "s0");
// move file1 from foo to bar
final Path fileInBar = new Path(bar, "file1");
hdfs.rename(file1InFoo, fileInBar);
// rename bar to newDir
final Path newDir = new Path(root, "newDir");
hdfs.rename(bar, newDir);
// move file2 from foo to newDir
final Path file2InNewDir = new Path(newDir, "file2");
hdfs.rename(file2InFoo, file2InNewDir);
// move file3 from foo to newDir and rename it to file1, this will overwrite
// the original file1
final Path file1InNewDir = new Path(newDir, "file1");
hdfs.rename(file3InFoo, file1InNewDir, Rename.OVERWRITE);
SnapshotTestHelper.createSnapshot(hdfs, root, "s1");
SnapshotDiffReport report = hdfs.getSnapshotDiffReport(root, "s0", "s1");
LOG.info("DiffList is \n\"" + report.toString() + "\"");
List<DiffReportEntry> entries = report.getDiffList();
assertEquals(7, entries.size());
assertTrue(existsInDiffReport(entries, DiffType.MODIFY, ""));
assertTrue(existsInDiffReport(entries, DiffType.MODIFY, foo.getName()));
assertTrue(existsInDiffReport(entries, DiffType.DELETE, bar.getName()));
assertTrue(existsInDiffReport(entries, DiffType.CREATE, newDir.getName()));
assertTrue(existsInDiffReport(entries, DiffType.DELETE, "foo/file1"));
assertTrue(existsInDiffReport(entries, DiffType.DELETE, "foo/file2"));
assertTrue(existsInDiffReport(entries, DiffType.DELETE, "foo/file3"));
}
} }