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