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