package org.apache.hadoop.raid; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Random; import java.util.zip.CRC32; 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.MiniDFSCluster; import org.apache.hadoop.hdfs.RaidDFSUtil; import org.apache.hadoop.hdfs.TestDatanodeBlockScanner; import org.apache.hadoop.hdfs.TestRaidDfs; import org.apache.hadoop.raid.TestBlockFixer; import org.apache.hadoop.hdfs.protocol.LocatedBlocks; import junit.framework.TestCase; public class TestDecoder extends TestCase { final static Log LOG = LogFactory.getLog(TestDecoder.class); 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 int NUM_DATANODES = 3; Configuration conf; String namenode = null; MiniDFSCluster dfsCluster = null; String hftp = null; FileSystem fileSys = null; RaidNode cnode = null; Random rand = new Random(); private void mySetup(int stripeLength) throws Exception { new File(TEST_DIR).mkdirs(); // Make sure data directory exists conf = new Configuration(); conf.setBoolean("raid.config.reload", true); conf.setLong("raid.config.reload.interval", RELOAD_INTERVAL); // scan all policies once every 5 second conf.setLong("raid.policy.rescan.interval", 5000); // do not use map-reduce cluster for Raiding conf.set("raid.classname", "org.apache.hadoop.raid.LocalRaidNode"); conf.set("raid.server.address", "localhost:0"); Utils.loadTestCodecs(conf, stripeLength, stripeLength, 1, 3, "/destraid", "/destraidrs", true, "org.apache.hadoop.raid.XORCode", "org.apache.hadoop.raid.ReedSolomonCode", false); conf.setBoolean("dfs.permissions", false); dfsCluster = new MiniDFSCluster(conf, NUM_DATANODES, true, null); dfsCluster.waitActive(); fileSys = dfsCluster.getFileSystem(); namenode = fileSys.getUri().toString(); FileSystem.setDefaultUri(conf, namenode); } private void doRaid(Path srcPath, Codec codec) throws IOException { RaidNode.doRaid(conf, fileSys.getFileStatus(srcPath), new Path(codec.parityDirectory), codec, new RaidNode.Statistics(), RaidUtils.NULL_PROGRESSABLE, false, 1, 1); } public void testFixBlock() throws Exception { int[] parallelisms = new int[] {1, 3, 4}; try { mySetup(5); for (int parallelism : parallelisms) { verifyDecoder("xor", parallelism); verifyDecoder("rs", parallelism); } } finally { if (dfsCluster != null) { dfsCluster.shutdown(); } } } public void verifyDecoder(String code, int parallelism) throws Exception { Codec codec = Codec.getCodec(code); conf.setInt("raid.encoder.parallelism", parallelism); ConfigBuilder cb = new ConfigBuilder(CONFIG_FILE); cb.addPolicy("RaidTest1", "/user/dikang/raidtest/file" + code + parallelism, 1, 1, code); cb.persist(); Path srcPath = new Path("/user/dikang/raidtest/file" + code + parallelism + "/file1"); long blockSize = 8192 * 1024L; long crc = TestRaidDfs.createTestFilePartialLastBlock(fileSys, srcPath, 1, 7, blockSize); doRaid(srcPath, codec); FileStatus srcStat = fileSys.getFileStatus(srcPath); ParityFilePair pair = ParityFilePair.getParityFile(codec, srcStat, conf); FileStatus file1Stat = fileSys.getFileStatus(srcPath); long length = file1Stat.getLen(); LocatedBlocks file1Loc = RaidDFSUtil.getBlockLocations((DistributedFileSystem)fileSys, srcPath.toUri().getPath(), 0, length); // corrupt file int[] corruptBlockIdxs = new int[] {5}; long errorOffset = 5 * blockSize; for (int idx: corruptBlockIdxs) { TestBlockFixer.corruptBlock(file1Loc.get(idx).getBlock(), dfsCluster); } RaidDFSUtil.reportCorruptBlocks((DistributedFileSystem)fileSys, srcPath, corruptBlockIdxs, blockSize); Decoder decoder = new Decoder(conf, codec); ByteArrayOutputStream out = new ByteArrayOutputStream(); decoder.codec.simulateBlockFix = true; CRC32 oldCRC = decoder.fixErasedBlock(fileSys, srcStat, fileSys, pair.getPath(), true, blockSize, errorOffset, blockSize, false, out, null, null, false); decoder.codec.simulateBlockFix = false; out = new ByteArrayOutputStream(); decoder.fixErasedBlock(fileSys, srcStat, fileSys, pair.getPath(), true, blockSize, errorOffset, blockSize, false, out, null, null, false); // calculate the new crc CRC32 newCRC = new CRC32(); byte[] constructedBytes = out.toByteArray(); newCRC.update(constructedBytes); assertEquals(oldCRC.getValue(), newCRC.getValue()); } }