|
@@ -0,0 +1,495 @@
|
|
|
+/*
|
|
|
+ * Licensed to the Apache Software Foundation (ASF) under one
|
|
|
+ * or more contributor license agreements. See the NOTICE file
|
|
|
+ * distributed with this work for additional information
|
|
|
+ * regarding copyright ownership. The ASF licenses this file
|
|
|
+ * to you under the Apache License, Version 2.0 (the
|
|
|
+ * "License"); you may not use this file except in compliance
|
|
|
+ * with the License. You may obtain a copy of the License at
|
|
|
+ *
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+ *
|
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ * See the License for the specific language governing permissions and
|
|
|
+ * limitations under the License.
|
|
|
+ */
|
|
|
+package org.apache.hadoop.hdfs.server.namenode.snapshot;
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.fs.Path;
|
|
|
+import org.apache.hadoop.fs.permission.FsPermission;
|
|
|
+import org.apache.hadoop.hdfs.*;
|
|
|
+import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.INode;
|
|
|
+import org.apache.hadoop.hdfs.server.namenode.visitor.NamespacePrintVisitor;
|
|
|
+import org.apache.hadoop.test.GenericTestUtils;
|
|
|
+import org.junit.After;
|
|
|
+import org.junit.Assert;
|
|
|
+import org.junit.Before;
|
|
|
+import org.junit.Test;
|
|
|
+import org.slf4j.event.Level;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.PrintWriter;
|
|
|
+
|
|
|
+import static org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager.DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED;
|
|
|
+import static org.junit.Assert.assertTrue;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Test FSImage correctness with ordered snapshot deletion.
|
|
|
+ */
|
|
|
+public class TestFSImageWithOrderedSnapshotDeletion {
|
|
|
+ {
|
|
|
+ SnapshotTestHelper.disableLogs();
|
|
|
+ GenericTestUtils.setLogLevel(INode.LOG, Level.TRACE);
|
|
|
+ }
|
|
|
+
|
|
|
+ static final long SEED = 0;
|
|
|
+ static final short NUM_DATANODES = 1;
|
|
|
+ static final int BLOCKSIZE = 1024;
|
|
|
+
|
|
|
+ private final Path dir = new Path("/TestSnapshot");
|
|
|
+ private static final String TEST_DIR =
|
|
|
+ GenericTestUtils.getTestDir().getAbsolutePath();
|
|
|
+
|
|
|
+ Configuration conf;
|
|
|
+ MiniDFSCluster cluster;
|
|
|
+ FSNamesystem fsn;
|
|
|
+ DistributedFileSystem hdfs;
|
|
|
+
|
|
|
+ @Before
|
|
|
+ public void setUp() throws Exception {
|
|
|
+ conf = new Configuration();
|
|
|
+ conf.setBoolean(DFS_NAMENODE_SNAPSHOT_DELETION_ORDERED, true);
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).numDataNodes(NUM_DATANODES)
|
|
|
+ .build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @After
|
|
|
+ public void tearDown() throws Exception {
|
|
|
+ if (cluster != null) {
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void rename(Path src, Path dst) throws Exception {
|
|
|
+ printTree("Before rename " + src + " -> " + dst);
|
|
|
+ hdfs.rename(src, dst);
|
|
|
+ printTree("After rename " + src + " -> " + dst);
|
|
|
+ }
|
|
|
+
|
|
|
+ void createFile(Path directory, String filename) throws Exception {
|
|
|
+ final Path f = new Path(directory, filename);
|
|
|
+ DFSTestUtil.createFile(hdfs, f, 0, NUM_DATANODES, SEED);
|
|
|
+ }
|
|
|
+
|
|
|
+ void appendFile(Path directory, String filename) throws Exception {
|
|
|
+ final Path f = new Path(directory, filename);
|
|
|
+ DFSTestUtil.appendFile(hdfs, f, "more data");
|
|
|
+ printTree("appended " + f);
|
|
|
+ }
|
|
|
+
|
|
|
+ void deleteSnapshot(Path directory, String snapshotName) throws Exception {
|
|
|
+ hdfs.deleteSnapshot(directory, snapshotName);
|
|
|
+ printTree("deleted snapshot " + snapshotName);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testDoubleRename() throws Exception {
|
|
|
+ final Path parent = new Path("/parent");
|
|
|
+ hdfs.mkdirs(parent);
|
|
|
+ final Path sub1 = new Path(parent, "sub1");
|
|
|
+ final Path sub1foo = new Path(sub1, "foo");
|
|
|
+ hdfs.mkdirs(sub1);
|
|
|
+ hdfs.mkdirs(sub1foo);
|
|
|
+ createFile(sub1foo, "file0");
|
|
|
+
|
|
|
+ printTree("before s0");
|
|
|
+ hdfs.allowSnapshot(parent);
|
|
|
+ hdfs.createSnapshot(parent, "s0");
|
|
|
+
|
|
|
+ createFile(sub1foo, "file1");
|
|
|
+ createFile(sub1foo, "file2");
|
|
|
+
|
|
|
+ final Path sub2 = new Path(parent, "sub2");
|
|
|
+ hdfs.mkdirs(sub2);
|
|
|
+ final Path sub2foo = new Path(sub2, "foo");
|
|
|
+ // mv /parent/sub1/foo to /parent/sub2/foo
|
|
|
+ rename(sub1foo, sub2foo);
|
|
|
+
|
|
|
+ hdfs.createSnapshot(parent, "s1");
|
|
|
+ hdfs.createSnapshot(parent, "s2");
|
|
|
+ printTree("created snapshots: s1, s2");
|
|
|
+
|
|
|
+ appendFile(sub2foo, "file1");
|
|
|
+ createFile(sub2foo, "file3");
|
|
|
+
|
|
|
+ final Path sub3 = new Path(parent, "sub3");
|
|
|
+ hdfs.mkdirs(sub3);
|
|
|
+ // mv /parent/sub2/foo to /parent/sub3/foo
|
|
|
+ rename(sub2foo, sub3);
|
|
|
+
|
|
|
+ hdfs.delete(sub3, true);
|
|
|
+ printTree("deleted " + sub3);
|
|
|
+
|
|
|
+ deleteSnapshot(parent, "s1");
|
|
|
+ restartCluster();
|
|
|
+
|
|
|
+ deleteSnapshot(parent, "s2");
|
|
|
+ restartCluster();
|
|
|
+ }
|
|
|
+
|
|
|
+ private File getDumpTreeFile(String directory, String suffix) {
|
|
|
+ return new File(directory, String.format("dumpTree_%s", suffix));
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Dump the fsdir tree to a temp file.
|
|
|
+ * @param fileSuffix suffix of the temp file for dumping
|
|
|
+ * @return the temp file
|
|
|
+ */
|
|
|
+ private File dumpTree2File(String fileSuffix) throws IOException {
|
|
|
+ File file = getDumpTreeFile(TEST_DIR, fileSuffix);
|
|
|
+ SnapshotTestHelper.dumpTree2File(fsn.getFSDirectory(), file);
|
|
|
+ return file;
|
|
|
+ }
|
|
|
+
|
|
|
+ void restartCluster() throws Exception {
|
|
|
+ final File before = dumpTree2File("before.txt");
|
|
|
+
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ final File after = dumpTree2File("after.txt");
|
|
|
+ SnapshotTestHelper.compareDumpedTreeInFile(before, after, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private final PrintWriter output = new PrintWriter(System.out, true);
|
|
|
+ private int printTreeCount = 0;
|
|
|
+
|
|
|
+ String printTree(String label) throws Exception {
|
|
|
+ output.println();
|
|
|
+ output.println();
|
|
|
+ output.println("***** " + printTreeCount++ + ": " + label);
|
|
|
+ final String b =
|
|
|
+ fsn.getFSDirectory().getINode("/").dumpTreeRecursively().toString();
|
|
|
+ output.println(b);
|
|
|
+
|
|
|
+ final String s = NamespacePrintVisitor.print2Sting(fsn);
|
|
|
+ Assert.assertEquals(b, s);
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testFSImageWithDoubleRename() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dira, "dirb");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ Path file1 = new Path(dirb, "file1");
|
|
|
+ DFSTestUtil.createFile(hdfs, file1, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ Path rennamePath = new Path(dirx, "dirb");
|
|
|
+ // mv /dir1/dira/dirb to /dir1/dirx/dirb
|
|
|
+ hdfs.rename(dirb, rennamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ DFSTestUtil.appendFile(hdfs, new Path("/dir1/dirx/dirb/file1"),
|
|
|
+ "more data");
|
|
|
+ Path renamePath1 = new Path(dir2, "dira");
|
|
|
+ hdfs.mkdirs(renamePath1);
|
|
|
+ //mv dirx/dirb to /dir2/dira/dirb
|
|
|
+ hdfs.rename(rennamePath, renamePath1);
|
|
|
+ hdfs.delete(renamePath1, true);
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testFSImageWithRename1() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dirx, "dirb");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ Path rennamePath = new Path(dira, "dirb");
|
|
|
+ // mv /dir1/dirx/dirb to /dir1/dira/dirb
|
|
|
+ hdfs.rename(dirb, rennamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s2");
|
|
|
+ Path diry = new Path("/dir1/dira/dirb/diry");
|
|
|
+ hdfs.mkdirs(diry);
|
|
|
+ hdfs.createSnapshot(dir1, "s3");
|
|
|
+ Path file1 = new Path("/dir1/dira/dirb/diry/file1");
|
|
|
+ DFSTestUtil.createFile(hdfs, file1, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(dir1, "s4");
|
|
|
+ hdfs.delete(new Path("/dir1/dira/dirb"), true);
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ hdfs.deleteSnapshot(dir1, "s3");
|
|
|
+ // file1 should exist in the last snapshot
|
|
|
+ assertTrue(hdfs.exists(
|
|
|
+ new Path("/dir1/.snapshot/s4/dira/dirb/diry/file1")));
|
|
|
+
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testFSImageWithRename2() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dirx, "dirb");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ Path rennamePath = new Path(dira, "dirb");
|
|
|
+ // mv /dir1/dirx/dirb to /dir1/dira/dirb
|
|
|
+ hdfs.rename(dirb, rennamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s2");
|
|
|
+ Path file1 = new Path("/dir1/dira/dirb/file1");
|
|
|
+ DFSTestUtil.createFile(hdfs,
|
|
|
+ new Path(
|
|
|
+ "/dir1/dira/dirb/file1"), BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(dir1, "s3");
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ hdfs.deleteSnapshot(dir1, "s3");
|
|
|
+ assertTrue(hdfs.exists(file1));
|
|
|
+
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(timeout = 60000)
|
|
|
+ public void testFSImageWithRename3() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dirx, "dirb");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ Path rennamePath = new Path(dira, "dirb");
|
|
|
+ // mv /dir1/dirx/dirb to /dir1/dira/dirb
|
|
|
+ hdfs.rename(dirb, rennamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s2");
|
|
|
+ Path diry = new Path("/dir1/dira/dirb/diry");
|
|
|
+ hdfs.mkdirs(diry);
|
|
|
+ hdfs.createSnapshot(dir1, "s3");
|
|
|
+ Path file1 = new Path("/dir1/dira/dirb/diry/file1");
|
|
|
+ DFSTestUtil.createFile(hdfs, file1, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(dir1, "s4");
|
|
|
+ hdfs.delete(new Path("/dir1/dira/dirb"), true);
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ hdfs.deleteSnapshot(dir1, "s3");
|
|
|
+ // file1 should exist in the last snapshot
|
|
|
+ assertTrue(hdfs.exists(new Path(
|
|
|
+ "/dir1/.snapshot/s4/dira/dirb/diry/file1")));
|
|
|
+
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testFSImageWithRename4() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dirx, "dirb");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ Path renamePath = new Path(dira, "dirb");
|
|
|
+ // mv /dir1/dirx/dirb to /dir1/dira/dirb
|
|
|
+ hdfs.rename(dirb, renamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s2");
|
|
|
+ Path diry = new Path("/dir1/dira/dirb/diry");
|
|
|
+ hdfs.mkdirs(diry);
|
|
|
+ hdfs.createSnapshot(dir1, "s3");
|
|
|
+ Path file1 = new Path("/dir1/dira/dirb/diry/file1");
|
|
|
+ DFSTestUtil.createFile(hdfs, file1, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(dir1, "s4");
|
|
|
+ hdfs.delete(new Path("/dir1/dira/dirb/diry/file1"), false);
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ hdfs.deleteSnapshot(dir1, "s3");
|
|
|
+ // file1 should exist in the last snapshot
|
|
|
+ assertTrue(hdfs.exists(
|
|
|
+ new Path("/dir1/.snapshot/s4/dira/dirb/diry/file1")));
|
|
|
+
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testFSImageWithRename5() throws Exception {
|
|
|
+ final Path dir1 = new Path("/dir1");
|
|
|
+ final Path dir2 = new Path("/dir2");
|
|
|
+ hdfs.mkdirs(dir1);
|
|
|
+ hdfs.mkdirs(dir2);
|
|
|
+ Path dira = new Path(dir1, "dira");
|
|
|
+ Path dirx = new Path(dir1, "dirx");
|
|
|
+ Path dirb = new Path(dira, "dirb");
|
|
|
+ Path dirc = new Path(dirb, "dirc");
|
|
|
+ hdfs.mkdirs(dira);
|
|
|
+ hdfs.mkdirs(dirb);
|
|
|
+ hdfs.mkdirs(dirc);
|
|
|
+ hdfs.mkdirs(dirx);
|
|
|
+ hdfs.allowSnapshot(dir1);
|
|
|
+ hdfs.createSnapshot(dir1, "s0");
|
|
|
+ Path dird = new Path(dirc, "dird");
|
|
|
+ Path dire = new Path(dird, "dire");
|
|
|
+ Path file1 = new Path(dire, "file1");
|
|
|
+ DFSTestUtil.createFile(hdfs, file1, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ Path rennamePath = new Path(dirx, "dirb");
|
|
|
+ // mv /dir1/dira/dirb to /dir1/dirx/dirb
|
|
|
+ hdfs.rename(dirb, rennamePath);
|
|
|
+ hdfs.createSnapshot(dir1, "s1");
|
|
|
+ DFSTestUtil.appendFile(hdfs,
|
|
|
+ new Path("/dir1/dirx/dirb/dirc/dird/dire/file1"), "more data");
|
|
|
+ Path renamePath1 = new Path(dir2, "dira");
|
|
|
+ hdfs.mkdirs(renamePath1);
|
|
|
+ //mv dirx/dirb to /dir2/dira/dirb
|
|
|
+ hdfs.rename(rennamePath, renamePath1);
|
|
|
+ hdfs.delete(renamePath1, true);
|
|
|
+ hdfs.deleteSnapshot(dir1, "s1");
|
|
|
+ // save namespace and restart cluster
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+ cluster.shutdown();
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).format(false)
|
|
|
+ .numDataNodes(NUM_DATANODES).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ fsn = cluster.getNamesystem();
|
|
|
+ hdfs = cluster.getFileSystem();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test (timeout=60000)
|
|
|
+ public void testDoubleRenamesWithSnapshotDelete() throws Exception {
|
|
|
+ final Path sub1 = new Path(dir, "sub1");
|
|
|
+ hdfs.mkdirs(sub1);
|
|
|
+ hdfs.allowSnapshot(sub1);
|
|
|
+ final Path dir1 = new Path(sub1, "dir1");
|
|
|
+ final Path dir2 = new Path(sub1, "dir2");
|
|
|
+ final Path dir3 = new Path(sub1, "dir3");
|
|
|
+ final String snap3 = "snap3";
|
|
|
+ final String snap4 = "snap4";
|
|
|
+ final String snap5 = "snap5";
|
|
|
+ final String snap6 = "snap6";
|
|
|
+ final Path foo = new Path(dir2, "foo");
|
|
|
+ final Path bar = new Path(dir2, "bar");
|
|
|
+ hdfs.createSnapshot(sub1, "snap1");
|
|
|
+ hdfs.mkdirs(dir1, new FsPermission((short) 0777));
|
|
|
+ rename(dir1, dir2);
|
|
|
+ hdfs.createSnapshot(sub1, "snap2");
|
|
|
+ DFSTestUtil.createFile(hdfs, foo, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ DFSTestUtil.createFile(hdfs, bar, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(sub1, snap3);
|
|
|
+ hdfs.delete(foo, false);
|
|
|
+ DFSTestUtil.createFile(hdfs, foo, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(sub1, snap4);
|
|
|
+ hdfs.delete(foo, false);
|
|
|
+ DFSTestUtil.createFile(hdfs, foo, BLOCKSIZE, (short) 1, SEED);
|
|
|
+ hdfs.createSnapshot(sub1, snap5);
|
|
|
+ rename(dir2, dir3);
|
|
|
+ hdfs.createSnapshot(sub1, snap6);
|
|
|
+ hdfs.delete(dir3, true);
|
|
|
+ deleteSnapshot(sub1, snap6);
|
|
|
+ deleteSnapshot(sub1, snap3);
|
|
|
+ // save namespace and restart Namenode
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_ENTER);
|
|
|
+ hdfs.saveNamespace();
|
|
|
+ hdfs.setSafeMode(HdfsConstants.SafeModeAction.SAFEMODE_LEAVE);
|
|
|
+ cluster.restartNameNode(true);
|
|
|
+ }
|
|
|
+}
|