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 java.io.IOException; 021import java.io.PrintStream; 022import java.io.UncheckedIOException; 023import java.util.ArrayList; 024import java.util.List; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.Cell; 028import org.apache.hadoop.hbase.CellUtil; 029import org.apache.hadoop.hbase.HBaseInterfaceAudience; 030import org.apache.hadoop.hbase.PrivateCellUtil; 031import org.apache.hadoop.hbase.client.RegionInfo; 032import org.apache.hadoop.hbase.io.hfile.CacheConfig; 033import org.apache.hadoop.hbase.io.hfile.HFile; 034import org.apache.hadoop.hbase.io.hfile.HFileScanner; 035import org.apache.hadoop.hbase.master.region.MasterRegionFactory; 036import org.apache.hadoop.hbase.procedure2.Procedure; 037import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 038import org.apache.hadoop.hbase.util.AbstractHBaseTool; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.apache.hadoop.hbase.util.CommonFSUtils; 041import org.apache.yetus.audience.InterfaceAudience; 042import org.apache.yetus.audience.InterfaceStability; 043 044import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; 045import org.apache.hbase.thirdparty.org.apache.commons.cli.Option; 046import org.apache.hbase.thirdparty.org.apache.commons.cli.OptionGroup; 047 048import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos; 049 050/** 051 * A tool to dump the procedures in the HFiles. 052 * <p/> 053 * The different between this and {@link org.apache.hadoop.hbase.io.hfile.HFilePrettyPrinter} is 054 * that, this class will decode the procedure in the cell for better debugging. You are free to use 055 * {@link org.apache.hadoop.hbase.io.hfile.HFilePrettyPrinter} to dump the same file as well. 056 */ 057@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) 058@InterfaceStability.Evolving 059public class HFileProcedurePrettyPrinter extends AbstractHBaseTool { 060 061 private Long procId; 062 063 private List<Path> files = new ArrayList<>(); 064 065 private final PrintStream out; 066 067 public HFileProcedurePrettyPrinter() { 068 this(System.out); 069 } 070 071 public HFileProcedurePrettyPrinter(PrintStream out) { 072 this.out = out; 073 } 074 075 @Override 076 protected void addOptions() { 077 addOptWithArg("w", "seekToPid", "Seek to this procedure id and print this procedure only"); 078 OptionGroup files = new OptionGroup(); 079 files.addOption(new Option("f", "file", true, 080 "File to scan. Pass full-path; e.g. hdfs://a:9000/MasterProcs/master/local/proc/xxx")); 081 files.addOption(new Option("a", "all", false, "Scan the whole procedure region.")); 082 files.setRequired(true); 083 options.addOptionGroup(files); 084 } 085 086 private void addAllHFiles() throws IOException { 087 Path masterProcDir = 088 new Path(CommonFSUtils.getRootDir(conf), MasterRegionFactory.MASTER_STORE_DIR); 089 Path tableDir = CommonFSUtils.getTableDir(masterProcDir, MasterRegionFactory.TABLE_NAME); 090 FileSystem fs = tableDir.getFileSystem(conf); 091 Path regionDir = 092 fs.listStatus(tableDir, p -> RegionInfo.isEncodedRegionName(Bytes.toBytes(p.getName())))[0] 093 .getPath(); 094 List<Path> regionFiles = HFile.getStoreFiles(fs, regionDir); 095 files.addAll(regionFiles); 096 } 097 098 @Override 099 protected void processOptions(CommandLine cmd) { 100 if (cmd.hasOption("w")) { 101 String key = cmd.getOptionValue("w"); 102 if (key != null && key.length() != 0) { 103 procId = Long.parseLong(key); 104 } else { 105 throw new IllegalArgumentException("Invalid row is specified."); 106 } 107 } 108 if (cmd.hasOption("f")) { 109 files.add(new Path(cmd.getOptionValue("f"))); 110 } 111 if (cmd.hasOption("a")) { 112 try { 113 addAllHFiles(); 114 } catch (IOException e) { 115 throw new UncheckedIOException(e); 116 } 117 } 118 } 119 120 private void printCell(Cell cell) throws IOException { 121 out.print("K: " + CellUtil.getCellKeyAsString(cell, 122 c -> Long.toString(Bytes.toLong(c.getRowArray(), c.getRowOffset(), c.getRowLength())))); 123 if (cell.getType() == Cell.Type.Put) { 124 if (cell.getValueLength() == 0) { 125 out.println(" V: mark deleted"); 126 } else { 127 Procedure<?> proc = ProcedureUtil.convertToProcedure(ProcedureProtos.Procedure.parser() 128 .parseFrom(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())); 129 out.println(" V: " + proc.toStringDetails()); 130 } 131 } else { 132 out.println(); 133 } 134 } 135 136 private void processFile(Path file) throws IOException { 137 out.println("Scanning -> " + file); 138 FileSystem fs = file.getFileSystem(conf); 139 try (HFile.Reader reader = HFile.createReader(fs, file, CacheConfig.DISABLED, true, conf); 140 HFileScanner scanner = reader.getScanner(conf, false, false, false)) { 141 if (procId != null) { 142 if ( 143 scanner.seekTo(PrivateCellUtil.createFirstOnRow(Bytes.toBytes(procId.longValue()))) != -1 144 ) { 145 do { 146 Cell cell = scanner.getCell(); 147 long currentProcId = 148 Bytes.toLong(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 149 if (currentProcId != procId.longValue()) { 150 break; 151 } 152 printCell(cell); 153 } while (scanner.next()); 154 } 155 } else { 156 if (scanner.seekTo()) { 157 do { 158 Cell cell = scanner.getCell(); 159 printCell(cell); 160 } while (scanner.next()); 161 } 162 } 163 } 164 } 165 166 @Override 167 protected int doWork() throws Exception { 168 for (Path file : files) { 169 processFile(file); 170 } 171 return 0; 172 } 173 174 public static void main(String[] args) { 175 new HFileProcedurePrettyPrinter().doStaticMain(args); 176 } 177}