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.FileNotFoundException;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.ThreadPoolExecutor;
29 import java.util.concurrent.TimeUnit;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.hbase.classification.InterfaceAudience;
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.fs.FSDataInputStream;
36 import org.apache.hadoop.fs.FSDataOutputStream;
37 import org.apache.hadoop.fs.FileStatus;
38 import org.apache.hadoop.fs.FileSystem;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.HColumnDescriptor;
41 import org.apache.hadoop.hbase.HRegionInfo;
42 import org.apache.hadoop.hbase.HTableDescriptor;
43 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionSnare;
44 import org.apache.hadoop.hbase.mob.MobUtils;
45 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
46 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
47 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotDataManifest;
48 import org.apache.hadoop.hbase.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
49 import org.apache.hadoop.hbase.regionserver.HRegion;
50 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
51 import org.apache.hadoop.hbase.regionserver.Store;
52 import org.apache.hadoop.hbase.regionserver.StoreFile;
53 import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.FSTableDescriptors;
56 import org.apache.hadoop.hbase.util.FSUtils;
57 import org.apache.hadoop.hbase.util.Threads;
58
59
60
61
62
63
64
65
66 @InterfaceAudience.Private
67 public class SnapshotManifest {
68 private static final Log LOG = LogFactory.getLog(SnapshotManifest.class);
69
70 private static final String DATA_MANIFEST_NAME = "data.manifest";
71
72 private List<SnapshotRegionManifest> regionManifests;
73 private SnapshotDescription desc;
74 private HTableDescriptor htd;
75
76 private final ForeignExceptionSnare monitor;
77 private final Configuration conf;
78 private final Path workingDir;
79 private final FileSystem fs;
80
81 private SnapshotManifest(final Configuration conf, final FileSystem fs,
82 final Path workingDir, final SnapshotDescription desc,
83 final ForeignExceptionSnare monitor) {
84 this.monitor = monitor;
85 this.desc = desc;
86 this.workingDir = workingDir;
87 this.conf = conf;
88 this.fs = fs;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public static SnapshotManifest create(final Configuration conf, final FileSystem fs,
105 final Path workingDir, final SnapshotDescription desc,
106 final ForeignExceptionSnare monitor) {
107 return new SnapshotManifest(conf, fs, workingDir, desc, monitor);
108 }
109
110
111
112
113
114
115
116
117
118
119 public static SnapshotManifest open(final Configuration conf, final FileSystem fs,
120 final Path workingDir, final SnapshotDescription desc) throws IOException {
121 SnapshotManifest manifest = new SnapshotManifest(conf, fs, workingDir, desc, null);
122 manifest.load();
123 return manifest;
124 }
125
126
127
128
129
130 public void addTableDescriptor(final HTableDescriptor htd) throws IOException {
131 this.htd = htd;
132 }
133
134 interface RegionVisitor<TRegion, TFamily> {
135 TRegion regionOpen(final HRegionInfo regionInfo) throws IOException;
136 void regionClose(final TRegion region) throws IOException;
137
138 TFamily familyOpen(final TRegion region, final byte[] familyName) throws IOException;
139 void familyClose(final TRegion region, final TFamily family) throws IOException;
140
141 void storeFile(final TRegion region, final TFamily family, final StoreFileInfo storeFile)
142 throws IOException;
143 }
144
145 private RegionVisitor createRegionVisitor(final SnapshotDescription desc) throws IOException {
146 switch (getSnapshotFormat(desc)) {
147 case SnapshotManifestV1.DESCRIPTOR_VERSION:
148 return new SnapshotManifestV1.ManifestBuilder(conf, fs, workingDir);
149 case SnapshotManifestV2.DESCRIPTOR_VERSION:
150 return new SnapshotManifestV2.ManifestBuilder(conf, fs, workingDir);
151 default:
152 throw new CorruptedSnapshotException("Invalid Snapshot version: "+ desc.getVersion(), desc);
153 }
154 }
155
156 public void addMobRegion(HRegionInfo regionInfo, HColumnDescriptor[] hcds) throws IOException {
157
158 RegionVisitor visitor = createRegionVisitor(desc);
159
160
161 LOG.debug("Storing '" + regionInfo + "' region-info for snapshot.");
162 Object regionData = visitor.regionOpen(regionInfo);
163 monitor.rethrowException();
164
165
166 LOG.debug("Creating references for hfiles");
167
168 Path mobRegionPath = MobUtils.getMobRegionPath(conf, regionInfo.getTable());
169 for (HColumnDescriptor hcd : hcds) {
170
171 if (!hcd.isMobEnabled()) {
172 continue;
173 }
174 Object familyData = visitor.familyOpen(regionData, hcd.getName());
175 monitor.rethrowException();
176
177 Path storePath = MobUtils.getMobFamilyPath(mobRegionPath, hcd.getNameAsString());
178 if (!fs.exists(storePath)) {
179 continue;
180 }
181 FileStatus[] stats = fs.listStatus(storePath);
182 if (stats == null) {
183 continue;
184 }
185 List<StoreFileInfo> storeFiles = new ArrayList<StoreFileInfo>();
186 for (FileStatus stat : stats) {
187 storeFiles.add(new StoreFileInfo(conf, fs, stat));
188 }
189 if (LOG.isDebugEnabled()) {
190 LOG.debug("Adding snapshot references for " + storeFiles + " hfiles");
191 }
192
193
194 for (int i = 0, sz = storeFiles.size(); i < sz; i++) {
195 StoreFileInfo storeFile = storeFiles.get(i);
196 monitor.rethrowException();
197
198
199 if (LOG.isDebugEnabled()) {
200 LOG.debug("Adding reference for file (" + (i + 1) + "/" + sz + "): "
201 + storeFile.getPath());
202 }
203 visitor.storeFile(regionData, familyData, storeFile);
204 }
205 visitor.familyClose(regionData, familyData);
206 }
207 visitor.regionClose(regionData);
208 }
209
210
211
212
213
214 public void addRegion(final HRegion region) throws IOException {
215
216 RegionVisitor visitor = createRegionVisitor(desc);
217
218
219 LOG.debug("Storing '" + region + "' region-info for snapshot.");
220 Object regionData = visitor.regionOpen(region.getRegionInfo());
221 monitor.rethrowException();
222
223
224 LOG.debug("Creating references for hfiles");
225
226 for (Store store : region.getStores()) {
227
228 Object familyData = visitor.familyOpen(regionData, store.getFamily().getName());
229 monitor.rethrowException();
230
231 List<StoreFile> storeFiles = new ArrayList<StoreFile>(store.getStorefiles());
232 if (LOG.isDebugEnabled()) {
233 LOG.debug("Adding snapshot references for " + storeFiles + " hfiles");
234 }
235
236
237 for (int i = 0, sz = storeFiles.size(); i < sz; i++) {
238 StoreFile storeFile = storeFiles.get(i);
239 monitor.rethrowException();
240
241
242 LOG.debug("Adding reference for file (" + (i+1) + "/" + sz + "): " + storeFile.getPath());
243 visitor.storeFile(regionData, familyData, storeFile.getFileInfo());
244 }
245 visitor.familyClose(regionData, familyData);
246 }
247 visitor.regionClose(regionData);
248 }
249
250
251
252
253
254 public void addRegion(final Path tableDir, final HRegionInfo regionInfo) throws IOException {
255
256 RegionVisitor visitor = createRegionVisitor(desc);
257
258 boolean isMobRegion = MobUtils.isMobRegionInfo(regionInfo);
259 try {
260
261 HRegionFileSystem regionFs = HRegionFileSystem.openRegionFromFileSystem(conf, fs,
262 tableDir, regionInfo, true);
263 monitor.rethrowException();
264
265
266 LOG.debug("Storing region-info for snapshot.");
267 Object regionData = visitor.regionOpen(regionInfo);
268 monitor.rethrowException();
269
270
271 LOG.debug("Creating references for hfiles");
272
273
274
275
276
277
278 Collection<String> familyNames = regionFs.getFamilies();
279 if (familyNames != null) {
280 for (String familyName: familyNames) {
281 Object familyData = visitor.familyOpen(regionData, Bytes.toBytes(familyName));
282 monitor.rethrowException();
283
284 Collection<StoreFileInfo> storeFiles = null;
285 if (isMobRegion) {
286 Path regionPath = MobUtils.getMobRegionPath(conf, regionInfo.getTable());
287 Path storePath = MobUtils.getMobFamilyPath(regionPath, familyName);
288 if (!fs.exists(storePath)) {
289 continue;
290 }
291 FileStatus[] stats = fs.listStatus(storePath);
292 if (stats == null) {
293 continue;
294 }
295 storeFiles = new ArrayList<StoreFileInfo>();
296 for (FileStatus stat : stats) {
297 storeFiles.add(new StoreFileInfo(conf, fs, stat));
298 }
299 } else {
300 storeFiles = regionFs.getStoreFiles(familyName);
301 }
302 if (storeFiles == null) {
303 if (LOG.isDebugEnabled()) {
304 LOG.debug("No files under family: " + familyName);
305 }
306 continue;
307 }
308
309
310 if (LOG.isDebugEnabled()) {
311 LOG.debug("Adding snapshot references for " + storeFiles + " hfiles");
312 }
313
314
315 int i = 0;
316 int sz = storeFiles.size();
317 for (StoreFileInfo storeFile: storeFiles) {
318 monitor.rethrowException();
319
320
321 LOG.debug("Adding reference for file (" + (++i) + "/" + sz + "): "
322 + storeFile.getPath());
323 visitor.storeFile(regionData, familyData, storeFile);
324 }
325 visitor.familyClose(regionData, familyData);
326 }
327 }
328 visitor.regionClose(regionData);
329 } catch (IOException e) {
330
331 if (!isMobRegion) {
332 throw e;
333 }
334 }
335 }
336
337
338
339
340
341
342
343
344 private void load() throws IOException {
345 switch (getSnapshotFormat(desc)) {
346 case SnapshotManifestV1.DESCRIPTOR_VERSION: {
347 this.htd = FSTableDescriptors.getTableDescriptorFromFs(fs, workingDir);
348 ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
349 try {
350 this.regionManifests =
351 SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
352 } finally {
353 tpool.shutdown();
354 }
355 break;
356 }
357 case SnapshotManifestV2.DESCRIPTOR_VERSION: {
358 SnapshotDataManifest dataManifest = readDataManifest();
359 if (dataManifest != null) {
360 htd = HTableDescriptor.convert(dataManifest.getTableSchema());
361 regionManifests = dataManifest.getRegionManifestsList();
362 } else {
363
364
365 List<SnapshotRegionManifest> v1Regions, v2Regions;
366 ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
367 try {
368 v1Regions = SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
369 v2Regions = SnapshotManifestV2.loadRegionManifests(conf, tpool, fs, workingDir, desc);
370 } finally {
371 tpool.shutdown();
372 }
373 if (v1Regions != null && v2Regions != null) {
374 regionManifests =
375 new ArrayList<SnapshotRegionManifest>(v1Regions.size() + v2Regions.size());
376 regionManifests.addAll(v1Regions);
377 regionManifests.addAll(v2Regions);
378 } else if (v1Regions != null) {
379 regionManifests = v1Regions;
380 } else
381 regionManifests = v2Regions;
382 }
383 }
384 break;
385 }
386 default:
387 throw new CorruptedSnapshotException("Invalid Snapshot version: "+ desc.getVersion(), desc);
388 }
389 }
390
391
392
393
394 public Path getSnapshotDir() {
395 return this.workingDir;
396 }
397
398
399
400
401 public SnapshotDescription getSnapshotDescription() {
402 return this.desc;
403 }
404
405
406
407
408 public HTableDescriptor getTableDescriptor() {
409 return this.htd;
410 }
411
412
413
414
415 public List<SnapshotRegionManifest> getRegionManifests() {
416 return this.regionManifests;
417 }
418
419
420
421
422
423 public Map<String, SnapshotRegionManifest> getRegionManifestsMap() {
424 if (regionManifests == null || regionManifests.size() == 0) return null;
425
426 HashMap<String, SnapshotRegionManifest> regionsMap =
427 new HashMap<String, SnapshotRegionManifest>(regionManifests.size());
428 for (SnapshotRegionManifest manifest: regionManifests) {
429 String regionName = getRegionNameFromManifest(manifest);
430 regionsMap.put(regionName, manifest);
431 }
432 return regionsMap;
433 }
434
435 public void consolidate() throws IOException {
436 if (getSnapshotFormat(desc) == SnapshotManifestV1.DESCRIPTOR_VERSION) {
437 Path rootDir = FSUtils.getRootDir(conf);
438 LOG.info("Using old Snapshot Format");
439
440 new FSTableDescriptors(conf, fs, rootDir)
441 .createTableDescriptorForTableDirectory(workingDir, htd, false);
442 } else {
443 LOG.debug("Convert to Single Snapshot Manifest");
444 convertToV2SingleManifest();
445 }
446 }
447
448
449
450
451
452 private void convertToV2SingleManifest() throws IOException {
453
454 List<SnapshotRegionManifest> v1Regions, v2Regions;
455 ThreadPoolExecutor tpool = createExecutor("SnapshotManifestLoader");
456 try {
457 v1Regions = SnapshotManifestV1.loadRegionManifests(conf, tpool, fs, workingDir, desc);
458 v2Regions = SnapshotManifestV2.loadRegionManifests(conf, tpool, fs, workingDir, desc);
459 } finally {
460 tpool.shutdown();
461 }
462
463 SnapshotDataManifest.Builder dataManifestBuilder = SnapshotDataManifest.newBuilder();
464 dataManifestBuilder.setTableSchema(htd.convert());
465
466 if (v1Regions != null && v1Regions.size() > 0) {
467 dataManifestBuilder.addAllRegionManifests(v1Regions);
468 }
469 if (v2Regions != null && v2Regions.size() > 0) {
470 dataManifestBuilder.addAllRegionManifests(v2Regions);
471 }
472
473
474
475
476
477 SnapshotDataManifest dataManifest = dataManifestBuilder.build();
478 writeDataManifest(dataManifest);
479 this.regionManifests = dataManifest.getRegionManifestsList();
480
481
482
483
484
485
486 if (v1Regions != null && v1Regions.size() > 0) {
487 for (SnapshotRegionManifest regionManifest: v1Regions) {
488 SnapshotManifestV1.deleteRegionManifest(fs, workingDir, regionManifest);
489 }
490 }
491 if (v2Regions != null && v2Regions.size() > 0) {
492 for (SnapshotRegionManifest regionManifest: v2Regions) {
493 SnapshotManifestV2.deleteRegionManifest(fs, workingDir, regionManifest);
494 }
495 }
496 }
497
498
499
500
501 private void writeDataManifest(final SnapshotDataManifest manifest)
502 throws IOException {
503 FSDataOutputStream stream = fs.create(new Path(workingDir, DATA_MANIFEST_NAME));
504 try {
505 manifest.writeTo(stream);
506 } finally {
507 stream.close();
508 }
509 }
510
511
512
513
514 private SnapshotDataManifest readDataManifest() throws IOException {
515 FSDataInputStream in = null;
516 try {
517 in = fs.open(new Path(workingDir, DATA_MANIFEST_NAME));
518 return SnapshotDataManifest.parseFrom(in);
519 } catch (FileNotFoundException e) {
520 return null;
521 } finally {
522 if (in != null) in.close();
523 }
524 }
525
526 private ThreadPoolExecutor createExecutor(final String name) {
527 return createExecutor(conf, name);
528 }
529
530 public static ThreadPoolExecutor createExecutor(final Configuration conf, final String name) {
531 int maxThreads = conf.getInt("hbase.snapshot.thread.pool.max", 8);
532 return Threads.getBoundedCachedThreadPool(maxThreads, 30L, TimeUnit.SECONDS,
533 Threads.getNamedThreadFactory(name));
534 }
535
536
537
538
539 static String getRegionNameFromManifest(final SnapshotRegionManifest manifest) {
540 byte[] regionName = HRegionInfo.createRegionName(
541 ProtobufUtil.toTableName(manifest.getRegionInfo().getTableName()),
542 manifest.getRegionInfo().getStartKey().toByteArray(),
543 manifest.getRegionInfo().getRegionId(), true);
544 return HRegionInfo.encodeRegionName(regionName);
545 }
546
547
548
549
550 private static int getSnapshotFormat(final SnapshotDescription desc) {
551 return desc.hasVersion() ? desc.getVersion() : SnapshotManifestV1.DESCRIPTOR_VERSION;
552 }
553 }