1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.snapshot;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.HashSet;
31 import java.util.TreeSet;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.fs.FileStatus;
36 import org.apache.hadoop.fs.FileSystem;
37 import org.apache.hadoop.fs.Path;
38 import org.apache.hadoop.fs.PathFilter;
39 import org.apache.hadoop.hbase.HBaseTestingUtility;
40 import org.apache.hadoop.hbase.HColumnDescriptor;
41 import org.apache.hadoop.hbase.HConstants;
42 import org.apache.hadoop.hbase.HRegionInfo;
43 import org.apache.hadoop.hbase.HTableDescriptor;
44 import org.apache.hadoop.hbase.TableName;
45 import org.apache.hadoop.hbase.TableNotEnabledException;
46 import org.apache.hadoop.hbase.client.Durability;
47 import org.apache.hadoop.hbase.client.HBaseAdmin;
48 import org.apache.hadoop.hbase.client.HTable;
49 import org.apache.hadoop.hbase.client.Put;
50 import org.apache.hadoop.hbase.master.HMaster;
51 import org.apache.hadoop.hbase.master.MasterFileSystem;
52 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
53 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
54 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
55 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneResponse;
56 import org.apache.hadoop.hbase.regionserver.HRegion;
57 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
58 import org.apache.hadoop.hbase.regionserver.HRegionServer;
59 import org.apache.hadoop.hbase.util.Bytes;
60 import org.apache.hadoop.hbase.util.FSTableDescriptors;
61 import org.apache.hadoop.hbase.util.FSUtils;
62 import org.apache.hadoop.hbase.util.FSVisitor;
63 import org.apache.hadoop.hbase.util.MD5Hash;
64 import org.junit.Assert;
65
66 import com.google.protobuf.ServiceException;
67
68
69
70
71 public class SnapshotTestingUtils {
72
73 private static final Log LOG = LogFactory.getLog(SnapshotTestingUtils.class);
74
75
76
77
78
79
80
81 public static void assertNoSnapshots(HBaseAdmin admin) throws IOException {
82 assertEquals("Have some previous snapshots", 0, admin.listSnapshots()
83 .size());
84 }
85
86
87
88
89
90 public static List<SnapshotDescription> assertExistsMatchingSnapshot(
91 HBaseAdmin admin, String snapshotName, TableName tableName)
92 throws IOException {
93
94 List<SnapshotDescription> snapshots = admin.listSnapshots();
95
96 List<SnapshotDescription> returnedSnapshots = new ArrayList<SnapshotDescription>();
97 for (SnapshotDescription sd : snapshots) {
98 if (snapshotName.equals(sd.getName()) &&
99 tableName.equals(TableName.valueOf(sd.getTable()))) {
100 returnedSnapshots.add(sd);
101 }
102 }
103
104 Assert.assertTrue("No matching snapshots found.", returnedSnapshots.size()>0);
105 return returnedSnapshots;
106 }
107
108
109
110
111 public static void assertOneSnapshotThatMatches(HBaseAdmin admin,
112 SnapshotDescription snapshot) throws IOException {
113 assertOneSnapshotThatMatches(admin, snapshot.getName(),
114 TableName.valueOf(snapshot.getTable()));
115 }
116
117
118
119
120
121 public static List<SnapshotDescription> assertOneSnapshotThatMatches(
122 HBaseAdmin admin, String snapshotName, TableName tableName)
123 throws IOException {
124
125 List<SnapshotDescription> snapshots = admin.listSnapshots();
126
127 assertEquals("Should only have 1 snapshot", 1, snapshots.size());
128 assertEquals(snapshotName, snapshots.get(0).getName());
129 assertEquals(tableName, TableName.valueOf(snapshots.get(0).getTable()));
130
131 return snapshots;
132 }
133
134
135
136
137
138 public static List<SnapshotDescription> assertOneSnapshotThatMatches(
139 HBaseAdmin admin, byte[] snapshot, TableName tableName) throws IOException {
140 return assertOneSnapshotThatMatches(admin, Bytes.toString(snapshot),
141 tableName);
142 }
143
144
145
146
147
148 public static void confirmSnapshotValid(
149 SnapshotDescription snapshotDescriptor, TableName tableName,
150 byte[] testFamily, Path rootDir, HBaseAdmin admin, FileSystem fs,
151 boolean requireLogs, Path logsDir, Set<String> snapshotServers)
152 throws IOException {
153 ArrayList nonEmptyTestFamilies = new ArrayList(1);
154 nonEmptyTestFamilies.add(testFamily);
155 confirmSnapshotValid(snapshotDescriptor, tableName,
156 nonEmptyTestFamilies, null, rootDir, admin, fs, requireLogs,
157 logsDir, snapshotServers);
158 }
159
160
161
162
163 public static void confirmEmptySnapshotValid(
164 SnapshotDescription snapshotDescriptor, TableName tableName,
165 byte[] testFamily, Path rootDir, HBaseAdmin admin, FileSystem fs,
166 boolean requireLogs, Path logsDir, Set<String> snapshotServers)
167 throws IOException {
168 ArrayList emptyTestFamilies = new ArrayList(1);
169 emptyTestFamilies.add(testFamily);
170 confirmSnapshotValid(snapshotDescriptor, tableName,
171 null, emptyTestFamilies, rootDir, admin, fs, requireLogs,
172 logsDir, snapshotServers);
173 }
174
175
176
177
178
179
180
181 public static void confirmSnapshotValid(
182 SnapshotDescription snapshotDescriptor, TableName tableName,
183 List<byte[]> nonEmptyTestFamilies, List<byte[]> emptyTestFamilies,
184 Path rootDir, HBaseAdmin admin, FileSystem fs, boolean requireLogs,
185 Path logsDir, Set<String> snapshotServers) throws IOException {
186
187 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(
188 snapshotDescriptor, rootDir);
189 assertTrue(fs.exists(snapshotDir));
190
191
192 Path snapshotinfo = new Path(snapshotDir, SnapshotDescriptionUtils.SNAPSHOTINFO_FILE);
193 assertTrue(fs.exists(snapshotinfo));
194
195
196 if (requireLogs) {
197 TakeSnapshotUtils.verifyAllLogsGotReferenced(fs, logsDir,
198 snapshotServers, snapshotDescriptor, new Path(snapshotDir,
199 HConstants.HREGION_LOGDIR_NAME));
200 }
201
202
203 HTableDescriptor desc = FSTableDescriptors.getTableDescriptorFromFs(fs, rootDir, tableName);
204 HTableDescriptor snapshotDesc = FSTableDescriptors.getTableDescriptorFromFs(fs, snapshotDir);
205 assertEquals(desc, snapshotDesc);
206
207
208 final Set<String> snapshotRegions = new HashSet<String>();
209 final Set<byte[]> snapshotFamilies = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
210 FSVisitor.visitTableStoreFiles(fs, snapshotDir, new FSVisitor.StoreFileVisitor() {
211 public void storeFile(final String region, final String family, final String hfileName)
212 throws IOException {
213 snapshotRegions.add(region);
214 snapshotFamilies.add(Bytes.toBytes(family));
215 }
216 });
217
218
219 if (nonEmptyTestFamilies != null) {
220 for (final byte[] familyName: nonEmptyTestFamilies) {
221 assertTrue(snapshotFamilies.contains(familyName));
222 }
223 }
224
225
226 if (emptyTestFamilies != null) {
227 for (final byte[] familyName: emptyTestFamilies) {
228 assertFalse(snapshotFamilies.contains(familyName));
229 }
230 }
231
232
233 if ((nonEmptyTestFamilies == null || nonEmptyTestFamilies.size() == 0) &&
234 (emptyTestFamilies != null && emptyTestFamilies.size() > 0)) {
235 assertEquals(0, snapshotRegions.size());
236 return;
237 }
238
239
240 List<HRegionInfo> regions = admin.getTableRegions(tableName);
241 assertEquals(regions.size(), snapshotRegions.size());
242
243
244 for (HRegionInfo info : regions) {
245 String regionName = info.getEncodedName();
246 assertTrue(snapshotRegions.contains(regionName));
247
248 Path regionDir = new Path(snapshotDir, regionName);
249 HRegionInfo snapshotRegionInfo = HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir);
250 assertEquals(info, snapshotRegionInfo);
251 }
252 }
253
254
255
256
257
258
259
260
261
262
263 public static void waitForSnapshotToComplete(HMaster master,
264 SnapshotDescription snapshot, long sleep) throws ServiceException {
265 final IsSnapshotDoneRequest request = IsSnapshotDoneRequest.newBuilder()
266 .setSnapshot(snapshot).build();
267 IsSnapshotDoneResponse done = IsSnapshotDoneResponse.newBuilder()
268 .buildPartial();
269 while (!done.getDone()) {
270 done = master.isSnapshotDone(null, request);
271 try {
272 Thread.sleep(sleep);
273 } catch (InterruptedException e) {
274 throw new ServiceException(e);
275 }
276 }
277 }
278
279 public static void cleanupSnapshot(HBaseAdmin admin, byte[] tableName)
280 throws IOException {
281 SnapshotTestingUtils.cleanupSnapshot(admin, Bytes.toString(tableName));
282 }
283
284 public static void cleanupSnapshot(HBaseAdmin admin, String snapshotName)
285 throws IOException {
286
287 admin.deleteSnapshot(snapshotName);
288 assertNoSnapshots(admin);
289 }
290
291
292
293
294
295
296
297
298
299 public static void expectSnapshotDoneException(HMaster master,
300 IsSnapshotDoneRequest snapshot,
301 Class<? extends HBaseSnapshotException> clazz) {
302 try {
303 master.isSnapshotDone(null, snapshot);
304 Assert.fail("didn't fail to lookup a snapshot");
305 } catch (ServiceException se) {
306 try {
307 throw ProtobufUtil.getRemoteException(se);
308 } catch (HBaseSnapshotException e) {
309 assertEquals("Threw wrong snapshot exception!", clazz, e.getClass());
310 } catch (Throwable t) {
311 Assert.fail("Threw an unexpected exception:" + t);
312 }
313 }
314 }
315
316
317
318
319
320
321
322
323
324 public static Path[] listHFiles(final FileSystem fs, final Path tableDir)
325 throws IOException {
326 final ArrayList<Path> hfiles = new ArrayList<Path>();
327 FSVisitor.visitTableStoreFiles(fs, tableDir, new FSVisitor.StoreFileVisitor() {
328 public void storeFile(final String region, final String family, final String hfileName)
329 throws IOException {
330 hfiles.add(new Path(tableDir, new Path(region, new Path(family, hfileName))));
331 }
332 });
333 return hfiles.toArray(new Path[hfiles.size()]);
334 }
335
336
337
338
339
340
341 public static void createSnapshotAndValidate(HBaseAdmin admin,
342 TableName tableName, String familyName, String snapshotNameString,
343 Path rootDir, FileSystem fs, boolean onlineSnapshot)
344 throws Exception {
345 ArrayList<byte[]> nonEmptyFamilyNames = new ArrayList<byte[]>(1);
346 nonEmptyFamilyNames.add(Bytes.toBytes(familyName));
347 createSnapshotAndValidate(admin, tableName, nonEmptyFamilyNames,
348 snapshotNameString, rootDir, fs, onlineSnapshot);
349 }
350
351
352
353
354
355 public static void createSnapshotAndValidate(HBaseAdmin admin,
356 TableName tableName, List<byte[]> nonEmptyFamilyNames, List<byte[]> emptyFamilyNames,
357 String snapshotNameString, Path rootDir, FileSystem fs, boolean onlineSnapshot)
358 throws Exception {
359 if (!onlineSnapshot) {
360 try {
361 admin.disableTable(tableName);
362 } catch (TableNotEnabledException tne) {
363 LOG.info("In attempting to disable " + tableName + " it turns out that the this table is " +
364 "already disabled.");
365 }
366 }
367 admin.snapshot(snapshotNameString, tableName);
368
369 List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertExistsMatchingSnapshot(admin,
370 snapshotNameString, tableName);
371 if (snapshots == null || snapshots.size() != 1) {
372 Assert.fail("Incorrect number of snapshots for table " + tableName);
373 }
374
375 SnapshotTestingUtils.confirmSnapshotValid(snapshots.get(0), tableName, nonEmptyFamilyNames,
376 emptyFamilyNames, rootDir, admin, fs, false,
377 new Path(rootDir, HConstants.HREGION_LOGDIR_NAME), null);
378 }
379
380
381
382
383 public static void waitForTableToBeOnline(final HBaseTestingUtility util,
384 final TableName tableName)
385 throws IOException, InterruptedException {
386 HRegionServer rs = util.getRSForFirstRegionInTable(tableName);
387 List<HRegion> onlineRegions = rs.getOnlineRegions(tableName);
388 for (HRegion region : onlineRegions) {
389 region.waitForFlushesAndCompactions();
390 }
391 util.getHBaseAdmin().isTableAvailable(tableName);
392 }
393
394 public static void createTable(final HBaseTestingUtility util, final TableName tableName,
395 final byte[]... families) throws IOException, InterruptedException {
396 HTableDescriptor htd = new HTableDescriptor(tableName);
397 for (byte[] family: families) {
398 HColumnDescriptor hcd = new HColumnDescriptor(family);
399 htd.addFamily(hcd);
400 }
401 byte[][] splitKeys = new byte[14][];
402 byte[] hex = Bytes.toBytes("123456789abcde");
403 for (int i = 0; i < splitKeys.length; ++i) {
404 splitKeys[i] = new byte[] { hex[i] };
405 }
406 util.getHBaseAdmin().createTable(htd, splitKeys);
407 waitForTableToBeOnline(util, tableName);
408 assertEquals(15, util.getHBaseAdmin().getTableRegions(tableName).size());
409 }
410
411 public static void loadData(final HBaseTestingUtility util, final TableName tableName, int rows,
412 byte[]... families) throws IOException, InterruptedException {
413 loadData(util, new HTable(util.getConfiguration(), tableName), rows, families);
414 }
415
416 public static void loadData(final HBaseTestingUtility util, final HTable table, int rows,
417 byte[]... families) throws IOException, InterruptedException {
418 table.setAutoFlush(false, true);
419
420
421 assertTrue(rows >= 16);
422 for (byte k0: Bytes.toBytes("0123456789abcdef")) {
423 byte[] k = new byte[] { k0 };
424 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), k);
425 byte[] key = Bytes.add(k, Bytes.toBytes(MD5Hash.getMD5AsHex(value)));
426 putData(table, families, key, value);
427 rows--;
428 }
429
430
431 while (rows-- > 0) {
432 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), Bytes.toBytes(rows));
433 byte[] key = Bytes.toBytes(MD5Hash.getMD5AsHex(value));
434 putData(table, families, key, value);
435 }
436 table.flushCommits();
437
438 waitForTableToBeOnline(util, table.getName());
439 }
440
441 private static void putData(final HTable table, final byte[][] families,
442 final byte[] key, final byte[] value) throws IOException {
443 byte[] q = Bytes.toBytes("q");
444 Put put = new Put(key);
445 put.setDurability(Durability.SKIP_WAL);
446 for (byte[] family: families) {
447 put.add(family, q, value);
448 }
449 table.put(put);
450 }
451
452 public static void deleteAllSnapshots(final HBaseAdmin admin)
453 throws IOException {
454
455 for (SnapshotDescription snapshot: admin.listSnapshots()) {
456 admin.deleteSnapshot(snapshot.getName());
457 }
458 SnapshotTestingUtils.assertNoSnapshots(admin);
459 }
460
461 public static void deleteArchiveDirectory(final HBaseTestingUtility util)
462 throws IOException {
463
464 MasterFileSystem mfs = util.getMiniHBaseCluster().getMaster().getMasterFileSystem();
465 Path archiveDir = new Path(mfs.getRootDir(), HConstants.HFILE_ARCHIVE_DIRECTORY);
466 mfs.getFileSystem().delete(archiveDir, true);
467 }
468
469 public static void verifyRowCount(final HBaseTestingUtility util, final TableName tableName,
470 long expectedRows) throws IOException {
471 HTable table = new HTable(util.getConfiguration(), tableName);
472 try {
473 assertEquals(expectedRows, util.countRows(table));
474 } finally {
475 table.close();
476 }
477 }
478 }