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.lang.management.ManagementFactory;
23  import java.lang.management.MemoryMXBean;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  import java.util.concurrent.atomic.AtomicLong;
28  import java.util.concurrent.atomic.AtomicReference;
29  
30  import junit.framework.TestCase;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.fs.Path;
36  import org.apache.hadoop.hbase.Cell;
37  import org.apache.hadoop.hbase.CellUtil;
38  import org.apache.hadoop.hbase.HBaseConfiguration;
39  import org.apache.hadoop.hbase.HBaseTestingUtility;
40  import org.apache.hadoop.hbase.HColumnDescriptor;
41  import org.apache.hadoop.hbase.HConstants;
42  import org.apache.hadoop.hbase.HRegionInfo;
43  import org.apache.hadoop.hbase.HTableDescriptor;
44  import org.apache.hadoop.hbase.KeepDeletedCells;
45  import org.apache.hadoop.hbase.KeyValue;
46  import org.apache.hadoop.hbase.KeyValueTestUtil;
47  import org.apache.hadoop.hbase.KeyValueUtil;
48  import org.apache.hadoop.hbase.TableName;
49  import org.apache.hadoop.hbase.client.Scan;
50  import org.apache.hadoop.hbase.exceptions.UnexpectedStateException;
51  import org.apache.hadoop.hbase.testclassification.MediumTests;
52  import org.apache.hadoop.hbase.util.Bytes;
53  import org.apache.hadoop.hbase.util.EnvironmentEdge;
54  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
55  import org.apache.hadoop.hbase.wal.WALFactory;
56  import org.junit.experimental.categories.Category;
57  
58  import com.google.common.base.Joiner;
59  import com.google.common.collect.Iterables;
60  import com.google.common.collect.Lists;
61  
62  import static org.mockito.Mockito.mock;
63  import static org.mockito.Mockito.when;
64  
65  /** memstore test case */
66  @Category(MediumTests.class)
67  public class TestDefaultMemStore extends TestCase {
68    private static final Log LOG = LogFactory.getLog(TestDefaultMemStore.class);
69    private DefaultMemStore memstore;
70    private static final int ROW_COUNT = 10;
71    private static final int QUALIFIER_COUNT = ROW_COUNT;
72    private static final byte [] FAMILY = Bytes.toBytes("column");
73    private MultiVersionConcurrencyControl mvcc;
74    private AtomicLong startSeqNum = new AtomicLong(0); 
75  
76    @Override
77    public void setUp() throws Exception {
78      super.setUp();
79      this.mvcc = new MultiVersionConcurrencyControl();
80      this.memstore = new DefaultMemStore();
81    }
82  
83    public void testPutSameKey() {
84      byte [] bytes = Bytes.toBytes(getName());
85      KeyValue kv = new KeyValue(bytes, bytes, bytes, bytes);
86      this.memstore.add(kv);
87      byte [] other = Bytes.toBytes("somethingelse");
88      KeyValue samekey = new KeyValue(bytes, bytes, bytes, other);
89      this.memstore.add(samekey);
90      Cell found = this.memstore.activeSection.getCellSkipListSet().first();
91      assertEquals(1, this.memstore.activeSection.getCellSkipListSet().sizeForTests());
92      assertTrue(Bytes.toString(found.getValue()), CellUtil.matchingValue(samekey, found));
93    }
94  
95    public void testPutSameCell() {
96      byte[] bytes = Bytes.toBytes(getName());
97      KeyValue kv = new KeyValue(bytes, bytes, bytes, bytes);
98      long sizeChangeForFirstCell = this.memstore.add(kv);
99      long sizeChangeForSecondCell = this.memstore.add(kv);
100     // make sure memstore size increase won't double-count MSLAB chunk size
101     assertEquals(DefaultMemStore.heapSizeChange(kv, true), sizeChangeForFirstCell);
102     if (this.memstore.activeSection.getMemStoreLAB() != null) {
103       // make sure memstore size increased when using MSLAB
104       assertEquals(memstore.getCellLength(kv), sizeChangeForSecondCell);
105       // make sure chunk size increased even when writing the same cell, if using MSLAB
106       if (this.memstore.activeSection.getMemStoreLAB() instanceof HeapMemStoreLAB) {
107         assertEquals(2 * memstore.getCellLength(kv),
108           ((HeapMemStoreLAB) this.memstore.activeSection.getMemStoreLAB())
109             .getCurrentChunk().getNextFreeOffset());
110       }
111     } else {
112       // make sure no memstore size change w/o MSLAB
113       assertEquals(0, sizeChangeForSecondCell);
114     }
115   }
116 
117   /**
118    * Test memstore snapshot happening while scanning.
119    * @throws IOException
120    */
121   public void testScanAcrossSnapshot() throws IOException {
122     int rowCount = addRows(this.memstore);
123     List<KeyValueScanner> memstorescanners = this.memstore.getScanners(0);
124     Scan scan = new Scan();
125     List<Cell> result = new ArrayList<Cell>();
126     Configuration conf = HBaseConfiguration.create();
127     ScanInfo scanInfo =
128         new ScanInfo(conf, null, 0, 1, HConstants.LATEST_TIMESTAMP, KeepDeletedCells.FALSE, 0,
129             this.memstore.comparator);
130     ScanType scanType = ScanType.USER_SCAN;
131     StoreScanner s = new StoreScanner(scan, scanInfo, scanType, null, memstorescanners);
132     int count = 0;
133     try {
134       while (s.next(result)) {
135         LOG.info(result);
136         count++;
137         // Row count is same as column count.
138         assertEquals(rowCount, result.size());
139         result.clear();
140       }
141     } finally {
142       s.close();
143     }
144     assertEquals(rowCount, count);
145     for (KeyValueScanner scanner : memstorescanners) {
146       scanner.close();
147     }
148 
149     memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
150     // Now assert can count same number even if a snapshot mid-scan.
151     s = new StoreScanner(scan, scanInfo, scanType, null, memstorescanners);
152     count = 0;
153     try {
154       while (s.next(result)) {
155         LOG.info(result);
156         // Assert the stuff is coming out in right order.
157         assertTrue(CellUtil.matchingRow(result.get(0), Bytes.toBytes(count)));
158         count++;
159         // Row count is same as column count.
160         assertEquals(rowCount, result.size());
161         if (count == 2) {
162           this.memstore.snapshot();
163           LOG.info("Snapshotted");
164         }
165         result.clear();
166       }
167     } finally {
168       s.close();
169     }
170     assertEquals(rowCount, count);
171     for (KeyValueScanner scanner : memstorescanners) {
172       scanner.close();
173     }
174     memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
175     // Assert that new values are seen in kvset as we scan.
176     long ts = System.currentTimeMillis();
177     s = new StoreScanner(scan, scanInfo, scanType, null, memstorescanners);
178     count = 0;
179     int snapshotIndex = 5;
180     try {
181       while (s.next(result)) {
182         LOG.info(result);
183         // Assert the stuff is coming out in right order.
184         assertTrue(CellUtil.matchingRow(result.get(0), Bytes.toBytes(count)));
185         // Row count is same as column count.
186         assertEquals("count=" + count + ", result=" + result, rowCount, result.size());
187         count++;
188         if (count == snapshotIndex) {
189           MemStoreSnapshot snapshot = this.memstore.snapshot();
190           this.memstore.clearSnapshot(snapshot.getId());
191           // Added more rows into kvset.  But the scanner wont see these rows.
192           addRows(this.memstore, ts);
193           LOG.info("Snapshotted, cleared it and then added values (which wont be seen)");
194         }
195         result.clear();
196       }
197     } finally {
198       s.close();
199     }
200     assertEquals(rowCount, count);
201   }
202 
203   /**
204    * A simple test which verifies the 3 possible states when scanning across snapshot.
205    * @throws IOException
206    * @throws CloneNotSupportedException 
207    */
208   public void testScanAcrossSnapshot2() throws IOException, CloneNotSupportedException {
209     // we are going to the scanning across snapshot with two kvs
210     // kv1 should always be returned before kv2
211     final byte[] one = Bytes.toBytes(1);
212     final byte[] two = Bytes.toBytes(2);
213     final byte[] f = Bytes.toBytes("f");
214     final byte[] q = Bytes.toBytes("q");
215     final byte[] v = Bytes.toBytes(3);
216 
217     final KeyValue kv1 = new KeyValue(one, f, q, v);
218     final KeyValue kv2 = new KeyValue(two, f, q, v);
219 
220     // use case 1: both kvs in kvset
221     this.memstore.add(kv1.clone());
222     this.memstore.add(kv2.clone());
223     verifyScanAcrossSnapshot2(kv1, kv2);
224 
225     // use case 2: both kvs in snapshot
226     this.memstore.snapshot();
227     verifyScanAcrossSnapshot2(kv1, kv2);
228 
229     // use case 3: first in snapshot second in kvset
230     this.memstore = new DefaultMemStore();
231     this.memstore.add(kv1.clone());
232     this.memstore.snapshot();
233     this.memstore.add(kv2.clone());
234     verifyScanAcrossSnapshot2(kv1, kv2);
235   }
236 
237   private void verifyScanAcrossSnapshot2(KeyValue kv1, KeyValue kv2)
238       throws IOException {
239     List<KeyValueScanner> memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
240     assertEquals(1, memstorescanners.size());
241     final KeyValueScanner scanner = memstorescanners.get(0);
242     scanner.seek(KeyValueUtil.createFirstOnRow(HConstants.EMPTY_START_ROW));
243     assertEquals(kv1, scanner.next());
244     assertEquals(kv2, scanner.next());
245     assertNull(scanner.next());
246   }
247 
248   private void assertScannerResults(KeyValueScanner scanner, KeyValue[] expected)
249       throws IOException {
250     scanner.seek(KeyValueUtil.createFirstOnRow(new byte[]{}));
251     List<Cell> returned = Lists.newArrayList();
252 
253     while (true) {
254       Cell next = scanner.next();
255       if (next == null) break;
256       returned.add(next);
257     }
258 
259     assertTrue(
260         "Got:\n" + Joiner.on("\n").join(returned) +
261         "\nExpected:\n" + Joiner.on("\n").join(expected),
262         Iterables.elementsEqual(Arrays.asList(expected), returned));
263     assertNull(scanner.peek());
264   }
265 
266   public void testMemstoreConcurrentControl() throws IOException {
267     final byte[] row = Bytes.toBytes(1);
268     final byte[] f = Bytes.toBytes("family");
269     final byte[] q1 = Bytes.toBytes("q1");
270     final byte[] q2 = Bytes.toBytes("q2");
271     final byte[] v = Bytes.toBytes("value");
272 
273     MultiVersionConcurrencyControl.WriteEntry w =
274         mvcc.begin();
275 
276     KeyValue kv1 = new KeyValue(row, f, q1, v);
277     kv1.setSequenceId(w.getWriteNumber());
278     memstore.add(kv1);
279 
280     assertTrue(this.memstore.getScanners(mvcc.getReadPoint()) == null);
281 
282     mvcc.completeAndWait(w);
283 
284     KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
285     assertScannerResults(s, new KeyValue[]{kv1});
286 
287     w = mvcc.begin();
288     KeyValue kv2 = new KeyValue(row, f, q2, v);
289     kv2.setSequenceId(w.getWriteNumber());
290     memstore.add(kv2);
291 
292     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
293     assertScannerResults(s, new KeyValue[]{kv1});
294 
295     mvcc.completeAndWait(w);
296 
297     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
298     assertScannerResults(s, new KeyValue[]{kv1, kv2});
299   }
300 
301   /**
302    * Regression test for HBASE-2616, HBASE-2670.
303    * When we insert a higher-memstoreTS version of a cell but with
304    * the same timestamp, we still need to provide consistent reads
305    * for the same scanner.
306    */
307   public void testMemstoreEditsVisibilityWithSameKey() throws IOException {
308     final byte[] row = Bytes.toBytes(1);
309     final byte[] f = Bytes.toBytes("family");
310     final byte[] q1 = Bytes.toBytes("q1");
311     final byte[] q2 = Bytes.toBytes("q2");
312     final byte[] v1 = Bytes.toBytes("value1");
313     final byte[] v2 = Bytes.toBytes("value2");
314 
315     // INSERT 1: Write both columns val1
316     MultiVersionConcurrencyControl.WriteEntry w =
317         mvcc.begin();
318 
319     KeyValue kv11 = new KeyValue(row, f, q1, v1);
320     kv11.setSequenceId(w.getWriteNumber());
321     memstore.add(kv11);
322 
323     KeyValue kv12 = new KeyValue(row, f, q2, v1);
324     kv12.setSequenceId(w.getWriteNumber());
325     memstore.add(kv12);
326     mvcc.completeAndWait(w);
327 
328     // BEFORE STARTING INSERT 2, SEE FIRST KVS
329     KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
330     assertScannerResults(s, new KeyValue[]{kv11, kv12});
331 
332     // START INSERT 2: Write both columns val2
333     w = mvcc.begin();
334     KeyValue kv21 = new KeyValue(row, f, q1, v2);
335     kv21.setSequenceId(w.getWriteNumber());
336     memstore.add(kv21);
337 
338     KeyValue kv22 = new KeyValue(row, f, q2, v2);
339     kv22.setSequenceId(w.getWriteNumber());
340     memstore.add(kv22);
341 
342     // BEFORE COMPLETING INSERT 2, SEE FIRST KVS
343     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
344     assertScannerResults(s, new KeyValue[]{kv11, kv12});
345 
346     // COMPLETE INSERT 2
347     mvcc.completeAndWait(w);
348 
349     // NOW SHOULD SEE NEW KVS IN ADDITION TO OLD KVS.
350     // See HBASE-1485 for discussion about what we should do with
351     // the duplicate-TS inserts
352     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
353     assertScannerResults(s, new KeyValue[]{kv21, kv11, kv22, kv12});
354   }
355 
356   /**
357    * When we insert a higher-memstoreTS deletion of a cell but with
358    * the same timestamp, we still need to provide consistent reads
359    * for the same scanner.
360    */
361   public void testMemstoreDeletesVisibilityWithSameKey() throws IOException {
362     final byte[] row = Bytes.toBytes(1);
363     final byte[] f = Bytes.toBytes("family");
364     final byte[] q1 = Bytes.toBytes("q1");
365     final byte[] q2 = Bytes.toBytes("q2");
366     final byte[] v1 = Bytes.toBytes("value1");
367     // INSERT 1: Write both columns val1
368     MultiVersionConcurrencyControl.WriteEntry w =
369         mvcc.begin();
370 
371     KeyValue kv11 = new KeyValue(row, f, q1, v1);
372     kv11.setSequenceId(w.getWriteNumber());
373     memstore.add(kv11);
374 
375     KeyValue kv12 = new KeyValue(row, f, q2, v1);
376     kv12.setSequenceId(w.getWriteNumber());
377     memstore.add(kv12);
378     mvcc.completeAndWait(w);
379 
380     // BEFORE STARTING INSERT 2, SEE FIRST KVS
381     KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
382     assertScannerResults(s, new KeyValue[]{kv11, kv12});
383 
384     // START DELETE: Insert delete for one of the columns
385     w = mvcc.begin();
386     KeyValue kvDel = new KeyValue(row, f, q2, kv11.getTimestamp(),
387         KeyValue.Type.DeleteColumn);
388     kvDel.setSequenceId(w.getWriteNumber());
389     memstore.add(kvDel);
390 
391     // BEFORE COMPLETING DELETE, SEE FIRST KVS
392     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
393     assertScannerResults(s, new KeyValue[]{kv11, kv12});
394 
395     // COMPLETE DELETE
396     mvcc.completeAndWait(w);
397 
398     // NOW WE SHOULD SEE DELETE
399     s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
400     assertScannerResults(s, new KeyValue[]{kv11, kvDel, kv12});
401   }
402 
403 
404   private static class ReadOwnWritesTester extends Thread {
405     static final int NUM_TRIES = 1000;
406 
407     final byte[] row;
408 
409     final byte[] f = Bytes.toBytes("family");
410     final byte[] q1 = Bytes.toBytes("q1");
411 
412     final MultiVersionConcurrencyControl mvcc;
413     final MemStore memstore;
414     final AtomicLong startSeqNum;
415 
416     AtomicReference<Throwable> caughtException;
417 
418 
419     public ReadOwnWritesTester(int id,
420                                MemStore memstore,
421                                MultiVersionConcurrencyControl mvcc,
422                                AtomicReference<Throwable> caughtException,
423                                AtomicLong startSeqNum)
424     {
425       this.mvcc = mvcc;
426       this.memstore = memstore;
427       this.caughtException = caughtException;
428       row = Bytes.toBytes(id);
429       this.startSeqNum = startSeqNum;
430     }
431 
432     public void run() {
433       try {
434         internalRun();
435       } catch (Throwable t) {
436         caughtException.compareAndSet(null, t);
437       }
438     }
439 
440     private void internalRun() throws IOException {
441       for (long i = 0; i < NUM_TRIES && caughtException.get() == null; i++) {
442         MultiVersionConcurrencyControl.WriteEntry w =
443             mvcc.begin();
444 
445         // Insert the sequence value (i)
446         byte[] v = Bytes.toBytes(i);
447 
448         KeyValue kv = new KeyValue(row, f, q1, i, v);
449         kv.setSequenceId(w.getWriteNumber());
450         memstore.add(kv);
451         mvcc.completeAndWait(w);
452 
453         // Assert that we can read back
454         KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
455         s.seek(kv);
456 
457         Cell ret = s.next();
458         assertNotNull("Didnt find own write at all", ret);
459         assertEquals("Didnt read own writes",
460                      kv.getTimestamp(), ret.getTimestamp());
461       }
462     }
463   }
464 
465   public void testReadOwnWritesUnderConcurrency() throws Throwable {
466 
467     int NUM_THREADS = 8;
468 
469     ReadOwnWritesTester threads[] = new ReadOwnWritesTester[NUM_THREADS];
470     AtomicReference<Throwable> caught = new AtomicReference<Throwable>();
471 
472     for (int i = 0; i < NUM_THREADS; i++) {
473       threads[i] = new ReadOwnWritesTester(i, memstore, mvcc, caught, this.startSeqNum);
474       threads[i].start();
475     }
476 
477     for (int i = 0; i < NUM_THREADS; i++) {
478       threads[i].join();
479     }
480 
481     if (caught.get() != null) {
482       throw caught.get();
483     }
484   }
485 
486   /**
487    * Test memstore snapshots
488    * @throws IOException
489    */
490   public void testSnapshotting() throws IOException {
491     final int snapshotCount = 5;
492     // Add some rows, run a snapshot. Do it a few times.
493     for (int i = 0; i < snapshotCount; i++) {
494       addRows(this.memstore);
495       runSnapshot(this.memstore);
496       assertEquals("History not being cleared", 0,
497         this.memstore.snapshotSection.getCellSkipListSet().sizeForTests());
498     }
499   }
500 
501   public void testMultipleVersionsSimple() throws Exception {
502     DefaultMemStore m = new DefaultMemStore(new Configuration(), KeyValue.COMPARATOR);
503     byte [] row = Bytes.toBytes("testRow");
504     byte [] family = Bytes.toBytes("testFamily");
505     byte [] qf = Bytes.toBytes("testQualifier");
506     long [] stamps = {1,2,3};
507     byte [][] values = {Bytes.toBytes("value0"), Bytes.toBytes("value1"),
508         Bytes.toBytes("value2")};
509     KeyValue key0 = new KeyValue(row, family, qf, stamps[0], values[0]);
510     KeyValue key1 = new KeyValue(row, family, qf, stamps[1], values[1]);
511     KeyValue key2 = new KeyValue(row, family, qf, stamps[2], values[2]);
512 
513     m.add(key0);
514     m.add(key1);
515     m.add(key2);
516 
517     assertTrue("Expected memstore to hold 3 values, actually has " +
518         m.activeSection.getCellSkipListSet().sizeForTests(),
519         m.activeSection.getCellSkipListSet().sizeForTests() == 3);
520   }
521 
522   //////////////////////////////////////////////////////////////////////////////
523   // Get tests
524   //////////////////////////////////////////////////////////////////////////////
525 
526   /** Test getNextRow from memstore
527    * @throws InterruptedException
528    */
529   public void testGetNextRow() throws Exception {
530     addRows(this.memstore);
531     // Add more versions to make it a little more interesting.
532     Thread.sleep(1);
533     addRows(this.memstore);
534     Cell closestToEmpty = this.memstore.getNextRow(KeyValue.LOWESTKEY);
535     assertTrue(KeyValue.COMPARATOR.compareRows(closestToEmpty,
536       new KeyValue(Bytes.toBytes(0), System.currentTimeMillis())) == 0);
537     for (int i = 0; i < ROW_COUNT; i++) {
538       Cell nr = this.memstore.getNextRow(new KeyValue(Bytes.toBytes(i),
539         System.currentTimeMillis()));
540       if (i + 1 == ROW_COUNT) {
541         assertEquals(nr, null);
542       } else {
543         assertTrue(KeyValue.COMPARATOR.compareRows(nr,
544           new KeyValue(Bytes.toBytes(i + 1), System.currentTimeMillis())) == 0);
545       }
546     }
547     //starting from each row, validate results should contain the starting row
548     Configuration conf = HBaseConfiguration.create();
549     for (int startRowId = 0; startRowId < ROW_COUNT; startRowId++) {
550       ScanInfo scanInfo = new ScanInfo(conf, FAMILY, 0, 1, Integer.MAX_VALUE,
551         KeepDeletedCells.FALSE, 0, this.memstore.comparator);
552       ScanType scanType = ScanType.USER_SCAN;
553       InternalScanner scanner = new StoreScanner(new Scan(
554           Bytes.toBytes(startRowId)), scanInfo, scanType, null,
555           memstore.getScanners(0));
556       List<Cell> results = new ArrayList<Cell>();
557       for (int i = 0; scanner.next(results); i++) {
558         int rowId = startRowId + i;
559         Cell left = results.get(0);
560         byte[] row1 = Bytes.toBytes(rowId);
561         assertTrue(
562             "Row name",
563             KeyValue.COMPARATOR.compareRows(left.getRowArray(), left.getRowOffset(),
564                 (int) left.getRowLength(), row1, 0, row1.length) == 0);
565         assertEquals("Count of columns", QUALIFIER_COUNT, results.size());
566         List<Cell> row = new ArrayList<Cell>();
567         for (Cell kv : results) {
568           row.add(kv);
569         }
570         isExpectedRowWithoutTimestamps(rowId, row);
571         // Clear out set.  Otherwise row results accumulate.
572         results.clear();
573       }
574     }
575   }
576 
577   public void testGet_memstoreAndSnapShot() throws IOException {
578     byte [] row = Bytes.toBytes("testrow");
579     byte [] fam = Bytes.toBytes("testfamily");
580     byte [] qf1 = Bytes.toBytes("testqualifier1");
581     byte [] qf2 = Bytes.toBytes("testqualifier2");
582     byte [] qf3 = Bytes.toBytes("testqualifier3");
583     byte [] qf4 = Bytes.toBytes("testqualifier4");
584     byte [] qf5 = Bytes.toBytes("testqualifier5");
585     byte [] val = Bytes.toBytes("testval");
586 
587     //Setting up memstore
588     memstore.add(new KeyValue(row, fam ,qf1, val));
589     memstore.add(new KeyValue(row, fam ,qf2, val));
590     memstore.add(new KeyValue(row, fam ,qf3, val));
591     //Creating a snapshot
592     memstore.snapshot();
593     assertEquals(3, memstore.snapshotSection.getCellSkipListSet().sizeForTests());
594     //Adding value to "new" memstore
595     assertEquals(0, memstore.activeSection.getCellSkipListSet().sizeForTests());
596     memstore.add(new KeyValue(row, fam ,qf4, val));
597     memstore.add(new KeyValue(row, fam ,qf5, val));
598     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
599   }
600 
601   //////////////////////////////////////////////////////////////////////////////
602   // Delete tests
603   //////////////////////////////////////////////////////////////////////////////
604   public void testGetWithDelete() throws IOException {
605     byte [] row = Bytes.toBytes("testrow");
606     byte [] fam = Bytes.toBytes("testfamily");
607     byte [] qf1 = Bytes.toBytes("testqualifier");
608     byte [] val = Bytes.toBytes("testval");
609 
610     long ts1 = System.nanoTime();
611     KeyValue put1 = new KeyValue(row, fam, qf1, ts1, val);
612     long ts2 = ts1 + 1;
613     KeyValue put2 = new KeyValue(row, fam, qf1, ts2, val);
614     long ts3 = ts2 +1;
615     KeyValue put3 = new KeyValue(row, fam, qf1, ts3, val);
616     memstore.add(put1);
617     memstore.add(put2);
618     memstore.add(put3);
619 
620     assertEquals(3, memstore.activeSection.getCellSkipListSet().sizeForTests());
621 
622     KeyValue del2 = new KeyValue(row, fam, qf1, ts2, KeyValue.Type.Delete, val);
623     memstore.delete(del2);
624 
625     List<Cell> expected = new ArrayList<Cell>();
626     expected.add(put3);
627     expected.add(del2);
628     expected.add(put2);
629     expected.add(put1);
630 
631     assertEquals(4, memstore.activeSection.getCellSkipListSet().sizeForTests());
632     int i = 0;
633     for(Cell cell : memstore.activeSection.getCellSkipListSet()) {
634       assertEquals(expected.get(i++), cell);
635     }
636   }
637 
638   public void testGetWithDeleteColumn() throws IOException {
639     byte [] row = Bytes.toBytes("testrow");
640     byte [] fam = Bytes.toBytes("testfamily");
641     byte [] qf1 = Bytes.toBytes("testqualifier");
642     byte [] val = Bytes.toBytes("testval");
643 
644     long ts1 = System.nanoTime();
645     KeyValue put1 = new KeyValue(row, fam, qf1, ts1, val);
646     long ts2 = ts1 + 1;
647     KeyValue put2 = new KeyValue(row, fam, qf1, ts2, val);
648     long ts3 = ts2 +1;
649     KeyValue put3 = new KeyValue(row, fam, qf1, ts3, val);
650     memstore.add(put1);
651     memstore.add(put2);
652     memstore.add(put3);
653 
654     assertEquals(3, memstore.activeSection.getCellSkipListSet().sizeForTests());
655 
656     KeyValue del2 =
657       new KeyValue(row, fam, qf1, ts2, KeyValue.Type.DeleteColumn, val);
658     memstore.delete(del2);
659 
660     List<Cell> expected = new ArrayList<Cell>();
661     expected.add(put3);
662     expected.add(del2);
663     expected.add(put2);
664     expected.add(put1);
665 
666     assertEquals(4, memstore.activeSection.getCellSkipListSet().sizeForTests());
667     int i = 0;
668     for (Cell cell: memstore.activeSection.getCellSkipListSet()) {
669       assertEquals(expected.get(i++), cell);
670     }
671   }
672 
673   public void testGetWithDeleteFamily() throws IOException {
674     byte [] row = Bytes.toBytes("testrow");
675     byte [] fam = Bytes.toBytes("testfamily");
676     byte [] qf1 = Bytes.toBytes("testqualifier1");
677     byte [] qf2 = Bytes.toBytes("testqualifier2");
678     byte [] qf3 = Bytes.toBytes("testqualifier3");
679     byte [] val = Bytes.toBytes("testval");
680     long ts = System.nanoTime();
681 
682     KeyValue put1 = new KeyValue(row, fam, qf1, ts, val);
683     KeyValue put2 = new KeyValue(row, fam, qf2, ts, val);
684     KeyValue put3 = new KeyValue(row, fam, qf3, ts, val);
685     KeyValue put4 = new KeyValue(row, fam, qf3, ts+1, val);
686 
687     memstore.add(put1);
688     memstore.add(put2);
689     memstore.add(put3);
690     memstore.add(put4);
691 
692     KeyValue del =
693       new KeyValue(row, fam, null, ts, KeyValue.Type.DeleteFamily, val);
694     memstore.delete(del);
695 
696     List<Cell> expected = new ArrayList<Cell>();
697     expected.add(del);
698     expected.add(put1);
699     expected.add(put2);
700     expected.add(put4);
701     expected.add(put3);
702 
703     assertEquals(5, memstore.activeSection.getCellSkipListSet().sizeForTests());
704     int i = 0;
705     for (Cell cell: memstore.activeSection.getCellSkipListSet()) {
706       assertEquals(expected.get(i++), cell);
707     }
708   }
709 
710   public void testKeepDeleteInmemstore() {
711     byte [] row = Bytes.toBytes("testrow");
712     byte [] fam = Bytes.toBytes("testfamily");
713     byte [] qf = Bytes.toBytes("testqualifier");
714     byte [] val = Bytes.toBytes("testval");
715     long ts = System.nanoTime();
716     memstore.add(new KeyValue(row, fam, qf, ts, val));
717     KeyValue delete = new KeyValue(row, fam, qf, ts, KeyValue.Type.Delete, val);
718     memstore.delete(delete);
719     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
720     assertEquals(delete, memstore.activeSection.getCellSkipListSet().first());
721   }
722 
723   public void testRetainsDeleteVersion() throws IOException {
724     // add a put to memstore
725     memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"));
726 
727     // now process a specific delete:
728     KeyValue delete = KeyValueTestUtil.create(
729         "row1", "fam", "a", 100, KeyValue.Type.Delete, "dont-care");
730     memstore.delete(delete);
731 
732     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
733     assertEquals(delete, memstore.activeSection.getCellSkipListSet().first());
734   }
735   public void testRetainsDeleteColumn() throws IOException {
736     // add a put to memstore
737     memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"));
738 
739     // now process a specific delete:
740     KeyValue delete = KeyValueTestUtil.create("row1", "fam", "a", 100,
741         KeyValue.Type.DeleteColumn, "dont-care");
742     memstore.delete(delete);
743 
744     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
745     assertEquals(delete, memstore.activeSection.getCellSkipListSet().first());
746   }
747 
748   public void testRetainsDeleteFamily() throws IOException {
749     // add a put to memstore
750     memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"));
751 
752     // now process a specific delete:
753     KeyValue delete = KeyValueTestUtil.create("row1", "fam", "a", 100,
754         KeyValue.Type.DeleteFamily, "dont-care");
755     memstore.delete(delete);
756 
757     assertEquals(2, memstore.activeSection.getCellSkipListSet().sizeForTests());
758     assertEquals(delete, memstore.activeSection.getCellSkipListSet().first());
759   }
760 
761   ////////////////////////////////////
762   //Test for timestamps
763   ////////////////////////////////////
764 
765   /**
766    * Test to ensure correctness when using Memstore with multiple timestamps
767    */
768   public void testMultipleTimestamps() throws Exception {
769     long[] timestamps = new long[] {20,10,5,1};
770     Scan scan = new Scan();
771 
772     for (long timestamp: timestamps)
773       addRows(memstore,timestamp);
774 
775     byte[] fam = Bytes.toBytes("fam");
776     HColumnDescriptor hcd = mock(HColumnDescriptor.class);
777     when(hcd.getName()).thenReturn(fam);
778     Store store = mock(Store.class);
779     when(store.getFamily()).thenReturn(hcd);
780     scan.setColumnFamilyTimeRange(fam, 0, 2);
781     assertTrue(memstore.shouldSeek(scan, store, Long.MIN_VALUE));
782 
783     scan.setColumnFamilyTimeRange(fam, 20, 82);
784     assertTrue(memstore.shouldSeek(scan, store, Long.MIN_VALUE));
785 
786     scan.setColumnFamilyTimeRange(fam, 10, 20);
787     assertTrue(memstore.shouldSeek(scan, store, Long.MIN_VALUE));
788 
789     scan.setColumnFamilyTimeRange(fam, 8, 12);
790     assertTrue(memstore.shouldSeek(scan, store, Long.MIN_VALUE));
791 
792     scan.setColumnFamilyTimeRange(fam, 28, 42);
793     assertTrue(!memstore.shouldSeek(scan, store, Long.MIN_VALUE));
794   }
795 
796   ////////////////////////////////////
797   //Test for upsert with MSLAB
798   ////////////////////////////////////
799 
800   /**
801    * Test a pathological pattern that shows why we can't currently
802    * use the MSLAB for upsert workloads. This test inserts data
803    * in the following pattern:
804    *
805    * - row0001 through row1000 (fills up one 2M Chunk)
806    * - row0002 through row1001 (fills up another 2M chunk, leaves one reference
807    *   to the first chunk
808    * - row0003 through row1002 (another chunk, another dangling reference)
809    *
810    * This causes OOME pretty quickly if we use MSLAB for upsert
811    * since each 2M chunk is held onto by a single reference.
812    */
813   public void testUpsertMSLAB() throws Exception {
814     Configuration conf = HBaseConfiguration.create();
815     conf.setBoolean(DefaultMemStore.USEMSLAB_KEY, true);
816     memstore = new DefaultMemStore(conf, KeyValue.COMPARATOR);
817 
818     int ROW_SIZE = 2048;
819     byte[] qualifier = new byte[ROW_SIZE - 4];
820 
821     MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
822     for (int i = 0; i < 3; i++) { System.gc(); }
823     long usageBefore = bean.getHeapMemoryUsage().getUsed();
824 
825     long size = 0;
826     long ts=0;
827 
828     for (int newValue = 0; newValue < 1000; newValue++) {
829       for (int row = newValue; row < newValue + 1000; row++) {
830         byte[] rowBytes = Bytes.toBytes(row);
831         size += memstore.updateColumnValue(rowBytes, FAMILY, qualifier, newValue, ++ts);
832       }
833     }
834     System.out.println("Wrote " + ts + " vals");
835     for (int i = 0; i < 3; i++) { System.gc(); }
836     long usageAfter = bean.getHeapMemoryUsage().getUsed();
837     System.out.println("Memory used: " + (usageAfter - usageBefore)
838         + " (heapsize: " + memstore.heapSize() +
839         " size: " + size + ")");
840   }
841 
842   //////////////////////////////////////////////////////////////////////////////
843   // Helpers
844   //////////////////////////////////////////////////////////////////////////////
845   private static byte [] makeQualifier(final int i1, final int i2){
846     return Bytes.toBytes(Integer.toString(i1) + ";" +
847         Integer.toString(i2));
848   }
849 
850   /**
851    * Add keyvalues with a fixed memstoreTs, and checks that memstore size is decreased
852    * as older keyvalues are deleted from the memstore.
853    * @throws Exception
854    */
855   public void testUpsertMemstoreSize() throws Exception {
856     Configuration conf = HBaseConfiguration.create();
857     memstore = new DefaultMemStore(conf, KeyValue.COMPARATOR);
858     long oldSize = memstore.activeSection.getHeapSize().get();
859 
860     List<Cell> l = new ArrayList<Cell>();
861     KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
862     KeyValue kv2 = KeyValueTestUtil.create("r", "f", "q", 101, "v");
863     KeyValue kv3 = KeyValueTestUtil.create("r", "f", "q", 102, "v");
864 
865     kv1.setSequenceId(1); kv2.setSequenceId(1);kv3.setSequenceId(1);
866     l.add(kv1); l.add(kv2); l.add(kv3);
867 
868     this.memstore.upsert(l, 2, null);// readpoint is 2
869     long newSize = this.memstore.activeSection.getHeapSize().get();
870     assert(newSize > oldSize);
871     //The kv1 should be removed.
872     assert(memstore.activeSection.getCellSkipListSet().sizeForTests() == 2);
873 
874     KeyValue kv4 = KeyValueTestUtil.create("r", "f", "q", 104, "v");
875     kv4.setSequenceId(1);
876     l.clear(); l.add(kv4);
877     this.memstore.upsert(l, 3, null);
878     assertEquals(newSize, this.memstore.activeSection.getHeapSize().get());
879     //The kv2 should be removed.
880     assert(memstore.activeSection.getCellSkipListSet().sizeForTests() == 2);
881     //this.memstore = null;
882   }
883 
884   ////////////////////////////////////
885   // Test for periodic memstore flushes 
886   // based on time of oldest edit
887   ////////////////////////////////////
888 
889   /**
890    * Tests that the timeOfOldestEdit is updated correctly for the 
891    * various edit operations in memstore.
892    * @throws Exception
893    */
894   public void testUpdateToTimeOfOldestEdit() throws Exception {
895     try {
896       EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
897       EnvironmentEdgeManager.injectEdge(edge);
898       DefaultMemStore memstore = new DefaultMemStore();
899       long t = memstore.timeOfOldestEdit();
900       assertEquals(t, Long.MAX_VALUE);
901 
902       // test the case that the timeOfOldestEdit is updated after a KV add
903       memstore.add(KeyValueTestUtil.create("r", "f", "q", 100, "v"));
904       t = memstore.timeOfOldestEdit();
905       assertTrue(t == 1234);
906       // snapshot() will reset timeOfOldestEdit. The method will also assert the 
907       // value is reset to Long.MAX_VALUE
908       t = runSnapshot(memstore);
909 
910       // test the case that the timeOfOldestEdit is updated after a KV delete
911       memstore.delete(KeyValueTestUtil.create("r", "f", "q", 100, "v"));
912       t = memstore.timeOfOldestEdit();
913       assertTrue(t == 1234);
914       t = runSnapshot(memstore);
915 
916       // test the case that the timeOfOldestEdit is updated after a KV upsert
917       List<Cell> l = new ArrayList<Cell>();
918       KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
919       kv1.setSequenceId(100);
920       l.add(kv1);
921       memstore.upsert(l, 1000, null);
922       t = memstore.timeOfOldestEdit();
923       assertTrue(t == 1234);
924     } finally {
925       EnvironmentEdgeManager.reset();
926     }
927   }
928 
929   /**
930    * Tests the HRegion.shouldFlush method - adds an edit in the memstore
931    * and checks that shouldFlush returns true, and another where it disables
932    * the periodic flush functionality and tests whether shouldFlush returns
933    * false. 
934    * @throws Exception
935    */
936   public void testShouldFlush() throws Exception {
937     Configuration conf = new Configuration();
938     conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, 1000);
939     checkShouldFlush(conf, true);
940     // test disable flush
941     conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, 0);
942     checkShouldFlush(conf, false);
943   }
944 
945   private void checkShouldFlush(Configuration conf, boolean expected) throws Exception {
946     try {
947       EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
948       EnvironmentEdgeManager.injectEdge(edge);
949       HBaseTestingUtility hbaseUtility = HBaseTestingUtility.createLocalHTU(conf);
950       HRegion region = hbaseUtility.createTestRegion("foobar", new HColumnDescriptor("foo"));
951 
952       List<Store> stores = region.getStores();
953       assertTrue(stores.size() == 1);
954 
955       Store s = stores.iterator().next();
956       edge.setCurrentTimeMillis(1234);
957       s.add(KeyValueTestUtil.create("r", "f", "q", 100, "v"));
958       edge.setCurrentTimeMillis(1234 + 100);
959       StringBuffer sb = new StringBuffer();
960       assertTrue(region.shouldFlush(sb) == false);
961       edge.setCurrentTimeMillis(1234 + 10000);
962       assertTrue(region.shouldFlush(sb) == expected);
963     } finally {
964       EnvironmentEdgeManager.reset();
965     }
966   }
967 
968   public void testShouldFlushMeta() throws Exception {
969     // write an edit in the META and ensure the shouldFlush (that the periodic memstore
970     // flusher invokes) returns true after SYSTEM_CACHE_FLUSH_INTERVAL (even though
971     // the MEMSTORE_PERIODIC_FLUSH_INTERVAL is set to a higher value)
972     Configuration conf = new Configuration();
973     conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, HRegion.SYSTEM_CACHE_FLUSH_INTERVAL * 10);
974     HBaseTestingUtility hbaseUtility = HBaseTestingUtility.createLocalHTU(conf);
975     Path testDir = hbaseUtility.getDataTestDir();
976     EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
977     EnvironmentEdgeManager.injectEdge(edge);
978     edge.setCurrentTimeMillis(1234);
979     WALFactory wFactory = new WALFactory(conf, null, "1234");
980     HRegion meta = HRegion.createHRegion(HRegionInfo.FIRST_META_REGIONINFO, testDir,
981         conf, HTableDescriptor.metaTableDescriptor(conf),
982         wFactory.getMetaWAL(HRegionInfo.FIRST_META_REGIONINFO.
983             getEncodedNameAsBytes()));
984     HRegionInfo hri = new HRegionInfo(TableName.valueOf("testShouldFlushMeta"),
985         Bytes.toBytes("row_0200"), Bytes.toBytes("row_0300"));
986     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("testShouldFlushMeta"));
987     desc.addFamily(new HColumnDescriptor("foo".getBytes()));
988     HRegion r =
989         HRegion.createHRegion(hri, testDir, conf, desc,
990             wFactory.getWAL(hri.getEncodedNameAsBytes(), hri.getTable().getNamespace()));
991     HRegion.addRegionToMETA(meta, r);
992     edge.setCurrentTimeMillis(1234 + 100);
993     StringBuffer sb = new StringBuffer();
994     assertTrue(meta.shouldFlush(sb) == false);
995     edge.setCurrentTimeMillis(edge.currentTime() + HRegion.SYSTEM_CACHE_FLUSH_INTERVAL + 1);
996     assertTrue(meta.shouldFlush(sb) == true);
997   }
998 
999   private class EnvironmentEdgeForMemstoreTest implements EnvironmentEdge {
1000     long t = 1234;
1001     @Override
1002     public long currentTime() {
1003       return t; 
1004     }
1005     public void setCurrentTimeMillis(long t) {
1006       this.t = t;
1007     }
1008   }
1009 
1010   /**
1011    * Adds {@link #ROW_COUNT} rows and {@link #QUALIFIER_COUNT}
1012    * @param hmc Instance to add rows to.
1013    * @return How many rows we added.
1014    * @throws IOException
1015    */
1016   private int addRows(final MemStore hmc) {
1017     return addRows(hmc, HConstants.LATEST_TIMESTAMP);
1018   }
1019 
1020   /**
1021    * Adds {@link #ROW_COUNT} rows and {@link #QUALIFIER_COUNT}
1022    * @param hmc Instance to add rows to.
1023    * @return How many rows we added.
1024    * @throws IOException
1025    */
1026   private int addRows(final MemStore hmc, final long ts) {
1027     for (int i = 0; i < ROW_COUNT; i++) {
1028       long timestamp = ts == HConstants.LATEST_TIMESTAMP?
1029         System.currentTimeMillis(): ts;
1030       for (int ii = 0; ii < QUALIFIER_COUNT; ii++) {
1031         byte [] row = Bytes.toBytes(i);
1032         byte [] qf = makeQualifier(i, ii);
1033         hmc.add(new KeyValue(row, FAMILY, qf, timestamp, qf));
1034       }
1035     }
1036     return ROW_COUNT;
1037   }
1038 
1039   private long runSnapshot(final DefaultMemStore hmc) throws UnexpectedStateException {
1040     // Save off old state.
1041     int oldHistorySize = hmc.snapshotSection.getCellSkipListSet().sizeForTests();
1042     MemStoreSnapshot snapshot = hmc.snapshot();
1043     // Make some assertions about what just happened.
1044     assertTrue("History size has not increased", oldHistorySize <
1045       hmc.snapshotSection.getCellSkipListSet().sizeForTests());
1046     long t = memstore.timeOfOldestEdit();
1047     assertTrue("Time of oldest edit is not Long.MAX_VALUE", t == Long.MAX_VALUE);
1048     hmc.clearSnapshot(snapshot.getId());
1049     return t;
1050   }
1051 
1052   private void isExpectedRowWithoutTimestamps(final int rowIndex,
1053       List<Cell> kvs) {
1054     int i = 0;
1055     for (Cell kv: kvs) {
1056       byte[] expectedColname = makeQualifier(rowIndex, i++);
1057       assertTrue("Column name", CellUtil.matchingQualifier(kv, expectedColname));
1058       // Value is column name as bytes.  Usually result is
1059       // 100 bytes in size at least. This is the default size
1060       // for BytesWriteable.  For comparison, convert bytes to
1061       // String and trim to remove trailing null bytes.
1062       assertTrue("Content", CellUtil.matchingValue(kv, expectedColname));
1063     }
1064   }
1065 
1066   private static void addRows(int count, final MemStore mem) {
1067     long nanos = System.nanoTime();
1068 
1069     for (int i = 0 ; i < count ; i++) {
1070       if (i % 1000 == 0) {
1071 
1072         System.out.println(i + " Took for 1k usec: " + (System.nanoTime() - nanos)/1000);
1073         nanos = System.nanoTime();
1074       }
1075       long timestamp = System.currentTimeMillis();
1076 
1077       for (int ii = 0; ii < QUALIFIER_COUNT ; ii++) {
1078         byte [] row = Bytes.toBytes(i);
1079         byte [] qf = makeQualifier(i, ii);
1080         mem.add(new KeyValue(row, FAMILY, qf, timestamp, qf));
1081       }
1082     }
1083   }
1084 
1085 
1086   static void doScan(MemStore ms, int iteration) throws IOException {
1087     long nanos = System.nanoTime();
1088     KeyValueScanner s = ms.getScanners(0).get(0);
1089     s.seek(KeyValueUtil.createFirstOnRow(new byte[]{}));
1090 
1091     System.out.println(iteration + " create/seek took: " + (System.nanoTime() - nanos)/1000);
1092     int cnt=0;
1093     while(s.next() != null) ++cnt;
1094 
1095     System.out.println(iteration + " took usec: " + (System.nanoTime() - nanos) / 1000 + " for: "
1096         + cnt);
1097 
1098   }
1099 
1100   public static void main(String [] args) throws IOException {
1101     MemStore ms = new DefaultMemStore();
1102 
1103     long n1 = System.nanoTime();
1104     addRows(25000, ms);
1105     System.out.println("Took for insert: " + (System.nanoTime()-n1)/1000);
1106 
1107     System.out.println("foo");
1108 
1109     for (int i = 0 ; i < 50 ; i++)
1110       doScan(ms, i);
1111   }
1112 }
1113