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 }