Search in sources :

Example 1 with Transactions

use of co.cask.cdap.data2.transaction.Transactions in project cdap by caskdata.

the class TableTest method testBasicGetPutWithTx.

@Test
public void testBasicGetPutWithTx() throws Exception {
    DatasetAdmin admin = getTableAdmin(CONTEXT1, MY_TABLE);
    admin.create();
    try {
        Transaction tx1 = txClient.startShort();
        Table myTable1 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable1).startTx(tx1);
        // write r1->c1,v1 but not commit
        myTable1.put(R1, a(C1), a(V1));
        // TableAssert.verify can see changes inside tx
        TableAssert.assertRow(a(C1, V1), myTable1.get(R1, a(C1, C2)).getColumns());
        Assert.assertArrayEquals(V1, myTable1.get(R1, C1));
        Assert.assertArrayEquals(null, myTable1.get(R1, C2));
        Assert.assertArrayEquals(null, myTable1.get(R2, C1));
        TableAssert.assertRow(a(C1, V1), myTable1.get(R1).getColumns());
        // start new tx (doesn't see changes of the tx1)
        Transaction tx2 = txClient.startShort();
        Table myTable2 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable2).startTx(tx2);
        // TableAssert.verify doesn't see changes of tx1
        TableAssert.assertRow(a(), myTable2.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable2.get(R1, C1));
        Assert.assertArrayEquals(null, myTable2.get(R1, C2));
        TableAssert.assertRow(a(), myTable2.get(R1));
        // write r2->c2,v2 in tx2
        myTable2.put(R2, a(C2), a(V2));
        // TableAssert.verify can see own changes
        TableAssert.assertRow(a(C2, V2), myTable2.get(R2, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable2.get(R2, C1));
        Assert.assertArrayEquals(V2, myTable2.get(R2, C2));
        TableAssert.assertRow(a(C2, V2), myTable2.get(R2));
        // TableAssert.verify tx1 cannot see changes of tx2
        TableAssert.assertRow(a(), myTable1.get(R2, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable1.get(R2, C1));
        Assert.assertArrayEquals(null, myTable1.get(R2, C2));
        TableAssert.assertRow(a(), myTable1.get(R2));
        // committing tx1 in stages to check races are handled well
        // * first, flush operations of table
        txClient.canCommitOrThrow(tx1, ((TransactionAware) myTable1).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable1).commitTx());
        // start tx3 and TableAssert.verify that changes of tx1 are not visible yet (even though they are flushed)
        Transaction tx3 = txClient.startShort();
        Table myTable3 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable3).startTx(tx3);
        TableAssert.assertRow(a(), myTable3.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable3.get(R1, C1));
        Assert.assertArrayEquals(null, myTable3.get(R1, C2));
        TableAssert.assertRow(a(), myTable3.get(R1));
        txClient.canCommitOrThrow(tx3, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable3).commitTx());
        txClient.commitOrThrow(tx3);
        // * second, make tx visible
        txClient.commitOrThrow(tx1);
        // start tx4 and TableAssert.verify that changes of tx1 are now visible
        // NOTE: table instance can be re-used in series of transactions
        Transaction tx4 = txClient.startShort();
        ((TransactionAware) myTable3).startTx(tx4);
        TableAssert.assertRow(a(C1, V1), myTable3.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(V1, myTable3.get(R1, C1));
        Assert.assertArrayEquals(null, myTable3.get(R1, C2));
        TableAssert.assertRow(a(C1, V1), myTable3.get(R1));
        // but tx2 still doesn't see committed changes of tx2
        TableAssert.assertRow(a(), myTable2.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable2.get(R1, C1));
        Assert.assertArrayEquals(null, myTable2.get(R1, C2));
        TableAssert.assertRow(a(), myTable2.get(R1));
        // and tx4 doesn't see changes of tx2
        TableAssert.assertRow(a(), myTable3.get(R2, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable3.get(R2, C1));
        Assert.assertArrayEquals(null, myTable3.get(R2, C2));
        TableAssert.assertRow(a(), myTable3.get(R2));
        // committing tx4
        txClient.canCommitOrThrow(tx4, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable3).commitTx());
        txClient.commitOrThrow(tx4);
        // do change in tx2 that is conflicting with tx1
        myTable2.put(R1, a(C1), a(V2));
        // change is OK and visible inside tx2
        TableAssert.assertRow(a(C1, V2), myTable2.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(V2, myTable2.get(R1, C1));
        Assert.assertArrayEquals(null, myTable2.get(R1, C2));
        TableAssert.assertRow(a(C1, V2), myTable2.get(R1));
        // cannot commit: conflict should be detected
        try {
            txClient.canCommitOrThrow(tx2, ((TransactionAware) myTable2).getTxChanges());
            Assert.fail("Conflict not detected!");
        } catch (TransactionConflictException e) {
        // expected
        }
        // rolling back tx2 changes and aborting tx
        ((TransactionAware) myTable2).rollbackTx();
        txClient.abort(tx2);
        // TableAssert.verifying that none of the changes of tx2 made it to be visible to other txs
        // NOTE: table instance can be re-used in series of transactions
        Transaction tx5 = txClient.startShort();
        ((TransactionAware) myTable3).startTx(tx5);
        TableAssert.assertRow(a(C1, V1), myTable3.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(V1, myTable3.get(R1, C1));
        Assert.assertArrayEquals(null, myTable3.get(R1, C2));
        TableAssert.assertRow(a(C1, V1), myTable3.get(R1));
        TableAssert.assertRow(a(), myTable3.get(R2, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable3.get(R2, C1));
        Assert.assertArrayEquals(null, myTable3.get(R2, C2));
        TableAssert.assertRow(a(), myTable3.get(R2));
        txClient.canCommitOrThrow(tx5, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable3).commitTx());
        txClient.commitOrThrow(tx5);
    } finally {
        admin.drop();
    }
}
Also used : Table(co.cask.cdap.api.dataset.table.Table) HBaseTable(co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable) Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) TransactionConflictException(org.apache.tephra.TransactionConflictException) Test(org.junit.Test)

