Search in sources :

Example 16 with TransactionAware

use of org.apache.tephra.TransactionAware in project cdap by caskdata.

the class TableTest method testStringPutGet.

private void testStringPutGet(Table t, String key, String col, String val) throws Exception {
    Transaction tx = txClient.startShort();
    ((TransactionAware) t).startTx(tx);
    t.put(new Put(key, col, val));
    Row row = t.get(new Get(key));
    Assert.assertTrue(!row.isEmpty());
    Assert.assertEquals(key, Bytes.toString(row.getRow()));
    Assert.assertEquals(1, row.getColumns().size());
    Assert.assertEquals(col, Bytes.toString(row.getColumns().entrySet().iterator().next().getKey()));
    Assert.assertEquals(val, Bytes.toString(row.getColumns().entrySet().iterator().next().getValue()));
    Assert.assertEquals(val, Bytes.toString(row.get(col)));
    Assert.assertEquals(val, row.getString(col));
    ((TransactionAware) t).rollbackTx();
    txClient.abort(tx);
}
Also used : Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) Get(co.cask.cdap.api.dataset.table.Get) Row(co.cask.cdap.api.dataset.table.Row) Put(co.cask.cdap.api.dataset.table.Put)

Example 17 with TransactionAware

use of org.apache.tephra.TransactionAware 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 18 with TransactionAware

use of org.apache.tephra.TransactionAware in project cdap by caskdata.

the class BufferingTableTest method testScanWithBuffering.

/**
 * Tests that writes being buffered in memory by the client are still visible during scans.
 */
@Test
public void testScanWithBuffering() throws Exception {
    String testScanWithBuffering = "testScanWithBuffering";
    DatasetAdmin admin = getTableAdmin(CONTEXT1, testScanWithBuffering);
    admin.create();
    try {
        // 
        Transaction tx1 = txClient.startShort();
        Table table1 = getTable(CONTEXT1, testScanWithBuffering);
        ((TransactionAware) table1).startTx(tx1);
        table1.put(Bytes.toBytes("1_01"), a(C1), a(V1));
        table1.put(Bytes.toBytes("1_02"), a(C1), a(V1));
        table1.put(Bytes.toBytes("1_03"), a(C1), a(V1));
        // written values should not yet be persisted
        TableAssert.assertScan(new byte[0][], new byte[0][][], ((BufferingTable) table1).scanPersisted(new Scan(Bytes.toBytes("1_"), Bytes.toBytes("2_"))));
        // buffered values should be visible in a scan
        TableAssert.assertScan(a(Bytes.toBytes("1_01"), Bytes.toBytes("1_02"), Bytes.toBytes("1_03")), aa(a(C1, V1), a(C1, V1), a(C1, V1)), table1.scan(Bytes.toBytes("1_"), Bytes.toBytes("2_")));
        txClient.canCommitOrThrow(tx1, ((TransactionAware) table1).getTxChanges());
        Assert.assertTrue(((TransactionAware) table1).commitTx());
        txClient.commitOrThrow(tx1);
        Transaction tx2 = txClient.startShort();
        ((TransactionAware) table1).startTx(tx2);
        // written values should be visible after commit
        TableAssert.assertScan(a(Bytes.toBytes("1_01"), Bytes.toBytes("1_02"), Bytes.toBytes("1_03")), aa(a(C1, V1), a(C1, V1), a(C1, V1)), table1.scan(Bytes.toBytes("1_"), Bytes.toBytes("2_")));
        txClient.commitOrThrow(tx2);
        Transaction tx3 = txClient.startShort();
        ((TransactionAware) table1).startTx(tx3);
        // test merging of buffered writes on existing rows
        table1.put(Bytes.toBytes("1_01"), a(C2), a(V2));
        table1.put(Bytes.toBytes("1_02"), a(C1), a(V2));
        table1.put(Bytes.toBytes("1_02a"), a(C1), a(V1));
        table1.put(Bytes.toBytes("1_02b"), a(C1), a(V1));
        table1.put(Bytes.toBytes("1_04"), a(C2), a(V2));
        // persisted values should be the same
        TableAssert.assertScan(a(Bytes.toBytes("1_01"), Bytes.toBytes("1_02"), Bytes.toBytes("1_03")), aa(a(C1, V1), a(C1, V1), a(C1, V1)), ((BufferingTable) table1).scanPersisted(new Scan(Bytes.toBytes("1_"), Bytes.toBytes("2_"))));
        // all values should be visible in buffered scan
        TableAssert.assertScan(a(Bytes.toBytes("1_01"), Bytes.toBytes("1_02"), Bytes.toBytes("1_02a"), Bytes.toBytes("1_02b"), Bytes.toBytes("1_03"), Bytes.toBytes("1_04")), aa(// 1_01
        a(C1, V1, C2, V2), // 1_02
        a(C1, V2), // 1_02a
        a(C1, V1), // 1_02b
        a(C1, V1), // 1_03
        a(C1, V1), // 1_04
        a(C2, V2)), table1.scan(Bytes.toBytes("1_"), Bytes.toBytes("2_")));
        txClient.canCommitOrThrow(tx3, ((TransactionAware) table1).getTxChanges());
        Assert.assertTrue(((TransactionAware) table1).commitTx());
        txClient.commitOrThrow(tx3);
        Transaction tx4 = txClient.startShort();
        ((TransactionAware) table1).startTx(tx4);
        // all values should be visible after commit
        TableAssert.assertScan(a(Bytes.toBytes("1_01"), Bytes.toBytes("1_02"), Bytes.toBytes("1_02a"), Bytes.toBytes("1_02b"), Bytes.toBytes("1_03"), Bytes.toBytes("1_04")), aa(// 1_01
        a(C1, V1, C2, V2), // 1_02
        a(C1, V2), // 1_02a
        a(C1, V1), // 1_02b
        a(C1, V1), // 1_03
        a(C1, V1), // 1_04
        a(C2, V2)), table1.scan(Bytes.toBytes("1_"), Bytes.toBytes("2_")));
        txClient.commitOrThrow(tx4);
    } finally {
        admin.drop();
    }
}
Also used : Table(co.cask.cdap.api.dataset.table.Table) Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) Scan(co.cask.cdap.api.dataset.table.Scan) Test(org.junit.Test)

