HBASE-25193: Add support for row prefix and type in the WAL Pretty Printer
Closes #2556 Signed-off-by: Wellington Chevreuil <wchevreuil@apache.org> Signed-off-by: Bharath Vissapragada <bharathv@apache.org> Signed-off-by: Duo Zhang <zhangduo@apache.org> Signed-off-by: Viraj Jasani <vjasani@apache.org>
This commit is contained in:
parent
d8de24c311
commit
5e3ffb1db6
|
@ -105,7 +105,7 @@ public class WALProcedurePrettyPrinter extends AbstractHBaseTool {
|
||||||
if (!Bytes.equals(PROC_FAMILY, 0, PROC_FAMILY.length, cell.getFamilyArray(),
|
if (!Bytes.equals(PROC_FAMILY, 0, PROC_FAMILY.length, cell.getFamilyArray(),
|
||||||
cell.getFamilyOffset(), cell.getFamilyLength())) {
|
cell.getFamilyOffset(), cell.getFamilyLength())) {
|
||||||
// We could have cells other than procedure edits, for example, a flush marker
|
// We could have cells other than procedure edits, for example, a flush marker
|
||||||
WALPrettyPrinter.printCell(out, op, false);
|
WALPrettyPrinter.printCell(out, op, false, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
long procId = Bytes.toLong(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
|
long procId = Bytes.toLong(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
|
||||||
|
|
|
@ -46,7 +46,7 @@ import org.apache.yetus.audience.InterfaceAudience;
|
||||||
import org.apache.yetus.audience.InterfaceStability;
|
import org.apache.yetus.audience.InterfaceStability;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.apache.hbase.thirdparty.com.google.common.base.Strings;
|
||||||
import org.apache.hbase.thirdparty.com.google.gson.Gson;
|
import org.apache.hbase.thirdparty.com.google.gson.Gson;
|
||||||
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
|
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLineParser;
|
import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLineParser;
|
||||||
|
@ -85,7 +85,12 @@ public class WALPrettyPrinter {
|
||||||
// List of tables for filter
|
// List of tables for filter
|
||||||
private final Set<String> tableSet;
|
private final Set<String> tableSet;
|
||||||
private String region;
|
private String region;
|
||||||
|
|
||||||
|
// exact row which needs to be filtered
|
||||||
private String row;
|
private String row;
|
||||||
|
// prefix of rows which needs to be filtered
|
||||||
|
private String rowPrefix;
|
||||||
|
|
||||||
private boolean outputOnlyRowKey;
|
private boolean outputOnlyRowKey;
|
||||||
// enable in order to output a single list of transactions from several files
|
// enable in order to output a single list of transactions from several files
|
||||||
private boolean persistentOutput;
|
private boolean persistentOutput;
|
||||||
|
@ -107,6 +112,7 @@ public class WALPrettyPrinter {
|
||||||
tableSet = new HashSet<>();
|
tableSet = new HashSet<>();
|
||||||
region = null;
|
region = null;
|
||||||
row = null;
|
row = null;
|
||||||
|
rowPrefix = null;
|
||||||
outputOnlyRowKey = false;
|
outputOnlyRowKey = false;
|
||||||
persistentOutput = false;
|
persistentOutput = false;
|
||||||
firstTxn = true;
|
firstTxn = true;
|
||||||
|
@ -181,6 +187,17 @@ public class WALPrettyPrinter {
|
||||||
this.row = row;
|
this.row = row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the rowPrefix key prefix by which output will be filtered
|
||||||
|
*
|
||||||
|
* @param rowPrefix
|
||||||
|
* when not null, serves as a filter; only log entries with rows
|
||||||
|
* having this prefix will be printed
|
||||||
|
*/
|
||||||
|
public void setRowPrefixFilter(String rowPrefix) {
|
||||||
|
this.rowPrefix = rowPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option to print the row key only in case you just need the row keys from the WAL
|
* Option to print the row key only in case you just need the row keys from the WAL
|
||||||
*/
|
*/
|
||||||
|
@ -301,16 +318,13 @@ public class WALPrettyPrinter {
|
||||||
List<Map<String, Object>> actions = new ArrayList<>();
|
List<Map<String, Object>> actions = new ArrayList<>();
|
||||||
for (Cell cell : edit.getCells()) {
|
for (Cell cell : edit.getCells()) {
|
||||||
// add atomic operation to txn
|
// add atomic operation to txn
|
||||||
Map<String, Object> op = new HashMap<>(toStringMap(cell, outputOnlyRowKey));
|
Map<String, Object> op =
|
||||||
if (outputValues) {
|
new HashMap<>(toStringMap(cell, outputOnlyRowKey, rowPrefix, row, outputValues));
|
||||||
op.put("value", Bytes.toStringBinary(CellUtil.cloneValue(cell)));
|
if (op.isEmpty()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
// check row output filter
|
|
||||||
if (row == null || ((String) op.get("row")).equals(row)) {
|
|
||||||
actions.add(op);
|
actions.add(op);
|
||||||
}
|
}
|
||||||
op.put("total_size_sum", cell.heapSize());
|
|
||||||
}
|
|
||||||
if (actions.isEmpty()) {
|
if (actions.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -326,16 +340,20 @@ public class WALPrettyPrinter {
|
||||||
out.print(GSON.toJson(txn));
|
out.print(GSON.toJson(txn));
|
||||||
} else {
|
} else {
|
||||||
// Pretty output, complete with indentation by atomic action
|
// Pretty output, complete with indentation by atomic action
|
||||||
|
if (!outputOnlyRowKey) {
|
||||||
out.println(String.format(outputTmpl,
|
out.println(String.format(outputTmpl,
|
||||||
txn.get("sequence"), txn.get("table"), txn.get("region"), new Date(writeTime)));
|
txn.get("sequence"), txn.get("table"), txn.get("region"), new Date(writeTime)));
|
||||||
|
}
|
||||||
for (int i = 0; i < actions.size(); i++) {
|
for (int i = 0; i < actions.size(); i++) {
|
||||||
Map<String, Object> op = actions.get(i);
|
Map<String, Object> op = actions.get(i);
|
||||||
printCell(out, op, outputValues);
|
printCell(out, op, outputValues, outputOnlyRowKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!outputOnlyRowKey) {
|
||||||
out.println("edit heap size: " + entry.getEdit().heapSize());
|
out.println("edit heap size: " + entry.getEdit().heapSize());
|
||||||
out.println("position: " + log.getPosition());
|
out.println("position: " + log.getPosition());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
log.close();
|
log.close();
|
||||||
}
|
}
|
||||||
|
@ -344,9 +362,17 @@ public class WALPrettyPrinter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void printCell(PrintStream out, Map<String, Object> op, boolean outputValues) {
|
public static void printCell(PrintStream out, Map<String, Object> op,
|
||||||
out.println("row=" + op.get("row") + ", type=" + op.get("type") + ", column=" +
|
boolean outputValues, boolean outputOnlyRowKey) {
|
||||||
op.get("family") + ":" + op.get("qualifier"));
|
String rowDetails = "row=" + op.get("row");
|
||||||
|
if (outputOnlyRowKey) {
|
||||||
|
out.println(rowDetails);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rowDetails += ", column=" + op.get("family") + ":" + op.get("qualifier");
|
||||||
|
rowDetails += ", type=" + op.get("type");
|
||||||
|
out.println(rowDetails);
|
||||||
if (op.get("tag") != null) {
|
if (op.get("tag") != null) {
|
||||||
out.println(" tag: " + op.get("tag"));
|
out.println(" tag: " + op.get("tag"));
|
||||||
}
|
}
|
||||||
|
@ -356,11 +382,20 @@ public class WALPrettyPrinter {
|
||||||
out.println("cell total size sum: " + op.get("total_size_sum"));
|
out.println("cell total size sum: " + op.get("total_size_sum"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Object> toStringMap(Cell cell, boolean printRowKeyOnly) {
|
public static Map<String, Object> toStringMap(Cell cell,
|
||||||
|
boolean printRowKeyOnly, String rowPrefix, String row, boolean outputValues) {
|
||||||
Map<String, Object> stringMap = new HashMap<>();
|
Map<String, Object> stringMap = new HashMap<>();
|
||||||
stringMap.put("row",
|
String rowKey = Bytes.toStringBinary(cell.getRowArray(),
|
||||||
Bytes.toStringBinary(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
|
cell.getRowOffset(), cell.getRowLength());
|
||||||
|
// Row and row prefix are mutually options so both cannot be true at the
|
||||||
|
// same time. We can include checks in the same condition
|
||||||
|
// Check if any of the filters are satisfied by the row, if not return empty map
|
||||||
|
if ((!Strings.isNullOrEmpty(rowPrefix) && !rowKey.startsWith(rowPrefix)) ||
|
||||||
|
(!Strings.isNullOrEmpty(row) && !rowKey.equals(row))) {
|
||||||
|
return stringMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringMap.put("row", rowKey);
|
||||||
if (printRowKeyOnly) {
|
if (printRowKeyOnly) {
|
||||||
return stringMap;
|
return stringMap;
|
||||||
}
|
}
|
||||||
|
@ -372,6 +407,7 @@ public class WALPrettyPrinter {
|
||||||
cell.getQualifierLength()));
|
cell.getQualifierLength()));
|
||||||
stringMap.put("timestamp", cell.getTimestamp());
|
stringMap.put("timestamp", cell.getTimestamp());
|
||||||
stringMap.put("vlen", cell.getValueLength());
|
stringMap.put("vlen", cell.getValueLength());
|
||||||
|
stringMap.put("total_size_sum", cell.heapSize());
|
||||||
if (cell.getTagsLength() > 0) {
|
if (cell.getTagsLength() > 0) {
|
||||||
List<String> tagsString = new ArrayList<>();
|
List<String> tagsString = new ArrayList<>();
|
||||||
Iterator<Tag> tagsIterator = PrivateCellUtil.tagsIterator(cell);
|
Iterator<Tag> tagsIterator = PrivateCellUtil.tagsIterator(cell);
|
||||||
|
@ -382,11 +418,14 @@ public class WALPrettyPrinter {
|
||||||
}
|
}
|
||||||
stringMap.put("tag", tagsString);
|
stringMap.put("tag", tagsString);
|
||||||
}
|
}
|
||||||
|
if (outputValues) {
|
||||||
|
stringMap.put("value", Bytes.toStringBinary(CellUtil.cloneValue(cell)));
|
||||||
|
}
|
||||||
return stringMap;
|
return stringMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Object> toStringMap(Cell cell) {
|
public static Map<String, Object> toStringMap(Cell cell) {
|
||||||
return toStringMap(cell, false);
|
return toStringMap(cell, false, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
@ -417,6 +456,7 @@ public class WALPrettyPrinter {
|
||||||
options.addOption("k", "outputOnlyRowKey", false,
|
options.addOption("k", "outputOnlyRowKey", false,
|
||||||
"Print only row keys");
|
"Print only row keys");
|
||||||
options.addOption("w", "row", true, "Row to filter by. Pass row name.");
|
options.addOption("w", "row", true, "Row to filter by. Pass row name.");
|
||||||
|
options.addOption("f", "rowPrefix", true, "Row prefix to filter by.");
|
||||||
options.addOption("g", "goto", true, "Position to seek to in the file");
|
options.addOption("g", "goto", true, "Position to seek to in the file");
|
||||||
|
|
||||||
WALPrettyPrinter printer = new WALPrettyPrinter();
|
WALPrettyPrinter printer = new WALPrettyPrinter();
|
||||||
|
@ -450,8 +490,17 @@ public class WALPrettyPrinter {
|
||||||
printer.setSequenceFilter(Long.parseLong(cmd.getOptionValue("s")));
|
printer.setSequenceFilter(Long.parseLong(cmd.getOptionValue("s")));
|
||||||
}
|
}
|
||||||
if (cmd.hasOption("w")) {
|
if (cmd.hasOption("w")) {
|
||||||
|
if (cmd.hasOption("f")) {
|
||||||
|
throw new ParseException("Row and Row-prefix cannot be supplied together");
|
||||||
|
}
|
||||||
printer.setRowFilter(cmd.getOptionValue("w"));
|
printer.setRowFilter(cmd.getOptionValue("w"));
|
||||||
}
|
}
|
||||||
|
if (cmd.hasOption("f")) {
|
||||||
|
if (cmd.hasOption("w")) {
|
||||||
|
throw new ParseException("Row and Row-prefix cannot be supplied together");
|
||||||
|
}
|
||||||
|
printer.setRowPrefixFilter(cmd.getOptionValue("f"));
|
||||||
|
}
|
||||||
if (cmd.hasOption("g")) {
|
if (cmd.hasOption("g")) {
|
||||||
printer.setPosition(Long.parseLong(cmd.getOptionValue("g")));
|
printer.setPosition(Long.parseLong(cmd.getOptionValue("g")));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue