View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
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     * Setup
100    * @throws Exception
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(); // all versions.
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     //Setting up tje Region and Store
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    * Getting data from memstore
192    * @throws IOException
193    */
194   @Test
195   public void testGetFromMemStore() throws IOException {
196     final Configuration conf = HBaseConfiguration.create();
197     init(name.getMethodName(), conf, false);
198 
199     //Put data in memstore
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     //Compare
218     Assert.assertEquals(expected.size(), results.size());
219     for(int i=0; i<results.size(); i++) {
220       // Verify the values
221       Assert.assertEquals(expected.get(i), results.get(i));
222     }
223   }
224 
225   /**
226    * Getting MOB data from files
227    * @throws IOException
228    */
229   @Test
230   public void testGetFromFiles() throws IOException {
231     final Configuration conf = TEST_UTIL.getConfiguration();
232     init(name.getMethodName(), conf, false);
233 
234     //Put data in memstore
235     this.store.add(new KeyValue(row, family, qf1, 1, value));
236     this.store.add(new KeyValue(row, family, qf2, 1, value));
237     //flush
238     flush(1);
239 
240     //Add more data
241     this.store.add(new KeyValue(row, family, qf3, 1, value));
242     this.store.add(new KeyValue(row, family, qf4, 1, value));
243     //flush
244     flush(2);
245 
246     //Add more data
247     this.store.add(new KeyValue(row, family, qf5, 1, value));
248     this.store.add(new KeyValue(row, family, qf6, 1, value));
249     //flush
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     //Compare
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    * Getting the reference data from files
271    * @throws IOException
272    */
273   @Test
274   public void testGetReferencesFromFiles() throws IOException {
275     final Configuration conf = HBaseConfiguration.create();
276     init(name.getMethodName(), conf, false);
277 
278     //Put data in memstore
279     this.store.add(new KeyValue(row, family, qf1, 1, value));
280     this.store.add(new KeyValue(row, family, qf2, 1, value));
281     //flush
282     flush(1);
283 
284     //Add more data
285     this.store.add(new KeyValue(row, family, qf3, 1, value));
286     this.store.add(new KeyValue(row, family, qf4, 1, value));
287     //flush
288     flush(2);
289 
290     //Add more data
291     this.store.add(new KeyValue(row, family, qf5, 1, value));
292     this.store.add(new KeyValue(row, family, qf6, 1, value));
293     //flush
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     //Compare
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    * Getting data from memstore and files
317    * @throws IOException
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     //Put data in memstore
327     this.store.add(new KeyValue(row, family, qf1, 1, value));
328     this.store.add(new KeyValue(row, family, qf2, 1, value));
329     //flush
330     flush(1);
331 
332     //Add more data
333     this.store.add(new KeyValue(row, family, qf3, 1, value));
334     this.store.add(new KeyValue(row, family, qf4, 1, value));
335     //flush
336     flush(2);
337 
338     //Add more data
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     //Compare
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    * Getting data from memstore and files
361    * @throws IOException
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     //Put data in memstore
376     this.store.add(new KeyValue(row, family, qf1, 1, value));
377     this.store.add(new KeyValue(row, family, qf2, 1, value));
378     //flush
379     flush(1);
380 
381     //Add more data
382     this.store.add(new KeyValue(row, family, qf3, 1, value));
383     this.store.add(new KeyValue(row, family, qf4, 1, value));
384     //flush
385     flush(2);
386 
387     //Add more data
388     this.store.add(new KeyValue(row, family, qf5, 1, value));
389     this.store.add(new KeyValue(row, family, qf6, 1, value));
390     //flush
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     //Compare
405     Assert.assertEquals(expected.size(), results.size());
406     for(int i=0; i<results.size(); i++) {
407       Cell cell = results.get(i);
408       //this is not mob reference cell.
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     //commit file
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     //resolve
437     Cell resultCell1 = store.resolve(seekKey1, false);
438     Cell resultCell2 = store.resolve(seekKey2, false);
439     Cell resultCell3 = store.resolve(seekKey3, false);
440     //compare
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    * Flush the memstore
451    * @param storeFilesSize
452    * @throws IOException
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    * Flush the memstore
463    * @param store
464    * @param id
465    * @throws IOException
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 }