package org.apache.hadoop.raid; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.impl.Log4JLogger; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.TestRaidDfs; import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; import org.apache.hadoop.hdfs.server.namenode.NameNode; import org.apache.hadoop.raid.PlacementMonitor.BlockInfo; import org.apache.hadoop.raid.TestPlacementMonitor.FakeBlockAndDatanodeResolver; import org.apache.hadoop.raid.TestPlacementMonitor.FakeExecutorService; import org.apache.hadoop.raid.Utils.Builder; import org.apache.log4j.Level; import junit.framework.TestCase; public class TestDirectoryPlacementMonitor extends TestCase { { ((Log4JLogger)NameNode.stateChangeLog).getLogger().setLevel(Level.ALL); ((Log4JLogger)FSNamesystem.LOG).getLogger().setLevel(Level.ALL); } final static Log LOG = LogFactory.getLog( "org.apache.hadoop.raid.TestDirectoryPlacementMonitor"); final String[] racks = {"/rack1", "/rack1", "/rack1", "/rack1", "/rack1", "/rack1"}; final String[] hosts = {"host1.rack1.com", "host2.rack1.com", "host3.rack1.com", "host4.rack1.com", "host5.rack1.com", "host6.rack1.com"}; final int stripeSize = 3; final long blockSize = 1024L; final long[] fileSizes = new long[]{blockSize + blockSize/2, // block 0, 1 3*blockSize, // block 2, 3 blockSize + blockSize/2 + 1}; // block 4, 5, 6, 7 final long[] blockSizes = new long[]{blockSize, 2*blockSize, blockSize/2}; private boolean checkHistogram(Configuration conf, FileSystem fileSys, FileStatus dirStat, FileStatus parityStat) throws IOException { //Remove the cached items HashMap<String, LocatedFileStatus> cache = PlacementMonitor.locatedFileStatusCache.get(); cache.clear(); PlacementMonitor.locatedFileStatusCache.remove(); PlacementMonitor placementMonitor = new PlacementMonitor(conf); placementMonitor.start(); BlockMover blockMover = placementMonitor.blockMover; TestPlacementMonitor tpm = new TestPlacementMonitor(); FakeExecutorService fakeBlockMover = tpm.new FakeExecutorService(); FakeBlockAndDatanodeResolver resolver = tpm.new FakeBlockAndDatanodeResolver(); blockMover.executor = fakeBlockMover; try { // Start to check the placement List<BlockInfo> srcLstBI = placementMonitor.getBlockInfos(fileSys, dirStat); List<BlockInfo> parityLstBI = new LinkedList<BlockInfo>(); if (parityStat != null) parityLstBI = placementMonitor.getBlockInfos(fileSys, parityStat); assertEquals("Source file blocks don't match parity file blocks", parityLstBI.size(), RaidNode.numStripes(srcLstBI.size(), stripeSize)); for (int i = 0; i< parityLstBI.size(); i++) { StringBuilder sb = new StringBuilder(); for (int j = i * stripeSize; j < srcLstBI.size() && j < (i+1)*stripeSize; j++) { sb.append(srcLstBI.get(j).blockLocation.getOffset() + ":"); for (String name: srcLstBI.get(j).blockLocation.getNames()) { sb.append(name); sb.append(" "); } sb.append(";"); } for (String name: parityLstBI.get(i).blockLocation.getNames()) { sb.append(name); sb.append(" "); } LOG.info("Stripe " + i + " " + sb); } placementMonitor.checkBlockLocations( srcLstBI, parityLstBI, Codec.getCodec("dir-rs"), null, dirStat, resolver); Map<Integer, Long> hist = placementMonitor.blockHistograms.get("dir-rs"); for (Integer key: hist.keySet()) { LOG.info(" Integer: " + key + " Long: " + hist.get(key)); } return hist.size() > 1; } finally { if (placementMonitor != null) { placementMonitor.stop(); } } } /** * This test creates a bunch of files under the directory * and monitor the block mover moves the blocks * @throws Exception */ public void testDirectoryPlacementMonitor() throws Exception { TestRaidPurge trp = new TestRaidPurge(); LOG.info("Test testDirectoryPlacementMonitor started."); long targetReplication = 1; long metaReplication = 1; long[] crcs = new long[3]; int[] seeds = new int[3]; final Path dir1 = new Path("/user/dhruba/dirraidrstest/1"); final Path destPath = new Path("/dir-raidrs/user/dhruba/dirraidrstest"); trp.createClusters(true, 6, racks, hosts); trp.conf.setLong(PurgeMonitor.PURGE_MONITOR_SLEEP_TIME_KEY, 10000L); trp.conf.setBoolean(PlacementMonitor.SIMULATE_KEY, false); trp.conf.setBoolean(BlockMover.RAID_TEST_TREAT_NODES_ON_DEFAULT_RACK_KEY, true); TestDirectoryRaidDfs.setupStripeStore(trp.conf, trp.fileSys); FileSystem fileSys = trp.fileSys; RaidNode cnode = null; try { trp.mySetup(targetReplication, metaReplication); Utils.loadTestCodecs(trp.conf, new Builder[] { Utils.getXORBuilder(), Utils.getXORBuilder().dirRaid( true).setParityDir("/dir-raid").setCodeId("dir-xor"), Utils.getRSBuilder().dirRaid(true).setParityDir( "/dir-raidrs").setCodeId("dir-rs").setParityLength( 1).setStripeLength(stripeSize) }); fileSys.delete(dir1, true); fileSys.delete(destPath, true); TestRaidDfs.createTestFiles(dir1, fileSizes, blockSizes, crcs, seeds, fileSys, (short)1); FileStatus dirStat = fileSys.getFileStatus(dir1); LOG.info("Created test files"); // create an instance of the RaidNode Configuration localConf = new Configuration(trp.conf); cnode = RaidNode.createRaidNode(null, localConf); TestRaidDfs.waitForDirRaided(LOG, fileSys, dir1, destPath); LOG.info("all are raided."); long startTime = System.currentTimeMillis(); boolean badPlacement = true; while (System.currentTimeMillis() - startTime < 120000 && badPlacement) { badPlacement = checkHistogram(trp.conf, fileSys, dirStat, fileSys.getFileStatus(new Path(destPath, dir1.getName()))); Thread.sleep(3000); } assertEquals("Files are still in bad placement", badPlacement, false); LOG.info("Test testDirectoryPlacementMonitor completed."); } catch (Exception e) { LOG.info("testDirectoryPlacementMonitor fails", e); throw e; } finally { if (cnode != null) { cnode.stop(); cnode.join(); } LOG.info("doTestPurge delete directory " + dir1); fileSys.delete(dir1, true); trp.stopClusters(); } } }