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