Example 19 with TransactionAware

use of org.apache.tephra.TransactionAware in project cdap by caskdata.

the class BufferingTableTest method testRollingBackAfterExceptionDuringPersist.

@Test
public void testRollingBackAfterExceptionDuringPersist() throws Exception {
    DatasetAdmin admin = getTableAdmin(CONTEXT1, MY_TABLE);
    admin.create();
    try {
        Transaction tx1 = txClient.startShort();
        BufferingTable myTable1 = new BufferingTableWithPersistingFailure(getTable(CONTEXT1, MY_TABLE));
        myTable1.startTx(tx1);
        // write some data but not commit
        myTable1.put(R1, a(C1), a(V1));
        myTable1.put(R2, a(C2), a(V2));
        // verify can see changes inside tx
        TableAssert.assertRow(a(C1, V1), myTable1.get(R1, a(C1)));
        TableAssert.assertRow(a(C2, V2), myTable1.get(R2, a(C2)));
        // persisting changes
        try {
            // should simulate exception
            myTable1.commitTx();
            Assert.assertFalse(true);
        } catch (Throwable th) {
        // Expected simulated exception
        }
        // let's pretend that after persisting changes we still got conflict when finalizing tx, so
        // rolling back changes
        Assert.assertTrue(myTable1.rollbackTx());
        // making tx visible
        txClient.abort(tx1);
        // start new tx
        Transaction tx2 = txClient.startShort();
        Table myTable2 = getTable(CONTEXT1, MY_TABLE);
        ((TransactionAware) myTable2).startTx(tx2);
        // verify don't see rolled back changes
        TableAssert.assertRow(a(), myTable2.get(R1, a(C1)));
        TableAssert.assertRow(a(), myTable2.get(R2, a(C2)));
    } finally {
        admin.drop();
    }
}
Also used : Table(co.cask.cdap.api.dataset.table.Table) Transaction(org.apache.tephra.Transaction) TransactionAware(org.apache.tephra.TransactionAware) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) Test(org.junit.Test)

Example 20 with TransactionAware

use of org.apache.tephra.TransactionAware in project cdap by caskdata.

the class UsageRegistryTest method testUsageRegistry.

