1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver;
19
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.NavigableSet;
27 import java.util.UUID;
28 import java.util.concurrent.ConcurrentHashMap;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.classification.InterfaceAudience;
33 import org.apache.hadoop.conf.Configuration;
34 import org.apache.hadoop.fs.FileSystem;
35 import org.apache.hadoop.fs.Path;
36 import org.apache.hadoop.hbase.Cell;
37 import org.apache.hadoop.hbase.CellComparator;
38 import org.apache.hadoop.hbase.HColumnDescriptor;
39 import org.apache.hadoop.hbase.HConstants;
40 import org.apache.hadoop.hbase.KeyValue;
41 import org.apache.hadoop.hbase.KeyValue.KVComparator;
42 import org.apache.hadoop.hbase.KeyValue.Type;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.Tag;
45 import org.apache.hadoop.hbase.client.Scan;
46 import org.apache.hadoop.hbase.filter.Filter;
47 import org.apache.hadoop.hbase.filter.FilterList;
48 import org.apache.hadoop.hbase.io.compress.Compression;
49 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
50 import org.apache.hadoop.hbase.io.hfile.CorruptHFileException;
51 import org.apache.hadoop.hbase.io.hfile.HFileContext;
52 import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
53 import org.apache.hadoop.hbase.master.TableLockManager;
54 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
55 import org.apache.hadoop.hbase.mob.MobCacheConfig;
56 import org.apache.hadoop.hbase.mob.MobConstants;
57 import org.apache.hadoop.hbase.mob.MobFile;
58 import org.apache.hadoop.hbase.mob.MobFileName;
59 import org.apache.hadoop.hbase.mob.MobStoreEngine;
60 import org.apache.hadoop.hbase.mob.MobUtils;
61 import org.apache.hadoop.hbase.regionserver.compactions.CompactionContext;
62 import org.apache.hadoop.hbase.regionserver.compactions.CompactionThroughputController;
63 import org.apache.hadoop.hbase.util.Bytes;
64 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
65 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
66 import org.apache.hadoop.hbase.util.IdLock;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 @InterfaceAudience.Private
85 public class HMobStore extends HStore {
86 private static final Log LOG = LogFactory.getLog(HMobStore.class);
87 private MobCacheConfig mobCacheConfig;
88 private Path homePath;
89 private Path mobFamilyPath;
90 private volatile long cellsCountCompactedToMob = 0;
91 private volatile long cellsCountCompactedFromMob = 0;
92 private volatile long cellsSizeCompactedToMob = 0;
93 private volatile long cellsSizeCompactedFromMob = 0;
94 private volatile long mobFlushCount = 0;
95 private volatile long mobFlushedCellsCount = 0;
96 private volatile long mobFlushedCellsSize = 0;
97 private volatile long mobScanCellsCount = 0;
98 private volatile long mobScanCellsSize = 0;
99 private HColumnDescriptor family;
100 private TableLockManager tableLockManager;
101 private TableName tableLockName;
102 private Map<String, List<Path>> map = new ConcurrentHashMap<String, List<Path>>();
103 private final IdLock keyLock = new IdLock();
104
105 public HMobStore(final HRegion region, final HColumnDescriptor family,
106 final Configuration confParam) throws IOException {
107 super(region, family, confParam);
108 this.family = family;
109 this.mobCacheConfig = (MobCacheConfig) cacheConf;
110 this.homePath = MobUtils.getMobHome(conf);
111 this.mobFamilyPath = MobUtils.getMobFamilyPath(conf, this.getTableName(),
112 family.getNameAsString());
113 List<Path> locations = new ArrayList<Path>(2);
114 locations.add(mobFamilyPath);
115 TableName tn = region.getTableDesc().getTableName();
116 locations.add(HFileArchiveUtil.getStoreArchivePath(conf, tn, MobUtils.getMobRegionInfo(tn)
117 .getEncodedName(), family.getNameAsString()));
118 map.put(Bytes.toString(tn.getName()), locations);
119 if (region.getRegionServerServices() != null) {
120 tableLockManager = region.getRegionServerServices().getTableLockManager();
121 tableLockName = MobUtils.getTableLockName(getTableName());
122 }
123 }
124
125
126
127
128 @Override
129 protected void createCacheConf(HColumnDescriptor family) {
130 cacheConf = new MobCacheConfig(conf, family);
131 }
132
133
134
135
136 public Configuration getConfiguration() {
137 return this.conf;
138 }
139
140
141
142
143
144 @Override
145 protected KeyValueScanner createScanner(Scan scan, final NavigableSet<byte[]> targetCols,
146 long readPt, KeyValueScanner scanner) throws IOException {
147 if (scanner == null) {
148 if (MobUtils.isRefOnlyScan(scan)) {
149 Filter refOnlyFilter = new MobReferenceOnlyFilter();
150 Filter filter = scan.getFilter();
151 if (filter != null) {
152 scan.setFilter(new FilterList(filter, refOnlyFilter));
153 } else {
154 scan.setFilter(refOnlyFilter);
155 }
156 }
157 scanner = scan.isReversed() ? new ReversedMobStoreScanner(this, getScanInfo(), scan,
158 targetCols, readPt) : new MobStoreScanner(this, getScanInfo(), scan, targetCols, readPt);
159 }
160 return scanner;
161 }
162
163
164
165
166 @Override
167 protected StoreEngine<?, ?, ?, ?> createStoreEngine(Store store, Configuration conf,
168 KVComparator cellComparator) throws IOException {
169 MobStoreEngine engine = new MobStoreEngine();
170 engine.createComponents(conf, store, cellComparator);
171 return engine;
172 }
173
174
175
176
177
178 private Path getTempDir() {
179 return new Path(homePath, MobConstants.TEMP_DIR_NAME);
180 }
181
182
183
184
185
186
187
188
189
190
191 public StoreFile.Writer createWriterInTmp(Date date, long maxKeyCount,
192 Compression.Algorithm compression, byte[] startKey) throws IOException {
193 if (startKey == null) {
194 startKey = HConstants.EMPTY_START_ROW;
195 }
196 Path path = getTempDir();
197 return createWriterInTmp(MobUtils.formatDate(date), path, maxKeyCount, compression, startKey);
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211 public StoreFile.Writer createDelFileWriterInTmp(Date date, long maxKeyCount,
212 Compression.Algorithm compression, byte[] startKey) throws IOException {
213 if (startKey == null) {
214 startKey = HConstants.EMPTY_START_ROW;
215 }
216 Path path = getTempDir();
217 String suffix = UUID
218 .randomUUID().toString().replaceAll("-", "") + "_del";
219 MobFileName mobFileName = MobFileName.create(startKey, MobUtils.formatDate(date), suffix);
220 return createWriterInTmp(mobFileName, path, maxKeyCount, compression);
221 }
222
223
224
225
226
227
228
229
230
231
232
233 public StoreFile.Writer createWriterInTmp(String date, Path basePath, long maxKeyCount,
234 Compression.Algorithm compression, byte[] startKey) throws IOException {
235 MobFileName mobFileName = MobFileName.create(startKey, date, UUID.randomUUID()
236 .toString().replaceAll("-", ""));
237 return createWriterInTmp(mobFileName, basePath, maxKeyCount, compression);
238 }
239
240
241
242
243
244
245
246
247
248
249 public StoreFile.Writer createWriterInTmp(MobFileName mobFileName, Path basePath, long maxKeyCount,
250 Compression.Algorithm compression) throws IOException {
251 final CacheConfig writerCacheConf = mobCacheConfig;
252 HFileContext hFileContext = new HFileContextBuilder().withCompression(compression)
253 .withIncludesMvcc(true).withIncludesTags(true)
254 .withCompressTags(family.isCompressTags())
255 .withChecksumType(checksumType)
256 .withBytesPerCheckSum(bytesPerChecksum)
257 .withBlockSize(blocksize)
258 .withHBaseCheckSum(true).withDataBlockEncoding(getFamily().getDataBlockEncoding())
259 .withEncryptionContext(cryptoContext)
260 .withCreateTime(EnvironmentEdgeManager.currentTime()).build();
261
262 StoreFile.Writer w = new StoreFile.WriterBuilder(conf, writerCacheConf, region.getFilesystem())
263 .withFilePath(new Path(basePath, mobFileName.getFileName()))
264 .withComparator(KeyValue.COMPARATOR).withBloomType(BloomType.NONE)
265 .withMaxKeyCount(maxKeyCount).withFileContext(hFileContext).build();
266 return w;
267 }
268
269
270
271
272
273
274
275 public void commitFile(final Path sourceFile, Path targetPath) throws IOException {
276 if (sourceFile == null) {
277 return;
278 }
279 Path dstPath = new Path(targetPath, sourceFile.getName());
280 validateMobFile(sourceFile);
281 String msg = "Renaming flushed file from " + sourceFile + " to " + dstPath;
282 LOG.info(msg);
283 Path parent = dstPath.getParent();
284 if (!region.getFilesystem().exists(parent)) {
285 region.getFilesystem().mkdirs(parent);
286 }
287 if (!region.getFilesystem().rename(sourceFile, dstPath)) {
288 throw new IOException("Failed rename of " + sourceFile + " to " + dstPath);
289 }
290 }
291
292
293
294
295
296
297 private void validateMobFile(Path path) throws IOException {
298 StoreFile storeFile = null;
299 try {
300 storeFile =
301 new StoreFile(region.getFilesystem(), path, conf, this.mobCacheConfig, BloomType.NONE);
302 storeFile.createReader();
303 } catch (IOException e) {
304 LOG.error("Fail to open mob file[" + path + "], keep it in temp directory.", e);
305 throw e;
306 } finally {
307 if (storeFile != null) {
308 storeFile.closeReader(false);
309 }
310 }
311 }
312
313
314
315
316
317
318
319
320
321 public Cell resolve(Cell reference, boolean cacheBlocks) throws IOException {
322 return resolve(reference, cacheBlocks, -1, true);
323 }
324
325
326
327
328
329
330
331
332
333
334
335 public Cell resolve(Cell reference, boolean cacheBlocks, long readPt,
336 boolean readEmptyValueOnMobCellMiss) throws IOException {
337 Cell result = null;
338 if (MobUtils.hasValidMobRefCellValue(reference)) {
339 String fileName = MobUtils.getMobFileName(reference);
340 Tag tableNameTag = MobUtils.getTableNameTag(reference);
341 if (tableNameTag != null) {
342 byte[] tableName = tableNameTag.getValue();
343 String tableNameString = Bytes.toString(tableName);
344 List<Path> locations = map.get(tableNameString);
345 if (locations == null) {
346 IdLock.Entry lockEntry = keyLock.getLockEntry(tableNameString.hashCode());
347 try {
348 locations = map.get(tableNameString);
349 if (locations == null) {
350 locations = new ArrayList<Path>(2);
351 TableName tn = TableName.valueOf(tableName);
352 locations.add(MobUtils.getMobFamilyPath(conf, tn, family.getNameAsString()));
353 locations.add(HFileArchiveUtil.getStoreArchivePath(conf, tn, MobUtils
354 .getMobRegionInfo(tn).getEncodedName(), family.getNameAsString()));
355 map.put(tableNameString, locations);
356 }
357 } finally {
358 keyLock.releaseLockEntry(lockEntry);
359 }
360 }
361 result = readCell(locations, fileName, reference, cacheBlocks, readPt,
362 readEmptyValueOnMobCellMiss);
363 }
364 }
365 if (result == null) {
366 LOG.warn("The KeyValue result is null, assemble a new KeyValue with the same row,family,"
367 + "qualifier,timestamp,type and tags but with an empty value to return.");
368 result = new KeyValue(reference.getRowArray(), reference.getRowOffset(),
369 reference.getRowLength(), reference.getFamilyArray(), reference.getFamilyOffset(),
370 reference.getFamilyLength(), reference.getQualifierArray(),
371 reference.getQualifierOffset(), reference.getQualifierLength(), reference.getTimestamp(),
372 Type.codeToType(reference.getTypeByte()), HConstants.EMPTY_BYTE_ARRAY,
373 0, 0, reference.getTagsArray(), reference.getTagsOffset(),
374 reference.getTagsLength());
375 }
376 return result;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 private Cell readCell(List<Path> locations, String fileName, Cell search, boolean cacheMobBlocks,
396 long readPt, boolean readEmptyValueOnMobCellMiss) throws IOException {
397 FileSystem fs = getFileSystem();
398 Throwable throwable = null;
399 for (Path location : locations) {
400 MobFile file = null;
401 Path path = new Path(location, fileName);
402 try {
403 file = mobCacheConfig.getMobFileCache().openFile(fs, path, mobCacheConfig);
404 return readPt != -1 ? file.readCell(search, cacheMobBlocks, readPt) : file.readCell(search,
405 cacheMobBlocks);
406 } catch (IOException e) {
407 mobCacheConfig.getMobFileCache().evictFile(fileName);
408 throwable = e;
409 if ((e instanceof FileNotFoundException) ||
410 (e.getCause() instanceof FileNotFoundException)) {
411 LOG.warn("Fail to read the cell, the mob file " + path + " doesn't exist", e);
412 } else if (e instanceof CorruptHFileException) {
413 LOG.error("The mob file " + path + " is corrupt", e);
414 break;
415 } else {
416 throw e;
417 }
418 } catch (NullPointerException e) {
419 mobCacheConfig.getMobFileCache().evictFile(fileName);
420 LOG.warn("Fail to read the cell", e);
421 throwable = e;
422 } catch (AssertionError e) {
423 mobCacheConfig.getMobFileCache().evictFile(fileName);
424 LOG.warn("Fail to read the cell", e);
425 throwable = e;
426 } finally {
427 if (file != null) {
428 mobCacheConfig.getMobFileCache().closeFile(file);
429 }
430 }
431 }
432 LOG.error("The mob file " + fileName + " could not be found in the locations " + locations
433 + " or it is corrupt");
434 if (readEmptyValueOnMobCellMiss) {
435 return null;
436 } else if (throwable instanceof IOException) {
437 throw (IOException) throwable;
438 } else {
439 throw new IOException(throwable);
440 }
441 }
442
443
444
445
446
447 public Path getPath() {
448 return mobFamilyPath;
449 }
450
451
452
453
454
455
456
457
458
459
460 @Override
461 public List<StoreFile> compact(CompactionContext compaction,
462 CompactionThroughputController throughputController) throws IOException {
463
464
465 if (compaction.getRequest().isAllFiles()) {
466
467
468
469
470
471
472
473
474 TableLock lock = null;
475 if (tableLockManager != null) {
476 lock = tableLockManager.readLock(tableLockName, "Major compaction in HMobStore");
477 }
478 boolean tableLocked = false;
479 String tableName = getTableName().getNameAsString();
480 if (lock != null) {
481 try {
482 LOG.info("Start to acquire a read lock for the table[" + tableName
483 + "], ready to perform the major compaction");
484 lock.acquire();
485 tableLocked = true;
486 } catch (Exception e) {
487 LOG.error("Fail to lock the table " + tableName, e);
488 }
489 } else {
490
491 tableLocked = true;
492 }
493 try {
494 if (!tableLocked) {
495 LOG.warn("Cannot obtain the table lock, maybe a sweep tool is running on this table["
496 + tableName + "], forcing the delete markers to be retained");
497 compaction.getRequest().forceRetainDeleteMarkers();
498 }
499 return super.compact(compaction, throughputController);
500 } finally {
501 if (tableLocked && lock != null) {
502 try {
503 lock.release();
504 } catch (IOException e) {
505 LOG.error("Fail to release the table lock " + tableName, e);
506 }
507 }
508 }
509 } else {
510
511 return super.compact(compaction, throughputController);
512 }
513 }
514
515 public void updateCellsCountCompactedToMob(long count) {
516 cellsCountCompactedToMob += count;
517 }
518
519 public long getCellsCountCompactedToMob() {
520 return cellsCountCompactedToMob;
521 }
522
523 public void updateCellsCountCompactedFromMob(long count) {
524 cellsCountCompactedFromMob += count;
525 }
526
527 public long getCellsCountCompactedFromMob() {
528 return cellsCountCompactedFromMob;
529 }
530
531 public void updateCellsSizeCompactedToMob(long size) {
532 cellsSizeCompactedToMob += size;
533 }
534
535 public long getCellsSizeCompactedToMob() {
536 return cellsSizeCompactedToMob;
537 }
538
539 public void updateCellsSizeCompactedFromMob(long size) {
540 cellsSizeCompactedFromMob += size;
541 }
542
543 public long getCellsSizeCompactedFromMob() {
544 return cellsSizeCompactedFromMob;
545 }
546
547 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "VO_VOLATILE_INCREMENT")
548 public void updateMobFlushCount() {
549 mobFlushCount++;
550 }
551
552 public long getMobFlushCount() {
553 return mobFlushCount;
554 }
555
556 public void updateMobFlushedCellsCount(long count) {
557 mobFlushedCellsCount += count;
558 }
559
560 public long getMobFlushedCellsCount() {
561 return mobFlushedCellsCount;
562 }
563
564 public void updateMobFlushedCellsSize(long size) {
565 mobFlushedCellsSize += size;
566 }
567
568 public long getMobFlushedCellsSize() {
569 return mobFlushedCellsSize;
570 }
571
572 public void updateMobScanCellsCount(long count) {
573 mobScanCellsCount += count;
574 }
575
576 public long getMobScanCellsCount() {
577 return mobScanCellsCount;
578 }
579
580 public void updateMobScanCellsSize(long size) {
581 mobScanCellsSize += size;
582 }
583
584 public long getMobScanCellsSize() {
585 return mobScanCellsSize;
586 }
587 }