1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.io.hfile;
19
20 import static org.junit.Assert.*;
21
22 import java.io.IOException;
23 import java.util.Random;
24
25 import org.apache.hadoop.conf.Configuration;
26 import org.apache.hadoop.fs.FileSystem;
27 import org.apache.hadoop.fs.Path;
28 import org.apache.hadoop.hbase.HBaseTestingUtility;
29 import org.apache.hadoop.hbase.HBaseConfiguration;
30 import org.apache.hadoop.hbase.HColumnDescriptor;
31 import org.apache.hadoop.hbase.util.Bytes;
32 import org.apache.hadoop.hbase.KeyValue;
33 import org.apache.hadoop.hbase.testclassification.SmallTests;
34 import org.apache.hadoop.hbase.fs.HFileSystem;
35 import org.apache.hadoop.hbase.regionserver.StoreFile;
36
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.experimental.categories.Category;
40
41 @Category(SmallTests.class)
42 public class TestPrefetch {
43
44 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
45
46 private static final int NUM_VALID_KEY_TYPES = KeyValue.Type.values().length - 2;
47 private static final int DATA_BLOCK_SIZE = 2048;
48 private static final int NUM_KV = 1000;
49 private static final Random RNG = new Random();
50
51 private Configuration conf;
52 private CacheConfig cacheConf;
53 private FileSystem fs;
54
55 @Before
56 public void setUp() throws IOException {
57 conf = TEST_UTIL.getConfiguration();
58 conf.setInt(HFile.FORMAT_VERSION_KEY, 3);
59 conf.setBoolean(CacheConfig.PREFETCH_BLOCKS_ON_OPEN_KEY, true);
60 fs = HFileSystem.get(conf);
61 CacheConfig.blockCacheDisabled = false;
62 cacheConf = new CacheConfig(conf);
63 }
64
65 @Test
66 public void testPrefetchSetInHCDWorks() {
67 HColumnDescriptor hcd = new HColumnDescriptor(Bytes.toBytes("f"));
68 hcd.setPrefetchBlocksOnOpen(true);
69 Configuration c = HBaseConfiguration.create();
70 assertFalse(c.getBoolean(CacheConfig.PREFETCH_BLOCKS_ON_OPEN_KEY, false));
71 CacheConfig cc = new CacheConfig(c, hcd);
72 assertTrue(cc.shouldPrefetchOnOpen());
73 }
74
75 @Test(timeout=60000)
76 public void testPrefetch() throws Exception {
77 Path storeFile = writeStoreFile();
78 readStoreFile(storeFile);
79 }
80
81 private void readStoreFile(Path storeFilePath) throws Exception {
82
83 HFileReaderV2 reader = (HFileReaderV2) HFile.createReader(fs,
84 storeFilePath, cacheConf, conf);
85
86 while (!((HFileReaderV3)reader).prefetchComplete()) {
87
88 Thread.sleep(1000);
89 }
90
91
92 BlockCache blockCache = cacheConf.getBlockCache();
93 long offset = 0;
94 while (offset < reader.getTrailer().getLoadOnOpenDataOffset()) {
95 HFileBlock block = reader.readBlock(offset, -1, false, true, false, true, null, null);
96 BlockCacheKey blockCacheKey = new BlockCacheKey(reader.getName(), offset);
97 boolean isCached = blockCache.getBlock(blockCacheKey, true, false, true) != null;
98 if (block.getBlockType() == BlockType.DATA ||
99 block.getBlockType() == BlockType.ROOT_INDEX ||
100 block.getBlockType() == BlockType.INTERMEDIATE_INDEX) {
101 assertTrue(isCached);
102 }
103 offset += block.getOnDiskSizeWithHeader();
104 }
105 }
106
107 private Path writeStoreFile() throws IOException {
108 Path storeFileParentDir = new Path(TEST_UTIL.getDataTestDir(), "TestPrefetch");
109 HFileContext meta = new HFileContextBuilder()
110 .withBlockSize(DATA_BLOCK_SIZE)
111 .build();
112 StoreFile.Writer sfw = new StoreFile.WriterBuilder(conf, cacheConf, fs)
113 .withOutputDir(storeFileParentDir)
114 .withComparator(KeyValue.COMPARATOR)
115 .withFileContext(meta)
116 .build();
117
118 final int rowLen = 32;
119 for (int i = 0; i < NUM_KV; ++i) {
120 byte[] k = TestHFileWriterV2.randomOrderedKey(RNG, i);
121 byte[] v = TestHFileWriterV2.randomValue(RNG);
122 int cfLen = RNG.nextInt(k.length - rowLen + 1);
123 KeyValue kv = new KeyValue(
124 k, 0, rowLen,
125 k, rowLen, cfLen,
126 k, rowLen + cfLen, k.length - rowLen - cfLen,
127 RNG.nextLong(),
128 generateKeyType(RNG),
129 v, 0, v.length);
130 sfw.append(kv);
131 }
132
133 sfw.close();
134 return sfw.getPath();
135 }
136
137 public static KeyValue.Type generateKeyType(Random rand) {
138 if (rand.nextBoolean()) {
139
140 return KeyValue.Type.Put;
141 } else {
142 KeyValue.Type keyType =
143 KeyValue.Type.values()[1 + rand.nextInt(NUM_VALID_KEY_TYPES)];
144 if (keyType == KeyValue.Type.Minimum || keyType == KeyValue.Type.Maximum)
145 {
146 throw new RuntimeException("Generated an invalid key type: " + keyType
147 + ". " + "Probably the layout of KeyValue.Type has changed.");
148 }
149 return keyType;
150 }
151 }
152
153 }