001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hdfs.tools.offlineEditsViewer;
019
020import org.apache.hadoop.classification.InterfaceAudience;
021import org.apache.hadoop.classification.InterfaceStability;
022
023import org.apache.hadoop.conf.Configured;
024import org.apache.hadoop.hdfs.tools.offlineEditsViewer.OfflineEditsLoader.OfflineEditsLoaderFactory;
025import org.apache.hadoop.util.Tool;
026import org.apache.hadoop.util.ToolRunner;
027
028import org.apache.commons.cli.CommandLine;
029import org.apache.commons.cli.CommandLineParser;
030import org.apache.commons.cli.OptionBuilder;
031import org.apache.commons.cli.Options;
032import org.apache.commons.cli.ParseException;
033import org.apache.commons.cli.PosixParser;
034
035/**
036 * This class implements an offline edits viewer, tool that
037 * can be used to view edit logs.
038 */
039@InterfaceAudience.Private
040@InterfaceStability.Unstable
041public class OfflineEditsViewer extends Configured implements Tool {
042
043  private final static String defaultProcessor = "xml";
044
045  /**
046   * Print help.
047   */  
048  private void printHelp() {
049    String summary =
050      "Usage: bin/hdfs oev [OPTIONS] -i INPUT_FILE -o OUTPUT_FILE\n" +
051      "Offline edits viewer\n" +
052      "Parse a Hadoop edits log file INPUT_FILE and save results\n" +
053      "in OUTPUT_FILE.\n" +
054      "Required command line arguments:\n" +
055      "-i,--inputFile <arg>   edits file to process, xml (case\n" +
056      "                       insensitive) extension means XML format,\n" +
057      "                       any other filename means binary format\n" +
058      "-o,--outputFile <arg>  Name of output file. If the specified\n" +
059      "                       file exists, it will be overwritten,\n" +
060      "                       format of the file is determined\n" +
061      "                       by -p option\n" +
062      "\n" + 
063      "Optional command line arguments:\n" +
064      "-p,--processor <arg>   Select which type of processor to apply\n" +
065      "                       against image file, currently supported\n" +
066      "                       processors are: binary (native binary format\n" +
067      "                       that Hadoop uses), xml (default, XML\n" +
068      "                       format), stats (prints statistics about\n" +
069      "                       edits file)\n" +
070      "-h,--help              Display usage information and exit\n" +
071      "-f,--fix-txids         Renumber the transaction IDs in the input,\n" +
072      "                       so that there are no gaps or invalid " +
073      "                       transaction IDs.\n" +
074      "-r,--recover           When reading binary edit logs, use recovery \n" +
075      "                       mode.  This will give you the chance to skip \n" +
076      "                       corrupt parts of the edit log.\n" +
077      "-v,--verbose           More verbose output, prints the input and\n" +
078      "                       output filenames, for processors that write\n" +
079      "                       to a file, also output to screen. On large\n" +
080      "                       image files this will dramatically increase\n" +
081      "                       processing time (default is false).\n";
082
083
084    System.out.println(summary);
085    System.out.println();
086    ToolRunner.printGenericCommandUsage(System.out);
087  }
088
089  /**
090   * Build command-line options and descriptions
091   *
092   * @return command line options
093   */
094  public static Options buildOptions() {
095    Options options = new Options();
096
097    // Build in/output file arguments, which are required, but there is no 
098    // addOption method that can specify this
099    OptionBuilder.isRequired();
100    OptionBuilder.hasArgs();
101    OptionBuilder.withLongOpt("outputFilename");
102    options.addOption(OptionBuilder.create("o"));
103    
104    OptionBuilder.isRequired();
105    OptionBuilder.hasArgs();
106    OptionBuilder.withLongOpt("inputFilename");
107    options.addOption(OptionBuilder.create("i"));
108    
109    options.addOption("p", "processor", true, "");
110    options.addOption("v", "verbose", false, "");
111    options.addOption("f", "fix-txids", false, "");
112    options.addOption("r", "recover", false, "");
113    options.addOption("h", "help", false, "");
114
115    return options;
116  }
117
118  /** Process an edit log using the chosen processor or visitor.
119   * 
120   * @param inputFilename   The file to process
121   * @param outputFilename  The output file name
122   * @param processor       If visitor is null, the processor to use
123   * @param visitor         If non-null, the visitor to use.
124   * 
125   * @return                0 on success; error code otherwise
126   */
127  public int go(String inputFileName, String outputFileName, String processor,
128      Flags flags, OfflineEditsVisitor visitor)
129  {
130    if (flags.getPrintToScreen()) {
131      System.out.println("input  [" + inputFileName  + "]");
132      System.out.println("output [" + outputFileName + "]");
133    }
134    try {
135      if (visitor == null) {
136        visitor = OfflineEditsVisitorFactory.getEditsVisitor(
137            outputFileName, processor, flags.getPrintToScreen());
138      }
139      boolean xmlInput = inputFileName.endsWith(".xml");
140      OfflineEditsLoader loader = OfflineEditsLoaderFactory.
141          createLoader(visitor, inputFileName, xmlInput, flags);
142      loader.loadEdits();
143    } catch(Exception e) {
144      System.err.println("Encountered exception. Exiting: " + e.getMessage());
145      e.printStackTrace(System.err);
146      return -1;
147    }
148    return 0;
149  }
150
151  public static class Flags {
152    private boolean printToScreen = false;
153    private boolean fixTxIds = false;
154    private boolean recoveryMode = false;
155    
156    public Flags() {
157    }
158    
159    public boolean getPrintToScreen() {
160      return printToScreen;
161    }
162    
163    public void setPrintToScreen() {
164      printToScreen = true;
165    }
166    
167    public boolean getFixTxIds() {
168      return fixTxIds;
169    }
170    
171    public void setFixTxIds() {
172      fixTxIds = true;
173    }
174    
175    public boolean getRecoveryMode() {
176      return recoveryMode;
177    }
178    
179    public void setRecoveryMode() {
180      recoveryMode = true;
181    }
182  }
183  
184  /**
185   * Main entry point for ToolRunner (see ToolRunner docs)
186   *
187   * @param argv The parameters passed to this program.
188   * @return 0 on success, non zero on error.
189   */
190  @Override
191  public int run(String[] argv) throws Exception {
192    Options options = buildOptions();
193    if(argv.length == 0) {
194      printHelp();
195      return -1;
196    }
197    CommandLineParser parser = new PosixParser();
198    CommandLine cmd;
199    try {
200      cmd = parser.parse(options, argv);
201    } catch (ParseException e) {
202      System.out.println(
203        "Error parsing command-line options: " + e.getMessage());
204      printHelp();
205      return -1;
206    }
207    
208    if(cmd.hasOption("h")) { // print help and exit
209      printHelp();
210      return -1;
211    }
212    String inputFileName = cmd.getOptionValue("i");
213    String outputFileName = cmd.getOptionValue("o");
214    String processor = cmd.getOptionValue("p");
215    if(processor == null) {
216      processor = defaultProcessor;
217    }
218    Flags flags = new Flags();
219    if (cmd.hasOption("r")) {
220      flags.setRecoveryMode();
221    }
222    if (cmd.hasOption("f")) {
223      flags.setFixTxIds();
224    }
225    if (cmd.hasOption("v")) {
226      flags.setPrintToScreen();
227    }
228    return go(inputFileName, outputFileName, processor, flags, null);
229  }
230
231  /**
232   * main() runs the offline edits viewer using ToolRunner
233   *
234   * @param argv Command line parameters.
235   */
236  public static void main(String[] argv) throws Exception {
237    int res = ToolRunner.run(new OfflineEditsViewer(), argv);
238    System.exit(res);
239  }
240}