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 private static final String HELP_OPT = "-h"; 043 private static final String HELP_LONGOPT = "--help"; 044 private final static String defaultProcessor = "xml"; 045 046 /** 047 * Print help. 048 */ 049 private void printHelp() { 050 String summary = 051 "Usage: bin/hdfs oev [OPTIONS] -i INPUT_FILE -o OUTPUT_FILE\n" + 052 "Offline edits viewer\n" + 053 "Parse a Hadoop edits log file INPUT_FILE and save results\n" + 054 "in OUTPUT_FILE.\n" + 055 "Required command line arguments:\n" + 056 "-i,--inputFile <arg> edits file to process, xml (case\n" + 057 " insensitive) extension means XML format,\n" + 058 " any other filename means binary format\n" + 059 "-o,--outputFile <arg> Name of output file. If the specified\n" + 060 " file exists, it will be overwritten,\n" + 061 " format of the file is determined\n" + 062 " by -p option\n" + 063 "\n" + 064 "Optional command line arguments:\n" + 065 "-p,--processor <arg> Select which type of processor to apply\n" + 066 " against image file, currently supported\n" + 067 " processors are: binary (native binary format\n" + 068 " that Hadoop uses), xml (default, XML\n" + 069 " format), stats (prints statistics about\n" + 070 " edits file)\n" + 071 "-h,--help Display usage information and exit\n" + 072 "-f,--fix-txids Renumber the transaction IDs in the input,\n" + 073 " so that there are no gaps or invalid\n" + 074 " transaction IDs.\n" + 075 "-r,--recover When reading binary edit logs, use recovery \n" + 076 " mode. This will give you the chance to skip \n" + 077 " corrupt parts of the edit log.\n" + 078 "-v,--verbose More verbose output, prints the input and\n" + 079 " output filenames, for processors that write\n" + 080 " to a file, also output to screen. On large\n" + 081 " image files this will dramatically increase\n" + 082 " processing time (default is false).\n"; 083 084 085 System.out.println(summary); 086 System.out.println(); 087 ToolRunner.printGenericCommandUsage(System.out); 088 } 089 090 /** 091 * Build command-line options and descriptions 092 * 093 * @return command line options 094 */ 095 public static Options buildOptions() { 096 Options options = new Options(); 097 098 // Build in/output file arguments, which are required, but there is no 099 // addOption method that can specify this 100 OptionBuilder.isRequired(); 101 OptionBuilder.hasArgs(); 102 OptionBuilder.withLongOpt("outputFilename"); 103 options.addOption(OptionBuilder.create("o")); 104 105 OptionBuilder.isRequired(); 106 OptionBuilder.hasArgs(); 107 OptionBuilder.withLongOpt("inputFilename"); 108 options.addOption(OptionBuilder.create("i")); 109 110 options.addOption("p", "processor", true, ""); 111 options.addOption("v", "verbose", false, ""); 112 options.addOption("f", "fix-txids", false, ""); 113 options.addOption("r", "recover", false, ""); 114 options.addOption("h", "help", false, ""); 115 116 return options; 117 } 118 119 /** Process an edit log using the chosen processor or visitor. 120 * 121 * @param inputFilename The file to process 122 * @param outputFilename The output file name 123 * @param processor If visitor is null, the processor to use 124 * @param visitor If non-null, the visitor to use. 125 * 126 * @return 0 on success; error code otherwise 127 */ 128 public int go(String inputFileName, String outputFileName, String processor, 129 Flags flags, OfflineEditsVisitor visitor) 130 { 131 if (flags.getPrintToScreen()) { 132 System.out.println("input [" + inputFileName + "]"); 133 System.out.println("output [" + outputFileName + "]"); 134 } 135 try { 136 if (visitor == null) { 137 visitor = OfflineEditsVisitorFactory.getEditsVisitor( 138 outputFileName, processor, flags.getPrintToScreen()); 139 } 140 boolean xmlInput = inputFileName.toLowerCase().endsWith(".xml"); 141 OfflineEditsLoader loader = OfflineEditsLoaderFactory. 142 createLoader(visitor, inputFileName, xmlInput, flags); 143 loader.loadEdits(); 144 } catch(Exception e) { 145 System.err.println("Encountered exception. Exiting: " + e.getMessage()); 146 e.printStackTrace(System.err); 147 return -1; 148 } 149 return 0; 150 } 151 152 public static class Flags { 153 private boolean printToScreen = false; 154 private boolean fixTxIds = false; 155 private boolean recoveryMode = false; 156 157 public Flags() { 158 } 159 160 public boolean getPrintToScreen() { 161 return printToScreen; 162 } 163 164 public void setPrintToScreen() { 165 printToScreen = true; 166 } 167 168 public boolean getFixTxIds() { 169 return fixTxIds; 170 } 171 172 public void setFixTxIds() { 173 fixTxIds = true; 174 } 175 176 public boolean getRecoveryMode() { 177 return recoveryMode; 178 } 179 180 public void setRecoveryMode() { 181 recoveryMode = true; 182 } 183 } 184 185 /** 186 * Main entry point for ToolRunner (see ToolRunner docs) 187 * 188 * @param argv The parameters passed to this program. 189 * @return 0 on success, non zero on error. 190 */ 191 @Override 192 public int run(String[] argv) throws Exception { 193 Options options = buildOptions(); 194 if(argv.length == 0) { 195 printHelp(); 196 return 0; 197 } 198 // print help and exit with zero exit code 199 if (argv.length == 1 && isHelpOption(argv[0])) { 200 printHelp(); 201 return 0; 202 } 203 CommandLineParser parser = new PosixParser(); 204 CommandLine cmd; 205 try { 206 cmd = parser.parse(options, argv); 207 } catch (ParseException e) { 208 System.out.println( 209 "Error parsing command-line options: " + e.getMessage()); 210 printHelp(); 211 return -1; 212 } 213 214 if (cmd.hasOption("h")) { 215 // print help and exit with non zero exit code since 216 // it is not expected to give help and other options together. 217 printHelp(); 218 return -1; 219 } 220 String inputFileName = cmd.getOptionValue("i"); 221 String outputFileName = cmd.getOptionValue("o"); 222 String processor = cmd.getOptionValue("p"); 223 if(processor == null) { 224 processor = defaultProcessor; 225 } 226 Flags flags = new Flags(); 227 if (cmd.hasOption("r")) { 228 flags.setRecoveryMode(); 229 } 230 if (cmd.hasOption("f")) { 231 flags.setFixTxIds(); 232 } 233 if (cmd.hasOption("v")) { 234 flags.setPrintToScreen(); 235 } 236 return go(inputFileName, outputFileName, processor, flags, null); 237 } 238 239 /** 240 * main() runs the offline edits viewer using ToolRunner 241 * 242 * @param argv Command line parameters. 243 */ 244 public static void main(String[] argv) throws Exception { 245 int res = ToolRunner.run(new OfflineEditsViewer(), argv); 246 System.exit(res); 247 } 248 249 private static boolean isHelpOption(String arg) { 250 return arg.equalsIgnoreCase(HELP_OPT) || 251 arg.equalsIgnoreCase(HELP_LONGOPT); 252 } 253}