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