1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import java.io.DataInput;
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.nio.ByteBuffer;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.HashSet;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.SortedSet;
33 import java.util.UUID;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicInteger;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.fs.FileSystem;
41 import org.apache.hadoop.fs.Path;
42 import org.apache.hadoop.hbase.Cell;
43 import org.apache.hadoop.hbase.CellUtil;
44 import org.apache.hadoop.hbase.HConstants;
45 import org.apache.hadoop.hbase.HDFSBlocksDistribution;
46 import org.apache.hadoop.hbase.KeyValue;
47 import org.apache.hadoop.hbase.KeyValue.KVComparator;
48 import org.apache.hadoop.hbase.KeyValueUtil;
49 import org.apache.hadoop.hbase.classification.InterfaceAudience;
50 import org.apache.hadoop.hbase.client.Scan;
51 import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
52 import org.apache.hadoop.hbase.io.TimeRange;
53 import org.apache.hadoop.hbase.io.hfile.BlockType;
54 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
55 import org.apache.hadoop.hbase.io.hfile.HFile;
56 import org.apache.hadoop.hbase.io.hfile.HFileContext;
57 import org.apache.hadoop.hbase.io.hfile.HFileScanner;
58 import org.apache.hadoop.hbase.io.hfile.HFileWriterV2;
59 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
60 import org.apache.hadoop.hbase.regionserver.compactions.Compactor;
61 import org.apache.hadoop.hbase.util.BloomFilter;
62 import org.apache.hadoop.hbase.util.BloomFilterFactory;
63 import org.apache.hadoop.hbase.util.BloomFilterWriter;
64 import org.apache.hadoop.hbase.util.Bytes;
65 import org.apache.hadoop.io.WritableUtils;
66
67 import com.google.common.annotations.VisibleForTesting;
68 import com.google.common.base.Function;
69 import com.google.common.base.Preconditions;
70 import com.google.common.collect.ImmutableList;
71 import com.google.common.collect.Ordering;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 @InterfaceAudience.LimitedPrivate("Coprocessor")
87 public class StoreFile {
88 private static final Log LOG = LogFactory.getLog(StoreFile.class.getName());
89
90
91
92
93 public static final byte [] MAX_SEQ_ID_KEY = Bytes.toBytes("MAX_SEQ_ID_KEY");
94
95
96 public static final byte[] MAJOR_COMPACTION_KEY =
97 Bytes.toBytes("MAJOR_COMPACTION_KEY");
98
99
100 public static final byte[] EXCLUDE_FROM_MINOR_COMPACTION_KEY =
101 Bytes.toBytes("EXCLUDE_FROM_MINOR_COMPACTION");
102
103
104 public static final byte[] BLOOM_FILTER_TYPE_KEY =
105 Bytes.toBytes("BLOOM_FILTER_TYPE");
106
107
108 public static final byte[] DELETE_FAMILY_COUNT =
109 Bytes.toBytes("DELETE_FAMILY_COUNT");
110
111
112 private static final byte[] LAST_BLOOM_KEY = Bytes.toBytes("LAST_BLOOM_KEY");
113
114
115 public static final byte[] TIMERANGE_KEY = Bytes.toBytes("TIMERANGE");
116
117
118 public static final byte[] EARLIEST_PUT_TS = Bytes.toBytes("EARLIEST_PUT_TS");
119
120
121
122
123 public static final byte[] COMPACTION_EVENT_KEY = Bytes.toBytes("COMPACTION_EVENT_KEY");
124
125 private final StoreFileInfo fileInfo;
126 private final FileSystem fs;
127
128
129 private final CacheConfig cacheConf;
130
131
132
133 private long sequenceid = -1;
134
135
136
137 private long maxMemstoreTS = -1;
138
139
140 private byte[] firstKey;
141
142 private byte[] lastKey;
143
144 private KVComparator comparator;
145
146 CacheConfig getCacheConf() {
147 return cacheConf;
148 }
149
150 public byte[] getFirstKey() {
151 return firstKey;
152 }
153
154 public byte[] getLastKey() {
155 return lastKey;
156 }
157
158 public KVComparator getComparator() {
159 return comparator;
160 }
161
162 public long getMaxMemstoreTS() {
163 return maxMemstoreTS;
164 }
165
166 public void setMaxMemstoreTS(long maxMemstoreTS) {
167 this.maxMemstoreTS = maxMemstoreTS;
168 }
169
170
171
172 private AtomicBoolean majorCompaction = null;
173
174
175
176 private boolean excludeFromMinorCompaction = false;
177
178
179 private final Set<String> compactedStoreFiles = new HashSet<>();
180
181
182 public static final byte[] BULKLOAD_TASK_KEY =
183 Bytes.toBytes("BULKLOAD_SOURCE_TASK");
184 public static final byte[] BULKLOAD_TIME_KEY =
185 Bytes.toBytes("BULKLOAD_TIMESTAMP");
186
187
188
189
190 private Map<byte[], byte[]> metadataMap;
191
192
193 private volatile Reader reader;
194
195
196
197
198
199 private final BloomType cfBloomType;
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 public StoreFile(final FileSystem fs, final Path p, final Configuration conf,
217 final CacheConfig cacheConf, final BloomType cfBloomType) throws IOException {
218 this(fs, new StoreFileInfo(conf, fs, p), conf, cacheConf, cfBloomType);
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 public StoreFile(final FileSystem fs, final StoreFileInfo fileInfo, final Configuration conf,
238 final CacheConfig cacheConf, final BloomType cfBloomType) throws IOException {
239 this.fs = fs;
240 this.fileInfo = fileInfo;
241 this.cacheConf = cacheConf;
242
243 if (BloomFilterFactory.isGeneralBloomEnabled(conf)) {
244 this.cfBloomType = cfBloomType;
245 } else {
246 LOG.info("Ignoring bloom filter check for file " + this.getPath() + ": " +
247 "cfBloomType=" + cfBloomType + " (disabled in config)");
248 this.cfBloomType = BloomType.NONE;
249 }
250 }
251
252
253
254
255
256 public StoreFile(final StoreFile other) {
257 this.fs = other.fs;
258 this.fileInfo = other.fileInfo;
259 this.cacheConf = other.cacheConf;
260 this.cfBloomType = other.cfBloomType;
261 }
262
263
264
265
266 public StoreFile cloneForReader() {
267 return new StoreFile(this);
268 }
269
270
271
272
273
274 public StoreFileInfo getFileInfo() {
275 return this.fileInfo;
276 }
277
278
279
280
281 public Path getPath() {
282 return this.fileInfo.getPath();
283 }
284
285
286
287
288 public Path getQualifiedPath() {
289 return this.fileInfo.getPath().makeQualified(fs);
290 }
291
292
293
294
295
296 public boolean isReference() {
297 return this.fileInfo.isReference();
298 }
299
300
301
302
303 public boolean isHFile() {
304 return StoreFileInfo.isHFile(this.fileInfo.getPath());
305 }
306
307
308
309
310 public boolean isMajorCompaction() {
311 if (this.majorCompaction == null) {
312 throw new NullPointerException("This has not been set yet");
313 }
314 return this.majorCompaction.get();
315 }
316
317
318
319
320 public boolean excludeFromMinorCompaction() {
321 return this.excludeFromMinorCompaction;
322 }
323
324
325
326
327 public long getMaxSequenceId() {
328 return this.sequenceid;
329 }
330
331 public long getModificationTimeStamp() throws IOException {
332 return (fileInfo == null) ? 0 : fileInfo.getModificationTime();
333 }
334
335
336
337
338
339
340 public byte[] getMetadataValue(byte[] key) {
341 return metadataMap.get(key);
342 }
343
344
345
346
347
348
349
350
351
352 public static long getMaxMemstoreTSInList(Collection<StoreFile> sfs) {
353 long max = 0;
354 for (StoreFile sf : sfs) {
355 if (!sf.isBulkLoadResult()) {
356 max = Math.max(max, sf.getMaxMemstoreTS());
357 }
358 }
359 return max;
360 }
361
362
363
364
365
366
367
368
369 public static long getMaxSequenceIdInList(Collection<StoreFile> sfs) {
370 long max = 0;
371 for (StoreFile sf : sfs) {
372 max = Math.max(max, sf.getMaxSequenceId());
373 }
374 return max;
375 }
376
377
378
379
380
381
382
383
384
385
386
387 public boolean isBulkLoadResult() {
388 boolean bulkLoadedHFile = false;
389 String fileName = this.getPath().getName();
390 int startPos = fileName.indexOf("SeqId_");
391 if (startPos != -1) {
392 bulkLoadedHFile = true;
393 }
394 return bulkLoadedHFile || metadataMap.containsKey(BULKLOAD_TIME_KEY);
395 }
396
397 @VisibleForTesting
398 public boolean isCompactedAway() {
399 if (this.reader != null) {
400 return this.reader.isCompactedAway();
401 }
402 return true;
403 }
404
405 @VisibleForTesting
406 public int getRefCount() {
407 return this.reader.refCount.get();
408 }
409
410
411
412
413 public long getBulkLoadTimestamp() {
414 byte[] bulkLoadTimestamp = metadataMap.get(BULKLOAD_TIME_KEY);
415 return (bulkLoadTimestamp == null) ? 0 : Bytes.toLong(bulkLoadTimestamp);
416 }
417
418
419
420
421
422 public HDFSBlocksDistribution getHDFSBlockDistribution() {
423 return this.fileInfo.getHDFSBlockDistribution();
424 }
425
426
427
428
429
430
431
432 private Reader open(boolean canUseDropBehind) throws IOException {
433 if (this.reader != null) {
434 throw new IllegalAccessError("Already open");
435 }
436
437
438 this.reader = fileInfo.open(this.fs, this.cacheConf, canUseDropBehind);
439
440
441 metadataMap = Collections.unmodifiableMap(this.reader.loadFileInfo());
442
443
444 byte [] b = metadataMap.get(MAX_SEQ_ID_KEY);
445 if (b != null) {
446
447
448
449
450
451 this.sequenceid = Bytes.toLong(b);
452 if (fileInfo.isTopReference()) {
453 this.sequenceid += 1;
454 }
455 }
456
457 if (isBulkLoadResult()){
458
459
460 String fileName = this.getPath().getName();
461
462 int startPos = fileName.lastIndexOf("SeqId_");
463 if (startPos != -1) {
464 this.sequenceid = Long.parseLong(fileName.substring(startPos + 6,
465 fileName.indexOf('_', startPos + 6)));
466
467 if (fileInfo.isTopReference()) {
468 this.sequenceid += 1;
469 }
470 }
471 this.reader.setBulkLoaded(true);
472 }
473 this.reader.setSequenceID(this.sequenceid);
474
475 b = metadataMap.get(HFileWriterV2.MAX_MEMSTORE_TS_KEY);
476 if (b != null) {
477 this.maxMemstoreTS = Bytes.toLong(b);
478 }
479
480 b = metadataMap.get(MAJOR_COMPACTION_KEY);
481 if (b != null) {
482 boolean mc = Bytes.toBoolean(b);
483 if (this.majorCompaction == null) {
484 this.majorCompaction = new AtomicBoolean(mc);
485 } else {
486 this.majorCompaction.set(mc);
487 }
488 } else {
489
490
491 this.majorCompaction = new AtomicBoolean(false);
492 }
493
494 b = metadataMap.get(EXCLUDE_FROM_MINOR_COMPACTION_KEY);
495 this.excludeFromMinorCompaction = (b != null && Bytes.toBoolean(b));
496
497 BloomType hfileBloomType = reader.getBloomFilterType();
498 if (cfBloomType != BloomType.NONE) {
499 reader.loadBloomfilter(BlockType.GENERAL_BLOOM_META);
500 if (hfileBloomType != cfBloomType) {
501 LOG.info("HFile Bloom filter type for "
502 + reader.getHFileReader().getName() + ": " + hfileBloomType
503 + ", but " + cfBloomType + " specified in column family "
504 + "configuration");
505 }
506 } else if (hfileBloomType != BloomType.NONE) {
507 LOG.info("Bloom filter turned off by CF config for "
508 + reader.getHFileReader().getName());
509 }
510
511
512 reader.loadBloomfilter(BlockType.DELETE_FAMILY_BLOOM_META);
513
514 try {
515 this.reader.timeRange = TimeRangeTracker.getTimeRange(metadataMap.get(TIMERANGE_KEY));
516 } catch (IllegalArgumentException e) {
517 LOG.error("Error reading timestamp range data from meta -- " +
518 "proceeding without", e);
519 this.reader.timeRange = null;
520 }
521
522 try {
523 byte[] data = metadataMap.get(COMPACTION_EVENT_KEY);
524 this.compactedStoreFiles.addAll(ProtobufUtil.toCompactedStoreFiles(data));
525 } catch (IOException e) {
526 LOG.error("Error reading compacted storefiles from meta data", e);
527 }
528
529
530 firstKey = reader.getFirstKey();
531 lastKey = reader.getLastKey();
532 comparator = reader.getComparator();
533 return this.reader;
534 }
535
536 public Reader createReader() throws IOException {
537 return createReader(false);
538 }
539
540
541
542
543
544 public Reader createReader(boolean canUseDropBehind) throws IOException {
545 if (this.reader == null) {
546 try {
547 this.reader = open(canUseDropBehind);
548 } catch (IOException e) {
549 try {
550 boolean evictOnClose =
551 cacheConf != null? cacheConf.shouldEvictOnClose(): true;
552 this.closeReader(evictOnClose);
553 } catch (IOException ee) {
554 }
555 throw e;
556 }
557
558 }
559 return this.reader;
560 }
561
562
563
564
565
566 public Reader getReader() {
567 return this.reader;
568 }
569
570
571
572
573
574 public synchronized void closeReader(boolean evictOnClose)
575 throws IOException {
576 if (this.reader != null) {
577 this.reader.close(evictOnClose);
578 this.reader = null;
579 }
580 }
581
582
583
584
585 public void markCompactedAway() {
586 if (this.reader != null) {
587 this.reader.markCompactedAway();
588 }
589 }
590
591
592
593
594
595 public void deleteReader() throws IOException {
596 boolean evictOnClose =
597 cacheConf != null? cacheConf.shouldEvictOnClose(): true;
598 closeReader(evictOnClose);
599 this.fs.delete(getPath(), true);
600 }
601
602 @Override
603 public String toString() {
604 return this.fileInfo.toString();
605 }
606
607
608
609
610 public String toStringDetailed() {
611 StringBuilder sb = new StringBuilder();
612 sb.append(this.getPath().toString());
613 sb.append(", isReference=").append(isReference());
614 sb.append(", isBulkLoadResult=").append(isBulkLoadResult());
615 if (isBulkLoadResult()) {
616 sb.append(", bulkLoadTS=").append(getBulkLoadTimestamp());
617 } else {
618 sb.append(", seqid=").append(getMaxSequenceId());
619 }
620 sb.append(", majorCompaction=").append(isMajorCompaction());
621
622 return sb.toString();
623 }
624
625 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="ICAST_INTEGER_MULTIPLY_CAST_TO_LONG",
626 justification="Will not overflow")
627 public static class WriterBuilder {
628 private final Configuration conf;
629 private final CacheConfig cacheConf;
630 private final FileSystem fs;
631
632 private KeyValue.KVComparator comparator = KeyValue.COMPARATOR;
633 private BloomType bloomType = BloomType.NONE;
634 private long maxKeyCount = 0;
635 private Path dir;
636 private Path filePath;
637 private InetSocketAddress[] favoredNodes;
638 private HFileContext fileContext;
639 private TimeRangeTracker trt;
640 private boolean shouldDropCacheBehind;
641 private Collection<StoreFile> compactedFiles = Collections.emptySet();
642
643 public WriterBuilder(Configuration conf, CacheConfig cacheConf,
644 FileSystem fs) {
645 this.conf = conf;
646 this.cacheConf = cacheConf;
647 this.fs = fs;
648 }
649
650
651
652
653
654
655 public WriterBuilder withTimeRangeTracker(final TimeRangeTracker trt) {
656 Preconditions.checkNotNull(trt);
657 this.trt = trt;
658 return this;
659 }
660
661
662
663
664
665
666
667
668 public WriterBuilder withOutputDir(Path dir) {
669 Preconditions.checkNotNull(dir);
670 this.dir = dir;
671 return this;
672 }
673
674
675
676
677
678
679 public WriterBuilder withFilePath(Path filePath) {
680 Preconditions.checkNotNull(filePath);
681 this.filePath = filePath;
682 return this;
683 }
684
685
686
687
688
689 public WriterBuilder withFavoredNodes(InetSocketAddress[] favoredNodes) {
690 this.favoredNodes = favoredNodes;
691 return this;
692 }
693
694 public WriterBuilder withComparator(KeyValue.KVComparator comparator) {
695 Preconditions.checkNotNull(comparator);
696 this.comparator = comparator;
697 return this;
698 }
699
700 public WriterBuilder withBloomType(BloomType bloomType) {
701 Preconditions.checkNotNull(bloomType);
702 this.bloomType = bloomType;
703 return this;
704 }
705
706
707
708
709
710 public WriterBuilder withMaxKeyCount(long maxKeyCount) {
711 this.maxKeyCount = maxKeyCount;
712 return this;
713 }
714
715 public WriterBuilder withFileContext(HFileContext fileContext) {
716 this.fileContext = fileContext;
717 return this;
718 }
719
720 public WriterBuilder withShouldDropCacheBehind(boolean shouldDropCacheBehind) {
721 this.shouldDropCacheBehind = shouldDropCacheBehind;
722 return this;
723 }
724
725 public WriterBuilder withCompactedFiles(Collection<StoreFile> compactedFiles) {
726 this.compactedFiles = compactedFiles;
727 return this;
728 }
729
730
731
732
733
734
735 public Writer build() throws IOException {
736 if ((dir == null ? 0 : 1) + (filePath == null ? 0 : 1) != 1) {
737 throw new IllegalArgumentException("Either specify parent directory " +
738 "or file path");
739 }
740
741 if (dir == null) {
742 dir = filePath.getParent();
743 }
744
745 if (!fs.exists(dir)) {
746 fs.mkdirs(dir);
747 }
748
749 if (filePath == null) {
750 filePath = getUniqueFile(fs, dir);
751 if (!BloomFilterFactory.isGeneralBloomEnabled(conf)) {
752 bloomType = BloomType.NONE;
753 }
754 }
755
756 if (comparator == null) {
757 comparator = KeyValue.COMPARATOR;
758 }
759 return new Writer(fs, filePath,
760 conf, cacheConf, comparator, bloomType, maxKeyCount, favoredNodes, fileContext,
761 shouldDropCacheBehind, trt, compactedFiles);
762 }
763 }
764
765
766
767
768
769
770 public static Path getUniqueFile(final FileSystem fs, final Path dir)
771 throws IOException {
772 if (!fs.getFileStatus(dir).isDirectory()) {
773 throw new IOException("Expecting " + dir.toString() +
774 " to be a directory");
775 }
776 return new Path(dir, UUID.randomUUID().toString().replaceAll("-", ""));
777 }
778
779 public Long getMinimumTimestamp() {
780 return getReader().timeRange == null? null: getReader().timeRange.getMin();
781 }
782
783 public Long getMaximumTimestamp() {
784 return getReader().timeRange == null? null: getReader().timeRange.getMax();
785 }
786
787
788
789
790
791
792
793 @SuppressWarnings("deprecation")
794 byte[] getFileSplitPoint(KVComparator comparator) throws IOException {
795 if (this.reader == null) {
796 LOG.warn("Storefile " + this + " Reader is null; cannot get split point");
797 return null;
798 }
799
800
801
802 byte [] midkey = this.reader.midkey();
803 if (midkey != null) {
804 KeyValue mk = KeyValue.createKeyValueFromKey(midkey, 0, midkey.length);
805 byte [] fk = this.reader.getFirstKey();
806 KeyValue firstKey = KeyValue.createKeyValueFromKey(fk, 0, fk.length);
807 byte [] lk = this.reader.getLastKey();
808 KeyValue lastKey = KeyValue.createKeyValueFromKey(lk, 0, lk.length);
809
810 if (comparator.compareRows(mk, firstKey) == 0 || comparator.compareRows(mk, lastKey) == 0) {
811 if (LOG.isDebugEnabled()) {
812 LOG.debug("cannot split because midkey is the same as first or last row");
813 }
814 return null;
815 }
816 return mk.getRow();
817 }
818 return null;
819 }
820
821 Set<String> getCompactedStoreFiles() {
822 return Collections.unmodifiableSet(this.compactedStoreFiles);
823 }
824
825
826
827
828
829 public static class Writer implements Compactor.CellSink {
830 private final BloomFilterWriter generalBloomFilterWriter;
831 private final BloomFilterWriter deleteFamilyBloomFilterWriter;
832 private final BloomType bloomType;
833 private byte[] lastBloomKey;
834 private int lastBloomKeyOffset, lastBloomKeyLen;
835 private KVComparator kvComparator;
836 private Cell lastCell = null;
837 private long earliestPutTs = HConstants.LATEST_TIMESTAMP;
838 private Cell lastDeleteFamilyCell = null;
839 private long deleteFamilyCnt = 0;
840
841
842
843
844
845
846
847
848 private final boolean timeRangeTrackerSet;
849 final TimeRangeTracker timeRangeTracker;
850
851 protected HFile.Writer writer;
852 private final Collection<StoreFile> compactedFiles;
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868 private Writer(FileSystem fs, Path path,
869 final Configuration conf,
870 CacheConfig cacheConf,
871 final KVComparator comparator, BloomType bloomType, long maxKeys,
872 InetSocketAddress[] favoredNodes, HFileContext fileContext, boolean shouldDropCacheBehind)
873 throws IOException {
874 this(fs, path, conf, cacheConf, comparator, bloomType, maxKeys, favoredNodes, fileContext,
875 shouldDropCacheBehind, null, Collections.<StoreFile>emptySet());
876 }
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894 private Writer(FileSystem fs, Path path,
895 final Configuration conf,
896 CacheConfig cacheConf,
897 final KVComparator comparator, BloomType bloomType, long maxKeys,
898 InetSocketAddress[] favoredNodes, HFileContext fileContext,
899 boolean shouldDropCacheBehind, final TimeRangeTracker trt,
900 Collection<StoreFile> compactedFiles)
901 throws IOException {
902 this.compactedFiles =
903 (compactedFiles == null ? Collections.<StoreFile> emptySet() : compactedFiles);
904
905
906
907 this.timeRangeTrackerSet = trt != null;
908 this.timeRangeTracker = this.timeRangeTrackerSet? trt: new TimeRangeTracker();
909 writer = HFile.getWriterFactory(conf, cacheConf)
910 .withPath(fs, path)
911 .withComparator(comparator)
912 .withFavoredNodes(favoredNodes)
913 .withFileContext(fileContext)
914 .withShouldDropCacheBehind(shouldDropCacheBehind)
915 .create();
916
917 this.kvComparator = comparator;
918
919 generalBloomFilterWriter = BloomFilterFactory.createGeneralBloomAtWrite(
920 conf, cacheConf, bloomType,
921 (int) Math.min(maxKeys, Integer.MAX_VALUE), writer);
922
923 if (generalBloomFilterWriter != null) {
924 this.bloomType = bloomType;
925 if (LOG.isTraceEnabled()) LOG.trace("Bloom filter type for " + path + ": " +
926 this.bloomType + ", " + generalBloomFilterWriter.getClass().getSimpleName());
927 } else {
928
929 this.bloomType = BloomType.NONE;
930 }
931
932
933
934 if (this.bloomType != BloomType.ROWCOL) {
935 this.deleteFamilyBloomFilterWriter = BloomFilterFactory
936 .createDeleteBloomAtWrite(conf, cacheConf,
937 (int) Math.min(maxKeys, Integer.MAX_VALUE), writer);
938 } else {
939 deleteFamilyBloomFilterWriter = null;
940 }
941 if (deleteFamilyBloomFilterWriter != null) {
942 if (LOG.isTraceEnabled()) LOG.trace("Delete Family Bloom filter type for " + path + ": "
943 + deleteFamilyBloomFilterWriter.getClass().getSimpleName());
944 }
945 }
946
947
948
949
950
951
952
953 public void appendMetadata(final long maxSequenceId, final boolean majorCompaction)
954 throws IOException {
955 appendMetadata(maxSequenceId, majorCompaction, Collections.<StoreFile> emptySet());
956 }
957
958
959
960
961
962
963
964
965 public void appendMetadata(final long maxSequenceId, final boolean majorCompaction,
966 final Collection<StoreFile> storeFiles) throws IOException {
967 writer.appendFileInfo(MAX_SEQ_ID_KEY, Bytes.toBytes(maxSequenceId));
968 writer.appendFileInfo(MAJOR_COMPACTION_KEY, Bytes.toBytes(majorCompaction));
969 writer.appendFileInfo(COMPACTION_EVENT_KEY, toCompactionEventTrackerBytes(storeFiles));
970 appendTrackedTimestampsToMetadata();
971 }
972
973
974
975
976
977
978
979
980
981
982
983
984
985 private byte[] toCompactionEventTrackerBytes(Collection<StoreFile> storeFiles) {
986 Set<String> notArchivedCompactedStoreFiles = new HashSet<>();
987 for (StoreFile sf : this.compactedFiles) {
988 notArchivedCompactedStoreFiles.add(sf.getPath().getName());
989 }
990 Set<String> compactedStoreFiles = new HashSet<>();
991 for (StoreFile storeFile : storeFiles) {
992 compactedStoreFiles.add(storeFile.getFileInfo().getPath().getName());
993 for (String csf : storeFile.getCompactedStoreFiles()) {
994 if (notArchivedCompactedStoreFiles.contains(csf)) {
995 compactedStoreFiles.add(csf);
996 }
997 }
998 }
999 return ProtobufUtil.toCompactionEventTrackerBytes(compactedStoreFiles);
1000 }
1001
1002
1003
1004
1005 public void appendTrackedTimestampsToMetadata() throws IOException {
1006 appendFileInfo(TIMERANGE_KEY,WritableUtils.toByteArray(timeRangeTracker));
1007 appendFileInfo(EARLIEST_PUT_TS, Bytes.toBytes(earliestPutTs));
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017 public void trackTimestamps(final Cell cell) {
1018 if (KeyValue.Type.Put.getCode() == cell.getTypeByte()) {
1019 earliestPutTs = Math.min(earliestPutTs, cell.getTimestamp());
1020 }
1021 if (!timeRangeTrackerSet) {
1022 timeRangeTracker.includeTimestamp(cell);
1023 }
1024 }
1025
1026 private void appendGeneralBloomfilter(final Cell cell) throws IOException {
1027 if (this.generalBloomFilterWriter != null) {
1028
1029 boolean newKey = true;
1030 if (this.lastCell != null) {
1031 switch(bloomType) {
1032 case ROW:
1033 newKey = ! kvComparator.matchingRows(cell, lastCell);
1034 break;
1035 case ROWCOL:
1036 newKey = ! kvComparator.matchingRowColumn(cell, lastCell);
1037 break;
1038 case NONE:
1039 newKey = false;
1040 break;
1041 default:
1042 throw new IOException("Invalid Bloom filter type: " + bloomType +
1043 " (ROW or ROWCOL expected)");
1044 }
1045 }
1046 if (newKey) {
1047
1048
1049
1050
1051
1052
1053
1054
1055 byte[] bloomKey;
1056 int bloomKeyOffset, bloomKeyLen;
1057
1058 switch (bloomType) {
1059 case ROW:
1060 bloomKey = cell.getRowArray();
1061 bloomKeyOffset = cell.getRowOffset();
1062 bloomKeyLen = cell.getRowLength();
1063 break;
1064 case ROWCOL:
1065
1066
1067
1068 bloomKey = generalBloomFilterWriter.createBloomKey(cell.getRowArray(),
1069 cell.getRowOffset(), cell.getRowLength(), cell.getQualifierArray(),
1070 cell.getQualifierOffset(), cell.getQualifierLength());
1071 bloomKeyOffset = 0;
1072 bloomKeyLen = bloomKey.length;
1073 break;
1074 default:
1075 throw new IOException("Invalid Bloom filter type: " + bloomType +
1076 " (ROW or ROWCOL expected)");
1077 }
1078 generalBloomFilterWriter.add(bloomKey, bloomKeyOffset, bloomKeyLen);
1079 if (lastBloomKey != null
1080 && generalBloomFilterWriter.getComparator().compareFlatKey(bloomKey,
1081 bloomKeyOffset, bloomKeyLen, lastBloomKey,
1082 lastBloomKeyOffset, lastBloomKeyLen) <= 0) {
1083 throw new IOException("Non-increasing Bloom keys: "
1084 + Bytes.toStringBinary(bloomKey, bloomKeyOffset, bloomKeyLen)
1085 + " after "
1086 + Bytes.toStringBinary(lastBloomKey, lastBloomKeyOffset,
1087 lastBloomKeyLen));
1088 }
1089 lastBloomKey = bloomKey;
1090 lastBloomKeyOffset = bloomKeyOffset;
1091 lastBloomKeyLen = bloomKeyLen;
1092 this.lastCell = cell;
1093 }
1094 }
1095 }
1096
1097 private void appendDeleteFamilyBloomFilter(final Cell cell)
1098 throws IOException {
1099 if (!CellUtil.isDeleteFamily(cell) && !CellUtil.isDeleteFamilyVersion(cell)) {
1100 return;
1101 }
1102
1103
1104 deleteFamilyCnt++;
1105 if (null != this.deleteFamilyBloomFilterWriter) {
1106 boolean newKey = true;
1107 if (lastDeleteFamilyCell != null) {
1108 newKey = !kvComparator.matchingRows(cell, lastDeleteFamilyCell);
1109 }
1110 if (newKey) {
1111 this.deleteFamilyBloomFilterWriter.add(cell.getRowArray(),
1112 cell.getRowOffset(), cell.getRowLength());
1113 this.lastDeleteFamilyCell = cell;
1114 }
1115 }
1116 }
1117
1118 public void append(final Cell cell) throws IOException {
1119 appendGeneralBloomfilter(cell);
1120 appendDeleteFamilyBloomFilter(cell);
1121 writer.append(cell);
1122 trackTimestamps(cell);
1123 }
1124
1125 public Path getPath() {
1126 return this.writer.getPath();
1127 }
1128
1129 boolean hasGeneralBloom() {
1130 return this.generalBloomFilterWriter != null;
1131 }
1132
1133
1134
1135
1136
1137
1138 BloomFilterWriter getGeneralBloomWriter() {
1139 return generalBloomFilterWriter;
1140 }
1141
1142 private boolean closeBloomFilter(BloomFilterWriter bfw) throws IOException {
1143 boolean haveBloom = (bfw != null && bfw.getKeyCount() > 0);
1144 if (haveBloom) {
1145 bfw.compactBloom();
1146 }
1147 return haveBloom;
1148 }
1149
1150 private boolean closeGeneralBloomFilter() throws IOException {
1151 boolean hasGeneralBloom = closeBloomFilter(generalBloomFilterWriter);
1152
1153
1154 if (hasGeneralBloom) {
1155 writer.addGeneralBloomFilter(generalBloomFilterWriter);
1156 writer.appendFileInfo(BLOOM_FILTER_TYPE_KEY,
1157 Bytes.toBytes(bloomType.toString()));
1158 if (lastBloomKey != null) {
1159 writer.appendFileInfo(LAST_BLOOM_KEY, Arrays.copyOfRange(
1160 lastBloomKey, lastBloomKeyOffset, lastBloomKeyOffset
1161 + lastBloomKeyLen));
1162 }
1163 }
1164 return hasGeneralBloom;
1165 }
1166
1167 private boolean closeDeleteFamilyBloomFilter() throws IOException {
1168 boolean hasDeleteFamilyBloom = closeBloomFilter(deleteFamilyBloomFilterWriter);
1169
1170
1171 if (hasDeleteFamilyBloom) {
1172 writer.addDeleteFamilyBloomFilter(deleteFamilyBloomFilterWriter);
1173 }
1174
1175
1176
1177 writer.appendFileInfo(DELETE_FAMILY_COUNT,
1178 Bytes.toBytes(this.deleteFamilyCnt));
1179
1180 return hasDeleteFamilyBloom;
1181 }
1182
1183 public void close() throws IOException {
1184 boolean hasGeneralBloom = this.closeGeneralBloomFilter();
1185 boolean hasDeleteFamilyBloom = this.closeDeleteFamilyBloomFilter();
1186
1187 writer.close();
1188
1189
1190
1191 if (StoreFile.LOG.isTraceEnabled()) {
1192 StoreFile.LOG.trace((hasGeneralBloom ? "" : "NO ") + "General Bloom and " +
1193 (hasDeleteFamilyBloom ? "" : "NO ") + "DeleteFamily" + " was added to HFile " +
1194 getPath());
1195 }
1196
1197 }
1198
1199 public void appendFileInfo(byte[] key, byte[] value) throws IOException {
1200 writer.appendFileInfo(key, value);
1201 }
1202
1203
1204
1205 HFile.Writer getHFileWriter() {
1206 return writer;
1207 }
1208 }
1209
1210
1211
1212
1213 public static class Reader {
1214 private static final Log LOG = LogFactory.getLog(Reader.class.getName());
1215
1216 protected BloomFilter generalBloomFilter = null;
1217 protected BloomFilter deleteFamilyBloomFilter = null;
1218 protected BloomType bloomFilterType;
1219 private final HFile.Reader reader;
1220 protected TimeRange timeRange;
1221 protected long sequenceID = -1;
1222 private byte[] lastBloomKey;
1223 private long deleteFamilyCnt = -1;
1224 private boolean bulkLoadResult = false;
1225
1226
1227
1228 private AtomicInteger refCount = new AtomicInteger(0);
1229
1230 private volatile boolean compactedAway = false;
1231
1232 public Reader(FileSystem fs, Path path, CacheConfig cacheConf, Configuration conf)
1233 throws IOException {
1234 reader = HFile.createReader(fs, path, cacheConf, conf);
1235 bloomFilterType = BloomType.NONE;
1236 }
1237
1238 void markCompactedAway() {
1239 this.compactedAway = true;
1240 }
1241
1242 public Reader(FileSystem fs, Path path, FSDataInputStreamWrapper in, long size,
1243 CacheConfig cacheConf, Configuration conf) throws IOException {
1244 reader = HFile.createReader(fs, path, in, size, cacheConf, conf);
1245 bloomFilterType = BloomType.NONE;
1246 }
1247
1248 public void setReplicaStoreFile(boolean isPrimaryReplicaStoreFile) {
1249 reader.setPrimaryReplicaReader(isPrimaryReplicaStoreFile);
1250 }
1251 public boolean isPrimaryReplicaReader() {
1252 return reader.isPrimaryReplicaReader();
1253 }
1254
1255
1256
1257
1258 Reader() {
1259 this.reader = null;
1260 }
1261
1262 public KVComparator getComparator() {
1263 return reader.getComparator();
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274 public StoreFileScanner getStoreFileScanner(boolean cacheBlocks,
1275 boolean pread) {
1276 return getStoreFileScanner(cacheBlocks, pread, false,
1277
1278
1279 0);
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290 public StoreFileScanner getStoreFileScanner(boolean cacheBlocks, boolean pread,
1291 boolean isCompaction, long readPt) {
1292 return new StoreFileScanner(this, getScanner(cacheBlocks, pread, isCompaction),
1293 !isCompaction, reader.hasMVCCInfo(), readPt);
1294 }
1295
1296
1297
1298
1299
1300 int getRefCount() {
1301 return refCount.get();
1302 }
1303
1304
1305
1306
1307
1308 void incrementRefCount() {
1309 refCount.incrementAndGet();
1310 }
1311
1312
1313
1314
1315
1316 void decrementRefCount() {
1317 refCount.decrementAndGet();
1318 }
1319
1320
1321
1322
1323 public boolean isReferencedInReads() {
1324 return refCount.get() != 0;
1325 }
1326
1327
1328
1329
1330 public boolean isCompactedAway() {
1331 return this.compactedAway;
1332 }
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343 @Deprecated
1344 public HFileScanner getScanner(boolean cacheBlocks, boolean pread) {
1345 return getScanner(cacheBlocks, pread, false);
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361 @Deprecated
1362 public HFileScanner getScanner(boolean cacheBlocks, boolean pread,
1363 boolean isCompaction) {
1364 return reader.getScanner(cacheBlocks, pread, isCompaction);
1365 }
1366
1367 public void close(boolean evictOnClose) throws IOException {
1368 reader.close(evictOnClose);
1369 }
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379 boolean passesTimerangeFilter(TimeRange tr, long oldestUnexpiredTS) {
1380 return this.timeRange == null? true:
1381 this.timeRange.includesTimeRange(tr) && this.timeRange.getMax() >= oldestUnexpiredTS;
1382 }
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 boolean passesBloomFilter(Scan scan,
1401 final SortedSet<byte[]> columns) {
1402
1403
1404 if (!scan.isGetScan()) {
1405 return true;
1406 }
1407
1408 byte[] row = scan.getStartRow();
1409 switch (this.bloomFilterType) {
1410 case ROW:
1411 return passesGeneralBloomFilter(row, 0, row.length, null, 0, 0);
1412
1413 case ROWCOL:
1414 if (columns != null && columns.size() == 1) {
1415 byte[] column = columns.first();
1416 return passesGeneralBloomFilter(row, 0, row.length, column, 0,
1417 column.length);
1418 }
1419
1420
1421
1422 return true;
1423
1424 default:
1425 return true;
1426 }
1427 }
1428
1429 public boolean passesDeleteFamilyBloomFilter(byte[] row, int rowOffset,
1430 int rowLen) {
1431
1432
1433 BloomFilter bloomFilter = this.deleteFamilyBloomFilter;
1434
1435
1436 if (reader.getTrailer().getEntryCount() == 0 || deleteFamilyCnt == 0) {
1437 return false;
1438 }
1439
1440 if (bloomFilter == null) {
1441 return true;
1442 }
1443
1444 try {
1445 if (!bloomFilter.supportsAutoLoading()) {
1446 return true;
1447 }
1448 return bloomFilter.contains(row, rowOffset, rowLen, null);
1449 } catch (IllegalArgumentException e) {
1450 LOG.error("Bad Delete Family bloom filter data -- proceeding without",
1451 e);
1452 setDeleteFamilyBloomFilterFaulty();
1453 }
1454
1455 return true;
1456 }
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 public boolean passesGeneralBloomFilter(byte[] row, int rowOffset,
1471 int rowLen, byte[] col, int colOffset, int colLen) {
1472
1473
1474 BloomFilter bloomFilter = this.generalBloomFilter;
1475 if (bloomFilter == null) {
1476 return true;
1477 }
1478
1479 byte[] key;
1480 switch (bloomFilterType) {
1481 case ROW:
1482 if (col != null) {
1483 throw new RuntimeException("Row-only Bloom filter called with " +
1484 "column specified");
1485 }
1486 if (rowOffset != 0 || rowLen != row.length) {
1487 throw new AssertionError("For row-only Bloom filters the row "
1488 + "must occupy the whole array");
1489 }
1490 key = row;
1491 break;
1492
1493 case ROWCOL:
1494 key = bloomFilter.createBloomKey(row, rowOffset, rowLen, col,
1495 colOffset, colLen);
1496
1497 break;
1498
1499 default:
1500 return true;
1501 }
1502
1503
1504 if (reader.getTrailer().getEntryCount() == 0)
1505 return false;
1506
1507 try {
1508 boolean shouldCheckBloom;
1509 ByteBuffer bloom;
1510 if (bloomFilter.supportsAutoLoading()) {
1511 bloom = null;
1512 shouldCheckBloom = true;
1513 } else {
1514 bloom = reader.getMetaBlock(HFile.BLOOM_FILTER_DATA_KEY,
1515 true);
1516 shouldCheckBloom = bloom != null;
1517 }
1518
1519 if (shouldCheckBloom) {
1520 boolean exists;
1521
1522
1523
1524
1525 boolean keyIsAfterLast = lastBloomKey != null
1526 && bloomFilter.getComparator().compareFlatKey(key, lastBloomKey) > 0;
1527
1528 if (bloomFilterType == BloomType.ROWCOL) {
1529
1530
1531
1532
1533 byte[] rowBloomKey = bloomFilter.createBloomKey(row, rowOffset, rowLen,
1534 null, 0, 0);
1535
1536 if (keyIsAfterLast
1537 && bloomFilter.getComparator().compareFlatKey(rowBloomKey,
1538 lastBloomKey) > 0) {
1539 exists = false;
1540 } else {
1541 exists =
1542 bloomFilter.contains(key, 0, key.length, bloom) ||
1543 bloomFilter.contains(rowBloomKey, 0, rowBloomKey.length,
1544 bloom);
1545 }
1546 } else {
1547 exists = !keyIsAfterLast
1548 && bloomFilter.contains(key, 0, key.length, bloom);
1549 }
1550
1551 return exists;
1552 }
1553 } catch (IOException e) {
1554 LOG.error("Error reading bloom filter data -- proceeding without",
1555 e);
1556 setGeneralBloomFilterFaulty();
1557 } catch (IllegalArgumentException e) {
1558 LOG.error("Bad bloom filter data -- proceeding without", e);
1559 setGeneralBloomFilterFaulty();
1560 }
1561
1562 return true;
1563 }
1564
1565
1566
1567
1568
1569
1570 public boolean passesKeyRangeFilter(Scan scan) {
1571 if (this.getFirstKey() == null || this.getLastKey() == null) {
1572
1573 return false;
1574 }
1575 if (Bytes.equals(scan.getStartRow(), HConstants.EMPTY_START_ROW)
1576 && Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW)) {
1577 return true;
1578 }
1579 KeyValue smallestScanKeyValue = scan.isReversed() ? KeyValueUtil
1580 .createFirstOnRow(scan.getStopRow()) : KeyValueUtil.createFirstOnRow(scan
1581 .getStartRow());
1582 KeyValue largestScanKeyValue = scan.isReversed() ? KeyValueUtil
1583 .createLastOnRow(scan.getStartRow()) : KeyValueUtil.createLastOnRow(scan
1584 .getStopRow());
1585 boolean nonOverLapping = (getComparator().compareFlatKey(
1586 this.getFirstKey(), largestScanKeyValue.getKey()) > 0 && !Bytes
1587 .equals(scan.isReversed() ? scan.getStartRow() : scan.getStopRow(),
1588 HConstants.EMPTY_END_ROW))
1589 || getComparator().compareFlatKey(this.getLastKey(),
1590 smallestScanKeyValue.getKey()) < 0;
1591 return !nonOverLapping;
1592 }
1593
1594 public Map<byte[], byte[]> loadFileInfo() throws IOException {
1595 Map<byte [], byte []> fi = reader.loadFileInfo();
1596
1597 byte[] b = fi.get(BLOOM_FILTER_TYPE_KEY);
1598 if (b != null) {
1599 bloomFilterType = BloomType.valueOf(Bytes.toString(b));
1600 }
1601
1602 lastBloomKey = fi.get(LAST_BLOOM_KEY);
1603 byte[] cnt = fi.get(DELETE_FAMILY_COUNT);
1604 if (cnt != null) {
1605 deleteFamilyCnt = Bytes.toLong(cnt);
1606 }
1607
1608 return fi;
1609 }
1610
1611 public void loadBloomfilter() {
1612 this.loadBloomfilter(BlockType.GENERAL_BLOOM_META);
1613 this.loadBloomfilter(BlockType.DELETE_FAMILY_BLOOM_META);
1614 }
1615
1616 private void loadBloomfilter(BlockType blockType) {
1617 try {
1618 if (blockType == BlockType.GENERAL_BLOOM_META) {
1619 if (this.generalBloomFilter != null)
1620 return;
1621
1622 DataInput bloomMeta = reader.getGeneralBloomFilterMetadata();
1623 if (bloomMeta != null) {
1624
1625 if (bloomFilterType == BloomType.NONE) {
1626 throw new IOException(
1627 "valid bloom filter type not found in FileInfo");
1628 } else {
1629 generalBloomFilter = BloomFilterFactory.createFromMeta(bloomMeta,
1630 reader);
1631 if (LOG.isTraceEnabled()) {
1632 LOG.trace("Loaded " + bloomFilterType.toString() + " "
1633 + generalBloomFilter.getClass().getSimpleName()
1634 + " metadata for " + reader.getName());
1635 }
1636 }
1637 }
1638 } else if (blockType == BlockType.DELETE_FAMILY_BLOOM_META) {
1639 if (this.deleteFamilyBloomFilter != null)
1640 return;
1641
1642 DataInput bloomMeta = reader.getDeleteBloomFilterMetadata();
1643 if (bloomMeta != null) {
1644 deleteFamilyBloomFilter = BloomFilterFactory.createFromMeta(
1645 bloomMeta, reader);
1646 LOG.info("Loaded Delete Family Bloom ("
1647 + deleteFamilyBloomFilter.getClass().getSimpleName()
1648 + ") metadata for " + reader.getName());
1649 }
1650 } else {
1651 throw new RuntimeException("Block Type: " + blockType.toString()
1652 + "is not supported for Bloom filter");
1653 }
1654 } catch (IOException e) {
1655 LOG.error("Error reading bloom filter meta for " + blockType
1656 + " -- proceeding without", e);
1657 setBloomFilterFaulty(blockType);
1658 } catch (IllegalArgumentException e) {
1659 LOG.error("Bad bloom filter meta " + blockType
1660 + " -- proceeding without", e);
1661 setBloomFilterFaulty(blockType);
1662 }
1663 }
1664
1665 private void setBloomFilterFaulty(BlockType blockType) {
1666 if (blockType == BlockType.GENERAL_BLOOM_META) {
1667 setGeneralBloomFilterFaulty();
1668 } else if (blockType == BlockType.DELETE_FAMILY_BLOOM_META) {
1669 setDeleteFamilyBloomFilterFaulty();
1670 }
1671 }
1672
1673
1674
1675
1676
1677
1678
1679
1680 public long getFilterEntries() {
1681 return generalBloomFilter != null ? generalBloomFilter.getKeyCount()
1682 : reader.getEntries();
1683 }
1684
1685 public void setGeneralBloomFilterFaulty() {
1686 generalBloomFilter = null;
1687 }
1688
1689 public void setDeleteFamilyBloomFilterFaulty() {
1690 this.deleteFamilyBloomFilter = null;
1691 }
1692
1693 public byte[] getLastKey() {
1694 return reader.getLastKey();
1695 }
1696
1697 public byte[] getLastRowKey() {
1698 return reader.getLastRowKey();
1699 }
1700
1701 public byte[] midkey() throws IOException {
1702 return reader.midkey();
1703 }
1704
1705 public long length() {
1706 return reader.length();
1707 }
1708
1709 public long getTotalUncompressedBytes() {
1710 return reader.getTrailer().getTotalUncompressedBytes();
1711 }
1712
1713 public long getEntries() {
1714 return reader.getEntries();
1715 }
1716
1717 public long getDeleteFamilyCnt() {
1718 return deleteFamilyCnt;
1719 }
1720
1721 public byte[] getFirstKey() {
1722 return reader.getFirstKey();
1723 }
1724
1725 public long indexSize() {
1726 return reader.indexSize();
1727 }
1728
1729 public BloomType getBloomFilterType() {
1730 return this.bloomFilterType;
1731 }
1732
1733 public long getSequenceID() {
1734 return sequenceID;
1735 }
1736
1737 public void setSequenceID(long sequenceID) {
1738 this.sequenceID = sequenceID;
1739 }
1740
1741 public void setBulkLoaded(boolean bulkLoadResult) {
1742 this.bulkLoadResult = bulkLoadResult;
1743 }
1744
1745 public boolean isBulkLoaded() {
1746 return this.bulkLoadResult;
1747 }
1748
1749 BloomFilter getGeneralBloomFilter() {
1750 return generalBloomFilter;
1751 }
1752
1753 long getUncompressedDataIndexSize() {
1754 return reader.getTrailer().getUncompressedDataIndexSize();
1755 }
1756
1757 public long getTotalBloomSize() {
1758 if (generalBloomFilter == null)
1759 return 0;
1760 return generalBloomFilter.getByteSize();
1761 }
1762
1763 public int getHFileVersion() {
1764 return reader.getTrailer().getMajorVersion();
1765 }
1766
1767 public int getHFileMinorVersion() {
1768 return reader.getTrailer().getMinorVersion();
1769 }
1770
1771 public HFile.Reader getHFileReader() {
1772 return reader;
1773 }
1774
1775 void disableBloomFilterForTesting() {
1776 generalBloomFilter = null;
1777 this.deleteFamilyBloomFilter = null;
1778 }
1779
1780 public long getMaxTimestamp() {
1781 return timeRange == null ? TimeRange.INITIAL_MAX_TIMESTAMP: timeRange.getMax();
1782 }
1783 }
1784
1785
1786
1787
1788 public abstract static class Comparators {
1789
1790
1791
1792
1793
1794
1795
1796
1797 public static final Comparator<StoreFile> SEQ_ID =
1798 Ordering.compound(ImmutableList.of(
1799 Ordering.natural().onResultOf(new GetSeqId()),
1800 Ordering.natural().onResultOf(new GetFileSize()).reverse(),
1801 Ordering.natural().onResultOf(new GetBulkTime()),
1802 Ordering.natural().onResultOf(new GetPathName())
1803 ));
1804
1805
1806
1807
1808
1809 public static final Comparator<StoreFile> SEQ_ID_MAX_TIMESTAMP =
1810 Ordering.compound(ImmutableList.of(
1811 Ordering.natural().onResultOf(new GetSeqId()),
1812 Ordering.natural().onResultOf(new GetMaxTimestamp()),
1813 Ordering.natural().onResultOf(new GetFileSize()).reverse(),
1814 Ordering.natural().onResultOf(new GetBulkTime()),
1815 Ordering.natural().onResultOf(new GetPathName())
1816 ));
1817
1818 private static class GetSeqId implements Function<StoreFile, Long> {
1819 @Override
1820 public Long apply(StoreFile sf) {
1821 return sf.getMaxSequenceId();
1822 }
1823 }
1824
1825 private static class GetFileSize implements Function<StoreFile, Long> {
1826 @Override
1827 public Long apply(StoreFile sf) {
1828 if (sf.getReader() != null) {
1829 return sf.getReader().length();
1830 } else {
1831
1832
1833 return -1L;
1834 }
1835 }
1836 }
1837
1838 private static class GetBulkTime implements Function<StoreFile, Long> {
1839 @Override
1840 public Long apply(StoreFile sf) {
1841 if (!sf.isBulkLoadResult()) return Long.MAX_VALUE;
1842 return sf.getBulkLoadTimestamp();
1843 }
1844 }
1845
1846 private static class GetPathName implements Function<StoreFile, String> {
1847 @Override
1848 public String apply(StoreFile sf) {
1849 return sf.getPath().getName();
1850 }
1851 }
1852
1853 private static class GetMaxTimestamp implements Function<StoreFile, Long> {
1854 @Override
1855 public Long apply(StoreFile sf) {
1856 return sf.getMaximumTimestamp() == null? (Long)Long.MAX_VALUE : sf.getMaximumTimestamp();
1857 }
1858 }
1859 }
1860 }