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.hbase.procedure2.store.wal; 019 020import java.io.IOException; 021import java.io.PrintStream; 022import java.util.ArrayList; 023import java.util.List; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.conf.Configured; 026import org.apache.hadoop.fs.FSDataInputStream; 027import org.apache.hadoop.fs.FileStatus; 028import org.apache.hadoop.fs.FileSystem; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.HBaseConfiguration; 031import org.apache.hadoop.hbase.HBaseInterfaceAudience; 032import org.apache.hadoop.hbase.procedure2.Procedure; 033import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 034import org.apache.hadoop.util.Tool; 035import org.apache.hadoop.util.ToolRunner; 036import org.apache.yetus.audience.InterfaceAudience; 037import org.apache.yetus.audience.InterfaceStability; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; 042import org.apache.hbase.thirdparty.org.apache.commons.cli.DefaultParser; 043import org.apache.hbase.thirdparty.org.apache.commons.cli.HelpFormatter; 044import org.apache.hbase.thirdparty.org.apache.commons.cli.Options; 045import org.apache.hbase.thirdparty.org.apache.commons.cli.ParseException; 046 047import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos.ProcedureWALEntry; 048import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos.ProcedureWALHeader; 049 050/** 051 * ProcedureWALPrettyPrinter prints the contents of a given ProcedureWAL file 052 * @see WALProcedureStore#main(String[]) if you want to check parse of a directory of WALs. 053 * @deprecated Since 2.3.0, will be removed in 4.0.0. Keep here only for rolling upgrading, now we 054 * use the new region based procedure store. 055 */ 056@Deprecated 057@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) 058@InterfaceStability.Evolving 059public class ProcedureWALPrettyPrinter extends Configured implements Tool { 060 private static final Logger LOG = LoggerFactory.getLogger(ProcedureWALPrettyPrinter.class); 061 062 private final PrintStream out; 063 064 public ProcedureWALPrettyPrinter() { 065 out = System.out; 066 } 067 068 /** 069 * Reads a log file and outputs its contents. 070 * @param conf HBase configuration relevant to this log file 071 * @param p path of the log file to be read 072 * @throws IOException IOException 073 */ 074 public void processFile(final Configuration conf, final Path p) throws IOException { 075 076 FileSystem fs = p.getFileSystem(conf); 077 if (!fs.exists(p)) { 078 System.err.println("ERROR, file doesnt exist: " + p); 079 return; 080 } 081 if (!fs.isFile(p)) { 082 System.err.println(p + " is not a file"); 083 return; 084 } 085 086 FileStatus logFile = fs.getFileStatus(p); 087 if (logFile.getLen() == 0) { 088 out.println("Zero length file: " + p); 089 return; 090 } 091 092 out.println("Opening procedure state-log: " + p); 093 ProcedureWALFile log = new ProcedureWALFile(fs, logFile); 094 processProcedureWALFile(log); 095 } 096 097 public void processProcedureWALFile(ProcedureWALFile log) throws IOException { 098 log.open(); 099 ProcedureWALHeader header = log.getHeader(); 100 printHeader(header); 101 102 FSDataInputStream stream = log.getStream(); 103 try { 104 boolean hasMore = true; 105 while (hasMore) { 106 ProcedureWALEntry entry = ProcedureWALFormat.readEntry(stream); 107 if (entry == null) { 108 out.println("No more entry, exiting with missing EOF"); 109 hasMore = false; 110 break; 111 } 112 switch (entry.getType()) { 113 case PROCEDURE_WAL_EOF: 114 hasMore = false; 115 break; 116 default: 117 printEntry(entry); 118 } 119 } 120 } catch (IOException e) { 121 out.println("got an exception while reading the procedure WAL " + e.getMessage()); 122 } finally { 123 log.close(); 124 } 125 } 126 127 private void printEntry(final ProcedureWALEntry entry) throws IOException { 128 out.println("EntryType=" + entry.getType()); 129 int procCount = entry.getProcedureCount(); 130 for (int i = 0; i < procCount; i++) { 131 Procedure<?> proc = ProcedureUtil.convertToProcedure(entry.getProcedure(i)); 132 printProcedure(proc); 133 } 134 } 135 136 private void printProcedure(Procedure<?> proc) { 137 out.println(proc.toStringDetails()); 138 } 139 140 private void printHeader(ProcedureWALHeader header) { 141 out.println("ProcedureWALHeader: "); 142 out.println(" Version: " + header.getVersion()); 143 out.println(" Type: " + header.getType()); 144 out.println(" LogId: " + header.getLogId()); 145 out.println(" MinProcId: " + header.getMinProcId()); 146 out.println(); 147 } 148 149 /** 150 * Pass one or more log file names and formatting options and it will dump out a text version of 151 * the contents on <code>stdout</code>. Command line arguments Thrown upon file system errors etc. 152 */ 153 @Override 154 public int run(final String[] args) throws IOException { 155 // create options 156 Options options = new Options(); 157 options.addOption("h", "help", false, "Output help message"); 158 options.addOption("f", "file", true, "File to print"); 159 160 final List<Path> files = new ArrayList<>(); 161 try { 162 CommandLine cmd = new DefaultParser().parse(options, args); 163 164 if (cmd.hasOption("f")) { 165 files.add(new Path(cmd.getOptionValue("f"))); 166 } 167 168 if (files.isEmpty() || cmd.hasOption("h")) { 169 HelpFormatter formatter = new HelpFormatter(); 170 formatter.printHelp("ProcedureWALPrettyPrinter ", options, true); 171 return (-1); 172 } 173 } catch (ParseException e) { 174 LOG.error("Failed to parse commandLine arguments", e); 175 HelpFormatter formatter = new HelpFormatter(); 176 formatter.printHelp("ProcedureWALPrettyPrinter ", options, true); 177 return (-1); 178 } 179 // get configuration, file system, and process the given files 180 for (Path file : files) { 181 processFile(getConf(), file); 182 } 183 return (0); 184 } 185 186 public static void main(String[] args) throws Exception { 187 final Configuration conf = HBaseConfiguration.create(); 188 int exitCode = ToolRunner.run(conf, new ProcedureWALPrettyPrinter(), args); 189 System.exit(exitCode); 190 } 191}