@Test
public void testUsageRegistry() {
    // instantiate a usage registry
    UsageRegistry registry = new DefaultUsageRegistry(new TransactionExecutorFactory() {

        @Override
        public TransactionExecutor createExecutor(Iterable<TransactionAware> iterable) {
            return dsFrameworkUtil.newInMemoryTransactionExecutor(iterable);
        }
    }, new ForwardingDatasetFramework(dsFrameworkUtil.getFramework()) {

        @Nullable
        @Override
        public <T extends Dataset> T getDataset(DatasetId datasetInstanceId, Map<String, String> arguments, @Nullable ClassLoader classLoader) throws DatasetManagementException, IOException {
            T t = super.getDataset(datasetInstanceId, arguments, classLoader);
            if (t instanceof UsageDataset) {
                @SuppressWarnings("unchecked") T t1 = (T) new WrappedUsageDataset((UsageDataset) t);
                return t1;
            }
            return t;
        }
    });
    // register usage for a stream and a dataset for single and multiple "owners", including a non-program
    registry.register(flow11, datasetInstance1);
    registry.register(flow12, stream1);
    registry.registerAll(ImmutableList.of(flow21, flow22), datasetInstance2);
    registry.registerAll(ImmutableList.of(flow21, flow22), stream1);
    int count = WrappedUsageDataset.registerCount;
    // validate usage
    Assert.assertEquals(ImmutableSet.of(datasetInstance1), registry.getDatasets(flow11));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow12));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow21));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow22));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow21));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow22));
    Assert.assertEquals(ImmutableSet.of(flow11), registry.getPrograms(datasetInstance1));
    Assert.assertEquals(ImmutableSet.of(flow21, flow22), registry.getPrograms(datasetInstance2));
    Assert.assertEquals(ImmutableSet.of(flow12, flow21, flow22), registry.getPrograms(stream1));
    // register datasets again
    registry.register(flow11, datasetInstance1);
    registry.registerAll(ImmutableList.of(flow21, flow22), datasetInstance2);
    // validate that this does re-register previous usages (DefaultUsageRegistry no longer avoids re-registration)
    count += 3;
    Assert.assertEquals(count, WrappedUsageDataset.registerCount);
    // validate usage
    Assert.assertEquals(ImmutableSet.of(datasetInstance1), registry.getDatasets(flow11));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow12));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow21));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow22));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow21));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow22));
    Assert.assertEquals(ImmutableSet.of(flow11), registry.getPrograms(datasetInstance1));
    Assert.assertEquals(ImmutableSet.of(flow21, flow22), registry.getPrograms(datasetInstance2));
    Assert.assertEquals(ImmutableSet.of(flow12, flow21, flow22), registry.getPrograms(stream1));
    // unregister app
    registry.unregister(flow11.getParent());
    // validate usage for that app is gone
    Assert.assertEquals(ImmutableSet.of(), registry.getDatasets(flow11));
    Assert.assertEquals(ImmutableSet.of(), registry.getStreams(flow12));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow21));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow22));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow21));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow22));
    Assert.assertEquals(ImmutableSet.of(), registry.getPrograms(datasetInstance1));
    Assert.assertEquals(ImmutableSet.of(flow21, flow22), registry.getPrograms(datasetInstance2));
    Assert.assertEquals(ImmutableSet.of(flow21, flow22), registry.getPrograms(stream1));
    // register application 1 again
    registry.register(flow11, datasetInstance1);
    registry.register(flow12, stream1);
    // validate it was re-registered
    Assert.assertEquals(ImmutableSet.of(datasetInstance1), registry.getDatasets(flow11));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow12));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow21));
    Assert.assertEquals(ImmutableSet.of(datasetInstance2), registry.getDatasets(flow22));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow21));
    Assert.assertEquals(ImmutableSet.of(stream1), registry.getStreams(flow22));
    Assert.assertEquals(ImmutableSet.of(flow11), registry.getPrograms(datasetInstance1));
    Assert.assertEquals(ImmutableSet.of(flow21, flow22), registry.getPrograms(datasetInstance2));
    Assert.assertEquals(ImmutableSet.of(flow12, flow21, flow22), registry.getPrograms(stream1));
    // validate that this actually re-registered previous usages (through code in wrapped usage dataset)
    Assert.assertEquals(count + 2, WrappedUsageDataset.registerCount);
}
Also used : TransactionExecutor(org.apache.tephra.TransactionExecutor) IOException(java.io.IOException) TransactionExecutorFactory(org.apache.tephra.TransactionExecutorFactory) DatasetId(co.cask.cdap.proto.id.DatasetId) DatasetManagementException(co.cask.cdap.api.dataset.DatasetManagementException) TransactionAware(org.apache.tephra.TransactionAware) ForwardingDatasetFramework(co.cask.cdap.data2.dataset2.ForwardingDatasetFramework) Nullable(javax.annotation.Nullable) Test(org.junit.Test)

Aggregations

TransactionAware (org.apache.tephra.TransactionAware)97 Test (org.junit.Test)65 TransactionExecutor (org.apache.tephra.TransactionExecutor)48 Table (co.cask.cdap.api.dataset.table.Table)39 Transaction (org.apache.tephra.Transaction)34 IOException (java.io.IOException)28 PartitionedFileSet (co.cask.cdap.api.dataset.lib.PartitionedFileSet)24 DatasetAdmin (co.cask.cdap.api.dataset.DatasetAdmin)23 HBaseTable (co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable)21 PartitionKey (co.cask.cdap.api.dataset.lib.PartitionKey)19 DataSetException (co.cask.cdap.api.dataset.DataSetException)16 List (java.util.List)13 Put (co.cask.cdap.api.dataset.table.Put)12 DatasetManagementException (co.cask.cdap.api.dataset.DatasetManagementException)11 TimePartitionedFileSet (co.cask.cdap.api.dataset.lib.TimePartitionedFileSet)11 Row (co.cask.cdap.api.dataset.table.Row)11 ArrayList (java.util.ArrayList)11 HashSet (java.util.HashSet)11 TransactionFailureException (org.apache.tephra.TransactionFailureException)11 PartitionNotFoundException (co.cask.cdap.api.dataset.PartitionNotFoundException)10