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