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