Example 2 with Transactions

use of co.cask.cdap.data2.transaction.Transactions in project cdap by caskdata.

the class TableTest method testBasicIncrementWithTx.

private void testBasicIncrementWithTx(boolean doIncrAndGet, boolean readless) throws Exception {
    DatasetProperties props = TableProperties.builder().setReadlessIncrementSupport(readless).build();
    DatasetAdmin admin = getTableAdmin(CONTEXT1, MY_TABLE, props);
    admin.create();
    Table myTable1, myTable2, myTable3, myTable4;
    try {
        Transaction tx1 = txClient.startShort();
        myTable1 = getTable(CONTEXT1, MY_TABLE, props);
        ((TransactionAware) myTable1).startTx(tx1);
        myTable1.put(R1, a(C1), a(L4));
        doIncrement(doIncrAndGet, myTable1, R1, a(C1), la(-3L), lb(1L));
        doIncrement(doIncrAndGet, myTable1, R1, a(C2), la(2L), lb(2L));
        // TableAssert.verify increment result visible inside tx before commit
        TableAssert.assertRow(a(C1, L1, C2, L2), myTable1.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(L1, myTable1.get(R1, C1));
        Assert.assertArrayEquals(L2, myTable1.get(R1, C2));
        Assert.assertArrayEquals(null, myTable1.get(R1, C3));
        TableAssert.assertRow(a(C1, L1), myTable1.get(R1, a(C1)));
        TableAssert.assertRow(a(C1, L1, C2, L2), myTable1.get(R1));
        // incrementing non-long value should fail
        myTable1.put(R1, a(C5), a(V5));
        try {
            doIncrement(doIncrAndGet, myTable1, R1, a(C5), la(5L), lb(-1L));
            Assert.fail("increment should have failed with NumberFormatException");
        } catch (NumberFormatException e) {
        // Expected
        }
        // previous increment should not do any change
        TableAssert.assertRow(a(C5, V5), myTable1.get(R1, a(C5)));
        Assert.assertArrayEquals(V5, myTable1.get(R1, C5));
        // start new tx (doesn't see changes of the tx1)
        Transaction tx2 = txClient.startShort();
        // committing tx1 in stages to check races are handled well
        // * first, flush operations of table
        txClient.canCommitOrThrow(tx1, ((TransactionAware) myTable1).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable1).commitTx());
        // check that tx2 doesn't see changes (even though they were flushed) of tx1
        // assuming current value is null
        myTable2 = getTable(CONTEXT1, MY_TABLE, props);
        ((TransactionAware) myTable2).startTx(tx2);
        TableAssert.assertRow(a(), myTable2.get(R1, a(C1, C2, C5)));
        Assert.assertArrayEquals(null, myTable2.get(R1, C1));
        Assert.assertArrayEquals(null, myTable2.get(R1, C2));
        Assert.assertArrayEquals(null, myTable2.get(R1, C5));
        TableAssert.assertRow(a(), myTable2.get(R1));
        doIncrement(doIncrAndGet, myTable2, R1, a(C1), la(55L), lb(55L));
        // start tx3 and TableAssert.verify same thing again
        Transaction tx3 = txClient.startShort();
        myTable3 = getTable(CONTEXT1, MY_TABLE, props);
        ((TransactionAware) myTable3).startTx(tx3);
        TableAssert.assertRow(a(), myTable3.get(R1, a(C1, C2, C5)));
        Assert.assertArrayEquals(null, myTable3.get(R1, C1));
        Assert.assertArrayEquals(null, myTable3.get(R1, C2));
        Assert.assertArrayEquals(null, myTable3.get(R1, C5));
        TableAssert.assertRow(a(), myTable3.get(R1));
        doIncrement(doIncrAndGet, myTable3, R1, a(C1), la(4L), lb(4L));
        // * second, make tx visible
        txClient.commitOrThrow(tx1);
        // TableAssert.verify that tx2 cannot commit because of the conflicts...
        try {
            txClient.canCommitOrThrow(tx2, ((TransactionAware) myTable2).getTxChanges());
            Assert.fail("Conflict not detected!");
        } catch (TransactionConflictException e) {
        // expected
        }
        ((TransactionAware) myTable2).rollbackTx();
        txClient.abort(tx2);
        // start tx4 and TableAssert.verify that changes of tx1 are now visible
        Transaction tx4 = txClient.startShort();
        myTable4 = getTable(CONTEXT1, MY_TABLE, props);
        ((TransactionAware) myTable4).startTx(tx4);
        TableAssert.assertRow(a(C1, L1, C2, L2, C5, V5), myTable4.get(R1, a(C1, C2, C3, C4, C5)));
        TableAssert.assertRow(a(C2, L2), myTable4.get(R1, a(C2)));
        Assert.assertArrayEquals(L1, myTable4.get(R1, C1));
        Assert.assertArrayEquals(L2, myTable4.get(R1, C2));
        Assert.assertArrayEquals(null, myTable4.get(R1, C3));
        Assert.assertArrayEquals(V5, myTable4.get(R1, C5));
        TableAssert.assertRow(a(C1, L1, C5, V5), myTable4.get(R1, a(C1, C5)));
        TableAssert.assertRow(a(C1, L1, C2, L2, C5, V5), myTable4.get(R1));
        // tx3 still cannot see tx1 changes, only its own
        TableAssert.assertRow(a(C1, L4), myTable3.get(R1, a(C1, C2, C5)));
        Assert.assertArrayEquals(L4, myTable3.get(R1, C1));
        Assert.assertArrayEquals(null, myTable3.get(R1, C2));
        Assert.assertArrayEquals(null, myTable3.get(R1, C5));
        TableAssert.assertRow(a(C1, L4), myTable3.get(R1));
        // and it cannot commit because its changes cause conflicts
        try {
            txClient.canCommitOrThrow(tx3, ((TransactionAware) myTable3).getTxChanges());
            Assert.fail("Conflict not detected!");
        } catch (TransactionConflictException e) {
        // expected
        }
        ((TransactionAware) myTable3).rollbackTx();
        txClient.abort(tx3);
        // TableAssert.verify we can do some ops with tx4 based on data written with tx1
        doIncrement(doIncrAndGet, myTable4, R1, a(C1, C2, C3), la(2L, 1L, 5L), lb(3L, 3L, 5L));
        myTable4.delete(R1, a(C2));
        doIncrement(doIncrAndGet, myTable4, R1, a(C4), la(3L), lb(3L));
        myTable4.delete(R1, a(C1));
        // committing tx4
        txClient.canCommitOrThrow(tx4, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable4).commitTx());
        txClient.commitOrThrow(tx4);
        // TableAssert.verifying the result contents in next transaction
        Transaction tx5 = txClient.startShort();
        // NOTE: table instance can be re-used in series of transactions
        ((TransactionAware) myTable4).startTx(tx5);
        TableAssert.assertRow(a(C3, L5, C4, L3, C5, V5), myTable4.get(R1, a(C1, C2, C3, C4, C5)));
        Assert.assertArrayEquals(null, myTable4.get(R1, C1));
        Assert.assertArrayEquals(null, myTable4.get(R1, C2));
        Assert.assertArrayEquals(L5, myTable4.get(R1, C3));
        Assert.assertArrayEquals(L3, myTable4.get(R1, C4));
        Assert.assertArrayEquals(V5, myTable4.get(R1, C5));
        TableAssert.assertRow(a(C3, L5, C4, L3, C5, V5), myTable4.get(R1));
        txClient.canCommitOrThrow(tx5, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable3).commitTx());
        txClient.commitOrThrow(tx5);
    } finally {
        admin.drop();
    }
}
Also used : Table(co.cask.cdap.api.dataset.table.Table) HBaseTable(co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable) Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) DatasetProperties(co.cask.cdap.api.dataset.DatasetProperties) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) TransactionConflictException(org.apache.tephra.TransactionConflictException)

