diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/RegionProcedureStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/RegionProcedureStore.java
index 169a194d6082..86930b9cc84e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/RegionProcedureStore.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/RegionProcedureStore.java
@@ -120,7 +120,7 @@ public class RegionProcedureStore extends ProcedureStoreBase {
private static final TableName TABLE_NAME = TableName.valueOf("master:procedure");
- private static final byte[] FAMILY = Bytes.toBytes("p");
+ static final byte[] FAMILY = Bytes.toBytes("p");
private static final byte[] PROC_QUALIFIER = Bytes.toBytes("d");
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/WALProcedurePrettyPrinter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/WALProcedurePrettyPrinter.java
new file mode 100644
index 000000000000..35f9fc0ce570
--- /dev/null
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure2/store/region/WALProcedurePrettyPrinter.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.procedure2.store.region;
+
+import static org.apache.hadoop.hbase.procedure2.store.region.RegionProcedureStore.FAMILY;
+
+import java.io.PrintStream;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.HBaseInterfaceAudience;
+import org.apache.hadoop.hbase.procedure2.Procedure;
+import org.apache.hadoop.hbase.procedure2.ProcedureUtil;
+import org.apache.hadoop.hbase.util.AbstractHBaseTool;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.wal.WAL;
+import org.apache.hadoop.hbase.wal.WALEdit;
+import org.apache.hadoop.hbase.wal.WALFactory;
+import org.apache.hadoop.hbase.wal.WALKey;
+import org.apache.hadoop.hbase.wal.WALPrettyPrinter;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.yetus.audience.InterfaceStability;
+
+import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
+
+import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
+
+/**
+ * A tool to dump the procedures in the WAL files.
+ *
+ * The different between this and {@link WALPrettyPrinter} is that, this class will decode the
+ * procedure in the WALEdit for better debugging. You are free to use {@link WALPrettyPrinter} to
+ * dump the safe file as well.
+ */
+@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
+@InterfaceStability.Evolving
+public class WALProcedurePrettyPrinter extends AbstractHBaseTool {
+
+ private static final String KEY_TMPL = "Sequence=%s, at write timestamp=%s";
+
+ private static final DateTimeFormatter FORMATTER =
+ DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault());
+
+ private String file;
+
+ private PrintStream out;
+
+ public WALProcedurePrettyPrinter() {
+ this(System.out);
+ }
+
+ public WALProcedurePrettyPrinter(PrintStream out) {
+ this.out = out;
+ }
+
+ @Override
+ protected void addOptions() {
+ }
+
+ @Override
+ protected void processOptions(CommandLine cmd) {
+ if (cmd.getArgList().size() != 1) {
+ throw new IllegalArgumentException("Please specify the file to dump");
+ }
+ file = cmd.getArgList().get(0);
+ }
+
+ @Override
+ protected int doWork() throws Exception {
+ Path path = new Path(file);
+ FileSystem fs = path.getFileSystem(conf);
+ try (WAL.Reader reader = WALFactory.createReader(fs, path, conf)) {
+ for (;;) {
+ WAL.Entry entry = reader.next();
+ if (entry == null) {
+ return 0;
+ }
+ WALKey key = entry.getKey();
+ WALEdit edit = entry.getEdit();
+ long sequenceId = key.getSequenceId();
+ long writeTime = key.getWriteTime();
+ out.println(
+ String.format(KEY_TMPL, sequenceId, FORMATTER.format(Instant.ofEpochMilli(writeTime))));
+ for (Cell cell : edit.getCells()) {
+ Map op = WALPrettyPrinter.toStringMap(cell);
+ if (!Bytes.equals(FAMILY, 0, FAMILY.length, cell.getFamilyArray(), cell.getFamilyOffset(),
+ cell.getFamilyLength())) {
+ // We could have cells other than procedure edits, for example, a flush marker
+ WALPrettyPrinter.printCell(out, op, false);
+ continue;
+ }
+ long procId = Bytes.toLong(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
+ out.println("pid=" + procId + ", type=" + op.get("type") + ", column=" +
+ op.get("family") + ":" + op.get("qualifier"));
+ if (cell.getType() == Cell.Type.Put) {
+ if (cell.getValueLength() > 0) {
+ // should be a normal put
+ Procedure> proc =
+ ProcedureUtil.convertToProcedure(ProcedureProtos.Procedure.parser()
+ .parseFrom(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
+ out.println("\t" + proc.toStringDetails());
+ } else {
+ // should be a 'delete' put
+ out.println("\tmark deleted");
+ }
+ }
+ out.println("cell total size sum: " + cell.heapSize());
+ }
+ out.println("edit heap size: " + edit.heapSize());
+ out.println("position: " + reader.getPosition());
+ }
+ }
+ }
+}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALPrettyPrinter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALPrettyPrinter.java
index 763cdf9545a0..4e9b7e4479e0 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALPrettyPrinter.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALPrettyPrinter.java
@@ -283,7 +283,7 @@ public void processFile(final Configuration conf, final Path p)
continue;
}
// initialize list into which we will store atomic actions
- List