package org.apache.hadoop.raid; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URI; import java.util.Random; import java.util.Set; import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.DistributedRaidFileSystem; import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.hdfs.TestRaidDfs; import junit.framework.TestCase; public class TestParityMovement extends TestCase { final static String TEST_DIR = new File( System.getProperty("test.build.data", "build/contrib/raid/test/data")).getAbsolutePath(); final static String CONFIG_FILE = new File(TEST_DIR, "test-raid.xml").getAbsolutePath(); final static long RELOAD_INTERVAL = 1000; final static Log LOG = LogFactory.getLog( "org.apache.hadoop.raid.TestParityMovement"); final static Random rand = new Random(); final static int NUM_DATANODES = 3; Configuration conf; String namenode = null; String hftp = null; MiniDFSCluster dfs = null; FileSystem fileSys = null; Path root = null; Set<String> allExpectedMissingFiles = null; protected void mySetup(String erasureCode, int rsParityLength) throws Exception { conf = new Configuration(); if (System.getProperty("hadoop.log.dir") == null) { String base = new File(".").getAbsolutePath(); System.setProperty("hadoop.log.dir", new Path(base).toString() + "/logs"); } new File(TEST_DIR).mkdirs(); // Make sure data directory exists conf.set("raid.config.file", CONFIG_FILE); conf.setBoolean("raid.config.reload", true); conf.setLong("raid.config.reload.interval", RELOAD_INTERVAL); // the RaidNode does the raiding inline conf.set("raid.classname", "org.apache.hadoop.raid.LocalRaidNode"); // use local block fixer conf.set("raid.blockfix.classname", "org.apache.hadoop.raid.LocalBlockIntegrityMonitor"); conf.set("raid.server.address", "localhost:0"); conf.setInt("fs.trash.interval", 1440); Utils.loadTestCodecs(conf, 5, 1, 3, "/destraid", "/destraidrs"); dfs = new MiniDFSCluster(conf, NUM_DATANODES, true, null); dfs.waitActive(); fileSys = dfs.getFileSystem(); namenode = fileSys.getUri().toString(); hftp = "hftp://localhost.localdomain:" + dfs.getNameNodePort(); FileSystem.setDefaultUri(conf, namenode); FileWriter fileWriter = new FileWriter(CONFIG_FILE); fileWriter.write("<?xml version=\"1.0\"?>\n"); String str = "<configuration> " + "<policy name = \"RaidTest1\"> " + "<srcPath prefix=\"/user/dhruba/raidtest\"/> " + "<codecId>xor</codecId> " + "<destPath> /destraid</destPath> " + "<property> " + "<name>targetReplication</name> " + "<value>1</value> " + "<description>after RAIDing, " + "decrease the replication factor of a file to this value." + "</description> " + "</property> " + "<property> " + "<name>metaReplication</name> " + "<value>1</value> " + "<description> replication factor of parity file" + "</description> " + "</property> " + "<property> " + "<name>modTimePeriod</name> " + "<value>2000</value> " + "<description> time (milliseconds) " + "after a file is modified to make it " + "a candidate for RAIDing " + "</description> " + "</property> " + "</policy>" + "</configuration>"; fileWriter.write(str); fileWriter.close(); } private void stopCluster() { if (null != dfs) { dfs.shutdown(); } } private DistributedRaidFileSystem getRaidFS() throws IOException { DistributedFileSystem dfs = (DistributedFileSystem)fileSys; Configuration clientConf = new Configuration(conf); clientConf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedRaidFileSystem"); clientConf.set("fs.raid.underlyingfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); clientConf.setBoolean("fs.hdfs.impl.disable.cache", true); URI dfsUri = dfs.getUri(); return (DistributedRaidFileSystem)FileSystem.get(dfsUri, clientConf); } private void doRaid(Path srcPath, Codec codec) throws IOException { RaidNode.doRaid(conf, fileSys.getFileStatus(srcPath), new Path("/destraid"), codec, new RaidNode.Statistics(), RaidUtils.NULL_PROGRESSABLE, false, 1, 1); } public void testRenameHar() throws Exception { try { mySetup("xor", 1); Path[] testPathList = new Path[] { new Path ("/user/dikang/raidtest/rename/f1"), new Path ("/user/dikang/raidtest/rename/f2"), new Path ("/user/dikang/raidtest/rename/f3")}; Path destHarPath = new Path ("/destraid/user/dikang/raidtest/rename"); DistributedRaidFileSystem raidFs = getRaidFS(); for (Path srcPath : testPathList) { TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 8, 8192L); } raidFs.mkdirs(destHarPath); raidFs.mkdirs(new Path(destHarPath, "rename" + RaidNode.HAR_SUFFIX)); raidFs.rename(new Path("/user/dikang/raidtest"), new Path("/user/dikang/raidtest1")); fail("Expected fail for HAR rename"); } catch (IOException ie) { String message = ie.getMessage(); assertTrue(message.contains("HAR dir")); } finally { stopCluster(); } } public void testRename() throws Exception { try { mySetup("xor", 1); Path srcPath = new Path("/user/dhruba/raidtest/rename/f1"); Path destPath = new Path("/user/dhruba/raidtest/rename/f2"); Path srcPath2 = new Path("/user/dhruba/raidtest/rename/f3"); Path destDirPath = new Path("/user/dhruba/raidtest/rename2"); Path destPath2 = new Path("/user/dhruba/raidtest/rename2/f3"); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 8, 8192L); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath2, 1, 8, 8192L); DistributedRaidFileSystem raidFs = getRaidFS(); assertTrue(raidFs.exists(srcPath)); assertFalse(raidFs.exists(destPath)); // generate the parity files. doRaid(srcPath, Codec.getCodec("xor")); doRaid(srcPath2, Codec.getCodec("xor")); FileStatus srcStat = fileSys.getFileStatus(srcPath); ParityFilePair parity = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat, conf); Path srcParityPath = parity.getPath(); assertTrue(raidFs.exists(srcParityPath)); assertFalse(raidFs.exists(destPath)); // do the rename file assertTrue(raidFs.rename(srcPath, destPath)); // verify the results. assertFalse(raidFs.exists(srcPath)); assertTrue(raidFs.exists(destPath)); assertFalse(raidFs.exists(srcParityPath)); FileStatus srcDest = fileSys.getFileStatus(destPath); parity = ParityFilePair.getParityFile(Codec.getCodec("xor"), srcDest, conf); assertTrue(raidFs.exists(parity.getPath())); // rename the dir assertFalse(raidFs.exists(destDirPath)); assertTrue(raidFs.rename(srcPath2.getParent(), destDirPath)); // verify the results. assertFalse(raidFs.exists(srcPath2.getParent())); assertTrue(raidFs.exists(destDirPath)); FileStatus srcDest2 = fileSys.getFileStatus(destPath2); parity = ParityFilePair.getParityFile(Codec.getCodec("xor"), srcDest2, conf); assertTrue(raidFs.exists(parity.getPath())); // try to rename not existed file. Path notExistedPath = new Path("/user/dhruba/raidtest/raidnotexist"); Path notExistedPath2 = new Path("/user/dhruba/raidtest/raidnotexist2"); assertFalse(raidFs.rename(notExistedPath, notExistedPath2)); } finally { stopCluster(); } } public void testIgnoreCheckingParity() throws Exception { try { mySetup("xor", 1); Path srcPath = new Path("/tmp/raidtest/delete/f1"); Path srcPath2 = new Path("/tmp/raidtest/rename/f2"); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 8, 8192L); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath2, 1, 8, 8192L); DistributedRaidFileSystem raidFs = getRaidFS(); assertTrue(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcPath2)); // generate the parity files. doRaid(srcPath, Codec.getCodec("xor")); doRaid(srcPath2, Codec.getCodec("xor")); FileStatus srcStat = fileSys.getFileStatus(srcPath); FileStatus srcStat2 = fileSys.getFileStatus(srcPath2); ParityFilePair parity = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat, conf); Path srcParityPath = parity.getPath(); ParityFilePair parity2 = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat2, conf); Path srcParityPath2 = parity2.getPath(); assertTrue(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // test delete file raidFs.delete(srcPath); // verify we did not delete the parityPath assertFalse(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcParityPath)); // test rename file raidFs.rename(srcPath2, new Path("/tmp/raidtest/rename/f3")); // verify we did not rename the parityPath assertFalse(raidFs.exists(srcPath2)); assertTrue(raidFs.exists(srcParityPath2)); } finally { stopCluster(); } } public void testIgnoreCheckingParity2() throws Exception { try { mySetup("xor", 1); conf.set(DistributedRaidFileSystem.DIRECTORIES_IGNORE_PARITY_CHECKING_KEY, "/ignore1/test/,/ignore2/test/"); Path srcPath = new Path("/ignore1/test/rename/f1"); Path srcPath2 = new Path("/ignore2/test/rename/f1"); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 8, 8192L); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath2, 1, 8, 8192L); DistributedRaidFileSystem raidFs = getRaidFS(); assertTrue(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcPath2)); // generate the parity files. doRaid(srcPath, Codec.getCodec("xor")); doRaid(srcPath2, Codec.getCodec("xor")); FileStatus srcStat = fileSys.getFileStatus(srcPath); FileStatus srcStat2 = fileSys.getFileStatus(srcPath2); ParityFilePair parity = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat, conf); Path srcParityPath = parity.getPath(); ParityFilePair parity2 = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat2, conf); Path srcParityPath2 = parity2.getPath(); assertTrue(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // test rename files raidFs.rename(srcPath, new Path("/ignore1/test/rename/f2")); raidFs.rename(srcPath2, new Path("/ignore2/test/rename/f2")); // verify we did not rename the parityPath assertFalse(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcParityPath)); assertFalse(raidFs.exists(srcPath2)); assertTrue(raidFs.exists(srcParityPath2)); } finally { stopCluster(); } } public void testDeleteAndUndelete() throws Exception { try { mySetup("xor", 1); Path srcPath = new Path("/user/dhruba/raidtest/rename/f1"); Path srcPath2 = new Path("/user/dhruba/raidtest/rename/f2"); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 8, 8192L); TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath2, 1, 8, 8192L); DistributedRaidFileSystem raidFs = getRaidFS(); assertTrue(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcPath2)); // generate the parity files. doRaid(srcPath, Codec.getCodec("xor")); doRaid(srcPath2, Codec.getCodec("xor")); FileStatus srcStat = fileSys.getFileStatus(srcPath); FileStatus srcStat2 = fileSys.getFileStatus(srcPath2); ParityFilePair parity = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat, conf); Path srcParityPath = parity.getPath(); ParityFilePair parity2 = ParityFilePair.getParityFile( Codec.getCodec("xor"), srcStat2, conf); Path srcParityPath2 = parity2.getPath(); assertTrue(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // do the delete file assertTrue(raidFs.delete(srcPath)); // verify the results. assertFalse(raidFs.exists(srcPath)); assertFalse(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // do the undelete using non-exist userName String nonExistedUser = UUID.randomUUID().toString(); assertFalse(raidFs.undelete(srcPath, nonExistedUser)); // verify the results assertFalse(raidFs.exists(srcPath)); assertFalse(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // do the undelete file using current userName assertTrue(raidFs.undelete(srcPath, null)); //verify the results. assertTrue(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // delete the dir assertTrue(raidFs.delete(srcPath2.getParent())); // verify the results. assertFalse(raidFs.exists(srcPath2.getParent())); assertFalse(raidFs.exists(srcParityPath)); assertFalse(raidFs.exists(srcParityPath2)); assertFalse(raidFs.exists(srcParityPath.getParent())); // undelete the dir assertTrue(raidFs.undelete(srcPath2.getParent(), null)); // verify the results. assertTrue(raidFs.exists(srcPath)); assertTrue(raidFs.exists(srcPath2)); assertTrue(raidFs.exists(srcParityPath)); assertTrue(raidFs.exists(srcParityPath2)); // try to delete not existed file. Path notExistedPath = new Path("/user/dhruba/raidtest/raidnotexist"); assertFalse(raidFs.delete(notExistedPath)); } finally { stopCluster(); } } }