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.InterruptedIOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.TreeMap;
34 import java.util.concurrent.ThreadPoolExecutor;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.hadoop.hbase.classification.InterfaceAudience;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.fs.FileStatus;
41 import org.apache.hadoop.fs.FileSystem;
42 import org.apache.hadoop.fs.Path;
43 import org.apache.hadoop.hbase.HColumnDescriptor;
44 import org.apache.hadoop.hbase.HRegionInfo;
45 import org.apache.hadoop.hbase.HTableDescriptor;
46 import org.apache.hadoop.hbase.TableName;
47 import org.apache.hadoop.hbase.backup.HFileArchiver;
48 import org.apache.hadoop.hbase.catalog.CatalogTracker;
49 import org.apache.hadoop.hbase.catalog.MetaEditor;
50 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
51 import org.apache.hadoop.hbase.io.HFileLink;
52 import org.apache.hadoop.hbase.io.Reference;
53 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
54 import org.apache.hadoop.hbase.monitoring.MonitoredTask;
55 import org.apache.hadoop.hbase.monitoring.TaskMonitor;
56 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
57 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
58 import org.apache.hadoop.hbase.regionserver.HRegion;
59 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
60 import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
61 import org.apache.hadoop.hbase.snapshot.SnapshotManifest;
62 import org.apache.hadoop.hbase.util.Bytes;
63 import org.apache.hadoop.hbase.util.FSUtils;
64 import org.apache.hadoop.hbase.util.ModifyRegionUtils;
65 import org.apache.hadoop.hbase.util.Pair;
66 import org.apache.hadoop.io.IOUtils;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 @InterfaceAudience.Private
110 public class RestoreSnapshotHelper {
111 private static final Log LOG = LogFactory.getLog(RestoreSnapshotHelper.class);
112
113 private final Map<byte[], byte[]> regionsMap =
114 new TreeMap<byte[], byte[]>(Bytes.BYTES_COMPARATOR);
115
116 private final Map<String, Pair<String, String> > parentsMap =
117 new HashMap<String, Pair<String, String> >();
118
119 private final ForeignExceptionDispatcher monitor;
120 private final MonitoredTask status;
121
122 private final SnapshotManifest snapshotManifest;
123 private final SnapshotDescription snapshotDesc;
124 private final TableName snapshotTable;
125
126 private final HTableDescriptor tableDesc;
127 private final Path rootDir;
128 private final Path tableDir;
129
130 private final Configuration conf;
131 private final FileSystem fs;
132 private final boolean createBackRefs;
133
134 public RestoreSnapshotHelper(final Configuration conf,
135 final FileSystem fs,
136 final SnapshotManifest manifest,
137 final HTableDescriptor tableDescriptor,
138 final Path rootDir,
139 final ForeignExceptionDispatcher monitor,
140 final MonitoredTask status) {
141 this(conf, fs, manifest, tableDescriptor, rootDir, monitor, status, true);
142 }
143
144 public RestoreSnapshotHelper(final Configuration conf,
145 final FileSystem fs,
146 final SnapshotManifest manifest,
147 final HTableDescriptor tableDescriptor,
148 final Path rootDir,
149 final ForeignExceptionDispatcher monitor,
150 final MonitoredTask status,
151 final boolean createBackRefs)
152 {
153 this.fs = fs;
154 this.conf = conf;
155 this.snapshotManifest = manifest;
156 this.snapshotDesc = manifest.getSnapshotDescription();
157 this.snapshotTable = TableName.valueOf(snapshotDesc.getTable());
158 this.tableDesc = tableDescriptor;
159 this.rootDir = rootDir;
160 this.tableDir = FSUtils.getTableDir(rootDir, tableDesc.getTableName());
161 this.monitor = monitor;
162 this.status = status;
163 this.createBackRefs = createBackRefs;
164 }
165
166
167
168
169
170 public RestoreMetaChanges restoreHdfsRegions() throws IOException {
171 ThreadPoolExecutor exec = SnapshotManifest.createExecutor(conf, "RestoreSnapshot");
172 try {
173 return restoreHdfsRegions(exec);
174 } finally {
175 exec.shutdown();
176 }
177 }
178
179 private RestoreMetaChanges restoreHdfsRegions(final ThreadPoolExecutor exec) throws IOException {
180 LOG.debug("starting restore");
181
182 Map<String, SnapshotRegionManifest> regionManifests = snapshotManifest.getRegionManifestsMap();
183 if (regionManifests == null) {
184 LOG.warn("Nothing to restore. Snapshot " + snapshotDesc + " looks empty");
185 return null;
186 }
187
188 RestoreMetaChanges metaChanges = new RestoreMetaChanges(parentsMap);
189
190
191
192 Set<String> regionNames = new HashSet<String>(regionManifests.keySet());
193
194
195
196 List<HRegionInfo> tableRegions = getTableRegions();
197 if (tableRegions != null) {
198 monitor.rethrowException();
199 for (HRegionInfo regionInfo: tableRegions) {
200 String regionName = regionInfo.getEncodedName();
201 if (regionNames.contains(regionName)) {
202 LOG.info("region to restore: " + regionName);
203 regionNames.remove(regionName);
204 metaChanges.addRegionToRestore(regionInfo);
205 } else {
206 LOG.info("region to remove: " + regionName);
207 metaChanges.addRegionToRemove(regionInfo);
208 }
209 }
210
211
212 monitor.rethrowException();
213 status.setStatus("Restoring table regions...");
214 restoreHdfsRegions(exec, regionManifests, metaChanges.getRegionsToRestore());
215 status.setStatus("Finished restoring all table regions.");
216
217
218 monitor.rethrowException();
219 status.setStatus("Starting to delete excess regions from table");
220 removeHdfsRegions(exec, metaChanges.getRegionsToRemove());
221 status.setStatus("Finished deleting excess regions from table.");
222 }
223
224
225 if (regionNames.size() > 0) {
226 List<HRegionInfo> regionsToAdd = new ArrayList<HRegionInfo>(regionNames.size());
227
228 monitor.rethrowException();
229 for (String regionName: regionNames) {
230 LOG.info("region to add: " + regionName);
231 regionsToAdd.add(HRegionInfo.convert(regionManifests.get(regionName).getRegionInfo()));
232 }
233
234
235 monitor.rethrowException();
236 status.setStatus("Cloning regions...");
237 HRegionInfo[] clonedRegions = cloneHdfsRegions(exec, regionManifests, regionsToAdd);
238 metaChanges.setNewRegions(clonedRegions);
239 status.setStatus("Finished cloning regions.");
240 }
241
242 return metaChanges;
243 }
244
245
246
247
248 public static class RestoreMetaChanges {
249 private final Map<String, Pair<String, String> > parentsMap;
250
251 private List<HRegionInfo> regionsToRestore = null;
252 private List<HRegionInfo> regionsToRemove = null;
253 private List<HRegionInfo> regionsToAdd = null;
254
255 RestoreMetaChanges(final Map<String, Pair<String, String> > parentsMap) {
256 this.parentsMap = parentsMap;
257 }
258
259
260
261
262 public boolean hasRegionsToAdd() {
263 return this.regionsToAdd != null && this.regionsToAdd.size() > 0;
264 }
265
266
267
268
269
270
271
272 public List<HRegionInfo> getRegionsToAdd() {
273 return this.regionsToAdd;
274 }
275
276
277
278
279 public boolean hasRegionsToRestore() {
280 return this.regionsToRestore != null && this.regionsToRestore.size() > 0;
281 }
282
283
284
285
286
287
288 public List<HRegionInfo> getRegionsToRestore() {
289 return this.regionsToRestore;
290 }
291
292
293
294
295 public boolean hasRegionsToRemove() {
296 return this.regionsToRemove != null && this.regionsToRemove.size() > 0;
297 }
298
299
300
301
302
303
304
305 public List<HRegionInfo> getRegionsToRemove() {
306 return this.regionsToRemove;
307 }
308
309 void setNewRegions(final HRegionInfo[] hris) {
310 if (hris != null) {
311 regionsToAdd = Arrays.asList(hris);
312 } else {
313 regionsToAdd = null;
314 }
315 }
316
317 void addRegionToRemove(final HRegionInfo hri) {
318 if (regionsToRemove == null) {
319 regionsToRemove = new LinkedList<HRegionInfo>();
320 }
321 regionsToRemove.add(hri);
322 }
323
324 void addRegionToRestore(final HRegionInfo hri) {
325 if (regionsToRestore == null) {
326 regionsToRestore = new LinkedList<HRegionInfo>();
327 }
328 regionsToRestore.add(hri);
329 }
330
331 public void updateMetaParentRegions(final CatalogTracker catalogTracker,
332 final List<HRegionInfo> regionInfos) throws IOException {
333 if (regionInfos == null || parentsMap.isEmpty()) return;
334
335
336 Map<String, HRegionInfo> regionsByName = new HashMap<String, HRegionInfo>(regionInfos.size());
337 List<HRegionInfo> parentRegions = new LinkedList();
338 for (HRegionInfo regionInfo: regionInfos) {
339 if (regionInfo.isSplitParent()) {
340 parentRegions.add(regionInfo);
341 } else {
342 regionsByName.put(regionInfo.getEncodedName(), regionInfo);
343 }
344 }
345
346
347 for (HRegionInfo regionInfo: parentRegions) {
348 Pair<String, String> daughters = parentsMap.get(regionInfo.getEncodedName());
349 if (daughters == null) {
350
351
352 LOG.warn("Skip update of unreferenced offline parent: " + regionInfo);
353 continue;
354 }
355
356
357 if (daughters.getSecond() == null) {
358 daughters.setSecond(daughters.getFirst());
359 }
360
361 LOG.debug("Update splits parent " + regionInfo.getEncodedName() + " -> " + daughters);
362 MetaEditor.addRegionToMeta(catalogTracker, regionInfo,
363 regionsByName.get(daughters.getFirst()),
364 regionsByName.get(daughters.getSecond()));
365 }
366 }
367 }
368
369
370
371
372 private void removeHdfsRegions(final ThreadPoolExecutor exec, final List<HRegionInfo> regions)
373 throws IOException {
374 if (regions == null || regions.size() == 0) return;
375 ModifyRegionUtils.editRegions(exec, regions, new ModifyRegionUtils.RegionEditTask() {
376 @Override
377 public void editRegion(final HRegionInfo hri) throws IOException {
378 HFileArchiver.archiveRegion(conf, fs, hri);
379 }
380 });
381 }
382
383
384
385
386 private void restoreHdfsRegions(final ThreadPoolExecutor exec,
387 final Map<String, SnapshotRegionManifest> regionManifests,
388 final List<HRegionInfo> regions) throws IOException {
389 if (regions == null || regions.size() == 0) return;
390 ModifyRegionUtils.editRegions(exec, regions, new ModifyRegionUtils.RegionEditTask() {
391 @Override
392 public void editRegion(final HRegionInfo hri) throws IOException {
393 restoreRegion(hri, regionManifests.get(hri.getEncodedName()));
394 }
395 });
396 }
397
398 private Map<String, List<SnapshotRegionManifest.StoreFile>> getRegionHFileReferences(
399 final SnapshotRegionManifest manifest) {
400 Map<String, List<SnapshotRegionManifest.StoreFile>> familyMap =
401 new HashMap<String, List<SnapshotRegionManifest.StoreFile>>(manifest.getFamilyFilesCount());
402 for (SnapshotRegionManifest.FamilyFiles familyFiles: manifest.getFamilyFilesList()) {
403 familyMap.put(familyFiles.getFamilyName().toStringUtf8(),
404 new ArrayList<SnapshotRegionManifest.StoreFile>(familyFiles.getStoreFilesList()));
405 }
406 return familyMap;
407 }
408
409
410
411
412
413 private void restoreRegion(final HRegionInfo regionInfo,
414 final SnapshotRegionManifest regionManifest) throws IOException {
415 Map<String, List<SnapshotRegionManifest.StoreFile>> snapshotFiles =
416 getRegionHFileReferences(regionManifest);
417
418 Path regionDir = new Path(tableDir, regionInfo.getEncodedName());
419 String tableName = tableDesc.getTableName().getNameAsString();
420
421
422 for (Path familyDir: FSUtils.getFamilyDirs(fs, regionDir)) {
423 byte[] family = Bytes.toBytes(familyDir.getName());
424 Set<String> familyFiles = getTableRegionFamilyFiles(familyDir);
425 List<SnapshotRegionManifest.StoreFile> snapshotFamilyFiles =
426 snapshotFiles.remove(familyDir.getName());
427 if (snapshotFamilyFiles != null) {
428 List<SnapshotRegionManifest.StoreFile> hfilesToAdd =
429 new ArrayList<SnapshotRegionManifest.StoreFile>();
430 for (SnapshotRegionManifest.StoreFile storeFile: snapshotFamilyFiles) {
431 if (familyFiles.contains(storeFile.getName())) {
432
433 familyFiles.remove(storeFile.getName());
434 } else {
435
436 hfilesToAdd.add(storeFile);
437 }
438 }
439
440
441 for (String hfileName: familyFiles) {
442 Path hfile = new Path(familyDir, hfileName);
443 LOG.trace("Removing hfile=" + hfileName +
444 " from region=" + regionInfo.getEncodedName() + " table=" + tableName);
445 HFileArchiver.archiveStoreFile(conf, fs, regionInfo, tableDir, family, hfile);
446 }
447
448
449 for (SnapshotRegionManifest.StoreFile storeFile: hfilesToAdd) {
450 LOG.debug("Adding HFileLink " + storeFile.getName() +
451 " to region=" + regionInfo.getEncodedName() + " table=" + tableName);
452 restoreStoreFile(familyDir, regionInfo, storeFile, createBackRefs);
453 }
454 } else {
455
456 LOG.trace("Removing family=" + Bytes.toString(family) +
457 " from region=" + regionInfo.getEncodedName() + " table=" + tableName);
458 HFileArchiver.archiveFamily(fs, conf, regionInfo, tableDir, family);
459 fs.delete(familyDir, true);
460 }
461 }
462
463
464 for (Map.Entry<String, List<SnapshotRegionManifest.StoreFile>> familyEntry:
465 snapshotFiles.entrySet()) {
466 Path familyDir = new Path(regionDir, familyEntry.getKey());
467 if (!fs.mkdirs(familyDir)) {
468 throw new IOException("Unable to create familyDir=" + familyDir);
469 }
470
471 for (SnapshotRegionManifest.StoreFile storeFile: familyEntry.getValue()) {
472 LOG.trace("Adding HFileLink " + storeFile.getName() + " to table=" + tableName);
473 restoreStoreFile(familyDir, regionInfo, storeFile, createBackRefs);
474 }
475 }
476 }
477
478
479
480
481 private Set<String> getTableRegionFamilyFiles(final Path familyDir) throws IOException {
482 Set<String> familyFiles = new HashSet<String>();
483
484 FileStatus[] hfiles = FSUtils.listStatus(fs, familyDir);
485 if (hfiles == null) return familyFiles;
486
487 for (FileStatus hfileRef: hfiles) {
488 String hfileName = hfileRef.getPath().getName();
489 familyFiles.add(hfileName);
490 }
491
492 return familyFiles;
493 }
494
495
496
497
498
499 private HRegionInfo[] cloneHdfsRegions(final ThreadPoolExecutor exec,
500 final Map<String, SnapshotRegionManifest> regionManifests,
501 final List<HRegionInfo> regions) throws IOException {
502 if (regions == null || regions.size() == 0) return null;
503
504 final Map<String, HRegionInfo> snapshotRegions =
505 new HashMap<String, HRegionInfo>(regions.size());
506
507
508 HRegionInfo[] clonedRegionsInfo = new HRegionInfo[regions.size()];
509 for (int i = 0; i < clonedRegionsInfo.length; ++i) {
510
511 HRegionInfo snapshotRegionInfo = regions.get(i);
512 clonedRegionsInfo[i] = cloneRegionInfo(snapshotRegionInfo);
513
514
515 String snapshotRegionName = snapshotRegionInfo.getEncodedName();
516 String clonedRegionName = clonedRegionsInfo[i].getEncodedName();
517 regionsMap.put(Bytes.toBytes(snapshotRegionName), Bytes.toBytes(clonedRegionName));
518 LOG.info("clone region=" + snapshotRegionName + " as " + clonedRegionName);
519
520
521 snapshotRegions.put(clonedRegionName, snapshotRegionInfo);
522 }
523
524
525 ModifyRegionUtils.createRegions(exec, conf, rootDir, tableDir,
526 tableDesc, clonedRegionsInfo, new ModifyRegionUtils.RegionFillTask() {
527 @Override
528 public void fillRegion(final HRegion region) throws IOException {
529 HRegionInfo snapshotHri = snapshotRegions.get(region.getRegionInfo().getEncodedName());
530 cloneRegion(region, snapshotHri, regionManifests.get(snapshotHri.getEncodedName()));
531 }
532 });
533
534 return clonedRegionsInfo;
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548 private void cloneRegion(final HRegion region, final HRegionInfo snapshotRegionInfo,
549 final SnapshotRegionManifest manifest) throws IOException {
550 final Path regionDir = new Path(tableDir, region.getRegionInfo().getEncodedName());
551 final String tableName = tableDesc.getTableName().getNameAsString();
552 for (SnapshotRegionManifest.FamilyFiles familyFiles: manifest.getFamilyFilesList()) {
553 Path familyDir = new Path(regionDir, familyFiles.getFamilyName().toStringUtf8());
554 for (SnapshotRegionManifest.StoreFile storeFile: familyFiles.getStoreFilesList()) {
555 LOG.info("Adding HFileLink " + storeFile.getName() + " to table=" + tableName);
556 restoreStoreFile(familyDir, snapshotRegionInfo, storeFile, createBackRefs);
557 }
558 }
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574 private void restoreStoreFile(final Path familyDir, final HRegionInfo regionInfo,
575 final SnapshotRegionManifest.StoreFile storeFile, final boolean createBackRef)
576 throws IOException {
577 String hfileName = storeFile.getName();
578 if (HFileLink.isHFileLink(hfileName)) {
579 HFileLink.createFromHFileLink(conf, fs, familyDir, hfileName, createBackRef);
580 } else if (StoreFileInfo.isReference(hfileName)) {
581 restoreReferenceFile(familyDir, regionInfo, storeFile);
582 } else {
583 HFileLink.create(conf, fs, familyDir, regionInfo, hfileName, createBackRef);
584 }
585 }
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 private void restoreReferenceFile(final Path familyDir, final HRegionInfo regionInfo,
606 final SnapshotRegionManifest.StoreFile storeFile) throws IOException {
607 String hfileName = storeFile.getName();
608
609
610 Path refPath =
611 StoreFileInfo.getReferredToFile(new Path(new Path(new Path(new Path(snapshotTable
612 .getNamespaceAsString(), snapshotTable.getQualifierAsString()), regionInfo
613 .getEncodedName()), familyDir.getName()), hfileName));
614 String snapshotRegionName = refPath.getParent().getParent().getName();
615 String fileName = refPath.getName();
616
617
618 String clonedRegionName = Bytes.toString(regionsMap.get(Bytes.toBytes(snapshotRegionName)));
619 if (clonedRegionName == null) clonedRegionName = snapshotRegionName;
620
621
622 Path linkPath = null;
623 String refLink = fileName;
624 if (!HFileLink.isHFileLink(fileName)) {
625 refLink = HFileLink.createHFileLinkName(snapshotTable, snapshotRegionName, fileName);
626 linkPath = new Path(familyDir,
627 HFileLink.createHFileLinkName(snapshotTable, regionInfo.getEncodedName(), hfileName));
628 }
629
630 Path outPath = new Path(familyDir, refLink + '.' + clonedRegionName);
631
632
633 if (storeFile.hasReference()) {
634 Reference reference = Reference.convert(storeFile.getReference());
635 reference.write(fs, outPath);
636 } else {
637 InputStream in;
638 if (linkPath != null) {
639 in = new HFileLink(conf, linkPath).open(fs);
640 } else {
641 linkPath = new Path(new Path(HRegion.getRegionDir(snapshotManifest.getSnapshotDir(),
642 regionInfo.getEncodedName()), familyDir.getName()), hfileName);
643 in = fs.open(linkPath);
644 }
645 OutputStream out = fs.create(outPath);
646 IOUtils.copyBytes(in, out, conf);
647 }
648
649
650 String regionName = Bytes.toString(regionsMap.get(regionInfo.getEncodedNameAsBytes()));
651 LOG.debug("Restore reference " + regionName + " to " + clonedRegionName);
652 synchronized (parentsMap) {
653 Pair<String, String> daughters = parentsMap.get(clonedRegionName);
654 if (daughters == null) {
655 daughters = new Pair<String, String>(regionName, null);
656 parentsMap.put(clonedRegionName, daughters);
657 } else if (!regionName.equals(daughters.getFirst())) {
658 daughters.setSecond(regionName);
659 }
660 }
661 }
662
663
664
665
666
667
668
669
670
671 public HRegionInfo cloneRegionInfo(final HRegionInfo snapshotRegionInfo) {
672 HRegionInfo regionInfo = new HRegionInfo(tableDesc.getTableName(),
673 snapshotRegionInfo.getStartKey(), snapshotRegionInfo.getEndKey(),
674 snapshotRegionInfo.isSplit(), snapshotRegionInfo.getRegionId());
675 regionInfo.setOffline(snapshotRegionInfo.isOffline());
676 return regionInfo;
677 }
678
679
680
681
682 private List<HRegionInfo> getTableRegions() throws IOException {
683 LOG.debug("get table regions: " + tableDir);
684 FileStatus[] regionDirs = FSUtils.listStatus(fs, tableDir, new FSUtils.RegionDirFilter(fs));
685 if (regionDirs == null) return null;
686
687 List<HRegionInfo> regions = new LinkedList<HRegionInfo>();
688 for (FileStatus regionDir: regionDirs) {
689 HRegionInfo hri = HRegionFileSystem.loadRegionInfoFileContent(fs, regionDir.getPath());
690 regions.add(hri);
691 }
692 LOG.debug("found " + regions.size() + " regions for table=" +
693 tableDesc.getTableName().getNameAsString());
694 return regions;
695 }
696
697
698
699
700
701
702
703
704
705 public static HTableDescriptor cloneTableSchema(final HTableDescriptor snapshotTableDescriptor,
706 final TableName tableName) throws IOException {
707 HTableDescriptor htd = new HTableDescriptor(tableName);
708 for (HColumnDescriptor hcd: snapshotTableDescriptor.getColumnFamilies()) {
709 htd.addFamily(hcd);
710 }
711 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
712 snapshotTableDescriptor.getValues().entrySet()) {
713 htd.setValue(e.getKey(), e.getValue());
714 }
715 for (Map.Entry<String, String> e: snapshotTableDescriptor.getConfiguration().entrySet()) {
716 htd.setConfiguration(e.getKey(), e.getValue());
717 }
718 return htd;
719 }
720
721
722
723
724
725
726
727
728
729
730 public static void copySnapshotForScanner(Configuration conf, FileSystem fs, Path rootDir,
731 Path restoreDir, String snapshotName) throws IOException {
732
733 if (!restoreDir.getFileSystem(conf).getUri().equals(rootDir.getFileSystem(conf).getUri())) {
734 throw new IllegalArgumentException("Filesystems for restore directory and HBase root directory " +
735 "should be the same");
736 }
737 if (restoreDir.toUri().getPath().startsWith(rootDir.toUri().getPath())) {
738 throw new IllegalArgumentException("Restore directory cannot be a sub directory of HBase " +
739 "root directory. RootDir: " + rootDir + ", restoreDir: " + restoreDir);
740 }
741
742 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
743 SnapshotDescription snapshotDesc = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
744 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshotDesc);
745
746 MonitoredTask status = TaskMonitor.get().createStatus(
747 "Restoring snapshot '" + snapshotName + "' to directory " + restoreDir);
748 ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher();
749
750
751
752 RestoreSnapshotHelper helper = new RestoreSnapshotHelper(conf, fs,
753 manifest, manifest.getTableDescriptor(), restoreDir, monitor, status, false);
754 helper.restoreHdfsRegions();
755
756 if (LOG.isDebugEnabled()) {
757 LOG.debug("Restored table dir:" + restoreDir);
758 FSUtils.logFileSystemState(fs, restoreDir, LOG);
759 }
760 }
761 }