private byte[] encodeStateColumn(ConsumerEntryState state) { // State column content is encoded as (writePointer) + (instanceId) + (state) byte[] stateContent = new byte[Longs.BYTES + Ints.BYTES + 1]; Bytes.putLong(stateContent, 0, transaction.getWritePointer()); Bytes.putInt(stateContent, Longs.BYTES, consumerConfig.getInstanceId()); Bytes.putByte(stateContent, Longs.BYTES + Ints.BYTES, state.getState()); return stateContent; }
@Test public void testCheckpointInvalidate() throws Exception { // start a transaction, using checkpoints between writes transactionContext.start(); Transaction origTx = transactionContext.getCurrentTransaction(); transactionAwareHTable.put( new Put(TestBytes.row).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); transactionContext.checkpoint(); Transaction checkpointTx1 = transactionContext.getCurrentTransaction(); transactionAwareHTable.put( new Put(TestBytes.row2).add(TestBytes.family, TestBytes.qualifier, TestBytes.value2)); transactionContext.checkpoint(); Transaction checkpointTx2 = transactionContext.getCurrentTransaction(); transactionAwareHTable.put( new Put(TestBytes.row3).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); TransactionSystemClient txClient = new InMemoryTxSystemClient(txManager); txClient.invalidate(transactionContext.getCurrentTransaction().getTransactionId()); // check that writes are not visible TransactionAwareHTable txTable2 = new TransactionAwareHTable(new HTable(conf, TestBytes.table)); TransactionContext txContext2 = new TransactionContext(txClient, txTable2); txContext2.start(); Transaction newTx = txContext2.getCurrentTransaction(); // all 3 writes pointers from the previous transaction should now be excluded assertTrue(newTx.isExcluded(origTx.getWritePointer())); assertTrue(newTx.isExcluded(checkpointTx1.getWritePointer())); assertTrue(newTx.isExcluded(checkpointTx2.getWritePointer())); verifyRow(txTable2, TestBytes.row, null); verifyRow(txTable2, TestBytes.row2, null); verifyRow(txTable2, TestBytes.row3, null); Scan scan = new Scan(); ResultScanner scanner = txTable2.getScanner(scan); assertNull(scanner.next()); scanner.close(); txContext2.finish(); }
@Test public void testCheckpoint() throws Exception { // start a transaction, using checkpoints between writes transactionContext.start(); transactionAwareHTable.put( new Put(TestBytes.row).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); Transaction origTx = transactionContext.getCurrentTransaction(); transactionContext.checkpoint(); Transaction postCheckpointTx = transactionContext.getCurrentTransaction(); assertEquals(origTx.getTransactionId(), postCheckpointTx.getTransactionId()); assertNotEquals(origTx.getWritePointer(), postCheckpointTx.getWritePointer()); long[] checkpointPtrs = postCheckpointTx.getCheckpointWritePointers(); assertEquals(1, checkpointPtrs.length); assertEquals(postCheckpointTx.getWritePointer(), checkpointPtrs[0]); transactionAwareHTable.put( new Put(TestBytes.row2).add(TestBytes.family, TestBytes.qualifier, TestBytes.value2)); transactionContext.checkpoint(); Transaction postCheckpointTx2 = transactionContext.getCurrentTransaction(); assertEquals(origTx.getTransactionId(), postCheckpointTx2.getTransactionId()); assertNotEquals(postCheckpointTx.getWritePointer(), postCheckpointTx2.getWritePointer()); long[] checkpointPtrs2 = postCheckpointTx2.getCheckpointWritePointers(); assertEquals(2, checkpointPtrs2.length); assertEquals(postCheckpointTx.getWritePointer(), checkpointPtrs2[0]); assertEquals(postCheckpointTx2.getWritePointer(), checkpointPtrs2[1]); transactionAwareHTable.put( new Put(TestBytes.row3).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); // by default, all rows should be visible with Read-Your-Writes verifyRow(transactionAwareHTable, TestBytes.row, TestBytes.value); verifyRow(transactionAwareHTable, TestBytes.row2, TestBytes.value2); verifyRow(transactionAwareHTable, TestBytes.row3, TestBytes.value); // when disabling current write pointer, only the previous checkpoints should be visible transactionContext .getCurrentTransaction() .setVisibility(Transaction.VisibilityLevel.SNAPSHOT_EXCLUDE_CURRENT); Get get = new Get(TestBytes.row); verifyRow(transactionAwareHTable, get, TestBytes.value); get = new Get(TestBytes.row2); verifyRow(transactionAwareHTable, get, TestBytes.value2); get = new Get(TestBytes.row3); verifyRow(transactionAwareHTable, get, null); // test scan results excluding current write pointer Scan scan = new Scan(); ResultScanner scanner = transactionAwareHTable.getScanner(scan); Result row = scanner.next(); assertNotNull(row); assertArrayEquals(TestBytes.row, row.getRow()); assertEquals(1, row.size()); assertArrayEquals(TestBytes.value, row.getValue(TestBytes.family, TestBytes.qualifier)); row = scanner.next(); assertNotNull(row); assertArrayEquals(TestBytes.row2, row.getRow()); assertEquals(1, row.size()); assertArrayEquals(TestBytes.value2, row.getValue(TestBytes.family, TestBytes.qualifier)); row = scanner.next(); assertNull(row); scanner.close(); transactionContext.getCurrentTransaction().setVisibility(Transaction.VisibilityLevel.SNAPSHOT); // check that writes are still not visible to other clients TransactionAwareHTable txTable2 = new TransactionAwareHTable(new HTable(conf, TestBytes.table)); TransactionContext txContext2 = new TransactionContext(new InMemoryTxSystemClient(txManager), txTable2); txContext2.start(); verifyRow(txTable2, TestBytes.row, null); verifyRow(txTable2, TestBytes.row2, null); verifyRow(txTable2, TestBytes.row3, null); txContext2.finish(); // commit transaction, verify writes are visible transactionContext.finish(); txContext2.start(); verifyRow(txTable2, TestBytes.row, TestBytes.value); verifyRow(txTable2, TestBytes.row2, TestBytes.value2); verifyRow(txTable2, TestBytes.row3, TestBytes.value); txContext2.finish(); txTable2.close(); }
@Test public void testNoneLevelConflictDetection() throws Exception { InMemoryTxSystemClient txClient = new InMemoryTxSystemClient(txManager); TransactionAwareHTable txTable1 = new TransactionAwareHTable( new HTable(conf, TestBytes.table), TxConstants.ConflictDetection.NONE); TransactionContext txContext1 = new TransactionContext(txClient, txTable1); TransactionAwareHTable txTable2 = new TransactionAwareHTable( new HTable(conf, TestBytes.table), TxConstants.ConflictDetection.NONE); TransactionContext txContext2 = new TransactionContext(txClient, txTable2); // overlapping writes to the same row + column should not conflict txContext1.start(); txTable1.put( new Put(TestBytes.row).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); // changes should not be visible yet txContext2.start(); Result row = txTable2.get(new Get(TestBytes.row)); assertTrue(row.isEmpty()); txTable2.put( new Put(TestBytes.row).add(TestBytes.family, TestBytes.qualifier, TestBytes.value2)); // both commits should succeed txContext1.finish(); txContext2.finish(); txContext1.start(); row = txTable1.get(new Get(TestBytes.row)); assertFalse(row.isEmpty()); assertArrayEquals(TestBytes.value2, row.getValue(TestBytes.family, TestBytes.qualifier)); txContext1.finish(); // transaction abort should still rollback changes txContext1.start(); txTable1.put( new Put(TestBytes.row2).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); txContext1.abort(); // changes to row2 should be rolled back txContext2.start(); Result row2 = txTable2.get(new Get(TestBytes.row2)); assertTrue(row2.isEmpty()); txContext2.finish(); // transaction invalidate should still make changes invisible txContext1.start(); Transaction tx1 = txContext1.getCurrentTransaction(); txTable1.put( new Put(TestBytes.row3).add(TestBytes.family, TestBytes.qualifier, TestBytes.value)); assertNotNull(tx1); txClient.invalidate(tx1.getWritePointer()); // changes to row2 should be rolled back txContext2.start(); Result row3 = txTable2.get(new Get(TestBytes.row3)); assertTrue(row3.isEmpty()); txContext2.finish(); }