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.region; 019 020import static org.apache.hadoop.hbase.master.region.MasterRegionFactory.PROC_FAMILY; 021 022import java.io.PrintStream; 023import java.time.Instant; 024import java.time.ZoneId; 025import java.time.format.DateTimeFormatter; 026import java.util.Map; 027import org.apache.hadoop.fs.FileSystem; 028import org.apache.hadoop.fs.Path; 029import org.apache.hadoop.hbase.Cell; 030import org.apache.hadoop.hbase.HBaseInterfaceAudience; 031import org.apache.hadoop.hbase.procedure2.Procedure; 032import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 033import org.apache.hadoop.hbase.util.AbstractHBaseTool; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.apache.hadoop.hbase.wal.WAL; 036import org.apache.hadoop.hbase.wal.WALEdit; 037import org.apache.hadoop.hbase.wal.WALFactory; 038import org.apache.hadoop.hbase.wal.WALKey; 039import org.apache.hadoop.hbase.wal.WALPrettyPrinter; 040import org.apache.yetus.audience.InterfaceAudience; 041import org.apache.yetus.audience.InterfaceStability; 042 043import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; 044 045import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos; 046 047/** 048 * A tool to dump the procedures in the WAL files. 049 * <p/> 050 * The different between this and {@link WALPrettyPrinter} is that, this class will decode the 051 * procedure in the WALEdit for better debugging. You are free to use {@link WALPrettyPrinter} to 052 * dump the same file as well. 053 */ 054@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) 055@InterfaceStability.Evolving 056public class WALProcedurePrettyPrinter extends AbstractHBaseTool { 057 058 private static final String KEY_TMPL = "Sequence=%s, at write timestamp=%s"; 059 060 private static final DateTimeFormatter FORMATTER = 061 DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()); 062 063 private String file; 064 065 private PrintStream out; 066 067 public WALProcedurePrettyPrinter() { 068 this(System.out); 069 } 070 071 public WALProcedurePrettyPrinter(PrintStream out) { 072 this.out = out; 073 } 074 075 @Override 076 protected void addOptions() { 077 } 078 079 @Override 080 protected void processOptions(CommandLine cmd) { 081 if (cmd.getArgList().size() != 1) { 082 throw new IllegalArgumentException("Please specify the file to dump"); 083 } 084 file = cmd.getArgList().get(0); 085 } 086 087 @Override 088 protected int doWork() throws Exception { 089 Path path = new Path(file); 090 FileSystem fs = path.getFileSystem(conf); 091 try (WAL.Reader reader = WALFactory.createReader(fs, path, conf)) { 092 for (;;) { 093 WAL.Entry entry = reader.next(); 094 if (entry == null) { 095 return 0; 096 } 097 WALKey key = entry.getKey(); 098 WALEdit edit = entry.getEdit(); 099 long sequenceId = key.getSequenceId(); 100 long writeTime = key.getWriteTime(); 101 out.println( 102 String.format(KEY_TMPL, sequenceId, FORMATTER.format(Instant.ofEpochMilli(writeTime)))); 103 for (Cell cell : edit.getCells()) { 104 Map<String, Object> op = WALPrettyPrinter.toStringMap(cell); 105 if ( 106 !Bytes.equals(PROC_FAMILY, 0, PROC_FAMILY.length, cell.getFamilyArray(), 107 cell.getFamilyOffset(), cell.getFamilyLength()) 108 ) { 109 // We could have cells other than procedure edits, for example, a flush marker 110 WALPrettyPrinter.printCell(out, op, false, false); 111 continue; 112 } 113 long procId = Bytes.toLong(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 114 out.println("pid=" + procId + ", type=" + op.get("type") + ", column=" + op.get("family") 115 + ":" + op.get("qualifier")); 116 if (cell.getType() == Cell.Type.Put) { 117 if (cell.getValueLength() > 0) { 118 // should be a normal put 119 Procedure<?> proc = 120 ProcedureUtil.convertToProcedure(ProcedureProtos.Procedure.parser() 121 .parseFrom(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); 122 out.println("\t" + proc.toStringDetails()); 123 } else { 124 // should be a 'delete' put 125 out.println("\tmark deleted"); 126 } 127 } 128 out.println("cell total size sum: " + cell.heapSize()); 129 } 130 out.println("edit heap size: " + edit.heapSize()); 131 out.println("position: " + reader.getPosition()); 132 } 133 } 134 } 135 136 public static void main(String[] args) { 137 new WALProcedurePrettyPrinter().doStaticMain(args); 138 } 139}