Example 3 with Transactions

use of co.cask.cdap.data2.transaction.Transactions in project cdap by caskdata.

the class WorkerProgramRunnerTest method beforeClass.

@BeforeClass
public static void beforeClass() throws IOException {
    // we are only gonna do long-running transactions here. Set the tx timeout to a ridiculously low value.
    // that will test that the long-running transactions actually bypass that timeout.
    CConfiguration conf = CConfiguration.create();
    conf.setInt(TxConstants.Manager.CFG_TX_TIMEOUT, 1);
    conf.setInt(TxConstants.Manager.CFG_TX_CLEANUP_INTERVAL, 2);
    Injector injector = AppFabricTestHelper.getInjector(conf);
    txService = injector.getInstance(TransactionManager.class);
    txExecutorFactory = injector.getInstance(TransactionExecutorFactory.class);
    dsFramework = injector.getInstance(DatasetFramework.class);
    datasetCache = new SingleThreadDatasetCache(new SystemDatasetInstantiator(dsFramework, WorkerProgramRunnerTest.class.getClassLoader(), null), injector.getInstance(TransactionSystemClient.class), NamespaceId.DEFAULT, DatasetDefinition.NO_ARGUMENTS, null, null);
    metricStore = injector.getInstance(MetricStore.class);
    txService.startAndWait();
}
Also used : DatasetFramework(co.cask.cdap.data2.dataset2.DatasetFramework) MetricStore(co.cask.cdap.api.metrics.MetricStore) Injector(com.google.inject.Injector) TransactionManager(org.apache.tephra.TransactionManager) SystemDatasetInstantiator(co.cask.cdap.data.dataset.SystemDatasetInstantiator) SingleThreadDatasetCache(co.cask.cdap.data2.dataset2.SingleThreadDatasetCache) CConfiguration(co.cask.cdap.common.conf.CConfiguration) TransactionExecutorFactory(co.cask.cdap.data2.transaction.TransactionExecutorFactory) BeforeClass(org.junit.BeforeClass)

