001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotNull;
022import static org.junit.Assert.assertNull;
023import static org.junit.Assert.assertTrue;
024
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.List;
029import java.util.NavigableMap;
030import java.util.Objects;
031import java.util.TreeMap;
032import java.util.concurrent.atomic.AtomicLong;
033import java.util.concurrent.atomic.AtomicReference;
034import org.apache.hadoop.conf.Configuration;
035import org.apache.hadoop.fs.Path;
036import org.apache.hadoop.hbase.Cell;
037import org.apache.hadoop.hbase.CellComparatorImpl;
038import org.apache.hadoop.hbase.CellUtil;
039import org.apache.hadoop.hbase.ExtendedCell;
040import org.apache.hadoop.hbase.HBaseClassTestRule;
041import org.apache.hadoop.hbase.HBaseConfiguration;
042import org.apache.hadoop.hbase.HBaseTestingUtil;
043import org.apache.hadoop.hbase.HConstants;
044import org.apache.hadoop.hbase.KeepDeletedCells;
045import org.apache.hadoop.hbase.KeyValue;
046import org.apache.hadoop.hbase.KeyValueTestUtil;
047import org.apache.hadoop.hbase.KeyValueUtil;
048import org.apache.hadoop.hbase.TableDescriptors;
049import org.apache.hadoop.hbase.TableName;
050import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
051import org.apache.hadoop.hbase.client.Put;
052import org.apache.hadoop.hbase.client.RegionInfo;
053import org.apache.hadoop.hbase.client.RegionInfoBuilder;
054import org.apache.hadoop.hbase.client.Scan;
055import org.apache.hadoop.hbase.client.TableDescriptor;
056import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
057import org.apache.hadoop.hbase.exceptions.UnexpectedStateException;
058import org.apache.hadoop.hbase.testclassification.MediumTests;
059import org.apache.hadoop.hbase.testclassification.RegionServerTests;
060import org.apache.hadoop.hbase.util.Bytes;
061import org.apache.hadoop.hbase.util.EnvironmentEdge;
062import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
063import org.apache.hadoop.hbase.util.FSTableDescriptors;
064import org.apache.hadoop.hbase.wal.WALFactory;
065import org.junit.AfterClass;
066import org.junit.Before;
067import org.junit.ClassRule;
068import org.junit.Rule;
069import org.junit.Test;
070import org.junit.experimental.categories.Category;
071import org.junit.rules.TestName;
072import org.slf4j.Logger;
073import org.slf4j.LoggerFactory;
074
075import org.apache.hbase.thirdparty.com.google.common.base.Joiner;
076import org.apache.hbase.thirdparty.com.google.common.collect.Iterables;
077import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
078
079/** memstore test case */
080@Category({ RegionServerTests.class, MediumTests.class })
081public class TestDefaultMemStore {
082
083  @ClassRule
084  public static final HBaseClassTestRule CLASS_RULE =
085    HBaseClassTestRule.forClass(TestDefaultMemStore.class);
086
087  private static final Logger LOG = LoggerFactory.getLogger(TestDefaultMemStore.class);
088  @Rule
089  public TestName name = new TestName();
090  protected AbstractMemStore memstore;
091  protected static final int ROW_COUNT = 10;
092  protected static final int QUALIFIER_COUNT = ROW_COUNT;
093  protected static final byte[] FAMILY = Bytes.toBytes("column");
094  protected MultiVersionConcurrencyControl mvcc;
095  protected AtomicLong startSeqNum = new AtomicLong(0);
096  protected ChunkCreator chunkCreator;
097
098  private String getName() {
099    return this.name.getMethodName();
100  }
101
102  @Before
103  public void setUp() throws Exception {
104    internalSetUp();
105    // no pool
106    this.chunkCreator = ChunkCreator.initialize(MemStoreLAB.CHUNK_SIZE_DEFAULT, false, 0, 0, 0,
107      null, MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT);
108    this.memstore = new DefaultMemStore();
109  }
110
111  @AfterClass
112  public static void tearDownClass() throws Exception {
113    ChunkCreator.getInstance().clearChunkIds();
114  }
115
116  protected void internalSetUp() throws Exception {
117    this.mvcc = new MultiVersionConcurrencyControl();
118  }
119
120  @Test
121  public void testPutSameKey() {
122    byte[] bytes = Bytes.toBytes(getName());
123    KeyValue kv = new KeyValue(bytes, bytes, bytes, bytes);
124    this.memstore.add(kv, null);
125    byte[] other = Bytes.toBytes("somethingelse");
126    KeyValue samekey = new KeyValue(bytes, bytes, bytes, other);
127    this.memstore.add(samekey, null);
128    Cell found = this.memstore.getActive().first();
129    assertEquals(1, this.memstore.getActive().getCellsCount());
130    assertTrue(Bytes.toString(found.getValueArray()), CellUtil.matchingValue(samekey, found));
131  }
132
133  @Test
134  public void testPutSameCell() {
135    byte[] bytes = Bytes.toBytes(getName());
136    KeyValue kv = new KeyValue(bytes, bytes, bytes, bytes);
137    MemStoreSizing sizeChangeForFirstCell = new NonThreadSafeMemStoreSizing();
138    this.memstore.add(kv, sizeChangeForFirstCell);
139    MemStoreSizing sizeChangeForSecondCell = new NonThreadSafeMemStoreSizing();
140    this.memstore.add(kv, sizeChangeForSecondCell);
141    // make sure memstore size increase won't double-count MSLAB chunk size
142    assertEquals(Segment.getCellLength(kv), sizeChangeForFirstCell.getMemStoreSize().getDataSize());
143    Segment segment = this.memstore.getActive();
144    MemStoreLAB msLab = segment.getMemStoreLAB();
145    if (msLab != null) {
146      // make sure memstore size increased even when writing the same cell, if using MSLAB
147      assertEquals(Segment.getCellLength(kv),
148        sizeChangeForSecondCell.getMemStoreSize().getDataSize());
149      // make sure chunk size increased even when writing the same cell, if using MSLAB
150      if (msLab instanceof MemStoreLABImpl) {
151        // since we add the chunkID at the 0th offset of the chunk and the
152        // chunkid is an int we need to account for those 4 bytes
153        assertEquals(2 * Segment.getCellLength(kv) + Bytes.SIZEOF_INT,
154          ((MemStoreLABImpl) msLab).getCurrentChunk().getNextFreeOffset());
155      }
156    } else {
157      // make sure no memstore size change w/o MSLAB
158      assertEquals(0, sizeChangeForSecondCell.getMemStoreSize().getDataSize());
159      assertEquals(0, sizeChangeForSecondCell.getMemStoreSize().getHeapSize());
160    }
161  }
162
163  /**
164   * Test memstore snapshot happening while scanning.
165   */
166  @Test
167  public void testScanAcrossSnapshot() throws IOException {
168    int rowCount = addRows(this.memstore);
169    List<KeyValueScanner> memstorescanners = this.memstore.getScanners(0);
170    Scan scan = new Scan();
171    List<Cell> result = new ArrayList<>();
172    Configuration conf = HBaseConfiguration.create();
173    ScanInfo scanInfo =
174      new ScanInfo(conf, null, 0, 1, HConstants.LATEST_TIMESTAMP, KeepDeletedCells.FALSE,
175        HConstants.DEFAULT_BLOCKSIZE, 0, this.memstore.getComparator(), false);
176    int count = 0;
177    try (StoreScanner s = new StoreScanner(scan, scanInfo, null, memstorescanners)) {
178      while (s.next(result)) {
179        LOG.info(Objects.toString(result));
180        count++;
181        // Row count is same as column count.
182        assertEquals(rowCount, result.size());
183        result.clear();
184      }
185    }
186    assertEquals(rowCount, count);
187    for (KeyValueScanner scanner : memstorescanners) {
188      scanner.close();
189    }
190
191    memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
192    // Now assert can count same number even if a snapshot mid-scan.
193    count = 0;
194    try (StoreScanner s = new StoreScanner(scan, scanInfo, null, memstorescanners)) {
195      while (s.next(result)) {
196        LOG.info(Objects.toString(result));
197        // Assert the stuff is coming out in right order.
198        assertTrue(CellUtil.matchingRows(result.get(0), Bytes.toBytes(count)));
199        count++;
200        // Row count is same as column count.
201        assertEquals(rowCount, result.size());
202        if (count == 2) {
203          this.memstore.snapshot();
204          LOG.info("Snapshotted");
205        }
206        result.clear();
207      }
208    }
209    assertEquals(rowCount, count);
210    for (KeyValueScanner scanner : memstorescanners) {
211      scanner.close();
212    }
213    memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
214    // Assert that new values are seen in kvset as we scan.
215    long ts = EnvironmentEdgeManager.currentTime();
216    count = 0;
217    int snapshotIndex = 5;
218    try (StoreScanner s = new StoreScanner(scan, scanInfo, null, memstorescanners)) {
219      while (s.next(result)) {
220        LOG.info(Objects.toString(result));
221        // Assert the stuff is coming out in right order.
222        assertTrue(CellUtil.matchingRows(result.get(0), Bytes.toBytes(count)));
223        // Row count is same as column count.
224        assertEquals("count=" + count + ", result=" + result, rowCount, result.size());
225        count++;
226        if (count == snapshotIndex) {
227          MemStoreSnapshot snapshot = this.memstore.snapshot();
228          this.memstore.clearSnapshot(snapshot.getId());
229          // Added more rows into kvset. But the scanner wont see these rows.
230          addRows(this.memstore, ts);
231          LOG.info("Snapshotted, cleared it and then added values (which wont be seen)");
232        }
233        result.clear();
234      }
235    }
236    assertEquals(rowCount, count);
237  }
238
239  /**
240   * A simple test which verifies the 3 possible states when scanning across snapshot.
241   */
242  @Test
243  public void testScanAcrossSnapshot2() throws IOException, CloneNotSupportedException {
244    // we are going to the scanning across snapshot with two kvs
245    // kv1 should always be returned before kv2
246    final byte[] one = Bytes.toBytes(1);
247    final byte[] two = Bytes.toBytes(2);
248    final byte[] f = Bytes.toBytes("f");
249    final byte[] q = Bytes.toBytes("q");
250    final byte[] v = Bytes.toBytes(3);
251
252    final KeyValue kv1 = new KeyValue(one, f, q, v);
253    final KeyValue kv2 = new KeyValue(two, f, q, v);
254
255    // use case 1: both kvs in kvset
256    this.memstore.add(kv1.clone(), null);
257    this.memstore.add(kv2.clone(), null);
258    // snapshot is empty,active segment is not empty,
259    // empty segment is skipped.
260    verifyOneScanAcrossSnapshot2(kv1, kv2);
261
262    // use case 2: both kvs in snapshot
263    // active segment is empty,snapshot is not empty,
264    // empty segment is skipped.
265    this.memstore.snapshot();
266    //
267    verifyOneScanAcrossSnapshot2(kv1, kv2);
268
269    // use case 3: first in snapshot second in kvset
270    this.memstore = new DefaultMemStore();
271    this.memstore.add(kv1.clone(), null);
272    this.memstore.snapshot();
273    this.memstore.add(kv2.clone(), null);
274    verifyScanAcrossSnapshot2(kv1, kv2);
275  }
276
277  protected void verifyScanAcrossSnapshot2(KeyValue kv1, KeyValue kv2) throws IOException {
278    List<KeyValueScanner> memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
279    assertEquals(2, memstorescanners.size());
280    final KeyValueScanner scanner0 = memstorescanners.get(0);
281    final KeyValueScanner scanner1 = memstorescanners.get(1);
282    scanner0.seek(KeyValueUtil.createFirstOnRow(HConstants.EMPTY_START_ROW));
283    scanner1.seek(KeyValueUtil.createFirstOnRow(HConstants.EMPTY_START_ROW));
284    Cell n0 = scanner0.next();
285    Cell n1 = scanner1.next();
286    assertTrue(kv1.equals(n0) || kv1.equals(n1));
287    assertTrue(kv2.equals(n0) || kv2.equals(n1) || kv2.equals(scanner0.next())
288      || kv2.equals(scanner1.next()));
289    assertNull(scanner0.next());
290    assertNull(scanner1.next());
291  }
292
293  protected void verifyOneScanAcrossSnapshot2(KeyValue kv1, KeyValue kv2) throws IOException {
294    List<KeyValueScanner> memstorescanners = this.memstore.getScanners(mvcc.getReadPoint());
295    assertEquals(1, memstorescanners.size());
296    final KeyValueScanner scanner0 = memstorescanners.get(0);
297    scanner0.seek(KeyValueUtil.createFirstOnRow(HConstants.EMPTY_START_ROW));
298    Cell n0 = scanner0.next();
299    Cell n1 = scanner0.next();
300    assertTrue(kv1.equals(n0));
301    assertTrue(kv2.equals(n1));
302    assertNull(scanner0.next());
303  }
304
305  protected void assertScannerResults(KeyValueScanner scanner, KeyValue[] expected)
306    throws IOException {
307    scanner.seek(KeyValueUtil.createFirstOnRow(new byte[] {}));
308    List<Cell> returned = Lists.newArrayList();
309
310    while (true) {
311      Cell next = scanner.next();
312      if (next == null) break;
313      returned.add(next);
314    }
315
316    assertTrue(
317      "Got:\n" + Joiner.on("\n").join(returned) + "\nExpected:\n" + Joiner.on("\n").join(expected),
318      Iterables.elementsEqual(Arrays.asList(expected), returned));
319    assertNull(scanner.peek());
320  }
321
322  @Test
323  public void testMemstoreConcurrentControl() throws IOException {
324    final byte[] row = Bytes.toBytes(1);
325    final byte[] f = Bytes.toBytes("family");
326    final byte[] q1 = Bytes.toBytes("q1");
327    final byte[] q2 = Bytes.toBytes("q2");
328    final byte[] v = Bytes.toBytes("value");
329
330    MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin();
331
332    KeyValue kv1 = new KeyValue(row, f, q1, v);
333    kv1.setSequenceId(w.getWriteNumber());
334    memstore.add(kv1, null);
335
336    KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
337    assertScannerResults(s, new KeyValue[] {});
338
339    mvcc.completeAndWait(w);
340
341    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
342    assertScannerResults(s, new KeyValue[] { kv1 });
343
344    w = mvcc.begin();
345    KeyValue kv2 = new KeyValue(row, f, q2, v);
346    kv2.setSequenceId(w.getWriteNumber());
347    memstore.add(kv2, null);
348
349    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
350    assertScannerResults(s, new KeyValue[] { kv1 });
351
352    mvcc.completeAndWait(w);
353
354    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
355    assertScannerResults(s, new KeyValue[] { kv1, kv2 });
356  }
357
358  /**
359   * Regression test for HBASE-2616, HBASE-2670. When we insert a higher-memstoreTS version of a
360   * cell but with the same timestamp, we still need to provide consistent reads for the same
361   * scanner.
362   */
363  @Test
364  public void testMemstoreEditsVisibilityWithSameKey() throws IOException {
365    final byte[] row = Bytes.toBytes(1);
366    final byte[] f = Bytes.toBytes("family");
367    final byte[] q1 = Bytes.toBytes("q1");
368    final byte[] q2 = Bytes.toBytes("q2");
369    final byte[] v1 = Bytes.toBytes("value1");
370    final byte[] v2 = Bytes.toBytes("value2");
371
372    // INSERT 1: Write both columns val1
373    MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin();
374
375    KeyValue kv11 = new KeyValue(row, f, q1, v1);
376    kv11.setSequenceId(w.getWriteNumber());
377    memstore.add(kv11, null);
378
379    KeyValue kv12 = new KeyValue(row, f, q2, v1);
380    kv12.setSequenceId(w.getWriteNumber());
381    memstore.add(kv12, null);
382    mvcc.completeAndWait(w);
383
384    // BEFORE STARTING INSERT 2, SEE FIRST KVS
385    KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
386    assertScannerResults(s, new KeyValue[] { kv11, kv12 });
387
388    // START INSERT 2: Write both columns val2
389    w = mvcc.begin();
390    KeyValue kv21 = new KeyValue(row, f, q1, v2);
391    kv21.setSequenceId(w.getWriteNumber());
392    memstore.add(kv21, null);
393
394    KeyValue kv22 = new KeyValue(row, f, q2, v2);
395    kv22.setSequenceId(w.getWriteNumber());
396    memstore.add(kv22, null);
397
398    // BEFORE COMPLETING INSERT 2, SEE FIRST KVS
399    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
400    assertScannerResults(s, new KeyValue[] { kv11, kv12 });
401
402    // COMPLETE INSERT 2
403    mvcc.completeAndWait(w);
404
405    // NOW SHOULD SEE NEW KVS IN ADDITION TO OLD KVS.
406    // See HBASE-1485 for discussion about what we should do with
407    // the duplicate-TS inserts
408    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
409    assertScannerResults(s, new KeyValue[] { kv21, kv11, kv22, kv12 });
410  }
411
412  /**
413   * When we insert a higher-memstoreTS deletion of a cell but with the same timestamp, we still
414   * need to provide consistent reads for the same scanner.
415   */
416  @Test
417  public void testMemstoreDeletesVisibilityWithSameKey() throws IOException {
418    final byte[] row = Bytes.toBytes(1);
419    final byte[] f = Bytes.toBytes("family");
420    final byte[] q1 = Bytes.toBytes("q1");
421    final byte[] q2 = Bytes.toBytes("q2");
422    final byte[] v1 = Bytes.toBytes("value1");
423    // INSERT 1: Write both columns val1
424    MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin();
425
426    KeyValue kv11 = new KeyValue(row, f, q1, v1);
427    kv11.setSequenceId(w.getWriteNumber());
428    memstore.add(kv11, null);
429
430    KeyValue kv12 = new KeyValue(row, f, q2, v1);
431    kv12.setSequenceId(w.getWriteNumber());
432    memstore.add(kv12, null);
433    mvcc.completeAndWait(w);
434
435    // BEFORE STARTING INSERT 2, SEE FIRST KVS
436    KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
437    assertScannerResults(s, new KeyValue[] { kv11, kv12 });
438
439    // START DELETE: Insert delete for one of the columns
440    w = mvcc.begin();
441    KeyValue kvDel = new KeyValue(row, f, q2, kv11.getTimestamp(), KeyValue.Type.DeleteColumn);
442    kvDel.setSequenceId(w.getWriteNumber());
443    memstore.add(kvDel, null);
444
445    // BEFORE COMPLETING DELETE, SEE FIRST KVS
446    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
447    assertScannerResults(s, new KeyValue[] { kv11, kv12 });
448
449    // COMPLETE DELETE
450    mvcc.completeAndWait(w);
451
452    // NOW WE SHOULD SEE DELETE
453    s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
454    assertScannerResults(s, new KeyValue[] { kv11, kvDel, kv12 });
455  }
456
457  private static class ReadOwnWritesTester extends Thread {
458    static final int NUM_TRIES = 1000;
459
460    final byte[] row;
461
462    final byte[] f = Bytes.toBytes("family");
463    final byte[] q1 = Bytes.toBytes("q1");
464
465    final MultiVersionConcurrencyControl mvcc;
466    final MemStore memstore;
467
468    AtomicReference<Throwable> caughtException;
469
470    public ReadOwnWritesTester(int id, MemStore memstore, MultiVersionConcurrencyControl mvcc,
471      AtomicReference<Throwable> caughtException) {
472      this.mvcc = mvcc;
473      this.memstore = memstore;
474      this.caughtException = caughtException;
475      row = Bytes.toBytes(id);
476    }
477
478    @Override
479    public void run() {
480      try {
481        internalRun();
482      } catch (Throwable t) {
483        caughtException.compareAndSet(null, t);
484      }
485    }
486
487    private void internalRun() throws IOException {
488      for (long i = 0; i < NUM_TRIES && caughtException.get() == null; i++) {
489        MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin();
490
491        // Insert the sequence value (i)
492        byte[] v = Bytes.toBytes(i);
493
494        KeyValue kv = new KeyValue(row, f, q1, i, v);
495        kv.setSequenceId(w.getWriteNumber());
496        memstore.add(kv, null);
497        mvcc.completeAndWait(w);
498
499        // Assert that we can read back
500        KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0);
501        s.seek(kv);
502
503        Cell ret = s.next();
504        assertNotNull("Didnt find own write at all", ret);
505        assertEquals("Didnt read own writes", kv.getTimestamp(), ret.getTimestamp());
506      }
507    }
508  }
509
510  @Test
511  public void testReadOwnWritesUnderConcurrency() throws Throwable {
512    int NUM_THREADS = 8;
513
514    ReadOwnWritesTester threads[] = new ReadOwnWritesTester[NUM_THREADS];
515    AtomicReference<Throwable> caught = new AtomicReference<>();
516
517    for (int i = 0; i < NUM_THREADS; i++) {
518      threads[i] = new ReadOwnWritesTester(i, memstore, mvcc, caught);
519      threads[i].start();
520    }
521
522    for (int i = 0; i < NUM_THREADS; i++) {
523      threads[i].join();
524    }
525
526    if (caught.get() != null) {
527      throw caught.get();
528    }
529  }
530
531  /**
532   * Test memstore snapshots
533   */
534  @Test
535  public void testSnapshotting() throws IOException {
536    final int snapshotCount = 5;
537    // Add some rows, run a snapshot. Do it a few times.
538    for (int i = 0; i < snapshotCount; i++) {
539      addRows(this.memstore);
540      runSnapshot(this.memstore);
541      assertEquals("History not being cleared", 0, this.memstore.getSnapshot().getCellsCount());
542    }
543  }
544
545  @Test
546  public void testMultipleVersionsSimple() throws Exception {
547    DefaultMemStore m = new DefaultMemStore(new Configuration(), CellComparatorImpl.COMPARATOR);
548    byte[] row = Bytes.toBytes("testRow");
549    byte[] family = Bytes.toBytes("testFamily");
550    byte[] qf = Bytes.toBytes("testQualifier");
551    long[] stamps = { 1, 2, 3 };
552    byte[][] values = { Bytes.toBytes("value0"), Bytes.toBytes("value1"), Bytes.toBytes("value2") };
553    KeyValue key0 = new KeyValue(row, family, qf, stamps[0], values[0]);
554    KeyValue key1 = new KeyValue(row, family, qf, stamps[1], values[1]);
555    KeyValue key2 = new KeyValue(row, family, qf, stamps[2], values[2]);
556
557    m.add(key0, null);
558    m.add(key1, null);
559    m.add(key2, null);
560
561    assertTrue("Expected memstore to hold 3 values, actually has " + m.getActive().getCellsCount(),
562      m.getActive().getCellsCount() == 3);
563  }
564
565  //////////////////////////////////////////////////////////////////////////////
566  // Get tests
567  //////////////////////////////////////////////////////////////////////////////
568
569  /**
570   * Test getNextRow from memstore
571   */
572  @Test
573  public void testGetNextRow() throws Exception {
574    addRows(this.memstore);
575    // Add more versions to make it a little more interesting.
576    Thread.sleep(1);
577    addRows(this.memstore);
578    Cell closestToEmpty = ((DefaultMemStore) this.memstore).getNextRow(KeyValue.LOWESTKEY);
579    assertTrue(CellComparatorImpl.COMPARATOR.compareRows(closestToEmpty,
580      new KeyValue(Bytes.toBytes(0), EnvironmentEdgeManager.currentTime())) == 0);
581    for (int i = 0; i < ROW_COUNT; i++) {
582      Cell nr = ((DefaultMemStore) this.memstore)
583        .getNextRow(new KeyValue(Bytes.toBytes(i), EnvironmentEdgeManager.currentTime()));
584      if (i + 1 == ROW_COUNT) {
585        assertNull(nr);
586      } else {
587        assertTrue(CellComparatorImpl.COMPARATOR.compareRows(nr,
588          new KeyValue(Bytes.toBytes(i + 1), EnvironmentEdgeManager.currentTime())) == 0);
589      }
590    }
591    // starting from each row, validate results should contain the starting row
592    Configuration conf = HBaseConfiguration.create();
593    for (int startRowId = 0; startRowId < ROW_COUNT; startRowId++) {
594      ScanInfo scanInfo =
595        new ScanInfo(conf, FAMILY, 0, 1, Integer.MAX_VALUE, KeepDeletedCells.FALSE,
596          HConstants.DEFAULT_BLOCKSIZE, 0, this.memstore.getComparator(), false);
597      try (InternalScanner scanner =
598        new StoreScanner(new Scan().withStartRow(Bytes.toBytes(startRowId)), scanInfo, null,
599          memstore.getScanners(0))) {
600        List<Cell> results = new ArrayList<>();
601        for (int i = 0; scanner.next(results); i++) {
602          int rowId = startRowId + i;
603          Cell left = results.get(0);
604          byte[] row1 = Bytes.toBytes(rowId);
605          assertTrue("Row name",
606            CellComparatorImpl.COMPARATOR.compareRows(left, row1, 0, row1.length) == 0);
607          assertEquals("Count of columns", QUALIFIER_COUNT, results.size());
608          List<Cell> row = new ArrayList<>();
609          for (Cell kv : results) {
610            row.add(kv);
611          }
612          isExpectedRowWithoutTimestamps(rowId, row);
613          // Clear out set. Otherwise row results accumulate.
614          results.clear();
615        }
616      }
617    }
618  }
619
620  @Test
621  public void testGet_memstoreAndSnapShot() throws IOException {
622    byte[] row = Bytes.toBytes("testrow");
623    byte[] fam = Bytes.toBytes("testfamily");
624    byte[] qf1 = Bytes.toBytes("testqualifier1");
625    byte[] qf2 = Bytes.toBytes("testqualifier2");
626    byte[] qf3 = Bytes.toBytes("testqualifier3");
627    byte[] qf4 = Bytes.toBytes("testqualifier4");
628    byte[] qf5 = Bytes.toBytes("testqualifier5");
629    byte[] val = Bytes.toBytes("testval");
630
631    // Setting up memstore
632    memstore.add(new KeyValue(row, fam, qf1, val), null);
633    memstore.add(new KeyValue(row, fam, qf2, val), null);
634    memstore.add(new KeyValue(row, fam, qf3, val), null);
635    // Creating a snapshot
636    memstore.snapshot();
637    assertEquals(3, memstore.getSnapshot().getCellsCount());
638    // Adding value to "new" memstore
639    assertEquals(0, memstore.getActive().getCellsCount());
640    memstore.add(new KeyValue(row, fam, qf4, val), null);
641    memstore.add(new KeyValue(row, fam, qf5, val), null);
642    assertEquals(2, memstore.getActive().getCellsCount());
643  }
644
645  //////////////////////////////////////////////////////////////////////////////
646  // Delete tests
647  //////////////////////////////////////////////////////////////////////////////
648  @Test
649  public void testGetWithDelete() throws IOException {
650    byte[] row = Bytes.toBytes("testrow");
651    byte[] fam = Bytes.toBytes("testfamily");
652    byte[] qf1 = Bytes.toBytes("testqualifier");
653    byte[] val = Bytes.toBytes("testval");
654
655    long ts1 = System.nanoTime();
656    KeyValue put1 = new KeyValue(row, fam, qf1, ts1, val);
657    long ts2 = ts1 + 1;
658    KeyValue put2 = new KeyValue(row, fam, qf1, ts2, val);
659    long ts3 = ts2 + 1;
660    KeyValue put3 = new KeyValue(row, fam, qf1, ts3, val);
661    memstore.add(put1, null);
662    memstore.add(put2, null);
663    memstore.add(put3, null);
664
665    assertEquals(3, memstore.getActive().getCellsCount());
666
667    KeyValue del2 = new KeyValue(row, fam, qf1, ts2, KeyValue.Type.Delete, val);
668    memstore.add(del2, null);
669
670    List<Cell> expected = new ArrayList<>();
671    expected.add(put3);
672    expected.add(del2);
673    expected.add(put2);
674    expected.add(put1);
675
676    assertEquals(4, memstore.getActive().getCellsCount());
677    int i = 0;
678    for (Cell cell : memstore.getActive().getCellSet()) {
679      assertEquals(expected.get(i++), cell);
680    }
681  }
682
683  @Test
684  public void testGetWithDeleteColumn() throws IOException {
685    byte[] row = Bytes.toBytes("testrow");
686    byte[] fam = Bytes.toBytes("testfamily");
687    byte[] qf1 = Bytes.toBytes("testqualifier");
688    byte[] val = Bytes.toBytes("testval");
689
690    long ts1 = System.nanoTime();
691    KeyValue put1 = new KeyValue(row, fam, qf1, ts1, val);
692    long ts2 = ts1 + 1;
693    KeyValue put2 = new KeyValue(row, fam, qf1, ts2, val);
694    long ts3 = ts2 + 1;
695    KeyValue put3 = new KeyValue(row, fam, qf1, ts3, val);
696    memstore.add(put1, null);
697    memstore.add(put2, null);
698    memstore.add(put3, null);
699
700    assertEquals(3, memstore.getActive().getCellsCount());
701
702    KeyValue del2 = new KeyValue(row, fam, qf1, ts2, KeyValue.Type.DeleteColumn, val);
703    memstore.add(del2, null);
704
705    List<Cell> expected = new ArrayList<>();
706    expected.add(put3);
707    expected.add(del2);
708    expected.add(put2);
709    expected.add(put1);
710
711    assertEquals(4, memstore.getActive().getCellsCount());
712    int i = 0;
713    for (Cell cell : memstore.getActive().getCellSet()) {
714      assertEquals(expected.get(i++), cell);
715    }
716  }
717
718  @Test
719  public void testGetWithDeleteFamily() throws IOException {
720    byte[] row = Bytes.toBytes("testrow");
721    byte[] fam = Bytes.toBytes("testfamily");
722    byte[] qf1 = Bytes.toBytes("testqualifier1");
723    byte[] qf2 = Bytes.toBytes("testqualifier2");
724    byte[] qf3 = Bytes.toBytes("testqualifier3");
725    byte[] val = Bytes.toBytes("testval");
726    long ts = System.nanoTime();
727
728    KeyValue put1 = new KeyValue(row, fam, qf1, ts, val);
729    KeyValue put2 = new KeyValue(row, fam, qf2, ts, val);
730    KeyValue put3 = new KeyValue(row, fam, qf3, ts, val);
731    KeyValue put4 = new KeyValue(row, fam, qf3, ts + 1, val);
732
733    memstore.add(put1, null);
734    memstore.add(put2, null);
735    memstore.add(put3, null);
736    memstore.add(put4, null);
737
738    KeyValue del = new KeyValue(row, fam, null, ts, KeyValue.Type.DeleteFamily, val);
739    memstore.add(del, null);
740
741    List<Cell> expected = new ArrayList<>();
742    expected.add(del);
743    expected.add(put1);
744    expected.add(put2);
745    expected.add(put4);
746    expected.add(put3);
747
748    assertEquals(5, memstore.getActive().getCellsCount());
749    int i = 0;
750    for (Cell cell : memstore.getActive().getCellSet()) {
751      assertEquals(expected.get(i++), cell);
752    }
753  }
754
755  @Test
756  public void testKeepDeleteInmemstore() {
757    byte[] row = Bytes.toBytes("testrow");
758    byte[] fam = Bytes.toBytes("testfamily");
759    byte[] qf = Bytes.toBytes("testqualifier");
760    byte[] val = Bytes.toBytes("testval");
761    long ts = System.nanoTime();
762    memstore.add(new KeyValue(row, fam, qf, ts, val), null);
763    KeyValue delete = new KeyValue(row, fam, qf, ts, KeyValue.Type.Delete, val);
764    memstore.add(delete, null);
765    assertEquals(2, memstore.getActive().getCellsCount());
766    assertEquals(delete, memstore.getActive().first());
767  }
768
769  @Test
770  public void testRetainsDeleteVersion() throws IOException {
771    // add a put to memstore
772    memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"), null);
773
774    // now process a specific delete:
775    KeyValue delete =
776      KeyValueTestUtil.create("row1", "fam", "a", 100, KeyValue.Type.Delete, "dont-care");
777    memstore.add(delete, null);
778
779    assertEquals(2, memstore.getActive().getCellsCount());
780    assertEquals(delete, memstore.getActive().first());
781  }
782
783  @Test
784  public void testRetainsDeleteColumn() throws IOException {
785    // add a put to memstore
786    memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"), null);
787
788    // now process a specific delete:
789    KeyValue delete =
790      KeyValueTestUtil.create("row1", "fam", "a", 100, KeyValue.Type.DeleteColumn, "dont-care");
791    memstore.add(delete, null);
792
793    assertEquals(2, memstore.getActive().getCellsCount());
794    assertEquals(delete, memstore.getActive().first());
795  }
796
797  @Test
798  public void testRetainsDeleteFamily() throws IOException {
799    // add a put to memstore
800    memstore.add(KeyValueTestUtil.create("row1", "fam", "a", 100, "dont-care"), null);
801
802    // now process a specific delete:
803    KeyValue delete =
804      KeyValueTestUtil.create("row1", "fam", "a", 100, KeyValue.Type.DeleteFamily, "dont-care");
805    memstore.add(delete, null);
806
807    assertEquals(2, memstore.getActive().getCellsCount());
808    assertEquals(delete, memstore.getActive().first());
809  }
810
811  //////////////////////////////////////////////////////////////////////////////
812  // Helpers
813  //////////////////////////////////////////////////////////////////////////////
814  private static byte[] makeQualifier(final int i1, final int i2) {
815    return Bytes.toBytes(Integer.toString(i1) + ";" + Integer.toString(i2));
816  }
817
818  /**
819   * Add keyvalues with a fixed memstoreTs, and checks that memstore size is decreased as older
820   * keyvalues are deleted from the memstore.
821   */
822  @Test
823  public void testUpsertMemstoreSize() throws Exception {
824    Configuration conf = HBaseConfiguration.create();
825    memstore = new DefaultMemStore(conf, CellComparatorImpl.COMPARATOR);
826    MemStoreSize oldSize = memstore.size();
827
828    List<ExtendedCell> l = new ArrayList<>();
829    KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
830    KeyValue kv2 = KeyValueTestUtil.create("r", "f", "q", 101, "v");
831    KeyValue kv3 = KeyValueTestUtil.create("r", "f", "q", 102, "v");
832
833    kv1.setSequenceId(1);
834    kv2.setSequenceId(1);
835    kv3.setSequenceId(1);
836    l.add(kv1);
837    l.add(kv2);
838    l.add(kv3);
839
840    this.memstore.upsert(l, 2, null);// readpoint is 2
841    MemStoreSize newSize = this.memstore.size();
842    assert (newSize.getDataSize() > oldSize.getDataSize());
843    // The kv1 should be removed.
844    assert (memstore.getActive().getCellsCount() == 2);
845
846    KeyValue kv4 = KeyValueTestUtil.create("r", "f", "q", 104, "v");
847    kv4.setSequenceId(1);
848    l.clear();
849    l.add(kv4);
850    this.memstore.upsert(l, 3, null);
851    assertEquals(newSize, this.memstore.size());
852    // The kv2 should be removed.
853    assert (memstore.getActive().getCellsCount() == 2);
854    // this.memstore = null;
855  }
856
857  ////////////////////////////////////
858  // Test for periodic memstore flushes
859  // based on time of oldest edit
860  ////////////////////////////////////
861
862  /**
863   * Tests that the timeOfOldestEdit is updated correctly for the various edit operations in
864   * memstore.
865   */
866  @Test
867  public void testUpdateToTimeOfOldestEdit() throws Exception {
868    try {
869      EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
870      EnvironmentEdgeManager.injectEdge(edge);
871      DefaultMemStore memstore = new DefaultMemStore();
872      long t = memstore.timeOfOldestEdit();
873      assertEquals(Long.MAX_VALUE, t);
874
875      // test the case that the timeOfOldestEdit is updated after a KV add
876      memstore.add(KeyValueTestUtil.create("r", "f", "q", 100, "v"), null);
877      t = memstore.timeOfOldestEdit();
878      assertTrue(t == 1234);
879      // snapshot() will reset timeOfOldestEdit. The method will also assert the
880      // value is reset to Long.MAX_VALUE
881      t = runSnapshot(memstore);
882
883      // test the case that the timeOfOldestEdit is updated after a KV delete
884      memstore.add(KeyValueTestUtil.create("r", "f", "q", 100, KeyValue.Type.Delete, "v"), null);
885      t = memstore.timeOfOldestEdit();
886      assertTrue(t == 1234);
887      t = runSnapshot(memstore);
888
889      // test the case that the timeOfOldestEdit is updated after a KV upsert
890      List<ExtendedCell> l = new ArrayList<>();
891      KeyValue kv1 = KeyValueTestUtil.create("r", "f", "q", 100, "v");
892      kv1.setSequenceId(100);
893      l.add(kv1);
894      memstore.upsert(l, 1000, null);
895      t = memstore.timeOfOldestEdit();
896      assertTrue(t == 1234);
897    } finally {
898      EnvironmentEdgeManager.reset();
899    }
900  }
901
902  /**
903   * Tests the HRegion.shouldFlush method - adds an edit in the memstore and checks that shouldFlush
904   * returns true, and another where it disables the periodic flush functionality and tests whether
905   * shouldFlush returns false.
906   */
907  @Test
908  public void testShouldFlush() throws Exception {
909    Configuration conf = new Configuration();
910    conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, 1000);
911    checkShouldFlush(conf, true);
912    // test disable flush
913    conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, 0);
914    checkShouldFlush(conf, false);
915  }
916
917  protected void checkShouldFlush(Configuration conf, boolean expected) throws Exception {
918    try {
919      EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
920      EnvironmentEdgeManager.injectEdge(edge);
921      HBaseTestingUtil hbaseUtility = new HBaseTestingUtil(conf);
922      String cf = "foo";
923      HRegion region =
924        hbaseUtility.createTestRegion("foobar", ColumnFamilyDescriptorBuilder.of(cf));
925
926      edge.setCurrentTimeMillis(1234);
927      Put p = new Put(Bytes.toBytes("r"));
928      p.add(KeyValueTestUtil.create("r", cf, "q", 100, "v"));
929      region.put(p);
930      edge.setCurrentTimeMillis(1234 + 100);
931      StringBuilder sb = new StringBuilder();
932      assertTrue(!region.shouldFlush(sb));
933      edge.setCurrentTimeMillis(1234 + 10000);
934      assertTrue(region.shouldFlush(sb) == expected);
935    } finally {
936      EnvironmentEdgeManager.reset();
937    }
938  }
939
940  @Test
941  public void testShouldFlushMeta() throws Exception {
942    // write an edit in the META and ensure the shouldFlush (that the periodic memstore
943    // flusher invokes) returns true after SYSTEM_CACHE_FLUSH_INTERVAL (even though
944    // the MEMSTORE_PERIODIC_FLUSH_INTERVAL is set to a higher value)
945    Configuration conf = new Configuration();
946    conf.setInt(HRegion.MEMSTORE_PERIODIC_FLUSH_INTERVAL, HRegion.SYSTEM_CACHE_FLUSH_INTERVAL * 10);
947    HBaseTestingUtil hbaseUtility = new HBaseTestingUtil(conf);
948    Path testDir = hbaseUtility.getDataTestDir();
949    EnvironmentEdgeForMemstoreTest edge = new EnvironmentEdgeForMemstoreTest();
950    EnvironmentEdgeManager.injectEdge(edge);
951    edge.setCurrentTimeMillis(1234);
952    WALFactory wFactory = new WALFactory(conf, "1234");
953    TableDescriptors tds = new FSTableDescriptors(conf);
954    FSTableDescriptors.tryUpdateMetaTableDescriptor(conf);
955    HRegion meta = HRegion.createHRegion(RegionInfoBuilder.FIRST_META_REGIONINFO, testDir, conf,
956      tds.get(TableName.META_TABLE_NAME), wFactory.getWAL(RegionInfoBuilder.FIRST_META_REGIONINFO));
957    // parameterized tests add [#] suffix get rid of [ and ].
958    TableDescriptor desc = TableDescriptorBuilder
959      .newBuilder(TableName.valueOf(name.getMethodName().replaceAll("[\\[\\]]", "_")))
960      .setColumnFamily(ColumnFamilyDescriptorBuilder.of("foo")).build();
961    RegionInfo hri = RegionInfoBuilder.newBuilder(desc.getTableName())
962      .setStartKey(Bytes.toBytes("row_0200")).setEndKey(Bytes.toBytes("row_0300")).build();
963    HRegion r = HRegion.createHRegion(hri, testDir, conf, desc, wFactory.getWAL(hri));
964    addRegionToMETA(meta, r);
965    edge.setCurrentTimeMillis(1234 + 100);
966    StringBuilder sb = new StringBuilder();
967    assertTrue(meta.shouldFlush(sb) == false);
968    edge.setCurrentTimeMillis(edge.currentTime() + HRegion.SYSTEM_CACHE_FLUSH_INTERVAL + 1);
969    assertTrue(meta.shouldFlush(sb) == true);
970  }
971
972  /**
973   * Inserts a new region's meta information into the passed <code>meta</code> region.
974   * @param meta hbase:meta HRegion to be updated
975   * @param r    HRegion to add to <code>meta</code>
976   */
977  private static void addRegionToMETA(final HRegion meta, final HRegion r) throws IOException {
978    // The row key is the region name
979    byte[] row = r.getRegionInfo().getRegionName();
980    final long now = EnvironmentEdgeManager.currentTime();
981    final List<Cell> cells = new ArrayList<>(2);
982    cells.add(new KeyValue(row, HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER, now,
983      RegionInfo.toByteArray(r.getRegionInfo())));
984    // Set into the root table the version of the meta table.
985    cells.add(new KeyValue(row, HConstants.CATALOG_FAMILY, HConstants.META_VERSION_QUALIFIER, now,
986      Bytes.toBytes(HConstants.META_VERSION)));
987    NavigableMap<byte[], List<Cell>> familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
988    familyMap.put(HConstants.CATALOG_FAMILY, cells);
989    meta.put(new Put(row, HConstants.LATEST_TIMESTAMP, familyMap));
990  }
991
992  private class EnvironmentEdgeForMemstoreTest implements EnvironmentEdge {
993    long t = 1234;
994
995    @Override
996    public long currentTime() {
997      return t;
998    }
999
1000    public void setCurrentTimeMillis(long t) {
1001      this.t = t;
1002    }
1003  }
1004
1005  /**
1006   * Adds {@link #ROW_COUNT} rows and {@link #QUALIFIER_COUNT}
1007   * @param hmc Instance to add rows to.
1008   * @return How many rows we added.
1009   */
1010  protected int addRows(final AbstractMemStore hmc) {
1011    return addRows(hmc, HConstants.LATEST_TIMESTAMP);
1012  }
1013
1014  /**
1015   * Adds {@link #ROW_COUNT} rows and {@link #QUALIFIER_COUNT}
1016   * @param hmc Instance to add rows to.
1017   * @return How many rows we added.
1018   */
1019  protected int addRows(final MemStore hmc, final long ts) {
1020    for (int i = 0; i < ROW_COUNT; i++) {
1021      long timestamp =
1022        ts == HConstants.LATEST_TIMESTAMP ? EnvironmentEdgeManager.currentTime() : ts;
1023      for (int ii = 0; ii < QUALIFIER_COUNT; ii++) {
1024        byte[] row = Bytes.toBytes(i);
1025        byte[] qf = makeQualifier(i, ii);
1026        hmc.add(new KeyValue(row, FAMILY, qf, timestamp, qf), null);
1027      }
1028    }
1029    return ROW_COUNT;
1030  }
1031
1032  private long runSnapshot(final AbstractMemStore hmc) throws UnexpectedStateException {
1033    // Save off old state.
1034    int oldHistorySize = hmc.getSnapshot().getCellsCount();
1035    MemStoreSnapshot snapshot = hmc.snapshot();
1036    // Make some assertions about what just happened.
1037    assertTrue("History size has not increased",
1038      oldHistorySize < hmc.getSnapshot().getCellsCount());
1039    long t = memstore.timeOfOldestEdit();
1040    assertTrue("Time of oldest edit is not Long.MAX_VALUE", t == Long.MAX_VALUE);
1041    hmc.clearSnapshot(snapshot.getId());
1042    return t;
1043  }
1044
1045  private void isExpectedRowWithoutTimestamps(final int rowIndex, List<Cell> kvs) {
1046    int i = 0;
1047    for (Cell kv : kvs) {
1048      byte[] expectedColname = makeQualifier(rowIndex, i++);
1049      assertTrue("Column name", CellUtil.matchingQualifier(kv, expectedColname));
1050      // Value is column name as bytes. Usually result is
1051      // 100 bytes in size at least. This is the default size
1052      // for BytesWriteable. For comparison, convert bytes to
1053      // String and trim to remove trailing null bytes.
1054      assertTrue("Content", CellUtil.matchingValue(kv, expectedColname));
1055    }
1056  }
1057
1058  private static void addRows(int count, final MemStore mem) {
1059    long nanos = System.nanoTime();
1060
1061    for (int i = 0; i < count; i++) {
1062      if (i % 1000 == 0) {
1063
1064        System.out.println(i + " Took for 1k usec: " + (System.nanoTime() - nanos) / 1000);
1065        nanos = System.nanoTime();
1066      }
1067      long timestamp = System.currentTimeMillis();
1068
1069      for (int ii = 0; ii < QUALIFIER_COUNT; ii++) {
1070        byte[] row = Bytes.toBytes(i);
1071        byte[] qf = makeQualifier(i, ii);
1072        mem.add(new KeyValue(row, FAMILY, qf, timestamp, qf), null);
1073      }
1074    }
1075  }
1076
1077  static void doScan(MemStore ms, int iteration) throws IOException {
1078    long nanos = System.nanoTime();
1079    KeyValueScanner s = ms.getScanners(0).get(0);
1080    s.seek(KeyValueUtil.createFirstOnRow(new byte[] {}));
1081
1082    System.out.println(iteration + " create/seek took: " + (System.nanoTime() - nanos) / 1000);
1083    int cnt = 0;
1084    while (s.next() != null)
1085      ++cnt;
1086
1087    System.out
1088      .println(iteration + " took usec: " + (System.nanoTime() - nanos) / 1000 + " for: " + cnt);
1089
1090  }
1091
1092  public static void main(String[] args) throws IOException {
1093    MemStore ms = new DefaultMemStore();
1094
1095    long n1 = System.nanoTime();
1096    addRows(25000, ms);
1097    System.out.println("Took for insert: " + (System.nanoTime() - n1) / 1000);
1098
1099    System.out.println("foo");
1100
1101    for (int i = 0; i < 50; i++)
1102      doScan(ms, i);
1103  }
1104}