You are viewing a plain text version of this content. The canonical link for it is here.
Posted to hdfs-commits@hadoop.apache.org by at...@apache.org on 2012/04/01 19:31:32 UTC

svn commit: r1308160 - in /hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs: CHANGES.txt src/test/java/org/apache/hadoop/test/HdfsTestDriver.java src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java

Author: atm
Date: Sun Apr  1 17:31:31 2012
New Revision: 1308160

URL: http://svn.apache.org/viewvc?rev=1308160&view=rev
Log:
HDFS-3167. CLI-based driver for MiniDFSCluster. Contributed by Henry Robinson.

Added:
    hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java
Modified:
    hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt
    hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/HdfsTestDriver.java

Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt?rev=1308160&r1=1308159&r2=1308160&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt (original)
+++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt Sun Apr  1 17:31:31 2012
@@ -68,6 +68,8 @@ Release 2.0.0 - UNRELEASED
     DistributedFileSystem to @InterfaceAudience.LimitedPrivate.
     (harsh via szetszwo)
 
+    HDFS-3167. CLI-based driver for MiniDFSCluster. (Henry Robinson via atm)
+
   IMPROVEMENTS
 
     HDFS-2018. Move all journal stream management code into one place.

Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/HdfsTestDriver.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/HdfsTestDriver.java?rev=1308160&r1=1308159&r2=1308160&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/HdfsTestDriver.java (original)
+++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/HdfsTestDriver.java Sun Apr  1 17:31:31 2012
@@ -36,7 +36,9 @@ public class HdfsTestDriver {
     this.pgd = pgd;
     try {
       pgd.addClass("dfsthroughput", BenchmarkThroughput.class, 
-      "measure hdfs throughput");
+          "measure hdfs throughput");
+      pgd.addClass("minidfscluster", MiniDFSClusterManager.class, 
+          "Run a single-process mini DFS cluster");
     } catch(Throwable e) {
       e.printStackTrace();
     }

