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