1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.io.hfile;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.Closeable;
23 import java.io.DataInput;
24 import java.io.DataInputStream;
25 import java.io.DataOutputStream;
26 import java.io.IOException;
27 import java.io.SequenceInputStream;
28 import java.net.InetSocketAddress;
29 import java.nio.ByteBuffer;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Comparator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.SortedMap;
37 import java.util.TreeMap;
38 import java.util.concurrent.atomic.AtomicLong;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42 import org.apache.hadoop.hbase.classification.InterfaceAudience;
43 import org.apache.hadoop.conf.Configuration;
44 import org.apache.hadoop.fs.FSDataInputStream;
45 import org.apache.hadoop.fs.FSDataOutputStream;
46 import org.apache.hadoop.fs.FileStatus;
47 import org.apache.hadoop.fs.FileSystem;
48 import org.apache.hadoop.fs.Path;
49 import org.apache.hadoop.fs.PathFilter;
50 import org.apache.hadoop.hbase.Cell;
51 import org.apache.hadoop.hbase.HConstants;
52 import org.apache.hadoop.hbase.KeyValue;
53 import org.apache.hadoop.hbase.KeyValue.KVComparator;
54 import org.apache.hadoop.hbase.fs.HFileSystem;
55 import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
56 import org.apache.hadoop.hbase.io.compress.Compression;
57 import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
58 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
59 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
60 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BytesBytesPair;
61 import org.apache.hadoop.hbase.protobuf.generated.HFileProtos;
62 import org.apache.hadoop.hbase.util.BloomFilterWriter;
63 import org.apache.hadoop.hbase.util.ByteStringer;
64 import org.apache.hadoop.hbase.util.Bytes;
65 import org.apache.hadoop.hbase.util.FSUtils;
66 import org.apache.hadoop.io.Writable;
67
68 import com.google.common.base.Preconditions;
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 @InterfaceAudience.Private
135 public class HFile {
136
137 static final Log LOG = LogFactory.getLog(HFile.class);
138
139
140
141
142 public final static int MAXIMUM_KEY_LENGTH = Integer.MAX_VALUE;
143
144
145
146
147 public final static Compression.Algorithm DEFAULT_COMPRESSION_ALGORITHM =
148 Compression.Algorithm.NONE;
149
150
151 public static final int MIN_FORMAT_VERSION = 2;
152
153
154
155 public static final int MAX_FORMAT_VERSION = 3;
156
157
158
159
160 public static final int MIN_FORMAT_VERSION_WITH_TAGS = 3;
161
162
163 public final static String DEFAULT_COMPRESSION =
164 DEFAULT_COMPRESSION_ALGORITHM.getName();
165
166
167 public static final String BLOOM_FILTER_DATA_KEY = "BLOOM_FILTER_DATA";
168
169
170
171
172
173
174
175 public final static int MIN_NUM_HFILE_PATH_LEVELS = 5;
176
177
178
179
180 public static final int DEFAULT_BYTES_PER_CHECKSUM = 16 * 1024;
181
182 static final AtomicLong checksumFailures = new AtomicLong();
183
184
185 public static final AtomicLong dataBlockReadCnt = new AtomicLong(0);
186
187
188
189
190
191 public static final long getChecksumFailuresCount() {
192 return checksumFailures.getAndSet(0);
193 }
194
195
196 public interface Writer extends Closeable {
197
198
199 void appendFileInfo(byte[] key, byte[] value) throws IOException;
200
201 void append(Cell cell) throws IOException;
202
203
204 Path getPath();
205
206
207
208
209
210 void addInlineBlockWriter(InlineBlockWriter bloomWriter);
211
212
213
214
215
216
217 void appendMetaBlock(String bloomFilterMetaKey, Writable metaWriter);
218
219
220
221
222
223
224 void addGeneralBloomFilter(BloomFilterWriter bfw);
225
226
227
228
229
230 void addDeleteFamilyBloomFilter(BloomFilterWriter bfw) throws IOException;
231
232
233
234
235 HFileContext getFileContext();
236 }
237
238
239
240
241
242 public static abstract class WriterFactory {
243 protected final Configuration conf;
244 protected final CacheConfig cacheConf;
245 protected FileSystem fs;
246 protected Path path;
247 protected FSDataOutputStream ostream;
248 protected KVComparator comparator = KeyValue.COMPARATOR;
249 protected InetSocketAddress[] favoredNodes;
250 private HFileContext fileContext;
251 protected boolean shouldDropBehind = false;
252
253 WriterFactory(Configuration conf, CacheConfig cacheConf) {
254 this.conf = conf;
255 this.cacheConf = cacheConf;
256 }
257
258 public WriterFactory withPath(FileSystem fs, Path path) {
259 Preconditions.checkNotNull(fs);
260 Preconditions.checkNotNull(path);
261 this.fs = fs;
262 this.path = path;
263 return this;
264 }
265
266 public WriterFactory withOutputStream(FSDataOutputStream ostream) {
267 Preconditions.checkNotNull(ostream);
268 this.ostream = ostream;
269 return this;
270 }
271
272 public WriterFactory withComparator(KVComparator comparator) {
273 Preconditions.checkNotNull(comparator);
274 this.comparator = comparator;
275 return this;
276 }
277
278 public WriterFactory withFavoredNodes(InetSocketAddress[] favoredNodes) {
279
280 this.favoredNodes = favoredNodes;
281 return this;
282 }
283
284 public WriterFactory withFileContext(HFileContext fileContext) {
285 this.fileContext = fileContext;
286 return this;
287 }
288
289 public WriterFactory withShouldDropCacheBehind(boolean shouldDropBehind) {
290 this.shouldDropBehind = shouldDropBehind;
291 return this;
292 }
293
294
295 public Writer create() throws IOException {
296 if ((path != null ? 1 : 0) + (ostream != null ? 1 : 0) != 1) {
297 throw new AssertionError("Please specify exactly one of " +
298 "filesystem/path or path");
299 }
300 if (path != null) {
301 ostream = AbstractHFileWriter.createOutputStream(conf, fs, path, favoredNodes);
302 try {
303 ostream.setDropBehind(shouldDropBehind && cacheConf.shouldDropBehindCompaction());
304 } catch (UnsupportedOperationException uoe) {
305 if (LOG.isTraceEnabled()) LOG.trace("Unable to set drop behind on " + path, uoe);
306 else if (LOG.isDebugEnabled()) LOG.debug("Unable to set drop behind on " + path);
307 }
308 }
309 return createWriter(fs, path, ostream,
310 comparator, fileContext);
311 }
312
313 protected abstract Writer createWriter(FileSystem fs, Path path, FSDataOutputStream ostream,
314 KVComparator comparator, HFileContext fileContext) throws IOException;
315 }
316
317
318 public static final String FORMAT_VERSION_KEY = "hfile.format.version";
319
320 public static int getFormatVersion(Configuration conf) {
321
322 int version = conf.getInt(FORMAT_VERSION_KEY, MIN_FORMAT_VERSION);
323 checkFormatVersion(version);
324 return version;
325 }
326
327
328
329
330
331
332 public static final WriterFactory getWriterFactoryNoCache(Configuration
333 conf) {
334 Configuration tempConf = new Configuration(conf);
335 tempConf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0.0f);
336 return HFile.getWriterFactory(conf, new CacheConfig(tempConf));
337 }
338
339
340
341
342 public static final WriterFactory getWriterFactory(Configuration conf,
343 CacheConfig cacheConf) {
344 int version = getFormatVersion(conf);
345 switch (version) {
346 case 2:
347 return new HFileWriterV2.WriterFactoryV2(conf, cacheConf);
348 case 3:
349 return new HFileWriterV3.WriterFactoryV3(conf, cacheConf);
350 default:
351 throw new IllegalArgumentException("Cannot create writer for HFile " +
352 "format version " + version);
353 }
354 }
355
356
357
358
359
360
361 public interface CachingBlockReader {
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379 HFileBlock readBlock(long offset, long onDiskBlockSize,
380 boolean cacheBlock, final boolean pread, final boolean isCompaction,
381 final boolean updateCacheMetrics, BlockType expectedBlockType,
382 DataBlockEncoding expectedDataBlockEncoding)
383 throws IOException;
384 }
385
386
387 public interface Reader extends Closeable, CachingBlockReader {
388
389
390
391
392
393 String getName();
394
395 KVComparator getComparator();
396
397 HFileScanner getScanner(boolean cacheBlocks, final boolean pread, final boolean isCompaction);
398
399 ByteBuffer getMetaBlock(String metaBlockName, boolean cacheBlock) throws IOException;
400
401 Map<byte[], byte[]> loadFileInfo() throws IOException;
402
403 byte[] getLastKey();
404
405 byte[] midkey() throws IOException;
406
407 long length();
408
409 long getEntries();
410
411 byte[] getFirstKey();
412
413 long indexSize();
414
415 byte[] getFirstRowKey();
416
417 byte[] getLastRowKey();
418
419 FixedFileTrailer getTrailer();
420
421 HFileBlockIndex.BlockIndexReader getDataBlockIndexReader();
422
423 HFileScanner getScanner(boolean cacheBlocks, boolean pread);
424
425 Compression.Algorithm getCompressionAlgorithm();
426
427
428
429
430
431
432 DataInput getGeneralBloomFilterMetadata() throws IOException;
433
434
435
436
437
438
439 DataInput getDeleteBloomFilterMetadata() throws IOException;
440
441 Path getPath();
442
443
444 void close(boolean evictOnClose) throws IOException;
445
446 DataBlockEncoding getDataBlockEncoding();
447
448 boolean hasMVCCInfo();
449
450
451
452
453 HFileContext getFileContext();
454
455 boolean isPrimaryReplicaReader();
456
457 void setPrimaryReplicaReader(boolean isPrimaryReplicaReader);
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SF_SWITCH_FALLTHROUGH",
473 justification="Intentional")
474 private static Reader pickReaderVersion(Path path, FSDataInputStreamWrapper fsdis,
475 long size, CacheConfig cacheConf, HFileSystem hfs, Configuration conf) throws IOException {
476 FixedFileTrailer trailer = null;
477 try {
478 boolean isHBaseChecksum = fsdis.shouldUseHBaseChecksum();
479 assert !isHBaseChecksum;
480 trailer = FixedFileTrailer.readFromStream(fsdis.getStream(isHBaseChecksum), size);
481 switch (trailer.getMajorVersion()) {
482 case 2:
483 return new HFileReaderV2(path, trailer, fsdis, size, cacheConf, hfs, conf);
484 case 3 :
485 return new HFileReaderV3(path, trailer, fsdis, size, cacheConf, hfs, conf);
486 default:
487 throw new IllegalArgumentException("Invalid HFile version " + trailer.getMajorVersion());
488 }
489 } catch (Throwable t) {
490 try {
491 fsdis.close();
492 } catch (Throwable t2) {
493 LOG.warn("Error closing fsdis FSDataInputStreamWrapper", t2);
494 }
495 throw new CorruptHFileException("Problem reading HFile Trailer from file " + path, t);
496 }
497 }
498
499
500
501
502
503
504
505
506
507
508
509 public static Reader createReader(FileSystem fs, Path path,
510 FSDataInputStreamWrapper fsdis, long size, CacheConfig cacheConf, Configuration conf)
511 throws IOException {
512 HFileSystem hfs = null;
513
514
515
516
517
518 if (!(fs instanceof HFileSystem)) {
519 hfs = new HFileSystem(fs);
520 } else {
521 hfs = (HFileSystem)fs;
522 }
523 return pickReaderVersion(path, fsdis, size, cacheConf, hfs, conf);
524 }
525
526
527
528
529
530
531
532
533
534 public static Reader createReader(
535 FileSystem fs, Path path, CacheConfig cacheConf, Configuration conf) throws IOException {
536 Preconditions.checkNotNull(cacheConf, "Cannot create Reader with null CacheConf");
537 FSDataInputStreamWrapper stream = new FSDataInputStreamWrapper(fs, path);
538 return pickReaderVersion(path, stream, fs.getFileStatus(path).getLen(),
539 cacheConf, stream.getHfs(), conf);
540 }
541
542
543
544
545 static Reader createReaderFromStream(Path path,
546 FSDataInputStream fsdis, long size, CacheConfig cacheConf, Configuration conf)
547 throws IOException {
548 FSDataInputStreamWrapper wrapper = new FSDataInputStreamWrapper(fsdis);
549 return pickReaderVersion(path, wrapper, size, cacheConf, null, conf);
550 }
551
552
553
554
555
556
557
558
559 public static boolean isHFileFormat(final FileSystem fs, final Path path) throws IOException {
560 return isHFileFormat(fs, fs.getFileStatus(path));
561 }
562
563
564
565
566
567
568
569
570 public static boolean isHFileFormat(final FileSystem fs, final FileStatus fileStatus)
571 throws IOException {
572 final Path path = fileStatus.getPath();
573 final long size = fileStatus.getLen();
574 FSDataInputStreamWrapper fsdis = new FSDataInputStreamWrapper(fs, path);
575 try {
576 boolean isHBaseChecksum = fsdis.shouldUseHBaseChecksum();
577 assert !isHBaseChecksum;
578 FixedFileTrailer.readFromStream(fsdis.getStream(isHBaseChecksum), size);
579 return true;
580 } catch (IllegalArgumentException e) {
581 return false;
582 } catch (IOException e) {
583 throw e;
584 } finally {
585 try {
586 fsdis.close();
587 } catch (Throwable t) {
588 LOG.warn("Error closing fsdis FSDataInputStreamWrapper: " + path, t);
589 }
590 }
591 }
592
593
594
595
596 public static class FileInfo implements SortedMap<byte[], byte[]> {
597 static final String RESERVED_PREFIX = "hfile.";
598 static final byte[] RESERVED_PREFIX_BYTES = Bytes.toBytes(RESERVED_PREFIX);
599 static final byte [] LASTKEY = Bytes.toBytes(RESERVED_PREFIX + "LASTKEY");
600 static final byte [] AVG_KEY_LEN = Bytes.toBytes(RESERVED_PREFIX + "AVG_KEY_LEN");
601 static final byte [] AVG_VALUE_LEN = Bytes.toBytes(RESERVED_PREFIX + "AVG_VALUE_LEN");
602 static final byte [] CREATE_TIME_TS = Bytes.toBytes(RESERVED_PREFIX + "CREATE_TIME_TS");
603 static final byte [] COMPARATOR = Bytes.toBytes(RESERVED_PREFIX + "COMPARATOR");
604 static final byte [] TAGS_COMPRESSED = Bytes.toBytes(RESERVED_PREFIX + "TAGS_COMPRESSED");
605 public static final byte [] MAX_TAGS_LEN = Bytes.toBytes(RESERVED_PREFIX + "MAX_TAGS_LEN");
606 private final SortedMap<byte [], byte []> map = new TreeMap<byte [], byte []>(Bytes.BYTES_COMPARATOR);
607
608 public FileInfo() {
609 super();
610 }
611
612
613
614
615
616
617
618
619
620
621
622
623 public FileInfo append(final byte[] k, final byte[] v,
624 final boolean checkPrefix) throws IOException {
625 if (k == null || v == null) {
626 throw new NullPointerException("Key nor value may be null");
627 }
628 if (checkPrefix && isReservedFileInfoKey(k)) {
629 throw new IOException("Keys with a " + FileInfo.RESERVED_PREFIX
630 + " are reserved");
631 }
632 put(k, v);
633 return this;
634 }
635
636 public void clear() {
637 this.map.clear();
638 }
639
640 public Comparator<? super byte[]> comparator() {
641 return map.comparator();
642 }
643
644 public boolean containsKey(Object key) {
645 return map.containsKey(key);
646 }
647
648 public boolean containsValue(Object value) {
649 return map.containsValue(value);
650 }
651
652 public Set<java.util.Map.Entry<byte[], byte[]>> entrySet() {
653 return map.entrySet();
654 }
655
656 public boolean equals(Object o) {
657 return map.equals(o);
658 }
659
660 public byte[] firstKey() {
661 return map.firstKey();
662 }
663
664 public byte[] get(Object key) {
665 return map.get(key);
666 }
667
668 public int hashCode() {
669 return map.hashCode();
670 }
671
672 public SortedMap<byte[], byte[]> headMap(byte[] toKey) {
673 return this.map.headMap(toKey);
674 }
675
676 public boolean isEmpty() {
677 return map.isEmpty();
678 }
679
680 public Set<byte[]> keySet() {
681 return map.keySet();
682 }
683
684 public byte[] lastKey() {
685 return map.lastKey();
686 }
687
688 public byte[] put(byte[] key, byte[] value) {
689 return this.map.put(key, value);
690 }
691
692 public void putAll(Map<? extends byte[], ? extends byte[]> m) {
693 this.map.putAll(m);
694 }
695
696 public byte[] remove(Object key) {
697 return this.map.remove(key);
698 }
699
700 public int size() {
701 return map.size();
702 }
703
704 public SortedMap<byte[], byte[]> subMap(byte[] fromKey, byte[] toKey) {
705 return this.map.subMap(fromKey, toKey);
706 }
707
708 public SortedMap<byte[], byte[]> tailMap(byte[] fromKey) {
709 return this.map.tailMap(fromKey);
710 }
711
712 public Collection<byte[]> values() {
713 return map.values();
714 }
715
716
717
718
719
720
721
722
723 void write(final DataOutputStream out) throws IOException {
724 HFileProtos.FileInfoProto.Builder builder = HFileProtos.FileInfoProto.newBuilder();
725 for (Map.Entry<byte [], byte[]> e: this.map.entrySet()) {
726 HBaseProtos.BytesBytesPair.Builder bbpBuilder = HBaseProtos.BytesBytesPair.newBuilder();
727 bbpBuilder.setFirst(ByteStringer.wrap(e.getKey()));
728 bbpBuilder.setSecond(ByteStringer.wrap(e.getValue()));
729 builder.addMapEntry(bbpBuilder.build());
730 }
731 out.write(ProtobufUtil.PB_MAGIC);
732 builder.build().writeDelimitedTo(out);
733 }
734
735
736
737
738
739
740
741
742 void read(final DataInputStream in) throws IOException {
743
744 int pblen = ProtobufUtil.lengthOfPBMagic();
745 byte [] pbuf = new byte[pblen];
746 if (in.markSupported()) in.mark(pblen);
747 int read = in.read(pbuf);
748 if (read != pblen) throw new IOException("read=" + read + ", wanted=" + pblen);
749 if (ProtobufUtil.isPBMagicPrefix(pbuf)) {
750 parsePB(HFileProtos.FileInfoProto.parseDelimitedFrom(in));
751 } else {
752 if (in.markSupported()) {
753 in.reset();
754 parseWritable(in);
755 } else {
756
757 ByteArrayInputStream bais = new ByteArrayInputStream(pbuf);
758 SequenceInputStream sis = new SequenceInputStream(bais, in);
759
760
761
762 parseWritable(new DataInputStream(sis));
763 }
764 }
765 }
766
767
768
769
770
771
772 void parseWritable(final DataInputStream in) throws IOException {
773
774 this.map.clear();
775
776 int entries = in.readInt();
777
778 for (int i = 0; i < entries; i++) {
779 byte [] key = Bytes.readByteArray(in);
780
781 in.readByte();
782 byte [] value = Bytes.readByteArray(in);
783 this.map.put(key, value);
784 }
785 }
786
787
788
789
790
791 void parsePB(final HFileProtos.FileInfoProto fip) {
792 this.map.clear();
793 for (BytesBytesPair pair: fip.getMapEntryList()) {
794 this.map.put(pair.getFirst().toByteArray(), pair.getSecond().toByteArray());
795 }
796 }
797 }
798
799
800 public static boolean isReservedFileInfoKey(byte[] key) {
801 return Bytes.startsWith(key, FileInfo.RESERVED_PREFIX_BYTES);
802 }
803
804
805
806
807
808
809
810
811
812
813
814
815
816 public static String[] getSupportedCompressionAlgorithms() {
817 return Compression.getSupportedAlgorithms();
818 }
819
820
821
822
823
824
825 static int longToInt(final long l) {
826
827
828 return (int)(l & 0x00000000ffffffffL);
829 }
830
831
832
833
834
835
836
837
838
839
840 static List<Path> getStoreFiles(FileSystem fs, Path regionDir)
841 throws IOException {
842 List<Path> regionHFiles = new ArrayList<Path>();
843 PathFilter dirFilter = new FSUtils.DirFilter(fs);
844 FileStatus[] familyDirs = fs.listStatus(regionDir, dirFilter);
845 for(FileStatus dir : familyDirs) {
846 FileStatus[] files = fs.listStatus(dir.getPath());
847 for (FileStatus file : files) {
848 if (!file.isDirectory() &&
849 (!file.getPath().toString().contains(HConstants.HREGION_OLDLOGDIR_NAME)) &&
850 (!file.getPath().toString().contains(HConstants.RECOVERED_EDITS_DIR))) {
851 regionHFiles.add(file.getPath());
852 }
853 }
854 }
855 return regionHFiles;
856 }
857
858
859
860
861
862
863
864
865
866
867 public static void checkFormatVersion(int version)
868 throws IllegalArgumentException {
869 if (version < MIN_FORMAT_VERSION || version > MAX_FORMAT_VERSION) {
870 throw new IllegalArgumentException("Invalid HFile version: " + version
871 + " (expected to be " + "between " + MIN_FORMAT_VERSION + " and "
872 + MAX_FORMAT_VERSION + ")");
873 }
874 }
875
876 public static void main(String[] args) throws Exception {
877
878 HFilePrettyPrinter.main(args);
879 }
880 }