Example 4 with Transactions

use of co.cask.cdap.data2.transaction.Transactions in project cdap by caskdata.

the class QueueEntryRow method canConsume.

/**
 * Looks at specific queue entry and determines if consumer with given consumer config and current transaction
 * can consume this entry. The answer can be
 * "yes" ({@link co.cask.cdap.data2.transaction.queue.QueueEntryRow.CanConsume#YES},
 * "no"  ({@link co.cask.cdap.data2.transaction.queue.QueueEntryRow.CanConsume#NO},
 * "no" with a hint that given consumer cannot consume any of the entries prior to this one
 *       ({@link co.cask.cdap.data2.transaction.queue.QueueEntryRow.CanConsume#NO_INCLUDING_ALL_OLDER}.
 * The latter one allows for some optimizations when doing scans of entries to be
 * consumed.
 *
 * @param consumerConfig config of the consumer
 * @param transaction current tx
 * @param enqueueWritePointer write pointer used by enqueue of this entry
 * @param counter counter of this entry
 * @param metaValue value of meta column of this entry
 * @param stateValue value of state column of this entry
 * @return one {@link co.cask.cdap.data2.transaction.queue.QueueEntryRow.CanConsume} as per description above.
 */
public static CanConsume canConsume(ConsumerConfig consumerConfig, Transaction transaction, long enqueueWritePointer, int counter, byte[] metaValue, byte[] stateValue) {
    DequeueStrategy dequeueStrategy = consumerConfig.getDequeueStrategy();
    if (stateValue != null) {
        // If the state is written by the current transaction, ignore it, as it's processing
        long stateWritePointer = QueueEntryRow.getStateWritePointer(stateValue);
        if (stateWritePointer == transaction.getWritePointer()) {
            return CanConsume.NO;
        }
        // If the state was updated by a different consumer instance that is still active, ignore this entry.
        // The assumption is, the corresponding instance is either processing (claimed)
        // or going to process it (due to rollback/restart).
        // This only applies to FIFO, as for hash and rr, repartition needs to happen if group size change.
        int stateInstanceId = QueueEntryRow.getStateInstanceId(stateValue);
        if (dequeueStrategy == DequeueStrategy.FIFO && stateInstanceId < consumerConfig.getGroupSize() && stateInstanceId != consumerConfig.getInstanceId()) {
            return CanConsume.NO;
        }
        // If state is PROCESSED and committed, ignore it:
        ConsumerEntryState state = QueueEntryRow.getState(stateValue);
        if (state == ConsumerEntryState.PROCESSED && transaction.isVisible(stateWritePointer)) {
            // Note: here we ignore the long-running transactions, because we know they don't interact with queues.
            if (enqueueWritePointer < transaction.getFirstShortInProgress()) {
                return CanConsume.NO_INCLUDING_ALL_OLDER;
            }
            return CanConsume.NO;
        }
    }
    // Always try to process (claim) if using FIFO. The resolution will be done by atomically setting state to CLAIMED
    int instanceId = consumerConfig.getInstanceId();
    if (dequeueStrategy == DequeueStrategy.ROUND_ROBIN) {
        instanceId = getRoundRobinConsumerInstance(enqueueWritePointer, counter, consumerConfig.getGroupSize());
    } else if (dequeueStrategy == DequeueStrategy.HASH) {
        try {
            Map<String, Integer> hashKeys = QueueEntry.deserializeHashKeys(metaValue);
            instanceId = getHashConsumerInstance(hashKeys, consumerConfig.getHashKey(), consumerConfig.getGroupSize());
        } catch (IOException e) {
            // SHOULD NEVER happen
            throw new RuntimeException(e);
        }
    }
    return consumerConfig.getInstanceId() == instanceId ? CanConsume.YES : CanConsume.NO;
}
Also used : DequeueStrategy(co.cask.cdap.data2.queue.DequeueStrategy) IOException(java.io.IOException) Map(java.util.Map)

