1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.snapshot;
20
21 import java.io.IOException;
22 import java.io.FileNotFoundException;
23 import java.net.URI;
24 import java.text.SimpleDateFormat;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.atomic.AtomicInteger;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import org.apache.hadoop.fs.Path;
39 import org.apache.hadoop.fs.FileStatus;
40 import org.apache.hadoop.fs.FileSystem;
41 import org.apache.hadoop.hbase.classification.InterfaceAudience;
42 import org.apache.hadoop.hbase.classification.InterfaceStability;
43 import org.apache.hadoop.conf.Configured;
44 import org.apache.hadoop.hbase.HRegionInfo;
45 import org.apache.hadoop.hbase.TableName;
46 import org.apache.hadoop.util.StringUtils;
47 import org.apache.hadoop.util.Tool;
48 import org.apache.hadoop.util.ToolRunner;
49
50 import org.apache.hadoop.conf.Configuration;
51 import org.apache.hadoop.hbase.HBaseConfiguration;
52 import org.apache.hadoop.hbase.io.HFileLink;
53 import org.apache.hadoop.hbase.io.WALLink;
54 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
55 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
56 import org.apache.hadoop.hbase.util.FSUtils;
57
58
59
60
61
62
63
64
65
66
67
68 @InterfaceAudience.Public
69 @InterfaceStability.Evolving
70 @Deprecated
71 public final class SnapshotInfo extends Configured implements Tool {
72 private static final Log LOG = LogFactory.getLog(SnapshotInfo.class);
73
74
75
76
77
78
79
80
81
82 public static class SnapshotStats {
83
84 static class FileInfo {
85 private final boolean corrupted;
86 private final boolean inArchive;
87 private final long size;
88
89 FileInfo(final boolean inArchive, final long size, final boolean corrupted) {
90 this.corrupted = corrupted;
91 this.inArchive = inArchive;
92 this.size = size;
93 }
94
95
96 public boolean inArchive() {
97 return this.inArchive;
98 }
99
100
101 public boolean isCorrupted() {
102 return this.corrupted;
103 }
104
105
106 public boolean isMissing() {
107 return this.size < 0;
108 }
109
110
111 public long getSize() {
112 return this.size;
113 }
114
115 String getStateToString() {
116 if (isCorrupted()) return "CORRUPTED";
117 if (isMissing()) return "NOT FOUND";
118 if (inArchive()) return "archive";
119 return null;
120 }
121 }
122
123 private AtomicInteger hfileArchiveCount = new AtomicInteger();
124 private AtomicInteger hfilesCorrupted = new AtomicInteger();
125 private AtomicInteger hfilesMissing = new AtomicInteger();
126 private AtomicInteger hfilesCount = new AtomicInteger();
127 private AtomicInteger logsMissing = new AtomicInteger();
128 private AtomicInteger logsCount = new AtomicInteger();
129 private AtomicLong hfileArchiveSize = new AtomicLong();
130 private AtomicLong hfileSize = new AtomicLong();
131 private AtomicLong nonSharedHfilesArchiveSize = new AtomicLong();
132 private AtomicLong logSize = new AtomicLong();
133
134 private final SnapshotDescription snapshot;
135 private final TableName snapshotTable;
136 private final Configuration conf;
137 private final FileSystem fs;
138
139 SnapshotStats(final Configuration conf, final FileSystem fs, final SnapshotDescription snapshot)
140 {
141 this.snapshot = snapshot;
142 this.snapshotTable = TableName.valueOf(snapshot.getTable());
143 this.conf = conf;
144 this.fs = fs;
145 }
146
147
148 public SnapshotDescription getSnapshotDescription() {
149 return this.snapshot;
150 }
151
152
153 public boolean isSnapshotCorrupted() {
154 return hfilesMissing.get() > 0 ||
155 logsMissing.get() > 0 ||
156 hfilesCorrupted.get() > 0;
157 }
158
159
160 public int getStoreFilesCount() {
161 return hfilesCount.get() + hfileArchiveCount.get();
162 }
163
164
165 public int getArchivedStoreFilesCount() {
166 return hfileArchiveCount.get();
167 }
168
169
170 public int getLogsCount() {
171 return logsCount.get();
172 }
173
174
175 public int getMissingStoreFilesCount() {
176 return hfilesMissing.get();
177 }
178
179
180 public int getCorruptedStoreFilesCount() {
181 return hfilesCorrupted.get();
182 }
183
184
185 public int getMissingLogsCount() {
186 return logsMissing.get();
187 }
188
189
190 public long getStoreFilesSize() {
191 return hfileSize.get() + hfileArchiveSize.get();
192 }
193
194
195 public long getSharedStoreFilesSize() {
196 return hfileSize.get();
197 }
198
199
200 public long getArchivedStoreFileSize() {
201 return hfileArchiveSize.get();
202 }
203
204
205
206
207
208
209 public long getNonSharedArchivedStoreFilesSize() {
210 return nonSharedHfilesArchiveSize.get();
211 }
212
213
214 public float getSharedStoreFilePercentage() {
215 return ((float)hfileSize.get() / (hfileSize.get() + hfileArchiveSize.get())) * 100;
216 }
217
218
219 public long getLogsSize() {
220 return logSize.get();
221 }
222
223
224
225
226
227
228
229
230 private boolean isArchivedFileStillReferenced(final Path filePath,
231 final Map<Path, Integer> snapshotFilesMap) {
232
233 Integer c = snapshotFilesMap.get(filePath);
234
235
236
237 if ((c != null) && (c == 1)) {
238 Path parentDir = filePath.getParent();
239 Path backRefDir = HFileLink.getBackReferencesDir(parentDir, filePath.getName());
240 try {
241 if (FSUtils.listStatus(fs, backRefDir) == null) {
242 return false;
243 }
244 } catch (IOException e) {
245
246
247 }
248 }
249 return true;
250 }
251
252
253
254
255
256
257
258
259
260 FileInfo addStoreFile(final HRegionInfo region, final String family,
261 final SnapshotRegionManifest.StoreFile storeFile,
262 final Map<Path, Integer> filesMap) throws IOException {
263 HFileLink link = HFileLink.build(conf, snapshotTable, region.getEncodedName(),
264 family, storeFile.getName());
265 boolean isCorrupted = false;
266 boolean inArchive = false;
267 long size = -1;
268 try {
269 if ((inArchive = fs.exists(link.getArchivePath()))) {
270 size = fs.getFileStatus(link.getArchivePath()).getLen();
271 hfileArchiveSize.addAndGet(size);
272 hfileArchiveCount.incrementAndGet();
273
274
275
276 if ((filesMap != null) &&
277 !isArchivedFileStillReferenced(link.getArchivePath(), filesMap)) {
278 nonSharedHfilesArchiveSize.addAndGet(size);
279 }
280 } else {
281 size = link.getFileStatus(fs).getLen();
282 hfileSize.addAndGet(size);
283 hfilesCount.incrementAndGet();
284 }
285 isCorrupted = (storeFile.hasFileSize() && storeFile.getFileSize() != size);
286 if (isCorrupted) hfilesCorrupted.incrementAndGet();
287 } catch (FileNotFoundException e) {
288 hfilesMissing.incrementAndGet();
289 }
290 return new FileInfo(inArchive, size, isCorrupted);
291 }
292
293
294
295
296
297
298
299 FileInfo addLogFile(final String server, final String logfile) throws IOException {
300 WALLink logLink = new WALLink(conf, server, logfile);
301 long size = -1;
302 try {
303 size = logLink.getFileStatus(fs).getLen();
304 logSize.addAndGet(size);
305 logsCount.incrementAndGet();
306 } catch (FileNotFoundException e) {
307 logsMissing.incrementAndGet();
308 }
309 return new FileInfo(false, size, false);
310 }
311 }
312
313 private boolean printSizeInBytes = false;
314 private FileSystem fs;
315 private Path rootDir;
316
317 private SnapshotManifest snapshotManifest;
318
319 @Override
320 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
321 justification="Intentional")
322 public int run(String[] args) throws IOException, InterruptedException {
323 final Configuration conf = getConf();
324 boolean listSnapshots = false;
325 String snapshotName = null;
326 boolean showSchema = false;
327 boolean showFiles = false;
328 boolean showStats = false;
329
330
331 for (int i = 0; i < args.length; i++) {
332 String cmd = args[i];
333 try {
334 if (cmd.equals("-snapshot")) {
335 snapshotName = args[++i];
336 } else if (cmd.equals("-files")) {
337 showFiles = true;
338 showStats = true;
339 } else if (cmd.equals("-stats")) {
340 showStats = true;
341 } else if (cmd.equals("-schema")) {
342 showSchema = true;
343 } else if (cmd.equals("-remote-dir")) {
344 Path sourceDir = new Path(args[++i]);
345 URI defaultFs = sourceDir.getFileSystem(conf).getUri();
346 FSUtils.setFsDefault(conf, new Path(defaultFs));
347 FSUtils.setRootDir(conf, sourceDir);
348 } else if (cmd.equals("-list-snapshots")) {
349 listSnapshots = true;
350 } else if (cmd.equals("-size-in-bytes")) {
351 printSizeInBytes = true;
352 } else if (cmd.equals("-h") || cmd.equals("--help")) {
353 printUsageAndExit();
354 } else {
355 System.err.println("UNEXPECTED: " + cmd);
356 printUsageAndExit();
357 }
358 } catch (Exception e) {
359 printUsageAndExit();
360 }
361 }
362
363
364 if (listSnapshots) {
365 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
366 System.out.printf("%-20s | %-20s | %s%n", "SNAPSHOT", "CREATION TIME", "TABLE NAME");
367 for (SnapshotDescription desc: getSnapshotList(conf)) {
368 System.out.printf("%-20s | %20s | %s%n",
369 desc.getName(),
370 df.format(new Date(desc.getCreationTime())),
371 desc.getTable());
372 }
373 return 0;
374 }
375
376 if (snapshotName == null) {
377 System.err.println("Missing snapshot name!");
378 printUsageAndExit();
379 return 1;
380 }
381
382 rootDir = FSUtils.getRootDir(conf);
383 fs = FileSystem.get(rootDir.toUri(), conf);
384 LOG.debug("fs=" + fs.getUri().toString() + " root=" + rootDir);
385
386
387 if (!loadSnapshotInfo(snapshotName)) {
388 System.err.println("Snapshot '" + snapshotName + "' not found!");
389 return 1;
390 }
391
392 printInfo();
393 if (showSchema) printSchema();
394 printFiles(showFiles, showStats);
395
396 return 0;
397 }
398
399
400
401
402
403
404 private boolean loadSnapshotInfo(final String snapshotName) throws IOException {
405 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
406 if (!fs.exists(snapshotDir)) {
407 LOG.warn("Snapshot '" + snapshotName + "' not found in: " + snapshotDir);
408 return false;
409 }
410
411 SnapshotDescription snapshotDesc = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
412 snapshotManifest = SnapshotManifest.open(getConf(), fs, snapshotDir, snapshotDesc);
413 return true;
414 }
415
416
417
418
419 private void printInfo() {
420 SnapshotDescription snapshotDesc = snapshotManifest.getSnapshotDescription();
421 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
422 System.out.println("Snapshot Info");
423 System.out.println("----------------------------------------");
424 System.out.println(" Name: " + snapshotDesc.getName());
425 System.out.println(" Type: " + snapshotDesc.getType());
426 System.out.println(" Table: " + snapshotDesc.getTable());
427 System.out.println(" Format: " + snapshotDesc.getVersion());
428 System.out.println("Created: " + df.format(new Date(snapshotDesc.getCreationTime())));
429 System.out.println();
430 }
431
432
433
434
435 private void printSchema() {
436 System.out.println("Table Descriptor");
437 System.out.println("----------------------------------------");
438 System.out.println(snapshotManifest.getTableDescriptor().toString());
439 System.out.println();
440 }
441
442
443
444
445
446 private void printFiles(final boolean showFiles, final boolean showStats) throws IOException {
447 if (showFiles) {
448 System.out.println("Snapshot Files");
449 System.out.println("----------------------------------------");
450 }
451
452
453 final SnapshotDescription snapshotDesc = snapshotManifest.getSnapshotDescription();
454 final String table = snapshotDesc.getTable();
455 final SnapshotStats stats = new SnapshotStats(this.getConf(), this.fs, snapshotDesc);
456 SnapshotReferenceUtil.concurrentVisitReferencedFiles(getConf(), fs, snapshotManifest,
457 "SnapshotInfo", new SnapshotReferenceUtil.SnapshotVisitor() {
458 @Override public void storeFile(final HRegionInfo regionInfo, final String family,
459 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
460 if (storeFile.hasReference()) return;
461
462 SnapshotStats.FileInfo info = stats.addStoreFile(regionInfo, family, storeFile, null);
463 if (showFiles) {
464 String state = info.getStateToString();
465 System.out.printf("%8s %s/%s/%s/%s %s%n",
466 (info.isMissing() ? "-" : fileSizeToString(info.getSize())), table,
467 regionInfo.getEncodedName(), family, storeFile.getName(),
468 state == null ? "" : "(" + state + ")");
469 }
470 }
471 });
472
473
474 System.out.println();
475 if (stats.isSnapshotCorrupted()) {
476 System.out.println("**************************************************************");
477 System.out.printf("BAD SNAPSHOT: %d hfile(s) and %d log(s) missing.%n",
478 stats.getMissingStoreFilesCount(), stats.getMissingLogsCount());
479 System.out.printf(" %d hfile(s) corrupted.%n",
480 stats.getCorruptedStoreFilesCount());
481 System.out.println("**************************************************************");
482 }
483
484 if (showStats) {
485 System.out.printf("%d HFiles (%d in archive), total size %s (%.2f%% %s shared with the source table)%n",
486 stats.getStoreFilesCount(), stats.getArchivedStoreFilesCount(),
487 fileSizeToString(stats.getStoreFilesSize()),
488 stats.getSharedStoreFilePercentage(),
489 fileSizeToString(stats.getSharedStoreFilesSize())
490 );
491 System.out.printf("%d Logs, total size %s%n",
492 stats.getLogsCount(), fileSizeToString(stats.getLogsSize()));
493 System.out.println();
494 }
495 }
496
497 private String fileSizeToString(long size) {
498 return printSizeInBytes ? Long.toString(size) : StringUtils.humanReadableInt(size);
499 }
500
501 private void printUsageAndExit() {
502 System.err.printf("Usage: bin/hbase snapshot info [options]%n");
503 System.err.println(" where [options] are:");
504 System.err.println(" -h|-help Show this help and exit.");
505 System.err.println(" -remote-dir Root directory that contains the snapshots.");
506 System.err.println(" -list-snapshots List all the available snapshots and exit.");
507 System.err.println(" -size-in-bytes Print the size of the files in bytes.");
508 System.err.println(" -snapshot NAME Snapshot to examine.");
509 System.err.println(" -files Files and logs list.");
510 System.err.println(" -stats Files and logs stats.");
511 System.err.println(" -schema Describe the snapshotted table.");
512 System.err.println();
513 System.err.println("Examples:");
514 System.err.println(" hbase snapshot info \\");
515 System.err.println(" -snapshot MySnapshot -files");
516 System.exit(1);
517 }
518
519
520
521
522
523
524
525 public static SnapshotStats getSnapshotStats(final Configuration conf,
526 final SnapshotDescription snapshot) throws IOException {
527 return getSnapshotStats(conf, snapshot, null);
528 }
529
530
531
532
533
534
535
536
537 public static SnapshotStats getSnapshotStats(final Configuration conf,
538 final SnapshotDescription snapshot,
539 final Map<Path, Integer> filesMap) throws IOException {
540 Path rootDir = FSUtils.getRootDir(conf);
541 FileSystem fs = FileSystem.get(rootDir.toUri(), conf);
542 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
543 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshot);
544 final SnapshotStats stats = new SnapshotStats(conf, fs, snapshot);
545 SnapshotReferenceUtil.concurrentVisitReferencedFiles(conf, fs, manifest,
546 "SnapshotsStatsAggregation", new SnapshotReferenceUtil.SnapshotVisitor() {
547 @Override
548 public void storeFile(final HRegionInfo regionInfo, final String family,
549 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
550 if (!storeFile.hasReference()) {
551 stats.addStoreFile(regionInfo, family, storeFile, filesMap);
552 }
553 }});
554 return stats;
555 }
556
557
558
559
560
561
562 public static List<SnapshotDescription> getSnapshotList(final Configuration conf)
563 throws IOException {
564 Path rootDir = FSUtils.getRootDir(conf);
565 FileSystem fs = FileSystem.get(rootDir.toUri(), conf);
566 Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
567 FileStatus[] snapshots = fs.listStatus(snapshotDir,
568 new SnapshotDescriptionUtils.CompletedSnaphotDirectoriesFilter(fs));
569 List<SnapshotDescription> snapshotLists =
570 new ArrayList<SnapshotDescription>(snapshots.length);
571 for (FileStatus snapshotDirStat: snapshots) {
572 snapshotLists.add(SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDirStat.getPath()));
573 }
574 return snapshotLists;
575 }
576
577
578
579
580
581
582
583
584
585
586
587 private static void getSnapshotFilesMap(final Configuration conf,
588 final SnapshotDescription snapshot, final ExecutorService exec,
589 final ConcurrentHashMap<Path, Integer> filesMap,
590 final AtomicLong uniqueHFilesArchiveSize, final AtomicLong uniqueHFilesSize)
591 throws IOException {
592 Path rootDir = FSUtils.getRootDir(conf);
593 final FileSystem fs = FileSystem.get(rootDir.toUri(), conf);
594
595 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
596 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshot);
597 SnapshotReferenceUtil.concurrentVisitReferencedFiles(conf, fs, manifest, exec,
598 new SnapshotReferenceUtil.SnapshotVisitor() {
599 @Override public void storeFile(final HRegionInfo regionInfo, final String family,
600 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
601 if (!storeFile.hasReference()) {
602 HFileLink link = HFileLink
603 .build(conf, TableName.valueOf(snapshot.getTable()), regionInfo.getEncodedName(),
604 family, storeFile.getName());
605 long size;
606 Integer count;
607 Path p;
608 AtomicLong al;
609 int c = 0;
610
611 if (fs.exists(link.getArchivePath())) {
612 p = link.getArchivePath();
613 al = uniqueHFilesArchiveSize;
614 size = fs.getFileStatus(p).getLen();
615 } else {
616 p = link.getOriginPath();
617 al = uniqueHFilesSize;
618 size = link.getFileStatus(fs).getLen();
619 }
620
621
622 count = filesMap.get(p);
623 if (count != null) {
624 c = count.intValue();
625 } else {
626 al.addAndGet(size);
627 }
628
629 filesMap.put(p, ++c);
630 }
631 }
632 });
633 }
634
635
636
637
638
639
640
641
642 public static Map<Path, Integer> getSnapshotsFilesMap(final Configuration conf,
643 AtomicLong uniqueHFilesArchiveSize, AtomicLong uniqueHFilesSize) throws IOException {
644 List<SnapshotDescription> snapshotList = getSnapshotList(conf);
645
646 if (snapshotList.size() == 0) {
647 return Collections.emptyMap();
648 }
649
650 ConcurrentHashMap<Path, Integer> fileMap = new ConcurrentHashMap<>();
651
652 ExecutorService exec = SnapshotManifest.createExecutor(conf, "SnapshotsFilesMapping");
653
654 try {
655 for (final SnapshotDescription snapshot : snapshotList) {
656 getSnapshotFilesMap(conf, snapshot, exec, fileMap, uniqueHFilesArchiveSize,
657 uniqueHFilesSize);
658 }
659 } finally {
660 exec.shutdown();
661 }
662
663 return fileMap;
664 }
665
666
667
668
669
670
671
672
673 static int innerMain(final String [] args) throws Exception {
674 return ToolRunner.run(HBaseConfiguration.create(), new SnapshotInfo(), args);
675 }
676
677 public static void main(String[] args) throws Exception {
678 System.exit(innerMain(args));
679 }
680 }