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 }