Example 5 with Transactions

use of co.cask.cdap.data2.transaction.Transactions in project cdap by caskdata.

the class TableTest method testBasicCompareAndSwapWithTx.

@Test
public void testBasicCompareAndSwapWithTx() throws Exception {
    DatasetAdmin admin = getTableAdmin(CONTEXT1, MY_TABLE);
    admin.create();
    try {
        Transaction tx1 = txClient.startShort();
        Table myTable1 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable1).startTx(tx1);
        // write r1->c1,v1 but not commit
        myTable1.put(R1, a(C1), a(V1));
        // write r1->c2,v2 but not commit
        Assert.assertTrue(myTable1.compareAndSwap(R1, C2, null, V5));
        // TableAssert.verify compare and swap result visible inside tx before commit
        TableAssert.assertRow(a(C1, V1, C2, V5), myTable1.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(V1, myTable1.get(R1, C1));
        Assert.assertArrayEquals(V5, myTable1.get(R1, C2));
        Assert.assertArrayEquals(null, myTable1.get(R1, C3));
        TableAssert.assertRow(a(C1, V1, C2, V5), myTable1.get(R1));
        // these should fail
        Assert.assertFalse(myTable1.compareAndSwap(R1, C1, null, V1));
        Assert.assertFalse(myTable1.compareAndSwap(R1, C1, V2, V1));
        Assert.assertFalse(myTable1.compareAndSwap(R1, C2, null, V2));
        Assert.assertFalse(myTable1.compareAndSwap(R1, C2, V2, V1));
        // but this should succeed
        Assert.assertTrue(myTable1.compareAndSwap(R1, C2, V5, V2));
        // start new tx (doesn't see changes of the tx1)
        Transaction tx2 = txClient.startShort();
        // committing tx1 in stages to check races are handled well
        // * first, flush operations of table
        txClient.canCommitOrThrow(tx1, ((TransactionAware) myTable1).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable1).commitTx());
        // check that tx2 doesn't see changes (even though they were flushed) of tx1 by trying to compareAndSwap
        // assuming current value is null
        Table myTable2 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable2).startTx(tx2);
        Assert.assertTrue(myTable2.compareAndSwap(R1, C1, null, V3));
        // start tx3 and TableAssert.verify same thing again
        Transaction tx3 = txClient.startShort();
        Table myTable3 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable3).startTx(tx3);
        Assert.assertTrue(myTable3.compareAndSwap(R1, C1, null, V2));
        // * second, make tx visible
        txClient.commitOrThrow(tx1);
        // TableAssert.verify that tx2 cannot commit because of the conflicts...
        try {
            txClient.canCommitOrThrow(tx2, ((TransactionAware) myTable2).getTxChanges());
            Assert.fail("Conflict not detected!");
        } catch (TransactionConflictException e) {
        // expected
        }
        ((TransactionAware) myTable2).rollbackTx();
        txClient.abort(tx2);
        // start tx4 and TableAssert.verify that changes of tx1 are now visible
        Transaction tx4 = txClient.startShort();
        Table myTable4 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable4).startTx(tx4);
        TableAssert.assertRow(a(C1, V1, C2, V2), myTable4.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(V1, myTable4.get(R1, C1));
        Assert.assertArrayEquals(V2, myTable4.get(R1, C2));
        Assert.assertArrayEquals(null, myTable4.get(R1, C3));
        TableAssert.assertRow(a(C2, V2), myTable4.get(R1, a(C2)));
        TableAssert.assertRow(a(C1, V1, C2, V2), myTable4.get(R1));
        // tx3 still cannot see tx1 changes
        Assert.assertTrue(myTable3.compareAndSwap(R1, C2, null, V5));
        // and it cannot commit because its changes cause conflicts
        try {
            txClient.canCommitOrThrow(tx3, ((TransactionAware) myTable3).getTxChanges());
            Assert.fail("Conflict not detected!");
        } catch (TransactionConflictException e) {
        // expected
        }
        ((TransactionAware) myTable3).rollbackTx();
        txClient.abort(tx3);
        // TableAssert.verify we can do some ops with tx4 based on data written with tx1
        Assert.assertFalse(myTable4.compareAndSwap(R1, C1, null, V4));
        Assert.assertFalse(myTable4.compareAndSwap(R1, C2, null, V5));
        Assert.assertTrue(myTable4.compareAndSwap(R1, C1, V1, V3));
        Assert.assertTrue(myTable4.compareAndSwap(R1, C2, V2, V4));
        myTable4.delete(R1, a(C1));
        // committing tx4
        txClient.canCommitOrThrow(tx4, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable4).commitTx());
        txClient.commitOrThrow(tx4);
        // TableAssert.verifying the result contents in next transaction
        Transaction tx5 = txClient.startShort();
        // NOTE: table instance can be re-used in series of transactions
        ((TransactionAware) myTable4).startTx(tx5);
        TableAssert.assertRow(a(C2, V4), myTable4.get(R1, a(C1, C2)));
        Assert.assertArrayEquals(null, myTable4.get(R1, C1));
        Assert.assertArrayEquals(V4, myTable4.get(R1, C2));
        TableAssert.assertRow(a(C2, V4), myTable4.get(R1));
        txClient.canCommitOrThrow(tx5, ((TransactionAware) myTable3).getTxChanges());
        Assert.assertTrue(((TransactionAware) myTable3).commitTx());
        txClient.commitOrThrow(tx5);
    } finally {
        admin.drop();
    }
}
Also used : Table(co.cask.cdap.api.dataset.table.Table) HBaseTable(co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable) Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) TransactionConflictException(org.apache.tephra.TransactionConflictException) Test(org.junit.Test)

