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     */
018    package org.apache.hadoop.hdfs.tools.offlineEditsViewer;
019    
020    import org.apache.hadoop.classification.InterfaceAudience;
021    import org.apache.hadoop.classification.InterfaceStability;
022    
023    import org.apache.hadoop.conf.Configured;
024    import org.apache.hadoop.hdfs.tools.offlineEditsViewer.OfflineEditsLoader.OfflineEditsLoaderFactory;
025    import org.apache.hadoop.util.Tool;
026    import org.apache.hadoop.util.ToolRunner;
027    
028    import org.apache.commons.cli.CommandLine;
029    import org.apache.commons.cli.CommandLineParser;
030    import org.apache.commons.cli.OptionBuilder;
031    import org.apache.commons.cli.Options;
032    import org.apache.commons.cli.ParseException;
033    import 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
041    public 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    }