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