View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.snapshot;
20  
21  import java.io.IOException;
22  import java.io.FileNotFoundException;
23  import java.text.SimpleDateFormat;
24  import java.util.concurrent.atomic.AtomicInteger;
25  import java.util.concurrent.atomic.AtomicLong;
26  import java.util.Date;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import org.apache.hadoop.fs.Path;
32  import org.apache.hadoop.fs.FileSystem;
33  import org.apache.hadoop.classification.InterfaceAudience;
34  import org.apache.hadoop.classification.InterfaceStability;
35  import org.apache.hadoop.conf.Configured;
36  import org.apache.hadoop.util.StringUtils;
37  import org.apache.hadoop.util.Tool;
38  import org.apache.hadoop.util.ToolRunner;
39  
40  import org.apache.hadoop.conf.Configuration;
41  import org.apache.hadoop.hbase.HBaseConfiguration;
42  import org.apache.hadoop.hbase.HTableDescriptor;
43  import org.apache.hadoop.hbase.io.HFileLink;
44  import org.apache.hadoop.hbase.io.HLogLink;
45  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
46  import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
47  import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
48  import org.apache.hadoop.hbase.util.Bytes;
49  import org.apache.hadoop.hbase.util.FSUtils;
50  import org.apache.hadoop.hbase.util.FSTableDescriptors;
51  
52  /**
53   * Tool for dumping snapshot information.
54   * <ol>
55   * <li> Table Descriptor
56   * <li> Snapshot creation time, type, format version, ...
57   * <li> List of hfiles and hlogs
58   * <li> Stats about hfiles and logs sizes, percentage of shared with the source table, ...
59   * </ol>
60   */
61  @InterfaceAudience.Public
62  @InterfaceStability.Evolving
63  public final class SnapshotInfo extends Configured implements Tool {
64    private static final Log LOG = LogFactory.getLog(SnapshotInfo.class);
65  
66    private FileSystem fs;
67    private Path rootDir;
68  
69    private HTableDescriptor snapshotTableDesc;
70    private SnapshotDescription snapshotDesc;
71    private Path snapshotDir;
72  
73    @Override
74    public int run(String[] args) throws IOException, InterruptedException {
75      String snapshotName = null;
76      boolean showSchema = false;
77      boolean showFiles = false;
78      boolean showStats = false;
79  
80      // Process command line args
81      for (int i = 0; i < args.length; i++) {
82        String cmd = args[i];
83        try {
84          if (cmd.equals("-snapshot")) {
85            snapshotName = args[++i];
86          } else if (cmd.equals("-files")) {
87            showFiles = true;
88          } else if (cmd.equals("-stats")) {
89            showStats = true;
90          } else if (cmd.equals("-schema")) {
91            showSchema = true;
92          } else if (cmd.equals("-h") || cmd.equals("--help")) {
93            printUsageAndExit();
94          } else {
95            System.err.println("UNEXPECTED: " + cmd);
96            printUsageAndExit();
97          }
98        } catch (Exception e) {
99          printUsageAndExit();
100       }
101     }
102 
103     if (snapshotName == null) {
104       System.err.println("Missing snapshot name!");
105       printUsageAndExit();
106       return 1;
107     }
108 
109     Configuration conf = getConf();
110     fs = FileSystem.get(conf);
111     rootDir = FSUtils.getRootDir(conf);
112 
113     // Load snapshot information
114     if (!loadSnapshotInfo(snapshotName)) {
115       System.err.println("Snapshot '" + snapshotName + "' not found!");
116       return 1;
117     }
118 
119     printInfo();
120     if (showSchema) printSchema();
121     if (showFiles || showStats) printFiles(showFiles);
122 
123     return 0;
124   }
125 
126   /**
127    * Load snapshot info and table descriptor for the specified snapshot
128    * @param snapshotName name of the snapshot to load
129    * @return false if snapshot is not found
130    */
131   private boolean loadSnapshotInfo(final String snapshotName) throws IOException {
132     snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
133     if (!fs.exists(snapshotDir)) {
134       LOG.warn("Snapshot '" + snapshotName + "' not found in: " + snapshotDir);
135       return false;
136     }
137 
138     snapshotDesc = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
139     snapshotTableDesc = FSTableDescriptors.getTableDescriptor(fs, snapshotDir);
140     return true;
141   }
142 
143   /**
144    * Dump the {@link SnapshotDescription}
145    */
146   private void printInfo() {
147     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
148     System.out.println("Snapshot Info");
149     System.out.println("----------------------------------------");
150     System.out.println("   Name: " + snapshotDesc.getName());
151     System.out.println("   Type: " + snapshotDesc.getType());
152     System.out.println("  Table: " + snapshotDesc.getTable());
153     System.out.println(" Format: " + snapshotDesc.getVersion());
154     System.out.println("Created: " + df.format(new Date(snapshotDesc.getCreationTime())));
155     System.out.println();
156   }
157 
158   /**
159    * Dump the {@link HTableDescriptor}
160    */
161   private void printSchema() {
162     System.out.println("Table Descriptor");
163     System.out.println("----------------------------------------");
164     System.out.println(snapshotTableDesc.toString());
165     System.out.println();
166   }
167 
168   /**
169    * Collect the hfiles and logs statistics of the snapshot and
170    * dump the file list if requested and the collected information.
171    */
172   private void printFiles(final boolean showFiles) throws IOException {
173     final String table = snapshotDesc.getTable();
174     final Configuration conf = getConf();
175 
176     if (showFiles) {
177       System.out.println("Snapshot Files");
178       System.out.println("----------------------------------------");
179     }
180 
181     // Collect information about hfiles and logs in the snapshot
182     final AtomicInteger hfileArchiveCount = new AtomicInteger();
183     final AtomicInteger hfilesMissing = new AtomicInteger();
184     final AtomicInteger hfilesCount = new AtomicInteger();
185     final AtomicInteger logsMissing = new AtomicInteger();
186     final AtomicInteger logsCount = new AtomicInteger();
187     final AtomicLong hfileArchiveSize = new AtomicLong();
188     final AtomicLong hfileSize = new AtomicLong();
189     final AtomicLong logSize = new AtomicLong();
190     SnapshotReferenceUtil.visitReferencedFiles(fs, snapshotDir,
191       new SnapshotReferenceUtil.FileVisitor() {
192         public void storeFile (final String region, final String family, final String hfile)
193             throws IOException {
194           Path path = new Path(family, HFileLink.createHFileLinkName(table, region, hfile));
195           HFileLink link = new HFileLink(conf, path);
196           boolean inArchive = false;
197           long size = -1;
198           try {
199             if ((inArchive = fs.exists(link.getArchivePath()))) {
200               size = fs.getFileStatus(link.getArchivePath()).getLen();
201               hfileArchiveSize.addAndGet(size);
202               hfileArchiveCount.addAndGet(1);
203             } else {
204               size = link.getFileStatus(fs).getLen();
205               hfileSize.addAndGet(size);
206               hfilesCount.addAndGet(1);
207             }
208           } catch (FileNotFoundException e) {
209             hfilesMissing.addAndGet(1);
210           }
211 
212           if (showFiles) {
213             System.out.printf("%8s %s/%s/%s/%s %s%n",
214               (size < 0 ? "-" : StringUtils.humanReadableInt(size)),
215               table, region, family, hfile,
216               (inArchive ? "(archive)" : (size < 0) ? "(NOT FOUND)" : ""));
217           }
218         }
219 
220         public void recoveredEdits (final String region, final String logfile)
221             throws IOException {
222           Path path = SnapshotReferenceUtil.getRecoveredEdits(snapshotDir, region, logfile);
223           long size = fs.getFileStatus(path).getLen();
224           logSize.addAndGet(size);
225           logsCount.addAndGet(1);
226 
227           if (showFiles) {
228             System.out.printf("%8s recovered.edits %s on region %s%n",
229               StringUtils.humanReadableInt(size), logfile, region);
230           }
231         }
232 
233         public void logFile (final String server, final String logfile)
234             throws IOException {
235           HLogLink logLink = new HLogLink(conf, server, logfile);
236           long size = -1;
237           try {
238             size = logLink.getFileStatus(fs).getLen();
239             logSize.addAndGet(size);
240             logsCount.addAndGet(1);
241           } catch (FileNotFoundException e) {
242             logsMissing.addAndGet(1);
243           }
244 
245           if (showFiles) {
246             System.out.printf("%8s log %s on server %s %s%n",
247               (size < 0 ? "-" : StringUtils.humanReadableInt(size)),
248               logfile, server,
249               (size < 0 ? "(NOT FOUND)" : ""));
250           }
251         }
252     });
253 
254     // Dump the stats
255     System.out.println();
256     if (hfilesMissing.get() > 0 || logsMissing.get() > 0) {
257       System.out.println("**************************************************************");
258       System.out.printf("BAD SNAPSHOT: %d hfile(s) and %d log(s) missing.%n",
259         hfilesMissing.get(), logsMissing.get());
260       System.out.println("**************************************************************");
261     }
262 
263     System.out.printf("%d HFiles (%d in archive), total size %s (%.2f%% %s shared with the source table)%n",
264       hfilesCount.get() + hfileArchiveCount.get(), hfileArchiveCount.get(),
265       StringUtils.humanReadableInt(hfileSize.get() + hfileArchiveSize.get()),
266       ((float)hfileSize.get() / (hfileSize.get() + hfileArchiveSize.get())) * 100,
267       StringUtils.humanReadableInt(hfileSize.get())
268     );
269     System.out.printf("%d Logs, total size %s%n",
270       logsCount.get(), StringUtils.humanReadableInt(logSize.get()));
271     System.out.println();
272   }
273 
274   private void printUsageAndExit() {
275     System.err.printf("Usage: bin/hbase %s [options]%n", getClass().getName());
276     System.err.println(" where [options] are:");
277     System.err.println("  -h|-help                Show this help and exit.");
278     System.err.println("  -snapshot NAME          Snapshot to examine.");
279     System.err.println("  -files                  Files and logs list.");
280     System.err.println("  -stats                  Files and logs stats.");
281     System.err.println("  -schema                 Describe the snapshotted table.");
282     System.err.println();
283     System.err.println("Examples:");
284     System.err.println("  hbase " + getClass() + " \\");
285     System.err.println("    -snapshot MySnapshot -files");
286     System.exit(1);
287   }
288 
289   /**
290    * The guts of the {@link #main} method.
291    * Call this method to avoid the {@link #main(String[])} System.exit.
292    * @param args
293    * @return errCode
294    * @throws Exception
295    */
296   static int innerMain(final String [] args) throws Exception {
297     return ToolRunner.run(HBaseConfiguration.create(), new SnapshotInfo(), args);
298   }
299 
300   public static void main(String[] args) throws Exception {
301      System.exit(innerMain(args));
302   }
303 }