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