1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.io.hfile;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.DataInput;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.LinkedHashSet;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.SortedMap;
34
35 import org.apache.commons.cli.CommandLine;
36 import org.apache.commons.cli.CommandLineParser;
37 import org.apache.commons.cli.HelpFormatter;
38 import org.apache.commons.cli.Option;
39 import org.apache.commons.cli.OptionGroup;
40 import org.apache.commons.cli.Options;
41 import org.apache.commons.cli.ParseException;
42 import org.apache.commons.cli.PosixParser;
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45 import org.apache.hadoop.hbase.classification.InterfaceAudience;
46 import org.apache.hadoop.hbase.classification.InterfaceStability;
47 import org.apache.hadoop.conf.Configuration;
48 import org.apache.hadoop.conf.Configured;
49 import org.apache.hadoop.fs.FileSystem;
50 import org.apache.hadoop.fs.Path;
51 import org.apache.hadoop.hbase.Cell;
52 import org.apache.hadoop.hbase.CellComparator;
53 import org.apache.hadoop.hbase.CellUtil;
54 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
55 import org.apache.hadoop.hbase.HConstants;
56 import org.apache.hadoop.hbase.TableName;
57 import org.apache.hadoop.hbase.HBaseConfiguration;
58 import org.apache.hadoop.hbase.HRegionInfo;
59 import org.apache.hadoop.hbase.KeyValue;
60 import org.apache.hadoop.hbase.KeyValueUtil;
61 import org.apache.hadoop.hbase.Tag;
62 import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
63 import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
64 import org.apache.hadoop.hbase.mob.MobUtils;
65 import org.apache.hadoop.hbase.regionserver.TimeRangeTracker;
66 import org.apache.hadoop.hbase.util.BloomFilter;
67 import org.apache.hadoop.hbase.util.BloomFilterFactory;
68 import org.apache.hadoop.hbase.util.ByteBloomFilter;
69 import org.apache.hadoop.hbase.util.Bytes;
70 import org.apache.hadoop.hbase.util.FSUtils;
71 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
72 import org.apache.hadoop.hbase.util.Writables;
73 import org.apache.hadoop.util.Tool;
74 import org.apache.hadoop.util.ToolRunner;
75
76 import com.yammer.metrics.core.Histogram;
77 import com.yammer.metrics.core.Metric;
78 import com.yammer.metrics.core.MetricName;
79 import com.yammer.metrics.core.MetricPredicate;
80 import com.yammer.metrics.core.MetricsRegistry;
81 import com.yammer.metrics.reporting.ConsoleReporter;
82
83
84
85
86 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
87 @InterfaceStability.Evolving
88 public class HFilePrettyPrinter extends Configured implements Tool {
89
90 private static final Log LOG = LogFactory.getLog(HFilePrettyPrinter.class);
91
92 private Options options = new Options();
93
94 private boolean verbose;
95 private boolean printValue;
96 private boolean printKey;
97 private boolean shouldPrintMeta;
98 private boolean printBlockIndex;
99 private boolean printBlockHeaders;
100 private boolean printStats;
101 private boolean checkRow;
102 private boolean checkFamily;
103 private boolean isSeekToRow = false;
104 private boolean checkMobIntegrity = false;
105 private Map<String, List<Path>> mobFileLocations;
106 private static final int FOUND_MOB_FILES_CACHE_CAPACITY = 50;
107 private static final int MISSING_MOB_FILES_CACHE_CAPACITY = 20;
108
109 private PrintStream out = System.out;
110 private PrintStream err = System.err;
111
112
113
114
115 private byte[] row = null;
116
117 private List<Path> files = new ArrayList<Path>();
118 private int count;
119
120 private static final String FOUR_SPACES = " ";
121
122 public HFilePrettyPrinter() {
123 super();
124 init();
125 }
126
127 public HFilePrettyPrinter(Configuration conf) {
128 super(conf);
129 init();
130 }
131
132 private void init() {
133 options.addOption("v", "verbose", false,
134 "Verbose output; emits file and meta data delimiters");
135 options.addOption("p", "printkv", false, "Print key/value pairs");
136 options.addOption("e", "printkey", false, "Print keys");
137 options.addOption("m", "printmeta", false, "Print meta data of file");
138 options.addOption("b", "printblocks", false, "Print block index meta data");
139 options.addOption("h", "printblockheaders", false, "Print block headers for each block.");
140 options.addOption("k", "checkrow", false,
141 "Enable row order check; looks for out-of-order keys");
142 options.addOption("a", "checkfamily", false, "Enable family check");
143 options.addOption("w", "seekToRow", true,
144 "Seek to this row and print all the kvs for this row only");
145 options.addOption("s", "stats", false, "Print statistics");
146 options.addOption("i", "checkMobIntegrity", false,
147 "Print all cells whose mob files are missing");
148
149 OptionGroup files = new OptionGroup();
150 files.addOption(new Option("f", "file", true,
151 "File to scan. Pass full-path; e.g. hdfs://a:9000/hbase/hbase:meta/12/34"));
152 files.addOption(new Option("r", "region", true,
153 "Region to scan. Pass region name; e.g. 'hbase:meta,,1'"));
154 options.addOptionGroup(files);
155 }
156
157 public void setPrintStreams(PrintStream out, PrintStream err) {
158 this.out = out;
159 this.err = err;
160 }
161
162 public boolean parseOptions(String args[]) throws ParseException,
163 IOException {
164 if (args.length == 0) {
165 HelpFormatter formatter = new HelpFormatter();
166 formatter.printHelp("HFile", options, true);
167 return false;
168 }
169 CommandLineParser parser = new PosixParser();
170 CommandLine cmd = parser.parse(options, args);
171
172 verbose = cmd.hasOption("v");
173 printValue = cmd.hasOption("p");
174 printKey = cmd.hasOption("e") || printValue;
175 shouldPrintMeta = cmd.hasOption("m");
176 printBlockIndex = cmd.hasOption("b");
177 printBlockHeaders = cmd.hasOption("h");
178 printStats = cmd.hasOption("s");
179 checkRow = cmd.hasOption("k");
180 checkFamily = cmd.hasOption("a");
181 checkMobIntegrity = cmd.hasOption("i");
182
183 if (cmd.hasOption("f")) {
184 files.add(new Path(cmd.getOptionValue("f")));
185 }
186
187 if (cmd.hasOption("w")) {
188 String key = cmd.getOptionValue("w");
189 if (key != null && key.length() != 0) {
190 row = Bytes.toBytesBinary(key);
191 isSeekToRow = true;
192 } else {
193 err.println("Invalid row is specified.");
194 System.exit(-1);
195 }
196 }
197
198 if (cmd.hasOption("r")) {
199 String regionName = cmd.getOptionValue("r");
200 byte[] rn = Bytes.toBytes(regionName);
201 byte[][] hri = HRegionInfo.parseRegionName(rn);
202 Path rootDir = FSUtils.getRootDir(getConf());
203 Path tableDir = FSUtils.getTableDir(rootDir, TableName.valueOf(hri[0]));
204 String enc = HRegionInfo.encodeRegionName(rn);
205 Path regionDir = new Path(tableDir, enc);
206 if (verbose)
207 out.println("region dir -> " + regionDir);
208 List<Path> regionFiles = HFile.getStoreFiles(FileSystem.get(getConf()),
209 regionDir);
210 if (verbose)
211 out.println("Number of region files found -> "
212 + regionFiles.size());
213 if (verbose) {
214 int i = 1;
215 for (Path p : regionFiles) {
216 if (verbose)
217 out.println("Found file[" + i++ + "] -> " + p);
218 }
219 }
220 files.addAll(regionFiles);
221 }
222
223 if(checkMobIntegrity) {
224 if (verbose) {
225 System.out.println("checkMobIntegrity is enabled");
226 }
227 mobFileLocations = new HashMap<String, List<Path>>();
228 }
229 return true;
230 }
231
232
233
234
235
236 @Override
237 public int run(String[] args) {
238 if (getConf() == null) {
239 throw new RuntimeException("A Configuration instance must be provided.");
240 }
241 try {
242 FSUtils.setFsDefault(getConf(), FSUtils.getRootDir(getConf()));
243 if (!parseOptions(args))
244 return 1;
245 } catch (IOException ex) {
246 LOG.error("Error parsing command-line options", ex);
247 return 1;
248 } catch (ParseException ex) {
249 LOG.error("Error parsing command-line options", ex);
250 return 1;
251 }
252
253
254 for (Path fileName : files) {
255 try {
256 int exitCode = processFile(fileName);
257 if (exitCode != 0) {
258 return exitCode;
259 }
260 } catch (IOException ex) {
261 LOG.error("Error reading " + fileName, ex);
262 return -2;
263 }
264 }
265
266 if (verbose || printKey) {
267 out.println("Scanned kv count -> " + count);
268 }
269
270 return 0;
271 }
272
273 public int processFile(Path file) throws IOException {
274 if (verbose)
275 out.println("Scanning -> " + file);
276
277 Path rootPath = FSUtils.getRootDir(getConf());
278 String rootString = rootPath + rootPath.SEPARATOR;
279 if (!file.toString().startsWith(rootString)) {
280
281
282
283 FileSystem rootFS = rootPath.getFileSystem(getConf());
284 String qualifiedFile = rootFS.getUri().toString() + file.toString();
285 if (!qualifiedFile.startsWith(rootString)) {
286 err.println("ERROR, file (" + file +
287 ") is not in HBase's root directory (" + rootString + ")");
288 return -2;
289 }
290 }
291
292 FileSystem fs = file.getFileSystem(getConf());
293 if (!fs.exists(file)) {
294 err.println("ERROR, file doesnt exist: " + file);
295 return -2;
296 }
297
298 HFile.Reader reader = HFile.createReader(fs, file, new CacheConfig(getConf()), getConf());
299
300 Map<byte[], byte[]> fileInfo = reader.loadFileInfo();
301
302 KeyValueStatsCollector fileStats = null;
303
304 if (verbose || printKey || checkRow || checkFamily || printStats || checkMobIntegrity) {
305
306 HFileScanner scanner = reader.getScanner(false, false, false);
307 fileStats = new KeyValueStatsCollector();
308 boolean shouldScanKeysValues = false;
309 if (this.isSeekToRow) {
310
311 shouldScanKeysValues =
312 (scanner.seekTo(KeyValueUtil.createFirstOnRow(this.row).getKey()) != -1);
313 } else {
314 shouldScanKeysValues = scanner.seekTo();
315 }
316 if (shouldScanKeysValues)
317 scanKeysValues(file, fileStats, scanner, row);
318 }
319
320
321 if (shouldPrintMeta) {
322 printMeta(reader, fileInfo);
323 }
324
325 if (printBlockIndex) {
326 out.println("Block Index:");
327 out.println(reader.getDataBlockIndexReader());
328 }
329
330 if (printBlockHeaders) {
331 out.println("Block Headers:");
332
333
334
335
336 FSDataInputStreamWrapper fsdis = new FSDataInputStreamWrapper(fs, file);
337 long fileSize = fs.getFileStatus(file).getLen();
338 FixedFileTrailer trailer =
339 FixedFileTrailer.readFromStream(fsdis.getStream(false), fileSize);
340 long offset = trailer.getFirstDataBlockOffset(),
341 max = trailer.getLastDataBlockOffset();
342 HFileBlock block;
343 while (offset <= max) {
344 block = reader.readBlock(offset, -1,
345
346 offset += block.getOnDiskSizeWithHeader();
347 out.println(block);
348 }
349 }
350
351 if (printStats) {
352 fileStats.finish();
353 out.println("Stats:\n" + fileStats);
354 }
355
356 reader.close();
357 return 0;
358 }
359
360 private void scanKeysValues(Path file, KeyValueStatsCollector fileStats,
361 HFileScanner scanner, byte[] row) throws IOException {
362 Cell pCell = null;
363 FileSystem fs = FileSystem.get(getConf());
364 Set<String> foundMobFiles = new LinkedHashSet<String>(FOUND_MOB_FILES_CACHE_CAPACITY);
365 Set<String> missingMobFiles = new LinkedHashSet<String>(MISSING_MOB_FILES_CACHE_CAPACITY);
366 do {
367 Cell cell = scanner.getKeyValue();
368 if (row != null && row.length != 0) {
369 int result = CellComparator.compareRows(cell.getRowArray(), cell.getRowOffset(),
370 cell.getRowLength(), row, 0, row.length);
371 if (result > 0) {
372 break;
373 } else if (result < 0) {
374 continue;
375 }
376 }
377
378 if (printStats) {
379 fileStats.collect(cell);
380 }
381
382 if (printKey) {
383 out.print("K: " + cell);
384 if (printValue) {
385 out.print(" V: "
386 + Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(),
387 cell.getValueLength()));
388 int i = 0;
389 List<Tag> tags = Tag.asList(cell.getTagsArray(), cell.getTagsOffset(),
390 cell.getTagsLength());
391 for (Tag tag : tags) {
392 out.print(String.format(" T[%d]: %s", i++,
393 Bytes.toStringBinary(tag.getBuffer(), tag.getTagOffset(), tag.getTagLength())));
394 }
395 }
396 out.println();
397 }
398
399 if (checkRow && pCell != null) {
400 if (CellComparator.compareRows(pCell, cell) > 0) {
401 err.println("WARNING, previous row is greater then"
402 + " current row\n\tfilename -> " + file + "\n\tprevious -> "
403 + CellUtil.getCellKeyAsString(pCell) + "\n\tcurrent -> "
404 + CellUtil.getCellKeyAsString(cell));
405 }
406 }
407
408 if (checkFamily) {
409 String fam = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(),
410 cell.getFamilyLength());
411 if (!file.toString().contains(fam)) {
412 err.println("WARNING, filename does not match kv family,"
413 + "\n\tfilename -> " + file + "\n\tkeyvalue -> "
414 + CellUtil.getCellKeyAsString(cell));
415 }
416 if (pCell != null && CellComparator.compareFamilies(pCell, cell) != 0) {
417 err.println("WARNING, previous kv has different family"
418 + " compared to current key\n\tfilename -> " + file
419 + "\n\tprevious -> " + CellUtil.getCellKeyAsString(pCell)
420 + "\n\tcurrent -> " + CellUtil.getCellKeyAsString(cell));
421 }
422 }
423
424 if (checkMobIntegrity && MobUtils.isMobReferenceCell(cell)) {
425 Tag tnTag = MobUtils.getTableNameTag(cell);
426 if (tnTag == null) {
427 System.err.println("ERROR, wrong tag format in mob reference cell "
428 + CellUtil.getCellKeyAsString(cell));
429 } else if (!MobUtils.hasValidMobRefCellValue(cell)) {
430 System.err.println("ERROR, wrong value format in mob reference cell "
431 + CellUtil.getCellKeyAsString(cell));
432 } else {
433 TableName tn = TableName.valueOf(tnTag.getValue());
434 String mobFileName = MobUtils.getMobFileName(cell);
435 boolean exist = mobFileExists(fs, tn, mobFileName,
436 Bytes.toString(CellUtil.cloneFamily(cell)), foundMobFiles, missingMobFiles);
437 if (!exist) {
438
439 System.err.println("ERROR, the mob file [" + mobFileName
440 + "] is missing referenced by cell " + CellUtil.getCellKeyAsString(cell));
441 }
442 }
443 }
444 pCell = cell;
445 ++count;
446 } while (scanner.next());
447 }
448
449
450
451
452 private boolean mobFileExists(FileSystem fs, TableName tn, String mobFileName, String family,
453 Set<String> foundMobFiles, Set<String> missingMobFiles) throws IOException {
454 if (foundMobFiles.contains(mobFileName)) {
455 return true;
456 }
457 if (missingMobFiles.contains(mobFileName)) {
458 return false;
459 }
460 String tableName = tn.getNameAsString();
461 List<Path> locations = mobFileLocations.get(tableName);
462 if (locations == null) {
463 locations = new ArrayList<Path>(2);
464 locations.add(MobUtils.getMobFamilyPath(getConf(), tn, family));
465 locations.add(HFileArchiveUtil.getStoreArchivePath(getConf(), tn,
466 MobUtils.getMobRegionInfo(tn).getEncodedName(), family));
467 mobFileLocations.put(tn.getNameAsString(), locations);
468 }
469 boolean exist = false;
470 for (Path location : locations) {
471 Path mobFilePath = new Path(location, mobFileName);
472 if (fs.exists(mobFilePath)) {
473 exist = true;
474 break;
475 }
476 }
477 if (exist) {
478 evictMobFilesIfNecessary(foundMobFiles, FOUND_MOB_FILES_CACHE_CAPACITY);
479 foundMobFiles.add(mobFileName);
480 } else {
481 evictMobFilesIfNecessary(missingMobFiles, MISSING_MOB_FILES_CACHE_CAPACITY);
482 missingMobFiles.add(mobFileName);
483 }
484 return exist;
485 }
486
487
488
489
490 private void evictMobFilesIfNecessary(Set<String> mobFileNames, int limit) {
491 if (mobFileNames.size() < limit) {
492 return;
493 }
494 int index = 0;
495 int evict = limit / 2;
496 Iterator<String> fileNamesItr = mobFileNames.iterator();
497 while (index < evict && fileNamesItr.hasNext()) {
498 fileNamesItr.next();
499 fileNamesItr.remove();
500 index++;
501 }
502 }
503
504
505
506
507
508 private static String asSeparateLines(String keyValueStr) {
509 return keyValueStr.replaceAll(", ([a-zA-Z]+=)",
510 ",\n" + FOUR_SPACES + "$1");
511 }
512
513 private void printMeta(HFile.Reader reader, Map<byte[], byte[]> fileInfo)
514 throws IOException {
515 out.println("Block index size as per heapsize: "
516 + reader.indexSize());
517 out.println(asSeparateLines(reader.toString()));
518 out.println("Trailer:\n "
519 + asSeparateLines(reader.getTrailer().toString()));
520 out.println("Fileinfo:");
521 for (Map.Entry<byte[], byte[]> e : fileInfo.entrySet()) {
522 out.print(FOUR_SPACES + Bytes.toString(e.getKey()) + " = ");
523 if (Bytes.compareTo(e.getKey(), Bytes.toBytes("MAX_SEQ_ID_KEY")) == 0) {
524 long seqid = Bytes.toLong(e.getValue());
525 out.println(seqid);
526 } else if (Bytes.compareTo(e.getKey(), Bytes.toBytes("TIMERANGE")) == 0) {
527
528 TimeRangeTracker timeRangeTracker = new TimeRangeTracker();
529 Writables.copyWritable(e.getValue(), timeRangeTracker);
530 out.println(timeRangeTracker.getMinimumTimestamp() + "...."
531 + timeRangeTracker.getMaximumTimestamp());
532 } else if (Bytes.compareTo(e.getKey(), FileInfo.AVG_KEY_LEN) == 0
533 || Bytes.compareTo(e.getKey(), FileInfo.AVG_VALUE_LEN) == 0) {
534 out.println(Bytes.toInt(e.getValue()));
535 } else {
536 out.println(Bytes.toStringBinary(e.getValue()));
537 }
538 }
539
540 try {
541
542 out.println("Mid-key: " + Bytes.toStringBinary(reader.midkey()));
543 } catch (Exception e) {
544 out.println ("Unable to retrieve the midkey");
545 }
546
547
548 DataInput bloomMeta = reader.getGeneralBloomFilterMetadata();
549 BloomFilter bloomFilter = null;
550 if (bloomMeta != null)
551 bloomFilter = BloomFilterFactory.createFromMeta(bloomMeta, reader);
552
553 out.println("Bloom filter:");
554 if (bloomFilter != null) {
555 out.println(FOUR_SPACES + bloomFilter.toString().replaceAll(
556 ByteBloomFilter.STATS_RECORD_SEP, "\n" + FOUR_SPACES));
557 } else {
558 out.println(FOUR_SPACES + "Not present");
559 }
560
561
562 bloomMeta = reader.getDeleteBloomFilterMetadata();
563 bloomFilter = null;
564 if (bloomMeta != null)
565 bloomFilter = BloomFilterFactory.createFromMeta(bloomMeta, reader);
566
567 out.println("Delete Family Bloom filter:");
568 if (bloomFilter != null) {
569 out.println(FOUR_SPACES
570 + bloomFilter.toString().replaceAll(ByteBloomFilter.STATS_RECORD_SEP,
571 "\n" + FOUR_SPACES));
572 } else {
573 out.println(FOUR_SPACES + "Not present");
574 }
575 }
576
577 private static class KeyValueStatsCollector {
578 private final MetricsRegistry metricsRegistry = new MetricsRegistry();
579 private final ByteArrayOutputStream metricsOutput = new ByteArrayOutputStream();
580 private final SimpleReporter simpleReporter = new SimpleReporter(metricsRegistry, new PrintStream(metricsOutput));
581 Histogram keyLen = metricsRegistry.newHistogram(HFilePrettyPrinter.class, "Key length");
582 Histogram valLen = metricsRegistry.newHistogram(HFilePrettyPrinter.class, "Val length");
583 Histogram rowSizeBytes = metricsRegistry.newHistogram(HFilePrettyPrinter.class, "Row size (bytes)");
584 Histogram rowSizeCols = metricsRegistry.newHistogram(HFilePrettyPrinter.class, "Row size (columns)");
585
586 long curRowBytes = 0;
587 long curRowCols = 0;
588
589 byte[] biggestRow = null;
590
591 private Cell prevCell = null;
592 private long maxRowBytes = 0;
593 private long curRowKeyLength;
594
595 public void collect(Cell cell) {
596 valLen.update(cell.getValueLength());
597 if (prevCell != null &&
598 KeyValue.COMPARATOR.compareRows(prevCell, cell) != 0) {
599
600 collectRow();
601 }
602 curRowBytes += KeyValueUtil.length(cell);
603 curRowKeyLength = KeyValueUtil.keyLength(cell);
604 curRowCols++;
605 prevCell = cell;
606 }
607
608 private void collectRow() {
609 rowSizeBytes.update(curRowBytes);
610 rowSizeCols.update(curRowCols);
611 keyLen.update(curRowKeyLength);
612
613 if (curRowBytes > maxRowBytes && prevCell != null) {
614 biggestRow = prevCell.getRow();
615 maxRowBytes = curRowBytes;
616 }
617
618 curRowBytes = 0;
619 curRowCols = 0;
620 }
621
622 public void finish() {
623 if (curRowCols > 0) {
624 collectRow();
625 }
626 }
627
628 @Override
629 public String toString() {
630 if (prevCell == null)
631 return "no data available for statistics";
632
633
634 simpleReporter.shutdown();
635 simpleReporter.run();
636 metricsRegistry.shutdown();
637
638 return
639 metricsOutput.toString() +
640 "Key of biggest row: " + Bytes.toStringBinary(biggestRow);
641 }
642 }
643
644 private static class SimpleReporter extends ConsoleReporter {
645 private final PrintStream out;
646
647 public SimpleReporter(MetricsRegistry metricsRegistry, PrintStream out) {
648 super(metricsRegistry, out, MetricPredicate.ALL);
649 this.out = out;
650 }
651
652 @Override
653 public void run() {
654 for (Map.Entry<String, SortedMap<MetricName, Metric>> entry : getMetricsRegistry().groupedMetrics(
655 MetricPredicate.ALL).entrySet()) {
656 try {
657 for (Map.Entry<MetricName, Metric> subEntry : entry.getValue().entrySet()) {
658 out.print(" " + subEntry.getKey().getName());
659 out.println(':');
660
661 subEntry.getValue().processWith(this, subEntry.getKey(), out);
662 }
663 } catch (Exception e) {
664 e.printStackTrace(out);
665 }
666 }
667 }
668
669 @Override
670 public void processHistogram(MetricName name, Histogram histogram, PrintStream stream) {
671 super.processHistogram(name, histogram, stream);
672 stream.printf(Locale.getDefault(), " count = %d%n", histogram.count());
673 }
674 }
675
676 public static void main(String[] args) throws Exception {
677 Configuration conf = HBaseConfiguration.create();
678
679 conf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0);
680 int ret = ToolRunner.run(conf, new HFilePrettyPrinter(), args);
681 System.exit(ret);
682 }
683 }