@Test public void testSimpleMvccOps() { MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); long readPoint = mvcc.getReadPoint(); MultiVersionConcurrencyControl.WriteEntry writeEntry = mvcc.begin(); mvcc.completeAndWait(writeEntry); assertEquals(readPoint + 1, mvcc.getReadPoint()); writeEntry = mvcc.begin(); // The write point advances even though we may have 'failed'... call complete on fail. mvcc.complete(writeEntry); assertEquals(readPoint + 2, mvcc.getWritePoint()); } }
@Override public void completeMiniBatchOperations( final MiniBatchOperationInProgress<Mutation> miniBatchOp, final WriteEntry writeEntry) throws IOException { super.completeMiniBatchOperations(miniBatchOp, writeEntry); region.mvcc.advanceTo(getOrigLogSeqNum()); } }
/** * Step the MVCC forward on to a new read/write basis. * @param newStartPoint */ public void advanceTo(long newStartPoint) { while (true) { long seqId = this.getWritePoint(); if (seqId >= newStartPoint) { break; } if (this.tryAdvanceTo(newStartPoint, seqId)) { break; } } }
/** * Complete a {@link WriteEntry} that was created by {@link #begin()} then wait until the * read point catches up to our write. * * At the end of this call, the global read point is at least as large as the write point * of the passed in WriteEntry. Thus, the write is visible to MVCC readers. */ public void completeAndWait(WriteEntry e) { if (!complete(e)) { waitForRead(e); } }
/** * Wait until the read point catches up to the write point; i.e. wait on all outstanding mvccs * to complete. */ public void await() { // Add a write and then wait on reads to catch up to it. completeAndWait(begin()); }
@Test public void testMemstoreConcurrentControl() throws IOException { final byte[] row = Bytes.toBytes(1); final byte[] f = Bytes.toBytes("family"); final byte[] q1 = Bytes.toBytes("q1"); final byte[] q2 = Bytes.toBytes("q2"); final byte[] v = Bytes.toBytes("value"); MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin(); KeyValue kv1 = new KeyValue(row, f, q1, v); kv1.setSequenceId(w.getWriteNumber()); memstore.add(kv1, null); KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0); assertScannerResults(s, new KeyValue[]{}); mvcc.completeAndWait(w); s = this.memstore.getScanners(mvcc.getReadPoint()).get(0); assertScannerResults(s, new KeyValue[]{kv1}); w = mvcc.begin(); KeyValue kv2 = new KeyValue(row, f, q2, v); kv2.setSequenceId(w.getWriteNumber()); memstore.add(kv2, null); s = this.memstore.getScanners(mvcc.getReadPoint()).get(0); assertScannerResults(s, new KeyValue[]{kv1}); mvcc.completeAndWait(w); s = this.memstore.getScanners(mvcc.getReadPoint()).get(0); assertScannerResults(s, new KeyValue[]{kv1, kv2}); }
writeEntry = mvcc.begin(); long flushOpSeqId = writeEntry.getWriteNumber(); FlushResultImpl flushResult = new FlushResultImpl(FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, flushOpSeqId, "Nothing to flush", writeFlushRequestMarkerToWAL(wal, writeFlushWalMarker)); mvcc.completeAndWait(writeEntry); mvcc.complete(writeEntry);
TableName.valueOf("test2727"); MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); HRegionInfo hri = createBasic3FamilyHRegionInfo(tableName); Path basedir = FSUtils.getTableDir(hbaseRootDir, tableName); assertTrue(seqid > mvcc.getWritePoint()); assertEquals(seqid - 1, mvcc.getWritePoint()); LOG.debug("region.getOpenSeqNum(): " + region.getOpenSeqNum() + ", wal3.id: " + mvcc.getReadPoint());
protected void internalSetUp() throws Exception { this.mvcc = new MultiVersionConcurrencyControl(); }
this.mvcc.await(); if (this.coprocessorHost != null) { Result r = this.coprocessorHost.preIncrementAfterRowLock(increment); if (walKey != null) mvcc.complete(walKey.getWriteEntry()); } else { if (walKey != null) mvcc.completeAndWait(walKey.getWriteEntry());
/** * @return readpoint considering given IsolationLevel. Pass {@code null} for default */ public long getReadPoint(IsolationLevel isolationLevel) { if (isolationLevel != null && isolationLevel == IsolationLevel.READ_UNCOMMITTED) { // This scan can read even uncommitted transactions return Long.MAX_VALUE; } return mvcc.getReadPoint(); }
/** * Call {@link #begin(Runnable)} with an empty {@link Runnable}. */ public WriteEntry begin() { return begin(() -> {}); }
StreamLacksCapabilityException { final TableName tableName = TableName.valueOf("testReplayEditsWrittenIntoWAL"); final MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(); final HRegionInfo hri = createBasic3FamilyHRegionInfo(tableName); final Path basedir = FSUtils.getTableDir(hbaseRootDir, tableName); WAL wal = createWAL(this.conf, hbaseRootDir, logName); region = HRegion.openHRegion(conf, this.fs, hbaseRootDir, hri, htd, wal); assertTrue(region.getOpenSeqNum() > mvcc.getWritePoint()); assertEquals(2, region.get(new Get(rowName)).size());
mvcc.complete(writeEntry); writeEntry = null; mvcc.completeAndWait(writeEntry);
/** * This method completes mini-batch operations by calling postBatchMutate() CP hook (if * required) and completing mvcc. */ public void completeMiniBatchOperations( final MiniBatchOperationInProgress<Mutation> miniBatchOp, final WriteEntry writeEntry) throws IOException { if (writeEntry != null) { region.mvcc.completeAndWait(writeEntry); } }
long writePoint = mvcc.getWritePoint();
mvcc.await();
/** * Construct and set read point. Write point is uninitialized. */ public MultiVersionConcurrencyControl(long startPoint) { tryAdvanceTo(startPoint, NONE); }
private void internalRun() throws IOException { for (long i = 0; i < NUM_TRIES && caughtException.get() == null; i++) { MultiVersionConcurrencyControl.WriteEntry w = mvcc.begin(); // Insert the sequence value (i) byte[] v = Bytes.toBytes(i); KeyValue kv = new KeyValue(row, f, q1, i, v); kv.setSequenceId(w.getWriteNumber()); memstore.add(kv, null); mvcc.completeAndWait(w); // Assert that we can read back KeyValueScanner s = this.memstore.getScanners(mvcc.getReadPoint()).get(0); s.seek(kv); Cell ret = s.next(); assertNotNull("Didnt find own write at all", ret); assertEquals("Didnt read own writes", kv.getTimestamp(), ret.getTimestamp()); } } }