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