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.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.NavigableSet;
28 import java.util.concurrent.ConcurrentSkipListSet;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.fs.FileSystem;
34 import org.apache.hadoop.fs.Path;
35 import org.apache.hadoop.hbase.Cell;
36 import org.apache.hadoop.hbase.CellUtil;
37 import org.apache.hadoop.hbase.HBaseConfiguration;
38 import org.apache.hadoop.hbase.HBaseTestingUtility;
39 import org.apache.hadoop.hbase.HColumnDescriptor;
40 import org.apache.hadoop.hbase.HRegionInfo;
41 import org.apache.hadoop.hbase.HTableDescriptor;
42 import org.apache.hadoop.hbase.KeyValue;
43 import org.apache.hadoop.hbase.testclassification.MediumTests;
44 import org.apache.hadoop.hbase.TableName;
45 import org.apache.hadoop.hbase.Tag;
46 import org.apache.hadoop.hbase.TagType;
47 import org.apache.hadoop.hbase.client.Get;
48 import org.apache.hadoop.hbase.client.Scan;
49 import org.apache.hadoop.hbase.mob.MobConstants;
50 import org.apache.hadoop.hbase.mob.MobUtils;
51 import org.apache.hadoop.hbase.monitoring.MonitoredTask;
52 import org.apache.hadoop.hbase.wal.WAL;
53 import org.apache.hadoop.hbase.wal.WALFactory;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.FSUtils;
56 import org.junit.Assert;
57 import org.junit.Before;
58 import org.junit.Rule;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61 import org.junit.rules.TestName;
62 import org.mockito.Mockito;
63
64 @Category(MediumTests.class)
65 public class TestHMobStore {
66 public static final Log LOG = LogFactory.getLog(TestHMobStore.class);
67 @Rule public TestName name = new TestName();
68
69 private HMobStore store;
70 private HRegion region;
71 private HColumnDescriptor hcd;
72 private FileSystem fs;
73 private byte [] table = Bytes.toBytes("table");
74 private byte [] family = Bytes.toBytes("family");
75 private byte [] row = Bytes.toBytes("row");
76 private byte [] row2 = Bytes.toBytes("row2");
77 private byte [] qf1 = Bytes.toBytes("qf1");
78 private byte [] qf2 = Bytes.toBytes("qf2");
79 private byte [] qf3 = Bytes.toBytes("qf3");
80 private byte [] qf4 = Bytes.toBytes("qf4");
81 private byte [] qf5 = Bytes.toBytes("qf5");
82 private byte [] qf6 = Bytes.toBytes("qf6");
83 private byte[] value = Bytes.toBytes("value");
84 private byte[] value2 = Bytes.toBytes("value2");
85 private Path mobFilePath;
86 private Date currentDate = new Date();
87 private KeyValue seekKey1;
88 private KeyValue seekKey2;
89 private KeyValue seekKey3;
90 private NavigableSet<byte[]> qualifiers =
91 new ConcurrentSkipListSet<byte[]>(Bytes.BYTES_COMPARATOR);
92 private List<Cell> expected = new ArrayList<Cell>();
93 private long id = System.currentTimeMillis();
94 private Get get = new Get(row);
95 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
96 private final String DIR = TEST_UTIL.getDataTestDir("TestHMobStore").toString();
97
98
99
100
101
102 @Before
103 public void setUp() throws Exception {
104 qualifiers.add(qf1);
105 qualifiers.add(qf3);
106 qualifiers.add(qf5);
107
108 Iterator<byte[]> iter = qualifiers.iterator();
109 while(iter.hasNext()){
110 byte [] next = iter.next();
111 expected.add(new KeyValue(row, family, next, 1, value));
112 get.addColumn(family, next);
113 get.setMaxVersions();
114 }
115 }
116
117 private void init(String methodName, Configuration conf, boolean testStore)
118 throws IOException {
119 hcd = new HColumnDescriptor(family);
120 hcd.setMobEnabled(true);
121 hcd.setMobThreshold(3L);
122 hcd.setMaxVersions(4);
123 init(methodName, conf, hcd, testStore);
124 }
125
126 private void init(String methodName, Configuration conf,
127 HColumnDescriptor hcd, boolean testStore) throws IOException {
128 conf.setInt("hfile.format.version", 3);
129 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(table));
130 init(methodName, conf, htd, hcd, testStore);
131 }
132
133 private void init(String methodName, Configuration conf, HTableDescriptor htd,
134 HColumnDescriptor hcd, boolean testStore) throws IOException {
135
136 Path basedir = new Path(DIR+methodName);
137 Path tableDir = FSUtils.getTableDir(basedir, htd.getTableName());
138 String logName = "logs";
139 Path logdir = new Path(basedir, logName);
140 FileSystem fs = FileSystem.get(conf);
141 fs.delete(logdir, true);
142
143 htd.addFamily(hcd);
144 HRegionInfo info = new HRegionInfo(htd.getTableName(), null, null, false);
145 final Configuration walConf = new Configuration(conf);
146 FSUtils.setRootDir(walConf, basedir);
147 final WALFactory wals = new WALFactory(walConf, null, methodName);
148 region = new HRegion(tableDir, wals.getWAL(info.getEncodedNameAsBytes()), fs, conf,
149 info, htd, null);
150
151 store = new HMobStore(region, hcd, conf);
152 if(testStore) {
153 init(conf, hcd);
154 }
155 }
156
157 private void init(Configuration conf, HColumnDescriptor hcd)
158 throws IOException {
159 Path basedir = FSUtils.getRootDir(conf);
160 fs = FileSystem.get(conf);
161 Path homePath = new Path(basedir, Bytes.toString(family) + Path.SEPARATOR
162 + Bytes.toString(family));
163 fs.mkdirs(homePath);
164
165 KeyValue key1 = new KeyValue(row, family, qf1, 1, value);
166 KeyValue key2 = new KeyValue(row, family, qf2, 1, value);
167 KeyValue key3 = new KeyValue(row2, family, qf3, 1, value2);
168 KeyValue[] keys = new KeyValue[] { key1, key2, key3 };
169 int maxKeyCount = keys.length;
170 StoreFile.Writer mobWriter = store.createWriterInTmp(currentDate, maxKeyCount,
171 hcd.getCompactionCompression(), region.getRegionInfo().getStartKey());
172 mobFilePath = mobWriter.getPath();
173
174 mobWriter.append(key1);
175 mobWriter.append(key2);
176 mobWriter.append(key3);
177 mobWriter.close();
178
179 String targetPathName = MobUtils.formatDate(currentDate);
180 byte[] referenceValue = Bytes.toBytes(targetPathName + Path.SEPARATOR + mobFilePath.getName());
181 Tag tableNameTag = new Tag(TagType.MOB_TABLE_NAME_TAG_TYPE, store.getTableName().getName());
182 KeyValue kv1 = new KeyValue(row, family, qf1, Long.MAX_VALUE, referenceValue);
183 KeyValue kv2 = new KeyValue(row, family, qf2, Long.MAX_VALUE, referenceValue);
184 KeyValue kv3 = new KeyValue(row2, family, qf3, Long.MAX_VALUE, referenceValue);
185 seekKey1 = MobUtils.createMobRefKeyValue(kv1, referenceValue, tableNameTag);
186 seekKey2 = MobUtils.createMobRefKeyValue(kv2, referenceValue, tableNameTag);
187 seekKey3 = MobUtils.createMobRefKeyValue(kv3, referenceValue, tableNameTag);
188 }
189
190
191
192
193
194 @Test
195 public void testGetFromMemStore() throws IOException {
196 final Configuration conf = HBaseConfiguration.create();
197 init(name.getMethodName(), conf, false);
198
199
200 this.store.add(new KeyValue(row, family, qf1, 1, value));
201 this.store.add(new KeyValue(row, family, qf2, 1, value));
202 this.store.add(new KeyValue(row, family, qf3, 1, value));
203 this.store.add(new KeyValue(row, family, qf4, 1, value));
204 this.store.add(new KeyValue(row, family, qf5, 1, value));
205 this.store.add(new KeyValue(row, family, qf6, 1, value));
206
207 Scan scan = new Scan(get);
208 InternalScanner scanner = (InternalScanner) store.getScanner(scan,
209 scan.getFamilyMap().get(store.getFamily().getName()),
210 0);
211
212 List<Cell> results = new ArrayList<Cell>();
213 scanner.next(results);
214 Collections.sort(results, KeyValue.COMPARATOR);
215 scanner.close();
216
217
218 Assert.assertEquals(expected.size(), results.size());
219 for(int i=0; i<results.size(); i++) {
220
221 Assert.assertEquals(expected.get(i), results.get(i));
222 }
223 }
224
225
226
227
228
229 @Test
230 public void testGetFromFiles() throws IOException {
231 final Configuration conf = TEST_UTIL.getConfiguration();
232 init(name.getMethodName(), conf, false);
233
234
235 this.store.add(new KeyValue(row, family, qf1, 1, value));
236 this.store.add(new KeyValue(row, family, qf2, 1, value));
237
238 flush(1);
239
240
241 this.store.add(new KeyValue(row, family, qf3, 1, value));
242 this.store.add(new KeyValue(row, family, qf4, 1, value));
243
244 flush(2);
245
246
247 this.store.add(new KeyValue(row, family, qf5, 1, value));
248 this.store.add(new KeyValue(row, family, qf6, 1, value));
249
250 flush(3);
251
252 Scan scan = new Scan(get);
253 InternalScanner scanner = (InternalScanner) store.getScanner(scan,
254 scan.getFamilyMap().get(store.getFamily().getName()),
255 0);
256
257 List<Cell> results = new ArrayList<Cell>();
258 scanner.next(results);
259 Collections.sort(results, KeyValue.COMPARATOR);
260 scanner.close();
261
262
263 Assert.assertEquals(expected.size(), results.size());
264 for(int i=0; i<results.size(); i++) {
265 Assert.assertEquals(expected.get(i), results.get(i));
266 }
267 }
268
269
270
271
272
273 @Test
274 public void testGetReferencesFromFiles() throws IOException {
275 final Configuration conf = HBaseConfiguration.create();
276 init(name.getMethodName(), conf, false);
277
278
279 this.store.add(new KeyValue(row, family, qf1, 1, value));
280 this.store.add(new KeyValue(row, family, qf2, 1, value));
281
282 flush(1);
283
284
285 this.store.add(new KeyValue(row, family, qf3, 1, value));
286 this.store.add(new KeyValue(row, family, qf4, 1, value));
287
288 flush(2);
289
290
291 this.store.add(new KeyValue(row, family, qf5, 1, value));
292 this.store.add(new KeyValue(row, family, qf6, 1, value));
293
294 flush(3);
295
296 Scan scan = new Scan(get);
297 scan.setAttribute(MobConstants.MOB_SCAN_RAW, Bytes.toBytes(Boolean.TRUE));
298 InternalScanner scanner = (InternalScanner) store.getScanner(scan,
299 scan.getFamilyMap().get(store.getFamily().getName()),
300 0);
301
302 List<Cell> results = new ArrayList<Cell>();
303 scanner.next(results);
304 Collections.sort(results, KeyValue.COMPARATOR);
305 scanner.close();
306
307
308 Assert.assertEquals(expected.size(), results.size());
309 for(int i=0; i<results.size(); i++) {
310 Cell cell = results.get(i);
311 Assert.assertTrue(MobUtils.isMobReferenceCell(cell));
312 }
313 }
314
315
316
317
318
319 @Test
320 public void testGetFromMemStoreAndFiles() throws IOException {
321
322 final Configuration conf = HBaseConfiguration.create();
323
324 init(name.getMethodName(), conf, false);
325
326
327 this.store.add(new KeyValue(row, family, qf1, 1, value));
328 this.store.add(new KeyValue(row, family, qf2, 1, value));
329
330 flush(1);
331
332
333 this.store.add(new KeyValue(row, family, qf3, 1, value));
334 this.store.add(new KeyValue(row, family, qf4, 1, value));
335
336 flush(2);
337
338
339 this.store.add(new KeyValue(row, family, qf5, 1, value));
340 this.store.add(new KeyValue(row, family, qf6, 1, value));
341
342 Scan scan = new Scan(get);
343 InternalScanner scanner = (InternalScanner) store.getScanner(scan,
344 scan.getFamilyMap().get(store.getFamily().getName()),
345 0);
346
347 List<Cell> results = new ArrayList<Cell>();
348 scanner.next(results);
349 Collections.sort(results, KeyValue.COMPARATOR);
350 scanner.close();
351
352
353 Assert.assertEquals(expected.size(), results.size());
354 for(int i=0; i<results.size(); i++) {
355 Assert.assertEquals(expected.get(i), results.get(i));
356 }
357 }
358
359
360
361
362
363 @Test
364 public void testMobCellSizeThreshold() throws IOException {
365
366 final Configuration conf = HBaseConfiguration.create();
367
368 HColumnDescriptor hcd;
369 hcd = new HColumnDescriptor(family);
370 hcd.setMobEnabled(true);
371 hcd.setMobThreshold(100);
372 hcd.setMaxVersions(4);
373 init(name.getMethodName(), conf, hcd, false);
374
375
376 this.store.add(new KeyValue(row, family, qf1, 1, value));
377 this.store.add(new KeyValue(row, family, qf2, 1, value));
378
379 flush(1);
380
381
382 this.store.add(new KeyValue(row, family, qf3, 1, value));
383 this.store.add(new KeyValue(row, family, qf4, 1, value));
384
385 flush(2);
386
387
388 this.store.add(new KeyValue(row, family, qf5, 1, value));
389 this.store.add(new KeyValue(row, family, qf6, 1, value));
390
391 flush(3);
392
393 Scan scan = new Scan(get);
394 scan.setAttribute(MobConstants.MOB_SCAN_RAW, Bytes.toBytes(Boolean.TRUE));
395 InternalScanner scanner = (InternalScanner) store.getScanner(scan,
396 scan.getFamilyMap().get(store.getFamily().getName()),
397 0);
398
399 List<Cell> results = new ArrayList<Cell>();
400 scanner.next(results);
401 Collections.sort(results, KeyValue.COMPARATOR);
402 scanner.close();
403
404
405 Assert.assertEquals(expected.size(), results.size());
406 for(int i=0; i<results.size(); i++) {
407 Cell cell = results.get(i);
408
409 Assert.assertFalse(MobUtils.isMobReferenceCell(cell));
410 Assert.assertEquals(expected.get(i), results.get(i));
411 Assert.assertEquals(100, store.getFamily().getMobThreshold());
412 }
413 }
414
415 @Test
416 public void testCommitFile() throws Exception {
417 final Configuration conf = HBaseConfiguration.create();
418 init(name.getMethodName(), conf, true);
419 String targetPathName = MobUtils.formatDate(new Date());
420 Path targetPath = new Path(store.getPath(), (targetPathName
421 + Path.SEPARATOR + mobFilePath.getName()));
422 fs.delete(targetPath, true);
423 Assert.assertFalse(fs.exists(targetPath));
424
425 store.commitFile(mobFilePath, targetPath);
426 Assert.assertTrue(fs.exists(targetPath));
427 }
428
429 @Test
430 public void testResolve() throws Exception {
431 final Configuration conf = HBaseConfiguration.create();
432 init(name.getMethodName(), conf, true);
433 String targetPathName = MobUtils.formatDate(currentDate);
434 Path targetPath = new Path(store.getPath(), targetPathName);
435 store.commitFile(mobFilePath, targetPath);
436
437 Cell resultCell1 = store.resolve(seekKey1, false);
438 Cell resultCell2 = store.resolve(seekKey2, false);
439 Cell resultCell3 = store.resolve(seekKey3, false);
440
441 Assert.assertEquals(Bytes.toString(value),
442 Bytes.toString(CellUtil.cloneValue(resultCell1)));
443 Assert.assertEquals(Bytes.toString(value),
444 Bytes.toString(CellUtil.cloneValue(resultCell2)));
445 Assert.assertEquals(Bytes.toString(value2),
446 Bytes.toString(CellUtil.cloneValue(resultCell3)));
447 }
448
449
450
451
452
453
454 private void flush(int storeFilesSize) throws IOException{
455 this.store.snapshot();
456 flushStore(store, id++);
457 Assert.assertEquals(storeFilesSize, this.store.getStorefiles().size());
458 Assert.assertEquals(0, ((DefaultMemStore)this.store.memstore).cellSet.size());
459 }
460
461
462
463
464
465
466
467 private static void flushStore(HMobStore store, long id) throws IOException {
468 StoreFlushContext storeFlushCtx = store.createFlushContext(id);
469 storeFlushCtx.prepare();
470 storeFlushCtx.flushCache(Mockito.mock(MonitoredTask.class));
471 storeFlushCtx.commit(Mockito.mock(MonitoredTask.class));
472 }
473 }