blob: e9f7e0c324b977ffc759129f609ec09cebb30fc9 [file] [log] [blame]
/**
* 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.tools;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FsShell;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
import org.apache.hadoop.hdfs.protocol.SnapshotInfo;
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.tools.mapred.CopyMapper;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* Base class to test "-rdiff s2 s1".
* Shared by "-rdiff s2 s1 src tgt" and "-rdiff s2 s1 tgt tgt"
*/
public abstract class TestDistCpSyncReverseBase {
private static MiniDFSCluster cluster;
private static final short DATA_NUM = 1;
private static final Configuration DFS_CONF = new HdfsConfiguration();
private Configuration conf;
private DistributedFileSystem dfs;
private DistCpOptions options;
private Path source;
private boolean isSrcNotSameAsTgt = true;
private final Path target = new Path("/target");
private final long blockSize = 1024;
abstract void initSourcePath();
private static List<String> lsr(final String prefix,
final FsShell shell, Path rootDir) throws Exception {
return lsr(prefix, shell, rootDir.toString(), null);
}
private List<String> lsrSource(final String prefix,
final FsShell shell, Path rootDir) throws Exception {
final Path spath = isSrcNotSameAsTgt? rootDir :
new Path(rootDir.toString(),
HdfsConstants.DOT_SNAPSHOT_DIR + Path.SEPARATOR + "s1");
return lsr(prefix, shell, spath.toString(), null);
}
private static List<String> lsr(final String prefix,
final FsShell shell, String rootDir, String glob) throws Exception {
final String dir = glob == null ? rootDir : glob;
System.out.println(prefix + " lsr root=" + rootDir);
final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
final PrintStream out = new PrintStream(bytes);
final PrintStream oldOut = System.out;
final PrintStream oldErr = System.err;
System.setOut(out);
System.setErr(out);
final String results;
try {
Assert.assertEquals(0, shell.run(new String[] {"-lsr", dir }));
results = bytes.toString();
} finally {
IOUtils.closeStream(out);
System.setOut(oldOut);
System.setErr(oldErr);
}
System.out.println("lsr results:\n" + results);
String dirname = rootDir;
if (rootDir.lastIndexOf(Path.SEPARATOR) != -1) {
dirname = rootDir.substring(rootDir.lastIndexOf(Path.SEPARATOR));
}
final List<String> paths = new ArrayList<String>();
for (StringTokenizer t = new StringTokenizer(results, "\n"); t
.hasMoreTokens();) {
final String s = t.nextToken();
final int i = s.indexOf(dirname);
if (i >= 0) {
paths.add(s.substring(i + dirname.length()));
}
}
Collections.sort(paths);
System.out
.println("lsr paths = " + paths.toString().replace(", ", ",\n "));
return paths;
}
public void setSource(final Path src) {
this.source = src;
}
public void setSrcNotSameAsTgt(final boolean srcNotSameAsTgt) {
isSrcNotSameAsTgt = srcNotSameAsTgt;
}
@BeforeClass
public static void setUp() throws Exception {
cluster = new MiniDFSCluster.Builder(DFS_CONF)
.numDataNodes(DATA_NUM)
.build();
cluster.waitActive();
}
@AfterClass
public static void tearDown() throws Exception {
if (cluster != null) {
cluster.shutdown();
}
}
@Before
public void init() throws Exception {
initSourcePath();
conf = new HdfsConfiguration(DFS_CONF);
dfs = cluster.getFileSystem();
if (isSrcNotSameAsTgt) {
dfs.mkdirs(source);
}
dfs.mkdirs(target);
options = new DistCpOptions(Arrays.asList(source), target);
options.setSyncFolder(true);
options.setUseRdiff("s2", "s1");
options.appendToConf(conf);
conf.set(DistCpConstants.CONF_LABEL_TARGET_WORK_PATH, target.toString());
conf.set(DistCpConstants.CONF_LABEL_TARGET_FINAL_PATH, target.toString());
}
@After
public void cleanup() throws Exception {
SnapshotManager snapshotManager = cluster
.getNameNode()
.getNamesystem()
.getSnapshotManager();
for (SnapshotInfo.Bean snapshot : snapshotManager.getSnapshots()) {
dfs.deleteSnapshot(new Path(
StringUtils.substringBefore(
snapshot.getSnapshotDirectory(), ".snapshot")),
snapshot.getSnapshotID());
}
dfs.delete(source, true);
dfs.delete(target, true);
IOUtils.cleanup(null, dfs);
}
/**
* Test the sync returns false in the following scenarios:
* 1. the source/target dir are not snapshottable dir
* 2. the source/target does not have the given snapshots
* 3. changes have been made in target
*/
@Test
public void testFallback() throws Exception {
// the source/target dir are not snapshottable dir
Assert.assertFalse(sync());
// make sure the source path has been updated to the snapshot path
final Path spath = new Path(source,
HdfsConstants.DOT_SNAPSHOT_DIR + Path.SEPARATOR + "s1");
Assert.assertEquals(spath, options.getSourcePaths().get(0));
// reset source path in options
options.setSourcePaths(Arrays.asList(source));
// the source/target does not have the given snapshots
dfs.allowSnapshot(source);
dfs.allowSnapshot(target);
Assert.assertFalse(sync());
Assert.assertEquals(spath, options.getSourcePaths().get(0));
// reset source path in options
options.setSourcePaths(Arrays.asList(source));
this.enableAndCreateFirstSnapshot();
dfs.createSnapshot(target, "s2");
Assert.assertTrue(sync());
// reset source paths in options
options.setSourcePaths(Arrays.asList(source));
// changes have been made in target
final Path subTarget = new Path(target, "sub");
dfs.mkdirs(subTarget);
Assert.assertFalse(sync());
// make sure the source path has been updated to the snapshot path
Assert.assertEquals(spath, options.getSourcePaths().get(0));
// reset source paths in options
options.setSourcePaths(Arrays.asList(source));
dfs.delete(subTarget, true);
Assert.assertTrue(sync());
}
private void syncAndVerify() throws Exception {
final FsShell shell = new FsShell(conf);
lsrSource("Before sync source: ", shell, source);
lsr("Before sync target: ", shell, target);
Assert.assertTrue(sync());
lsrSource("After sync source: ", shell, source);
lsr("After sync target: ", shell, target);
verifyCopy(dfs.getFileStatus(source), dfs.getFileStatus(target), false);
}
private boolean sync() throws Exception {
DistCpSync distCpSync = new DistCpSync(options, conf);
return distCpSync.sync();
}
private void enableAndCreateFirstSnapshot() throws Exception {
if (isSrcNotSameAsTgt) {
dfs.allowSnapshot(source);
dfs.createSnapshot(source, "s1");
}
dfs.allowSnapshot(target);
dfs.createSnapshot(target, "s1");
}
private void createSecondSnapshotAtTarget() throws Exception {
dfs.createSnapshot(target, "s2");
}
private void createMiddleSnapshotAtTarget() throws Exception {
dfs.createSnapshot(target, "s1.5");
}
/**
* create some files and directories under the given directory.
* the final subtree looks like this:
* dir/
* foo/ bar/
* d1/ f1 d2/ f2
* f3 f4
*/
private void initData(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path d1 = new Path(foo, "d1");
final Path f1 = new Path(foo, "f1");
final Path d2 = new Path(bar, "d2");
final Path f2 = new Path(bar, "f2");
final Path f3 = new Path(d1, "f3");
final Path f4 = new Path(d2, "f4");
DFSTestUtil.createFile(dfs, f1, blockSize, DATA_NUM, 0);
DFSTestUtil.createFile(dfs, f2, blockSize, DATA_NUM, 0);
DFSTestUtil.createFile(dfs, f3, blockSize, DATA_NUM, 0);
DFSTestUtil.createFile(dfs, f4, blockSize, DATA_NUM, 0);
}
/**
* make some changes under the given directory (created in the above way).
* 1. rename dir/foo/d1 to dir/bar/d1
* 2. delete dir/bar/d1/f3
* 3. rename dir/foo to /dir/bar/d1/foo
* 4. delete dir/bar/d1/foo/f1
* 5. create file dir/bar/d1/foo/f1 whose size is 2*BLOCK_SIZE
* 6. append one BLOCK to file dir/bar/f2
* 7. rename dir/bar to dir/foo
*
* Thus after all these ops the subtree looks like this:
* dir/
* foo/
* d1/ f2(A) d2/
* foo/ f4
* f1(new)
*/
private int changeData(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path d1 = new Path(foo, "d1");
final Path f2 = new Path(bar, "f2");
final Path bar_d1 = new Path(bar, "d1");
int numDeletedModified = 0;
dfs.rename(d1, bar_d1);
numDeletedModified += 1; // modify ./foo
numDeletedModified += 1; // modify ./bar
final Path f3 = new Path(bar_d1, "f3");
dfs.delete(f3, true);
numDeletedModified += 1; // delete f3
final Path newfoo = new Path(bar_d1, "foo");
dfs.rename(foo, newfoo);
numDeletedModified += 1; // modify ./foo/d1
final Path f1 = new Path(newfoo, "f1");
dfs.delete(f1, true);
numDeletedModified += 1; // delete ./foo/f1
DFSTestUtil.createFile(dfs, f1, 2 * blockSize, DATA_NUM, 0);
DFSTestUtil.appendFile(dfs, f2, (int) blockSize);
numDeletedModified += 1; // modify ./bar/f2
dfs.rename(bar, new Path(dir, "foo"));
return numDeletedModified;
}
/**
* Test the basic functionality.
*/
@Test
public void testSync() throws Exception {
if (isSrcNotSameAsTgt) {
initData(source);
}
initData(target);
enableAndCreateFirstSnapshot();
final FsShell shell = new FsShell(conf);
lsrSource("Before source: ", shell, source);
lsr("Before target: ", shell, target);
// make changes under target
int numDeletedModified = changeData(target);
createSecondSnapshotAtTarget();
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
DistCpSync distCpSync = new DistCpSync(options, conf);
lsr("Before sync target: ", shell, target);
// do the sync
Assert.assertTrue(distCpSync.sync());
lsr("After sync target: ", shell, target);
// make sure the source path has been updated to the snapshot path
final Path spath = new Path(source,
HdfsConstants.DOT_SNAPSHOT_DIR + Path.SEPARATOR + "s1");
Assert.assertEquals(spath, options.getSourcePaths().get(0));
// build copy listing
final Path listingPath = new Path("/tmp/META/fileList.seq");
CopyListing listing = new SimpleCopyListing(conf, new Credentials(),
distCpSync);
listing.buildListing(listingPath, options);
Map<Text, CopyListingFileStatus> copyListing = getListing(listingPath);
CopyMapper copyMapper = new CopyMapper();
StubContext stubContext = new StubContext(conf, null, 0);
Mapper<Text, CopyListingFileStatus, Text, Text>.Context context =
stubContext.getContext();
// Enable append
context.getConfiguration().setBoolean(
DistCpOptionSwitch.APPEND.getConfigLabel(), true);
copyMapper.setup(context);
for (Map.Entry<Text, CopyListingFileStatus> entry :
copyListing.entrySet()) {
copyMapper.map(entry.getKey(), entry.getValue(), context);
}
lsrSource("After mapper source: ", shell, source);
lsr("After mapper target: ", shell, target);
// verify that we only list modified and created files/directories
Assert.assertEquals(numDeletedModified, copyListing.size());
// verify that we only copied new appended data of f2 and the new file f1
Assert.assertEquals(blockSize * 3, stubContext.getReporter()
.getCounter(CopyMapper.Counter.BYTESCOPIED).getValue());
// verify the source and target now has the same structure
verifyCopy(dfs.getFileStatus(spath), dfs.getFileStatus(target), false);
}
private Map<Text, CopyListingFileStatus> getListing(Path listingPath)
throws Exception {
SequenceFile.Reader reader = null;
Map<Text, CopyListingFileStatus> values = new HashMap<>();
try {
reader = new SequenceFile.Reader(conf,
SequenceFile.Reader.file(listingPath));
Text key = new Text();
CopyListingFileStatus value = new CopyListingFileStatus();
while (reader.next(key, value)) {
values.put(key, value);
key = new Text();
value = new CopyListingFileStatus();
}
} finally {
if (reader != null) {
reader.close();
}
}
return values;
}
private void verifyCopy(FileStatus s, FileStatus t, boolean compareName)
throws Exception {
Assert.assertEquals(s.isDirectory(), t.isDirectory());
if (compareName) {
Assert.assertEquals(s.getPath().getName(), t.getPath().getName());
}
if (!s.isDirectory()) {
// verify the file content is the same
byte[] sbytes = DFSTestUtil.readFileBuffer(dfs, s.getPath());
byte[] tbytes = DFSTestUtil.readFileBuffer(dfs, t.getPath());
Assert.assertArrayEquals(sbytes, tbytes);
} else {
FileStatus[] slist = dfs.listStatus(s.getPath());
FileStatus[] tlist = dfs.listStatus(t.getPath());
Assert.assertEquals(slist.length, tlist.length);
for (int i = 0; i < slist.length; i++) {
verifyCopy(slist[i], tlist[i], true);
}
}
}
/**
* Test the case that "current" is snapshotted as "s2".
* @throws Exception
*/
@Test
public void testSyncWithCurrent() throws Exception {
options.setUseRdiff(".", "s1");
if (isSrcNotSameAsTgt) {
initData(source);
}
initData(target);
enableAndCreateFirstSnapshot();
// make changes under target
changeData(target);
// do the sync
Assert.assertTrue(sync());
final Path spath = new Path(source,
HdfsConstants.DOT_SNAPSHOT_DIR + Path.SEPARATOR + "s1");
// make sure the source path is still unchanged
Assert.assertEquals(spath, options.getSourcePaths().get(0));
}
private void initData2(Path dir) throws Exception {
final Path test = new Path(dir, "test");
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path f1 = new Path(test, "f1");
final Path f2 = new Path(foo, "f2");
final Path f3 = new Path(bar, "f3");
DFSTestUtil.createFile(dfs, f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, f2, blockSize, DATA_NUM, 1L);
DFSTestUtil.createFile(dfs, f3, blockSize, DATA_NUM, 2L);
}
private void changeData2(Path dir) throws Exception {
final Path tmpFoo = new Path(dir, "tmpFoo");
final Path test = new Path(dir, "test");
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
dfs.rename(test, tmpFoo);
dfs.rename(foo, test);
dfs.rename(bar, foo);
dfs.rename(tmpFoo, bar);
}
@Test
public void testSync2() throws Exception {
if (isSrcNotSameAsTgt) {
initData2(source);
}
initData2(target);
enableAndCreateFirstSnapshot();
// make changes under target
changeData2(target);
createSecondSnapshotAtTarget();
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
syncAndVerify();
}
private void initData3(Path dir) throws Exception {
final Path test = new Path(dir, "test");
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path f1 = new Path(test, "file");
final Path f2 = new Path(foo, "file");
final Path f3 = new Path(bar, "file");
DFSTestUtil.createFile(dfs, f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, f2, blockSize * 2, DATA_NUM, 1L);
DFSTestUtil.createFile(dfs, f3, blockSize * 3, DATA_NUM, 2L);
}
private void changeData3(Path dir) throws Exception {
final Path test = new Path(dir, "test");
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path f1 = new Path(test, "file");
final Path f2 = new Path(foo, "file");
final Path f3 = new Path(bar, "file");
final Path newf1 = new Path(test, "newfile");
final Path newf2 = new Path(foo, "newfile");
final Path newf3 = new Path(bar, "newfile");
dfs.rename(f1, newf1);
dfs.rename(f2, newf2);
dfs.rename(f3, newf3);
}
/**
* Test a case where there are multiple source files with the same name.
*/
@Test
public void testSync3() throws Exception {
if (isSrcNotSameAsTgt) {
initData3(source);
}
initData3(target);
enableAndCreateFirstSnapshot();
// make changes under target
changeData3(target);
createSecondSnapshotAtTarget();
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
syncAndVerify();
}
private void initData4(Path dir) throws Exception {
final Path d1 = new Path(dir, "d1");
final Path d2 = new Path(d1, "d2");
final Path f1 = new Path(d2, "f1");
DFSTestUtil.createFile(dfs, f1, blockSize, DATA_NUM, 0L);
}
private int changeData4(Path dir) throws Exception {
final Path d1 = new Path(dir, "d1");
final Path d11 = new Path(dir, "d11");
final Path d2 = new Path(d1, "d2");
final Path d21 = new Path(d1, "d21");
final Path f1 = new Path(d2, "f1");
int numDeletedAndModified = 0;
dfs.delete(f1, false);
numDeletedAndModified += 1;
dfs.rename(d2, d21);
numDeletedAndModified += 1;
dfs.rename(d1, d11);
numDeletedAndModified += 1;
return numDeletedAndModified;
}
/**
* Test a case where multiple level dirs are renamed.
*/
@Test
public void testSync4() throws Exception {
if (isSrcNotSameAsTgt) {
initData4(source);
}
initData4(target);
enableAndCreateFirstSnapshot();
final FsShell shell = new FsShell(conf);
lsr("Before change target: ", shell, target);
// make changes under target
int numDeletedAndModified = changeData4(target);
createSecondSnapshotAtTarget();
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
testAndVerify(numDeletedAndModified);
}
private void initData5(Path dir) throws Exception {
final Path d1 = new Path(dir, "d1");
final Path d2 = new Path(dir, "d2");
final Path f1 = new Path(d1, "f1");
final Path f2 = new Path(d2, "f2");
DFSTestUtil.createFile(dfs, f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, f2, blockSize, DATA_NUM, 0L);
}
private int changeData5(Path dir) throws Exception {
final Path d1 = new Path(dir, "d1");
final Path d2 = new Path(dir, "d2");
final Path f1 = new Path(d1, "f1");
final Path tmp = new Path(dir, "tmp");
int numDeletedAndModified = 0;
dfs.delete(f1, false);
numDeletedAndModified += 1;
dfs.rename(d1, tmp);
numDeletedAndModified += 1;
dfs.rename(d2, d1);
numDeletedAndModified += 1;
final Path f2 = new Path(d1, "f2");
dfs.delete(f2, false);
numDeletedAndModified += 1;
return numDeletedAndModified;
}
/**
* Test a case with different delete and rename sequences.
*/
@Test
public void testSync5() throws Exception {
if (isSrcNotSameAsTgt) {
initData5(source);
}
initData5(target);
enableAndCreateFirstSnapshot();
// make changes under target
int numDeletedAndModified = changeData5(target);
createSecondSnapshotAtTarget();
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
testAndVerify(numDeletedAndModified);
}
private void testAndVerify(int numDeletedAndModified)
throws Exception{
SnapshotDiffReport report = dfs.getSnapshotDiffReport(target, "s2", "s1");
System.out.println(report);
final FsShell shell = new FsShell(conf);
lsrSource("Before sync source: ", shell, source);
lsr("Before sync target: ", shell, target);
DistCpSync distCpSync = new DistCpSync(options, conf);
// do the sync
distCpSync.sync();
lsr("After sync target: ", shell, target);
// make sure the source path has been updated to the snapshot path
final Path spath = new Path(source,
HdfsConstants.DOT_SNAPSHOT_DIR + Path.SEPARATOR + "s1");
Assert.assertEquals(spath, options.getSourcePaths().get(0));
// build copy listing
final Path listingPath = new Path("/tmp/META/fileList.seq");
CopyListing listing = new SimpleCopyListing(conf, new Credentials(), distCpSync);
listing.buildListing(listingPath, options);
Map<Text, CopyListingFileStatus> copyListing = getListing(listingPath);
CopyMapper copyMapper = new CopyMapper();
StubContext stubContext = new StubContext(conf, null, 0);
Mapper<Text, CopyListingFileStatus, Text, Text>.Context context =
stubContext.getContext();
// Enable append
context.getConfiguration().setBoolean(
DistCpOptionSwitch.APPEND.getConfigLabel(), true);
copyMapper.setup(context);
for (Map.Entry<Text, CopyListingFileStatus> entry :
copyListing.entrySet()) {
copyMapper.map(entry.getKey(), entry.getValue(), context);
}
// verify that we only list modified and created files/directories
Assert.assertEquals(numDeletedAndModified, copyListing.size());
lsr("After Copy target: ", shell, target);
// verify the source and target now has the same structure
verifyCopy(dfs.getFileStatus(spath), dfs.getFileStatus(target), false);
}
private void initData6(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path foo_f1 = new Path(foo, "f1");
final Path bar_f1 = new Path(bar, "f1");
DFSTestUtil.createFile(dfs, foo_f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, bar_f1, blockSize, DATA_NUM, 0L);
}
private int changeData6(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path foo2 = new Path(dir, "foo2");
final Path foo_f1 = new Path(foo, "f1");
int numDeletedModified = 0;
dfs.rename(foo, foo2);
dfs.rename(bar, foo);
dfs.rename(foo2, bar);
DFSTestUtil.appendFile(dfs, foo_f1, (int) blockSize);
numDeletedModified += 1; // modify ./bar/f1
return numDeletedModified;
}
/**
* Test a case where there is a cycle in renaming dirs.
*/
@Test
public void testSync6() throws Exception {
if (isSrcNotSameAsTgt) {
initData6(source);
}
initData6(target);
enableAndCreateFirstSnapshot();
int numDeletedModified = changeData6(target);
createSecondSnapshotAtTarget();
testAndVerify(numDeletedModified);
}
private void initData7(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path foo_f1 = new Path(foo, "f1");
final Path bar_f1 = new Path(bar, "f1");
DFSTestUtil.createFile(dfs, foo_f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, bar_f1, blockSize, DATA_NUM, 0L);
}
private int changeData7(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path foo2 = new Path(dir, "foo2");
final Path foo_f1 = new Path(foo, "f1");
final Path foo2_f2 = new Path(foo2, "f2");
final Path foo_d1 = new Path(foo, "d1");
final Path foo_d1_f3 = new Path(foo_d1, "f3");
int numDeletedAndModified = 0;
dfs.rename(foo, foo2);
DFSTestUtil.createFile(dfs, foo_f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.appendFile(dfs, foo_f1, (int) blockSize);
dfs.rename(foo_f1, foo2_f2);
/*
* Difference between snapshot s1 and current directory under directory
/target:
M .
+ ./foo
R ./foo -> ./foo2
M ./foo
+ ./foo/f2
*/
numDeletedAndModified += 1; // "M ./foo"
DFSTestUtil.createFile(dfs, foo_d1_f3, blockSize, DATA_NUM, 0L);
return numDeletedAndModified;
}
/**
* Test a case where rename a dir, then create a new dir with the same name
* and sub dir.
*/
@Test
public void testSync7() throws Exception {
if (isSrcNotSameAsTgt) {
initData7(source);
}
initData7(target);
enableAndCreateFirstSnapshot();
int numDeletedAndModified = changeData7(target);
createSecondSnapshotAtTarget();
testAndVerify(numDeletedAndModified);
}
private void initData8(Path dir) throws Exception {
final Path foo = new Path(dir, "foo");
final Path bar = new Path(dir, "bar");
final Path d1 = new Path(dir, "d1");
final Path foo_f1 = new Path(foo, "f1");
final Path bar_f1 = new Path(bar, "f1");
final Path d1_f1 = new Path(d1, "f1");
DFSTestUtil.createFile(dfs, foo_f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, bar_f1, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, d1_f1, blockSize, DATA_NUM, 0L);
}
private int changeData8(Path dir, boolean createMiddleSnapshot)
throws Exception {
final Path foo = new Path(dir, "foo");
final Path createdDir = new Path(dir, "c");
final Path d1 = new Path(dir, "d1");
final Path d1_f1 = new Path(d1, "f1");
final Path createdDir_f1 = new Path(createdDir, "f1");
final Path foo_f3 = new Path(foo, "f3");
final Path new_foo = new Path(createdDir, "foo");
final Path foo_f4 = new Path(foo, "f4");
final Path foo_d1 = new Path(foo, "d1");
final Path bar = new Path(dir, "bar");
final Path bar1 = new Path(dir, "bar1");
int numDeletedAndModified = 0;
DFSTestUtil.createFile(dfs, foo_f3, blockSize, DATA_NUM, 0L);
DFSTestUtil.createFile(dfs, createdDir_f1, blockSize, DATA_NUM, 0L);
dfs.rename(createdDir_f1, foo_f4);
dfs.rename(d1_f1, createdDir_f1); // rename ./d1/f1 -> ./c/f1
numDeletedAndModified += 1; // modify ./c/foo/d1
if (createMiddleSnapshot) {
this.createMiddleSnapshotAtTarget();
}
dfs.rename(d1, foo_d1);
numDeletedAndModified += 1; // modify ./c/foo
dfs.rename(foo, new_foo);
dfs.rename(bar, bar1);
return numDeletedAndModified;
}
/**
* Test a case where create a dir, then mv a existed dir into it.
*/
@Test
public void testSync8() throws Exception {
if (isSrcNotSameAsTgt) {
initData8(source);
}
initData8(target);
enableAndCreateFirstSnapshot();
int numDeletedModified = changeData8(target, false);
createSecondSnapshotAtTarget();
testAndVerify(numDeletedModified);
}
/**
* Test a case where create a dir, then mv a existed dir into it.
* The difference between this one and testSync8 is, this one
* also creates a snapshot s1.5 in between s1 and s2.
*/
@Test
public void testSync9() throws Exception {
if (isSrcNotSameAsTgt) {
initData8(source);
}
initData8(target);
enableAndCreateFirstSnapshot();
int numDeletedModified = changeData8(target, true);
createSecondSnapshotAtTarget();
testAndVerify(numDeletedModified);
}
}