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.Collections;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
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.conf.Configuration;
36 import org.apache.hadoop.fs.FSDataOutputStream;
37 import org.apache.hadoop.fs.FileSystem;
38 import org.apache.hadoop.fs.FileStatus;
39 import org.apache.hadoop.fs.FSDataInputStream;
40 import org.apache.hadoop.fs.Path;
41 import org.apache.hadoop.fs.PathFilter;
42 import org.apache.hadoop.hbase.HBaseTestingUtility;
43 import org.apache.hadoop.hbase.HColumnDescriptor;
44 import org.apache.hadoop.hbase.HConstants;
45 import org.apache.hadoop.hbase.HRegionInfo;
46 import org.apache.hadoop.hbase.HTableDescriptor;
47 import org.apache.hadoop.hbase.TableName;
48 import org.apache.hadoop.hbase.TableNotEnabledException;
49 import org.apache.hadoop.hbase.classification.InterfaceAudience;
50 import org.apache.hadoop.hbase.client.Admin;
51 import org.apache.hadoop.hbase.client.BufferedMutator;
52 import org.apache.hadoop.hbase.client.Durability;
53 import org.apache.hadoop.hbase.client.HTable;
54 import org.apache.hadoop.hbase.client.Put;
55 import org.apache.hadoop.hbase.client.Table;
56 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
57 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
58 import org.apache.hadoop.hbase.io.HFileLink;
59 import org.apache.hadoop.hbase.master.HMaster;
60 import org.apache.hadoop.hbase.master.MasterFileSystem;
61 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
62 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
63 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
64 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
65 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneResponse;
66 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
67 import org.apache.hadoop.hbase.regionserver.HRegionServer;
68 import org.apache.hadoop.hbase.regionserver.Region;
69 import org.apache.hadoop.hbase.util.Bytes;
70 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
71 import org.apache.hadoop.hbase.util.FSTableDescriptors;
72 import org.apache.hadoop.hbase.util.FSVisitor;
73 import org.apache.hadoop.hbase.util.FSUtils;
74 import org.apache.hadoop.hbase.util.MD5Hash;
75 import org.junit.Assert;
76
77 import com.google.protobuf.ServiceException;
78
79
80
81
82 @InterfaceAudience.Private
83 public final class SnapshotTestingUtils {
84
85 private static final Log LOG = LogFactory.getLog(SnapshotTestingUtils.class);
86 private static byte[] KEYS = Bytes.toBytes("0123456789");
87
88 private SnapshotTestingUtils() {
89
90 }
91
92
93
94
95
96
97
98 public static void assertNoSnapshots(Admin admin) throws IOException {
99 assertEquals("Have some previous snapshots", 0, admin.listSnapshots()
100 .size());
101 }
102
103
104
105
106
107 public static List<SnapshotDescription> assertExistsMatchingSnapshot(
108 Admin admin, String snapshotName, TableName tableName)
109 throws IOException {
110
111 List<SnapshotDescription> snapshots = admin.listSnapshots();
112
113 List<SnapshotDescription> returnedSnapshots = new ArrayList<SnapshotDescription>();
114 for (SnapshotDescription sd : snapshots) {
115 if (snapshotName.equals(sd.getName()) &&
116 tableName.equals(TableName.valueOf(sd.getTable()))) {
117 returnedSnapshots.add(sd);
118 }
119 }
120
121 Assert.assertTrue("No matching snapshots found.", returnedSnapshots.size()>0);
122 return returnedSnapshots;
123 }
124
125
126
127
128 public static void assertOneSnapshotThatMatches(Admin admin,
129 SnapshotDescription snapshot) throws IOException {
130 assertOneSnapshotThatMatches(admin, snapshot.getName(),
131 TableName.valueOf(snapshot.getTable()));
132 }
133
134
135
136
137
138 public static List<SnapshotDescription> assertOneSnapshotThatMatches(
139 Admin admin, String snapshotName, TableName tableName)
140 throws IOException {
141
142 List<SnapshotDescription> snapshots = admin.listSnapshots();
143
144 assertEquals("Should only have 1 snapshot", 1, snapshots.size());
145 assertEquals(snapshotName, snapshots.get(0).getName());
146 assertEquals(tableName, TableName.valueOf(snapshots.get(0).getTable()));
147
148 return snapshots;
149 }
150
151
152
153
154
155 public static List<SnapshotDescription> assertOneSnapshotThatMatches(
156 Admin admin, byte[] snapshot, TableName tableName) throws IOException {
157 return assertOneSnapshotThatMatches(admin, Bytes.toString(snapshot),
158 tableName);
159 }
160
161 public static void confirmSnapshotValid(HBaseTestingUtility testUtil,
162 SnapshotDescription snapshotDescriptor, TableName tableName, byte[] family)
163 throws IOException {
164 MasterFileSystem mfs = testUtil.getHBaseCluster().getMaster().getMasterFileSystem();
165 confirmSnapshotValid(snapshotDescriptor, tableName, family,
166 mfs.getRootDir(), testUtil.getHBaseAdmin(), mfs.getFileSystem());
167 }
168
169
170
171
172
173 public static void confirmSnapshotValid(
174 SnapshotDescription snapshotDescriptor, TableName tableName,
175 byte[] testFamily, Path rootDir, Admin admin, FileSystem fs)
176 throws IOException {
177 ArrayList nonEmptyTestFamilies = new ArrayList(1);
178 nonEmptyTestFamilies.add(testFamily);
179 confirmSnapshotValid(snapshotDescriptor, tableName,
180 nonEmptyTestFamilies, null, rootDir, admin, fs);
181 }
182
183
184
185
186 public static void confirmEmptySnapshotValid(
187 SnapshotDescription snapshotDescriptor, TableName tableName,
188 byte[] testFamily, Path rootDir, Admin admin, FileSystem fs)
189 throws IOException {
190 ArrayList emptyTestFamilies = new ArrayList(1);
191 emptyTestFamilies.add(testFamily);
192 confirmSnapshotValid(snapshotDescriptor, tableName,
193 null, emptyTestFamilies, rootDir, admin, fs);
194 }
195
196
197
198
199
200
201
202 public static void confirmSnapshotValid(
203 SnapshotDescription snapshotDescriptor, TableName tableName,
204 List<byte[]> nonEmptyTestFamilies, List<byte[]> emptyTestFamilies,
205 Path rootDir, Admin admin, FileSystem fs) throws IOException {
206 final Configuration conf = admin.getConfiguration();
207
208
209 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(
210 snapshotDescriptor, rootDir);
211 assertTrue("target snapshot directory, '"+ snapshotDir +"', doesn't exist.", fs.exists(snapshotDir));
212
213 SnapshotDescription desc = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
214
215
216 final Set<byte[]> snapshotFamilies = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
217
218 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, desc);
219 Map<String, SnapshotRegionManifest> regionManifests = manifest.getRegionManifestsMap();
220 for (SnapshotRegionManifest regionManifest: regionManifests.values()) {
221 SnapshotReferenceUtil.visitRegionStoreFiles(regionManifest,
222 new SnapshotReferenceUtil.StoreFileVisitor() {
223 @Override
224 public void storeFile(final HRegionInfo regionInfo, final String family,
225 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
226 snapshotFamilies.add(Bytes.toBytes(family));
227 }
228 });
229 }
230
231
232 if (nonEmptyTestFamilies != null) {
233 for (final byte[] familyName: nonEmptyTestFamilies) {
234 assertTrue("Expected snapshot to contain family '" + Bytes.toString(familyName) + "', but it does not.", snapshotFamilies.contains(familyName));
235 }
236 }
237
238
239 if (emptyTestFamilies != null) {
240 for (final byte[] familyName: emptyTestFamilies) {
241 assertFalse("Expected snapshot to skip empty family '" + Bytes.toString(familyName) + "', but it is present.", snapshotFamilies.contains(familyName));
242 }
243 }
244
245
246 List<HRegionInfo> regions = admin.getTableRegions(tableName);
247
248 RegionReplicaUtil.removeNonDefaultRegions(regions);
249
250
251
252 int regionCountExclusiveSplitParent = 0;
253 for (SnapshotRegionManifest snapshotRegionManifest : regionManifests.values()) {
254 HRegionInfo hri = HRegionInfo.convert(snapshotRegionManifest.getRegionInfo());
255 if (hri.isOffline() && (hri.isSplit() || hri.isSplitParent())) {
256 continue;
257 }
258 regionCountExclusiveSplitParent++;
259 }
260 assertEquals("Wrong number of regions.", regions.size(), regionCountExclusiveSplitParent);
261
262
263 for (HRegionInfo info : regions) {
264 String regionName = info.getEncodedName();
265 assertTrue("Missing region name: '" + regionName + "'", regionManifests.containsKey(regionName));
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278 public static void waitForSnapshotToComplete(HMaster master, SnapshotDescription snapshot,
279 long sleep) throws ServiceException {
280 final IsSnapshotDoneRequest request = IsSnapshotDoneRequest.newBuilder()
281 .setSnapshot(snapshot).build();
282 IsSnapshotDoneResponse done = IsSnapshotDoneResponse.newBuilder()
283 .buildPartial();
284 while (!done.getDone()) {
285 done = master.getMasterRpcServices().isSnapshotDone(null, request);
286 try {
287 Thread.sleep(sleep);
288 } catch (InterruptedException e) {
289 throw new ServiceException(e);
290 }
291 }
292 }
293
294
295
296
297
298 public static void snapshot(Admin admin,
299 final String snapshotName, final String tableName,
300 SnapshotDescription.Type type, int numTries) throws IOException {
301 int tries = 0;
302 CorruptedSnapshotException lastEx = null;
303 while (tries++ < numTries) {
304 try {
305 admin.snapshot(snapshotName, TableName.valueOf(tableName), type);
306 return;
307 } catch (CorruptedSnapshotException cse) {
308 LOG.warn("Got CorruptedSnapshotException", cse);
309 lastEx = cse;
310 }
311 }
312 throw lastEx;
313 }
314
315 public static void cleanupSnapshot(Admin admin, byte[] tableName)
316 throws IOException {
317 SnapshotTestingUtils.cleanupSnapshot(admin, Bytes.toString(tableName));
318 }
319
320 public static void cleanupSnapshot(Admin admin, String snapshotName)
321 throws IOException {
322
323 admin.deleteSnapshot(snapshotName);
324 assertNoSnapshots(admin);
325 }
326
327
328
329
330
331
332
333
334
335 public static void expectSnapshotDoneException(HMaster master,
336 IsSnapshotDoneRequest snapshot,
337 Class<? extends HBaseSnapshotException> clazz) {
338 try {
339 master.getMasterRpcServices().isSnapshotDone(null, snapshot);
340 Assert.fail("didn't fail to lookup a snapshot");
341 } catch (ServiceException se) {
342 try {
343 throw ProtobufUtil.getRemoteException(se);
344 } catch (HBaseSnapshotException e) {
345 assertEquals("Threw wrong snapshot exception!", clazz, e.getClass());
346 } catch (Throwable t) {
347 Assert.fail("Threw an unexpected exception:" + t);
348 }
349 }
350 }
351
352
353
354
355
356
357
358
359
360 public static ArrayList<String> listHFileNames(final FileSystem fs, final Path tableDir)
361 throws IOException {
362 final ArrayList<String> hfiles = new ArrayList<String>();
363 FSVisitor.visitTableStoreFiles(fs, tableDir, new FSVisitor.StoreFileVisitor() {
364 @Override
365 public void storeFile(final String region, final String family, final String hfileName)
366 throws IOException {
367 hfiles.add(hfileName);
368 }
369 });
370 Collections.sort(hfiles);
371 return hfiles;
372 }
373
374
375
376
377
378
379 public static void createSnapshotAndValidate(Admin admin,
380 TableName tableName, String familyName, String snapshotNameString,
381 Path rootDir, FileSystem fs, boolean onlineSnapshot)
382 throws Exception {
383 ArrayList<byte[]> nonEmptyFamilyNames = new ArrayList<byte[]>(1);
384 nonEmptyFamilyNames.add(Bytes.toBytes(familyName));
385 createSnapshotAndValidate(admin, tableName, nonEmptyFamilyNames,
386 snapshotNameString, rootDir, fs, onlineSnapshot);
387 }
388
389
390
391
392
393 public static void createSnapshotAndValidate(Admin admin,
394 TableName tableName, List<byte[]> nonEmptyFamilyNames, List<byte[]> emptyFamilyNames,
395 String snapshotNameString, Path rootDir, FileSystem fs, boolean onlineSnapshot)
396 throws Exception {
397 if (!onlineSnapshot) {
398 try {
399 LOG.info("prepping for offline snapshot.");
400 admin.disableTable(tableName);
401 } catch (TableNotEnabledException tne) {
402 LOG.info("In attempting to disable " + tableName + " it turns out that the this table is " +
403 "already disabled.");
404 }
405 }
406 LOG.info("taking snapshot.");
407 admin.snapshot(snapshotNameString, tableName);
408
409 LOG.info("Confirming snapshot exists.");
410 List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertExistsMatchingSnapshot(admin,
411 snapshotNameString, tableName);
412 if (snapshots == null || snapshots.size() != 1) {
413 Assert.fail("Incorrect number of snapshots for table " + tableName);
414 }
415
416 LOG.info("validating snapshot.");
417 SnapshotTestingUtils.confirmSnapshotValid(snapshots.get(0), tableName, nonEmptyFamilyNames,
418 emptyFamilyNames, rootDir, admin, fs);
419 }
420
421
422
423
424
425
426
427
428
429 public static ArrayList corruptSnapshot(final HBaseTestingUtility util, final String snapshotName)
430 throws IOException {
431 final MasterFileSystem mfs = util.getHBaseCluster().getMaster().getMasterFileSystem();
432 final FileSystem fs = mfs.getFileSystem();
433
434 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName,
435 mfs.getRootDir());
436 SnapshotDescription snapshotDesc = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
437 final TableName table = TableName.valueOf(snapshotDesc.getTable());
438
439 final ArrayList corruptedFiles = new ArrayList();
440 final Configuration conf = util.getConfiguration();
441 SnapshotReferenceUtil.visitTableStoreFiles(conf, fs, snapshotDir, snapshotDesc,
442 new SnapshotReferenceUtil.StoreFileVisitor() {
443 @Override
444 public void storeFile(final HRegionInfo regionInfo, final String family,
445 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
446 String region = regionInfo.getEncodedName();
447 String hfile = storeFile.getName();
448 HFileLink link = HFileLink.build(conf, table, region, family, hfile);
449 if (corruptedFiles.size() % 2 == 0) {
450 fs.delete(link.getAvailablePath(fs), true);
451 corruptedFiles.add(hfile);
452 }
453 }
454 });
455
456 assertTrue(corruptedFiles.size() > 0);
457 return corruptedFiles;
458 }
459
460
461
462
463 public static class SnapshotMock {
464 private final static String TEST_FAMILY = "cf";
465 public final static int TEST_NUM_REGIONS = 4;
466
467 private final Configuration conf;
468 private final FileSystem fs;
469 private final Path rootDir;
470
471 static class RegionData {
472 public HRegionInfo hri;
473 public Path tableDir;
474 public Path[] files;
475
476 public RegionData(final Path tableDir, final HRegionInfo hri, final int nfiles) {
477 this.tableDir = tableDir;
478 this.hri = hri;
479 this.files = new Path[nfiles];
480 }
481 }
482
483 public static class SnapshotBuilder {
484 private final RegionData[] tableRegions;
485 private final SnapshotDescription desc;
486 private final HTableDescriptor htd;
487 private final Configuration conf;
488 private final FileSystem fs;
489 private final Path rootDir;
490 private Path snapshotDir;
491 private int snapshotted = 0;
492
493 public SnapshotBuilder(final Configuration conf, final FileSystem fs,
494 final Path rootDir, final HTableDescriptor htd,
495 final SnapshotDescription desc, final RegionData[] tableRegions)
496 throws IOException {
497 this.fs = fs;
498 this.conf = conf;
499 this.rootDir = rootDir;
500 this.htd = htd;
501 this.desc = desc;
502 this.tableRegions = tableRegions;
503 this.snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);
504 new FSTableDescriptors(conf, snapshotDir.getFileSystem(conf), rootDir)
505 .createTableDescriptorForTableDirectory(snapshotDir, htd, false);
506 }
507
508 public HTableDescriptor getTableDescriptor() {
509 return this.htd;
510 }
511
512 public SnapshotDescription getSnapshotDescription() {
513 return this.desc;
514 }
515
516 public Path getSnapshotsDir() {
517 return this.snapshotDir;
518 }
519
520 public Path[] addRegion() throws IOException {
521 return addRegion(desc);
522 }
523
524 public Path[] addRegionV1() throws IOException {
525 return addRegion(desc.toBuilder()
526 .setVersion(SnapshotManifestV1.DESCRIPTOR_VERSION)
527 .build());
528 }
529
530 public Path[] addRegionV2() throws IOException {
531 return addRegion(desc.toBuilder()
532 .setVersion(SnapshotManifestV2.DESCRIPTOR_VERSION)
533 .build());
534 }
535
536 private Path[] addRegion(final SnapshotDescription desc) throws IOException {
537 if (this.snapshotted == tableRegions.length) {
538 throw new UnsupportedOperationException("No more regions in the table");
539 }
540
541 RegionData regionData = tableRegions[this.snapshotted++];
542 ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(desc.getName());
543 SnapshotManifest manifest = SnapshotManifest.create(conf, fs, snapshotDir, desc, monitor);
544 manifest.addRegion(regionData.tableDir, regionData.hri);
545 return regionData.files;
546 }
547
548 private void corruptFile(Path p) throws IOException {
549 String manifestName = p.getName();
550
551
552 Path newP = new Path(p.getParent(), manifestName + "1");
553 fs.rename(p, newP);
554
555
556 FSDataOutputStream out = fs.create(p);
557
558
559
560 FSDataInputStream input = fs.open(newP);
561 byte[] buffer = new byte[25];
562 int len = input.read(0, buffer, 0, 25);
563 if (len > 1) {
564 out.write(buffer, 0, len - 1);
565 }
566 out.close();
567
568
569 fs.delete(newP);
570 }
571
572
573
574
575
576
577 public void corruptOneRegionManifest() throws IOException {
578 FileStatus[] manifestFiles = FSUtils.listStatus(fs, snapshotDir, new PathFilter() {
579 @Override public boolean accept(Path path) {
580 return path.getName().startsWith(SnapshotManifestV2.SNAPSHOT_MANIFEST_PREFIX);
581 }
582 });
583
584 if (manifestFiles.length == 0) return;
585
586
587 Path p = manifestFiles[0].getPath();
588 corruptFile(p);
589 }
590
591 public void missOneRegionSnapshotFile() throws IOException {
592 FileStatus[] manifestFiles = FSUtils.listStatus(fs, snapshotDir);
593 for (FileStatus fileStatus : manifestFiles) {
594 String fileName = fileStatus.getPath().getName();
595 if (fileName.endsWith(SnapshotDescriptionUtils.SNAPSHOTINFO_FILE)
596 || fileName.endsWith(".tabledesc")
597 || fileName.endsWith(SnapshotDescriptionUtils.SNAPSHOT_TMP_DIR_NAME)) {
598 fs.delete(fileStatus.getPath(), true);
599 }
600 }
601 }
602
603
604
605
606
607
608 public void corruptDataManifest() throws IOException {
609 FileStatus[] manifestFiles = FSUtils.listStatus(fs, snapshotDir, new PathFilter() {
610 @Override
611 public boolean accept(Path path) {
612 return path.getName().startsWith(SnapshotManifest.DATA_MANIFEST_NAME);
613 }
614 });
615
616 if (manifestFiles.length == 0) return;
617
618
619 Path p = manifestFiles[0].getPath();
620 corruptFile(p);
621 }
622
623 public Path commit() throws IOException {
624 ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(desc.getName());
625 SnapshotManifest manifest = SnapshotManifest.create(conf, fs, snapshotDir, desc, monitor);
626 manifest.addTableDescriptor(htd);
627 manifest.consolidate();
628 Path workingDir = snapshotDir;
629 Path completedSnapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(desc, rootDir);
630 SnapshotDescriptionUtils.completeSnapshot(completedSnapshotDir, workingDir, fs,
631 workingDir.getFileSystem(conf), conf);
632 snapshotDir = completedSnapshotDir;
633 return snapshotDir;
634 }
635
636 public void consolidate() throws IOException {
637 ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(desc.getName());
638 SnapshotManifest manifest = SnapshotManifest.create(conf, fs, snapshotDir, desc, monitor);
639 manifest.addTableDescriptor(htd);
640 manifest.consolidate();
641 }
642 }
643
644 public SnapshotMock(final Configuration conf, final FileSystem fs, final Path rootDir) {
645 this.fs = fs;
646 this.conf = conf;
647 this.rootDir = rootDir;
648 }
649
650 public SnapshotBuilder createSnapshotV1(final String snapshotName, final String tableName)
651 throws IOException {
652 return createSnapshot(snapshotName, tableName, SnapshotManifestV1.DESCRIPTOR_VERSION);
653 }
654
655 public SnapshotBuilder createSnapshotV1(final String snapshotName, final String tableName,
656 final int numRegions) throws IOException {
657 return createSnapshot(snapshotName, tableName, numRegions, SnapshotManifestV1.DESCRIPTOR_VERSION);
658 }
659
660 public SnapshotBuilder createSnapshotV2(final String snapshotName, final String tableName)
661 throws IOException {
662 return createSnapshot(snapshotName, tableName, SnapshotManifestV2.DESCRIPTOR_VERSION);
663 }
664
665 public SnapshotBuilder createSnapshotV2(final String snapshotName, final String tableName,
666 final int numRegions) throws IOException {
667 return createSnapshot(snapshotName, tableName, numRegions, SnapshotManifestV2.DESCRIPTOR_VERSION);
668 }
669
670 public SnapshotBuilder createSnapshotV2(final String snapshotName, final String tableName,
671 final int numRegions, final long ttl) throws IOException {
672 return createSnapshot(snapshotName, tableName, numRegions,
673 SnapshotManifestV2.DESCRIPTOR_VERSION, ttl);
674 }
675
676 private SnapshotBuilder createSnapshot(final String snapshotName, final String tableName,
677 final int version) throws IOException {
678 return createSnapshot(snapshotName, tableName, TEST_NUM_REGIONS, version);
679 }
680
681 private SnapshotBuilder createSnapshot(final String snapshotName, final String tableName,
682 final int numRegions, final int version) throws IOException {
683 HTableDescriptor htd = createHtd(tableName);
684 RegionData[] regions = createTable(htd, numRegions);
685
686 SnapshotDescription desc = SnapshotDescription.newBuilder()
687 .setTable(htd.getNameAsString())
688 .setName(snapshotName)
689 .setVersion(version)
690 .build();
691
692 Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);
693 SnapshotDescriptionUtils.writeSnapshotInfo(desc, workingDir, workingDir.getFileSystem(conf));
694 return new SnapshotBuilder(conf, fs, rootDir, htd, desc, regions);
695 }
696
697 private SnapshotBuilder createSnapshot(final String snapshotName, final String tableName,
698 final int numRegions, final int version, final long ttl) throws IOException {
699 HTableDescriptor htd = createHtd(tableName);
700 RegionData[] regions = createTable(htd, numRegions);
701 SnapshotDescription desc = SnapshotDescription.newBuilder()
702 .setTable(htd.getTableName().getNameAsString())
703 .setName(snapshotName)
704 .setVersion(version)
705 .setCreationTime(EnvironmentEdgeManager.currentTime())
706 .setTtl(ttl)
707 .build();
708 Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir, conf);
709 SnapshotDescriptionUtils.writeSnapshotInfo(desc, workingDir, fs);
710 return new SnapshotBuilder(conf, fs, rootDir, htd, desc, regions);
711 }
712
713 public HTableDescriptor createHtd(final String tableName) {
714 HTableDescriptor htd = new HTableDescriptor(tableName);
715 htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
716 return htd;
717 }
718
719 private RegionData[] createTable(final HTableDescriptor htd, final int nregions)
720 throws IOException {
721 Path tableDir = FSUtils.getTableDir(rootDir, htd.getTableName());
722 new FSTableDescriptors(conf).createTableDescriptorForTableDirectory(tableDir, htd, false);
723
724 assertTrue(nregions % 2 == 0);
725 RegionData[] regions = new RegionData[nregions];
726 for (int i = 0; i < regions.length; i += 2) {
727 byte[] startKey = Bytes.toBytes(0 + i * 2);
728 byte[] endKey = Bytes.toBytes(1 + i * 2);
729
730
731 HRegionInfo hri = new HRegionInfo(htd.getTableName(), startKey, endKey);
732 HRegionFileSystem rfs = HRegionFileSystem.createRegionOnFileSystem(conf, fs, tableDir, hri);
733 regions[i] = new RegionData(tableDir, hri, 3);
734 for (int j = 0; j < regions[i].files.length; ++j) {
735 Path storeFile = createStoreFile(rfs.createTempName());
736 regions[i].files[j] = rfs.commitStoreFile(TEST_FAMILY, storeFile);
737 }
738
739
740
741 startKey = Bytes.toBytes(2 + i * 2);
742 endKey = Bytes.toBytes(3 + i * 2);
743 hri = new HRegionInfo(htd.getTableName());
744 rfs = HRegionFileSystem.createRegionOnFileSystem(conf, fs, tableDir, hri);
745 regions[i+1] = new RegionData(tableDir, hri, regions[i].files.length);
746 for (int j = 0; j < regions[i].files.length; ++j) {
747 String refName = regions[i].files[j].getName() + '.' + regions[i].hri.getEncodedName();
748 Path refFile = createStoreFile(new Path(rootDir, refName));
749 regions[i+1].files[j] = rfs.commitStoreFile(TEST_FAMILY, refFile);
750 }
751 }
752 return regions;
753 }
754
755 private Path createStoreFile(final Path storeFile)
756 throws IOException {
757 FSDataOutputStream out = fs.create(storeFile);
758 try {
759 out.write(Bytes.toBytes(storeFile.toString()));
760 } finally {
761 out.close();
762 }
763 return storeFile;
764 }
765 }
766
767
768
769
770 public static void waitForTableToBeOnline(final HBaseTestingUtility util,
771 final TableName tableName)
772 throws IOException, InterruptedException {
773 HRegionServer rs = util.getRSForFirstRegionInTable(tableName);
774 List<Region> onlineRegions = rs.getOnlineRegions(tableName);
775 for (Region region : onlineRegions) {
776 region.waitForFlushesAndCompactions();
777 }
778
779 util.waitFor(60000, util.predicateTableAvailable(tableName));
780 }
781
782 public static void createTable(final HBaseTestingUtility util, final TableName tableName,
783 int regionReplication, final byte[]... families) throws IOException, InterruptedException {
784 HTableDescriptor htd = new HTableDescriptor(tableName);
785 htd.setRegionReplication(regionReplication);
786 for (byte[] family : families) {
787 HColumnDescriptor hcd = new HColumnDescriptor(family);
788 htd.addFamily(hcd);
789 }
790 byte[][] splitKeys = getSplitKeys();
791 util.createTable(htd, splitKeys);
792 assertEquals((splitKeys.length + 1) * regionReplication,
793 util.getHBaseAdmin().getTableRegions(tableName).size());
794 }
795
796 public static byte[][] getSplitKeys() {
797 byte[][] splitKeys = new byte[KEYS.length-2][];
798 for (int i = 0; i < splitKeys.length; ++i) {
799 splitKeys[i] = new byte[] { KEYS[i+1] };
800 }
801 return splitKeys;
802 }
803
804 public static void createTable(final HBaseTestingUtility util, final TableName tableName,
805 final byte[]... families) throws IOException, InterruptedException {
806 createTable(util, tableName, 1, families);
807 }
808
809 public static void loadData(final HBaseTestingUtility util, final TableName tableName, int rows,
810 byte[]... families) throws IOException, InterruptedException {
811 try (BufferedMutator mutator = util.getConnection().getBufferedMutator(tableName)) {
812 loadData(util, mutator, rows, families);
813 }
814 }
815
816 public static void loadData(final HBaseTestingUtility util, final BufferedMutator mutator, int rows,
817 byte[]... families) throws IOException, InterruptedException {
818
819 assertTrue(rows >= KEYS.length);
820 for (byte k0: KEYS) {
821 byte[] k = new byte[] { k0 };
822 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), k);
823 byte[] key = Bytes.add(k, Bytes.toBytes(MD5Hash.getMD5AsHex(value)));
824 final byte[][] families1 = families;
825 final byte[] key1 = key;
826 final byte[] value1 = value;
827 mutator.mutate(createPut(families1, key1, value1));
828 rows--;
829 }
830
831
832 while (rows-- > 0) {
833 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), Bytes.toBytes(rows));
834 byte[] key = Bytes.toBytes(MD5Hash.getMD5AsHex(value));
835 final byte[][] families1 = families;
836 final byte[] key1 = key;
837 final byte[] value1 = value;
838 mutator.mutate(createPut(families1, key1, value1));
839 }
840 mutator.flush();
841
842 waitForTableToBeOnline(util, mutator.getName());
843 }
844
845 private static Put createPut(final byte[][] families, final byte[] key, final byte[] value) {
846 byte[] q = Bytes.toBytes("q");
847 Put put = new Put(key);
848 put.setDurability(Durability.SKIP_WAL);
849 for (byte[] family: families) {
850 put.add(family, q, value);
851 }
852 return put;
853 }
854
855 public static void deleteAllSnapshots(final Admin admin)
856 throws IOException {
857
858 for (SnapshotDescription snapshot: admin.listSnapshots()) {
859 admin.deleteSnapshot(snapshot.getName());
860 }
861 SnapshotTestingUtils.assertNoSnapshots(admin);
862 }
863
864 public static void deleteArchiveDirectory(final HBaseTestingUtility util)
865 throws IOException {
866
867 MasterFileSystem mfs = util.getMiniHBaseCluster().getMaster().getMasterFileSystem();
868 Path archiveDir = new Path(mfs.getRootDir(), HConstants.HFILE_ARCHIVE_DIRECTORY);
869 mfs.getFileSystem().delete(archiveDir, true);
870 }
871
872 public static void verifyRowCount(final HBaseTestingUtility util, final TableName tableName,
873 long expectedRows) throws IOException {
874 Table table = new HTable(util.getConfiguration(), tableName);
875 try {
876 assertEquals(expectedRows, util.countRows(table));
877 } finally {
878 table.close();
879 }
880 }
881
882 public static void verifyReplicasCameOnline(TableName tableName, Admin admin,
883 int regionReplication) throws IOException {
884 List<HRegionInfo> regions = admin.getTableRegions(tableName);
885 HashSet<HRegionInfo> set = new HashSet<HRegionInfo>();
886 for (HRegionInfo hri : regions) {
887 set.add(RegionReplicaUtil.getRegionInfoForDefaultReplica(hri));
888 for (int i = 0; i < regionReplication; i++) {
889 HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hri, i);
890 if (!regions.contains(replica)) {
891 Assert.fail(replica + " is not contained in the list of online regions");
892 }
893 }
894 }
895 assert(set.size() == getSplitKeys().length + 1);
896 }
897 }