Package org.apache.hadoop.raid

Source Code of org.apache.hadoop.raid.TestRaidPurge

/**
* 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.raid;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.log4j.Level;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.mapred.MiniMRCluster;
import org.apache.hadoop.raid.protocol.PolicyInfo;
import org.apache.hadoop.hdfs.TestRaidDfs;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.raid.Utils.Builder;

/**
* If a file gets deleted, then verify that the parity file gets deleted too.
*/
public class TestRaidPurge 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.TestRaidPurge");
  final Random rand = new Random();

  {
    ((Log4JLogger)RaidNode.LOG).getLogger().setLevel(Level.ALL);
  }


  Configuration conf;
  String namenode = null;
  String hftp = null;
  MiniDFSCluster dfs = null;
  MiniMRCluster mr = null;
  FileSystem fileSys = null;
  String jobTrackerName = null;

  public void createClusters(boolean local, int numNodes) throws Exception {
    createClusters(local, numNodes, null, null);
  }
 
  /**
   * create mapreduce and dfs clusters
   */
  public void createClusters(boolean local, int numNodes,
      String[] racks, String[] hosts) throws Exception {

    new File(TEST_DIR).mkdirs(); // Make sure data directory exists
    conf = new Configuration();
    conf.set("raid.config.file", CONFIG_FILE);
    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);
    // the RaidNode does the raiding inline (instead of submitting to map/reduce)
    if (local) {
      conf.set("raid.classname", "org.apache.hadoop.raid.LocalRaidNode");
    } else {
      conf.set("raid.classname", "org.apache.hadoop.raid.DistRaidNode");
    }
    // use local block fixer
    conf.set("raid.blockfix.classname",
             "org.apache.hadoop.raid.LocalBlockIntegrityMonitor");
    conf.set("dfs.block.replicator.classname",
             "org.apache.hadoop.hdfs.server.namenode.BlockPlacementPolicyRaid");

    conf.set("raid.server.address", "localhost:0");
    conf.setLong("dfs.blockreport.intervalMsec", 1000L);
   
    // create a dfs and map-reduce cluster
    final int taskTrackers = numNodes;

    dfs = new MiniDFSCluster(conf, numNodes, true, racks, hosts);
    dfs.waitActive();
    fileSys = dfs.getFileSystem();
    namenode = fileSys.getUri().toString();
    mr = new MiniMRCluster(taskTrackers, namenode, numNodes);
    jobTrackerName = "localhost:" + mr.getJobTrackerPort();
    hftp = "hftp://localhost.localdomain:" + dfs.getNameNodePort();

    FileSystem.setDefaultUri(conf, namenode);
    conf.set("mapred.job.tracker", jobTrackerName);
    //Don't allow empty file to be raid
    conf.setLong(RaidNode.MINIMUM_RAIDABLE_FILESIZE_KEY, 1L);
  }
   
  public void mySetup(long targetReplication,
    long metaReplication) throws Exception {
    // Initialize Raid Policy config
    ConfigBuilder cb = new ConfigBuilder(CONFIG_FILE);
    cb.addPolicy("policy1", "/user/dhruba/raidtest",
        targetReplication, metaReplication);
    cb.addPolicy("policy2", "/user/dhruba/dirraidtest",
        targetReplication, metaReplication, "dir-xor");
    cb.addPolicy("policy3", "/user/dhruba/dirraidrstest",
        targetReplication, metaReplication, "dir-rs");
    cb.persist();
  }

  /**
   * stop clusters created earlier
   */
  public void stopClusters() throws Exception {
    if (mr != null) { mr.shutdown(); }
    if (dfs != null) { dfs.shutdown(); }
  }

  /**
   * Test that parity files that do not have an associated master file
   * get deleted.
   */
  public void testPurge() throws Exception {
    LOG.info("Test testPurge  started.");

    long blockSizes    []  = {1024L};
    long stripeLengths []  = {5};
    long targetReplication = 1;
    long metaReplication   = 1;
    int  numBlock          = 9;
    int  iter = 0;

    createClusters(true, 3);
    try {
      for (long blockSize : blockSizes) {
        for (long stripeLength : stripeLengths) {
           doTestPurge(iter, targetReplication, metaReplication,
                       stripeLength, blockSize, numBlock);
           iter++;
        }
      }
    } finally {
      stopClusters();
    }
    LOG.info("Test testPurge completed.");
  }
 
  private void waitFilesDelete(List<Path> destPaths) throws IOException,
    InterruptedException {
    // wait till parity file and directory are automatically deleted
    for (Path destPath: destPaths) {
      while (fileSys.listStatus(destPath).length > 0) {
        LOG.info("doTestPurge waiting for parity files to be removed.");
        Thread.sleep(1000);                  // keep waiting
      }
    }
  }
 
  /**
   * Create parity file, delete original file and then validate that
   * parity file is automatically deleted.
   */
  private void doTestPurge(int iter, long targetReplication,
                          long metaReplication, long stripeLength,
                          long blockSize, int numBlock) throws Exception {
    LOG.info("doTestPurge started---------------------------:" " iter " + iter +
             " blockSize=" + blockSize + " stripeLength=" + stripeLength);
    mySetup(targetReplication, metaReplication);
    Utils.loadTestCodecs(conf, new Builder[] {
        Utils.getXORBuilder().setStripeLength(stripeLength),
        Utils.getXORBuilder().setStripeLength(stripeLength).dirRaid(
            true).setParityDir("/dir-raid").setCodeId("dir-xor")
    });
   
    Path dir = new Path("/user/dhruba/raidtest/");
    Path file1 = new Path(dir + "/file" + iter);
    Path dir1 = new Path("/user/dhruba/dirraidtest/" + iter);
    Path file2 = new Path(dir1 + "/file1");
    Path file3 = new Path(dir1 + "/file2");
    RaidNode cnode = null;
    try {
      List<Path> destPaths = new ArrayList<Path>();
      Path destPath1 = new Path("/raid/user/dhruba/raidtest");
      destPaths.add(destPath1);
      Path destPath2 = new Path("/dir-raid/user/dhruba/dirraidtest");
      destPaths.add(destPath2);
      fileSys.delete(dir, true);
      fileSys.delete(dir1, true);
      fileSys.delete(destPath1, true);
      fileSys.delete(destPath2, true);
      TestRaidNode.createOldFile(fileSys, file1, 1, numBlock, blockSize);
      TestRaidNode.createOldFile(fileSys, file2, 1, numBlock, blockSize);
      TestRaidNode.createOldFile(fileSys, file3, 1, numBlock, blockSize);
      LOG.info("doTestPurge created test files for iteration " + iter);

      // create an instance of the RaidNode
      Configuration localConf = new Configuration(conf);
      cnode = RaidNode.createRaidNode(null, localConf);
     
      TestRaidDfs.waitForFileRaided(LOG, fileSys, file1, destPath1);
      TestRaidDfs.waitForDirRaided(LOG, fileSys, dir1, destPath2);
      LOG.info("doTestPurge all files found in Raid.");

      // delete original file
      assertTrue("Unable to delete original file " + file1 ,
                 fileSys.delete(file1, true));
      LOG.info("deleted file " + file1);

      // delete original directory
      assertTrue("Unable to delete original directory " + dir1,
                 fileSys.delete(dir1, true));
      LOG.info("deleted directory " + dir1);
      waitFilesDelete(destPaths);
    } catch (Exception e) {
      LOG.info("doTestPurge Exception " + e +
                                          StringUtils.stringifyException(e));
      throw e;
    } finally {
      if (cnode != null) { cnode.stop(); cnode.join(); }
      LOG.info("doTestPurge delete file " + file1);
      fileSys.delete(file1, true);
      fileSys.delete(dir1, true);
    }
    LOG.info("doTestPurge completed:" + " blockSize=" + blockSize +
             " stripeLength=" + stripeLength);
  }

  /**
   * Create a file, wait for parity file to get HARed. Then modify the file,
   * wait for the HAR to get purged.
   */
  public void testPurgeHar() throws Exception {
    LOG.info("testPurgeHar started");
    createClusters(true, 3);
    mySetup(1, 1);
    Utils.loadTestCodecs(conf, new Builder[] {
        Utils.getXORBuilder().setStripeLength(5),
    });
    Path dir = new Path("/user/dhruba/raidtest/");
    Path destPath = new Path("/raid/user/dhruba/raidtest");
    Path file1 = new Path(dir + "/file");
    RaidNode cnode = null;
    try {
      TestRaidNode.createOldFile(fileSys, file1, 1, 8, 8192L);
      LOG.info("testPurgeHar created test files");

      // create an instance of the RaidNode
      Configuration localConf = new Configuration(conf);
      localConf.setInt(RaidNode.RAID_PARITY_HAR_THRESHOLD_DAYS_KEY, 0);
      cnode = RaidNode.createRaidNode(null, localConf);

      // Wait till har is created.
      while (true) {
        try {
          FileStatus[] listPaths = fileSys.listStatus(destPath);
          if (listPaths != null && listPaths.length == 1) {
            FileStatus s = listPaths[0];
            LOG.info("testPurgeHar found path " + s.getPath());
            if (s.getPath().toString().endsWith(".har")) {
              break;
            }
          }
        } catch (FileNotFoundException e) {
          //ignore
        }
        Thread.sleep(1000);                  // keep waiting
      }

      // Set an old timestamp.
      fileSys.setTimes(file1, 0, 0);

      boolean found = false;
      FileStatus[] listPaths = null;
      while (!found || listPaths == null || listPaths.length > 1) {
        listPaths = fileSys.listStatus(destPath);
        if (listPaths != null) {
          for (FileStatus s: listPaths) {
            LOG.info("testPurgeHar waiting for parity file to be recreated" +
              " and har to be deleted found " + s.getPath());
            if (s.getPath().toString().endsWith("file") &&
                s.getModificationTime() == 0) {
              found = true;
            }
          }
        }
        Thread.sleep(1000);
      }
    } catch (Exception e) {
      LOG.info("testPurgeHar Exception " + e +
          StringUtils.stringifyException(e));
      throw e;
    } finally {
      if (cnode != null) { cnode.stop(); cnode.join(); }
      fileSys.delete(dir, true);
      fileSys.delete(destPath, true);
      stopClusters();
    }
  }

  /**
   * Create parity file, delete original file's directory and then validate that
   * parity directory is automatically deleted.
   */
  public void testPurgeDirectory() throws Exception {
    long stripeLength = 5;
    long blockSize = 8192;
    long targetReplication = 1;
    long metaReplication   = 1;
    int  numBlock          = 9;

    createClusters(true, 3);
    mySetup(targetReplication, metaReplication);
    Utils.loadTestCodecs(conf, new Builder[] {
        Utils.getXORBuilder().setStripeLength(stripeLength),
        Utils.getXORBuilder().setStripeLength(stripeLength).dirRaid(
            true).setParityDir("/dir-raid").setCodeId("dir-xor")
    });
    Path dir = new Path("/user/dhruba/raidtest/");
    Path file1 = new Path(dir + "/file1");
    Path dir1 = new Path("/user/dhruba/dirraidtest/1");
    Path file2 = new Path(dir1 + "/file2");
    Path file3 = new Path(dir1 + "/file3");
    RaidNode cnode = null;
    try {
      List<Path> destPaths = new ArrayList<Path>();
      Path destPath1 = new Path("/raid/user/dhruba/raidtest");
      destPaths.add(destPath1);
      Path destPath2 = new Path("/dir-raid/user/dhruba/dirraidtest");
      destPaths.add(destPath2);
      TestRaidNode.createOldFile(fileSys, file1, 1, numBlock, blockSize);
      TestRaidNode.createOldFile(fileSys, file2, 1, numBlock, blockSize);
      TestRaidNode.createOldFile(fileSys, file3, 1, numBlock, blockSize);
     
      // create an instance of the RaidNode
      Configuration localConf = new Configuration(conf);
      cnode = RaidNode.createRaidNode(null, localConf);
      TestRaidDfs.waitForFileRaided(LOG, fileSys, file1, destPath1);
      TestRaidDfs.waitForDirRaided(LOG, fileSys, dir1, destPath2);

      // delete original directory.
      assertTrue("Unable to delete original directory " + file1 ,
                 fileSys.delete(file1.getParent(), true));
      LOG.info("deleted directory " + file1.getParent());
     
      // delete original directory
      assertTrue("Unable to delete original direcotry" + dir1,
          fileSys.delete(dir1.getParent(), true));
      LOG.info("deleted directory " + dir1.getParent());

      // wait till parity file and directory are automatically deleted
      long start = System.currentTimeMillis();
      while ((fileSys.exists(destPath1) ||
              fileSys.exists(destPath2)) &&
            System.currentTimeMillis() - start < 120000) {
        LOG.info("testPurgeDirectory waiting for parity files to be removed.");
        Thread.sleep(1000);                  // keep waiting
      }
      assertFalse(fileSys.exists(destPath1));
      assertFalse(fileSys.exists(destPath2));

    } catch (Exception e) {
      LOG.info("testPurgeDirectory Exception " + e +
                                          StringUtils.stringifyException(e));
      throw e;
    } finally {
      if (cnode != null) { cnode.stop(); cnode.join(); }
      LOG.info("testPurgeDirectory delete file " + file1);
      fileSys.delete(file1, true);
      fileSys.delete(dir1, true);
      stopClusters();
    }
  }

  /**
   * Test that an XOR parity file is removed when a RS parity file is detected.
   */
  public void testPurgePreference() throws Exception {
    LOG.info("Test testPurgePreference started");
    createClusters(true, 3);
    Utils.loadTestCodecs(conf, new Builder[] {
        Utils.getXORBuilder(), // priority 100
        Utils.getXORBuilder().dirRaid(true).setParityDir(
            "/dir-raid").setCodeId("dir-xor").setPriority(101),
        Utils.getRSBuilder()// priority 300
        Utils.getRSBuilder().dirRaid(true).setParityDir(
            "/dir-raidrs").setCodeId("dir-rs").setPriority(301),
        Utils.getXORBuilder().setParityDir("/test-raidrs").setCodeId(
            "testrs").setPriority(1000).simulatedBlockFixed(true)
    });
    mySetup(1, 1);
    Path dir = new Path("/user/test/raidtest");
    Path file1 = new Path(dir + "/file1");
    HashMap<String, PolicyInfo> infos = new HashMap<String, PolicyInfo>();
    for (Codec code: Codec.getCodecs()) {
      PolicyInfo pi = new PolicyInfo("testPurgePreference", conf);
      pi.setSrcPath("/user/test/raidtest");
      pi.setCodecId(code.id);
      pi.setDescription("test policy");
      pi.setProperty("targetReplication", "1");
      pi.setProperty("metaReplication", "1");
      infos.put(code.id, pi);
    }
   
    try {
      LOG.info("Create a old file");
      TestRaidNode.createOldFile(fileSys, file1, 1, 9, 8192L);
      FileStatus stat = fileSys.getFileStatus(file1);
      FileStatus dirStat = fileSys.getFileStatus(dir);
      HashMap<String, Path> parityFiles = new HashMap<String, Path>();
      // Create the parity files.
      LOG.info("Start Raiding");
      for (PolicyInfo pi: infos.values()){
        Codec code = Codec.getCodec(pi.getCodecId());
        FileStatus fsStat = (code.isDirRaid)? dirStat: stat;
        RaidNode.doRaid(
          conf, pi, fsStat, new RaidNode.Statistics(), Reporter.NULL);
        Path parity = RaidNode.getOriginalParityFile(new Path(code.parityDirectory),
              fsStat.getPath());
        assertTrue(fileSys.exists(parity));
        parityFiles.put(pi.getCodecId(), parity);
      }
      LOG.info("Finished Raiding");
      // Check purge of a single parity file.
      PurgeMonitor purgeMonitor = new PurgeMonitor(conf, null);
      LOG.info("Purge testrs");
      purgeMonitor.purgeCode(Codec.getCodec("testrs"));
      // Simulate code couldn't purge normal code even with higher priority
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-rs")));
      assertTrue(fileSys.exists(parityFiles.get("rs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-xor")));
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("Purge dir-rs");
      purgeMonitor.purgeCode(Codec.getCodec("dir-rs"));
      // Calling purge under the Dir-RS path has no effect.
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-rs")));
      assertTrue(fileSys.exists(parityFiles.get("rs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-xor")));
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("Purge rs");
      purgeMonitor.purgeCode(Codec.getCodec("rs"));
      // Calling purge under the rs path will delete rs
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-rs")));
      assertFalse(fileSys.exists(parityFiles.get("rs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-xor")));
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("Purge dir-xor");
      purgeMonitor.purgeCode(Codec.getCodec("dir-xor"));
      // Calling purge under the Dir-xor path will delete dir-xor
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-rs")));
      assertFalse(fileSys.exists(parityFiles.get("dir-xor")));
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("Purge xor");
      purgeMonitor.purgeCode(Codec.getCodec("xor"));
      assertFalse(fileSys.exists(parityFiles.get("xor")));
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-rs")));
     
      LOG.info("delete dir-rs parity file");
      fileSys.delete(parityFiles.get("dir-rs"), true);
      assertFalse(fileSys.exists(parityFiles.get("dir-rs")));
      //Recreate RS and Dir-XOR
      LOG.info("Raid rs");
      RaidNode.doRaid(
          conf, infos.get("rs"), stat, new RaidNode.Statistics(),
          Reporter.NULL);
      assertTrue(fileSys.exists(parityFiles.get("rs")));
      LOG.info("Raid dir-xor");
      RaidNode.doRaid(
          conf, infos.get("dir-xor"), dirStat, new RaidNode.Statistics(),
          Reporter.NULL);
      assertTrue(fileSys.exists(parityFiles.get("dir-xor")));
      LOG.info("Raid xor");
      RaidNode.doRaid(
          conf, infos.get("xor"), stat, new RaidNode.Statistics(),
          Reporter.NULL);
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("Purge dir-xor should fail because rs doesn't have parity " +
          "file for directory, only dir-rs could purge dir-xor");
      purgeMonitor.purgeCode(Codec.getCodec("dir-xor"));
      // Calling purge under the Dir-XOR path succeeds
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("rs")));
      assertTrue(fileSys.exists(parityFiles.get("dir-xor")));
      assertTrue(fileSys.exists(parityFiles.get("xor")));
     
      LOG.info("delete dir-xor parity file");
      fileSys.delete(parityFiles.get("dir-xor"), true);
      assertFalse(fileSys.exists(parityFiles.get("dir-xor")));
     
      LOG.info("Purge xor");
      purgeMonitor.purgeCode(Codec.getCodec("xor"));
      // Calling purge under the Dir-RS path has no effect.
      assertTrue(fileSys.exists(parityFiles.get("testrs")));
      assertTrue(fileSys.exists(parityFiles.get("rs")));
      assertFalse(fileSys.exists(parityFiles.get("xor")));
     
      // The following is har related stuff
      
      Path rsParity = parityFiles.get("rs");
      Path xorParity = parityFiles.get("xor");
      PolicyInfo infoXor = infos.get("xor");
      PolicyInfo infoRs = infos.get("rs");
      // Now check the purge of a parity har.
      // Delete the RS parity for now.
      fileSys.delete(rsParity, true);
      // Recreate the XOR parity.
      Path xorHar = new Path("/raid", "user/test/raidtest/raidtest" +
          RaidNode.HAR_SUFFIX);
      RaidNode.doRaid(
        conf, infoXor, stat, new RaidNode.Statistics(), Reporter.NULL);
      assertTrue(fileSys.exists(xorParity));
      assertFalse(fileSys.exists(xorHar));

      // Create the har.
      long cutoff = System.currentTimeMillis();
      // create an instance of the RaidNode
      Configuration localConf = new Configuration(conf);
      RaidNode cnode = RaidNode.createRaidNode(localConf);
      FileStatus raidStat =
         fileSys.getFileStatus(new Path("/raid"));
      cnode.recurseHar(Codec.getCodec("xor"), fileSys, raidStat,
        "/raid", fileSys, cutoff,
        Codec.getCodec(infoXor.getCodecId()).tmpHarDirectory);

      // Call purge to get rid of the parity file. The har should remain.
      purgeMonitor.purgeCode(Codec.getCodec("xor"));
      // XOR har should exist but xor parity file should have been purged.
      assertFalse(fileSys.exists(xorParity));
      assertTrue(fileSys.exists(xorHar));

      // Now create the RS parity.
      RaidNode.doRaid(
        conf, infoRs, stat, new RaidNode.Statistics(), Reporter.NULL);
      purgeMonitor.purgeCode(Codec.getCodec("xor"));
      // XOR har should get deleted.
      assertTrue(fileSys.exists(rsParity));
      assertFalse(fileSys.exists(xorParity));
      assertFalse(fileSys.exists(xorHar));
      LOG.info("Test testPurgePreference completed");
    } finally {
      stopClusters();
    }
  }
}
TOP

Related Classes of org.apache.hadoop.raid.TestRaidPurge

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.