Aggregations

DatasetAdmin (co.cask.cdap.api.dataset.DatasetAdmin)3 Table (co.cask.cdap.api.dataset.table.Table)3 HBaseTable (co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable)3 Transaction (org.apache.tephra.Transaction)3 TransactionAware (org.apache.tephra.TransactionAware)3 TransactionConflictException (org.apache.tephra.TransactionConflictException)3 Test (org.junit.Test)2 DatasetProperties (co.cask.cdap.api.dataset.DatasetProperties)1 MetricStore (co.cask.cdap.api.metrics.MetricStore)1 CConfiguration (co.cask.cdap.common.conf.CConfiguration)1 SystemDatasetInstantiator (co.cask.cdap.data.dataset.SystemDatasetInstantiator)1 DatasetFramework (co.cask.cdap.data2.dataset2.DatasetFramework)1 SingleThreadDatasetCache (co.cask.cdap.data2.dataset2.SingleThreadDatasetCache)1 DequeueStrategy (co.cask.cdap.data2.queue.DequeueStrategy)1 TransactionExecutorFactory (co.cask.cdap.data2.transaction.TransactionExecutorFactory)1 Injector (com.google.inject.Injector)1 IOException (java.io.IOException)1 Map (java.util.Map)1 TransactionManager (org.apache.tephra.TransactionManager)1 BeforeClass (org.junit.BeforeClass)1