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