Added: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java?rev=1308160&view=auto
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java (added)
+++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/test/MiniDFSClusterManager.java Sun Apr  1 17:31:31 2012
@@ -0,0 +1,259 @@
+/**
+ * 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.test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
+import org.mortbay.util.ajax.JSON;
+
+/**
+ * This class drives the creation of a mini-cluster on the local machine. By
+ * default, a MiniDFSCluster is spawned on the first available ports that are
+ * found.
+ * 
+ * A series of command line flags controls the startup cluster options.
+ * 
+ * This class can dump a Hadoop configuration and some basic metadata (in JSON)
+ * into a textfile.
+ * 
+ * To shutdown the cluster, kill the process.
+ * 
+ * To run this from the command line, do the following (replacing the jar
+ * version as appropriate):
+ * 
+ * $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/share/hadoop/hdfs/hadoop-hdfs-0.24.0-SNAPSHOT-tests.jar org.apache.hadoop.test.MiniDFSClusterManager -options...
+ */
+public class MiniDFSClusterManager {
+  private static final Log LOG =
+    LogFactory.getLog(MiniDFSClusterManager.class);
+
+  private MiniDFSCluster dfs;
+  private String writeDetails;
+  private int numDataNodes;
+  private int nameNodePort;
+  private StartupOption dfsOpts;
+  private String writeConfig;
+  private Configuration conf;
+  
+  private static final long SLEEP_INTERVAL_MS = 1000 * 60;
+
+  /**
+   * Creates configuration options object.
+   */
+  @SuppressWarnings("static-access")
+  private Options makeOptions() {
+    Options options = new Options();
+    options
+        .addOption("datanodes", true, "How many datanodes to start (default 1)")
+        .addOption("format", false, "Format the DFS (default false)")
+        .addOption("cmdport", true,
+            "Which port to listen on for commands (default 0--we choose)")
+        .addOption("nnport", true, "NameNode port (default 0--we choose)")
+        .addOption("namenode", true, "URL of the namenode (default "
+            + "is either the DFS cluster or a temporary dir)")     
+        .addOption(OptionBuilder
+            .hasArgs()
+            .withArgName("property=value")
+            .withDescription("Options to pass into configuration object")
+            .create("D"))
+        .addOption(OptionBuilder
+            .hasArg()
+            .withArgName("path")
+            .withDescription("Save configuration to this XML file.")
+            .create("writeConfig"))
+         .addOption(OptionBuilder
+            .hasArg()
+            .withArgName("path")
+            .withDescription("Write basic information to this JSON file.")
+            .create("writeDetails"))
+        .addOption(OptionBuilder.withDescription("Prints option help.")
+            .create("help"));
+    return options;
+  }
+
+  /**
+   * Main entry-point.
+   */
+  public void run(String[] args) throws IOException {
+    if (!parseArguments(args)) {
+      return;
+    }
+    start();
+    sleepForever();
+  }
+
+  private void sleepForever() {
+    while (true) {
+      try {
+        Thread.sleep(SLEEP_INTERVAL_MS);
+        if (!dfs.isClusterUp()) {
+          LOG.info("Cluster is no longer up, exiting");
+          return;
+        }
+      } catch (InterruptedException _) {
+        // nothing
+      }
+    }
+  }
+
+  /**
+   * Starts DFS as specified in member-variable options. Also writes out
+   * configuration and details, if requested.
+   */
+  public void start() throws IOException, FileNotFoundException {
+    dfs = new MiniDFSCluster.Builder(conf).nameNodePort(nameNodePort)
+                                          .numDataNodes(numDataNodes)
+                                          .startupOption(dfsOpts)
+                                          .build();
+    dfs.waitActive();
+    
+    LOG.info("Started MiniDFSCluster -- namenode on port "
+        + dfs.getNameNodePort());
+
+    if (writeConfig != null) {
+      FileOutputStream fos = new FileOutputStream(new File(writeConfig));
+      conf.writeXml(fos);
+      fos.close();
+    }
+
+    if (writeDetails != null) {
+      Map<String, Object> map = new TreeMap<String, Object>();
+      if (dfs != null) {
+        map.put("namenode_port", dfs.getNameNodePort());
+      }
+
+      FileWriter fw = new FileWriter(new File(writeDetails));
+      fw.write(new JSON().toJSON(map));
+      fw.close();
+    }
+  }
+
+  /**
+   * Parses arguments and fills out the member variables.
+   * @param args Command-line arguments.
+   * @return true on successful parse; false to indicate that the
+   * program should exit.
+   */
+  private boolean parseArguments(String[] args) {
+    Options options = makeOptions();
+    CommandLine cli;
+    try {
+      CommandLineParser parser = new GnuParser();
+      cli = parser.parse(options, args);
+    } catch(ParseException e) {
+      LOG.warn("options parsing failed:  "+e.getMessage());
+      new HelpFormatter().printHelp("...", options);
+      return false;
+    }
+
+    if (cli.hasOption("help")) {
+      new HelpFormatter().printHelp("...", options);
+      return false;
+    }
+    
+    if (cli.getArgs().length > 0) {
+      for (String arg : cli.getArgs()) {
+        LOG.error("Unrecognized option: " + arg);
+        new HelpFormatter().printHelp("...", options);
+        return false;
+      }
+    }
+
+    // HDFS
+    numDataNodes = intArgument(cli, "datanodes", 1);
+    nameNodePort = intArgument(cli, "nnport", 0);
+    dfsOpts = cli.hasOption("format") ?
+        StartupOption.FORMAT : StartupOption.REGULAR;
+
+    // Runner
+    writeDetails = cli.getOptionValue("writeDetails");
+    writeConfig = cli.getOptionValue("writeConfig");
+
+    // General
+    conf = new HdfsConfiguration();
+    updateConfiguration(conf, cli.getOptionValues("D"));
+
+    return true;
+  }
+
+  /**
+   * Updates configuration based on what's given on the command line.
+   *
+   * @param conf2 The configuration object
+   * @param keyvalues An array of interleaved key value pairs.
+   */
+  private void updateConfiguration(Configuration conf2, String[] keyvalues) {
+    int num_confs_updated = 0;
+    if (keyvalues != null) {
+      for (String prop : keyvalues) {
+        String[] keyval = prop.split("=", 2);
+        if (keyval.length == 2) {
+          conf2.set(keyval[0], keyval[1]);
+          num_confs_updated++;
+        } else {
+          LOG.warn("Ignoring -D option " + prop);
+        }
+      }
+    }
+    LOG.info("Updated " + num_confs_updated +
+        " configuration settings from command line.");
+  }
+
+  /**
+   * Extracts an integer argument with specified default value.
+   */
+  private int intArgument(CommandLine cli, String argName, int defaultValue) {
+    String o = cli.getOptionValue(argName);
+    try {
+      if (o != null) {
+        return Integer.parseInt(o);
+      } 
+    } catch (NumberFormatException ex) {
+      LOG.error("Couldn't parse value (" + o + ") for option " 
+          + argName + ". Using default: " + defaultValue);
+    }
+    
+    return defaultValue;    
+  }
+
+  /**
+   * Starts a MiniDFSClusterManager with parameters drawn from the command line.
+   */
+  public static void main(String[] args) throws IOException {
+    new MiniDFSClusterManager().run(args);
+  }
+}