Search in sources :

Example 16 with Transaction

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

the class TableTest method testMultiIncrementWithFlush.

private void testMultiIncrementWithFlush(boolean readless) throws Exception {
    final String tableName = "incrFlush";
    DatasetProperties props = TableProperties.builder().setReadlessIncrementSupport(readless).build();
    DatasetAdmin admin = getTableAdmin(CONTEXT1, tableName, props);
    admin.create();
    Map<String, String> args = new HashMap<>();
    if (readless) {
        args.put(HBaseTable.SAFE_INCREMENTS, "true");
    }
    Table table = getTable(CONTEXT1, tableName, props, args);
    Transaction tx = txClient.startShort();
    try {
        ((TransactionAware) table).startTx(tx);
        // Write an increment, then flush it by calling commitTx.
        table.increment(new Increment(R1, C1, 10L));
        ((TransactionAware) table).commitTx();
    } finally {
        // invalidate the tx, leaving an excluded write in the table
        txClient.invalidate(tx.getTransactionId());
    }
    // validate the first write is not visible
    tx = txClient.startShort();
    try {
        ((TransactionAware) table).startTx(tx);
        Assert.assertEquals(null, table.get(new Get(R1, C1)).getLong(C1));
    } finally {
        txClient.commitOrThrow(tx);
    }
    tx = txClient.startShort();
    try {
        ((TransactionAware) table).startTx(tx);
        // Write an increment, then flush it by calling commitTx.
        table.increment(new Increment(R1, C1, 1L));
        ((TransactionAware) table).commitTx();
        // Write another increment, from both table instances
        table.increment(new Increment(R1, C1, 1L));
        if (readless) {
            Table table2 = getTable(CONTEXT1, tableName, props, args);
            ((TransactionAware) table2).startTx(tx);
            table2.increment(new Increment(R1, C1, 1L));
            ((TransactionAware) table2).commitTx();
        }
        ((TransactionAware) table).commitTx();
    } finally {
        txClient.commitOrThrow(tx);
    }
    // validate all increments are visible to a new tx
    tx = txClient.startShort();
    try {
        ((TransactionAware) table).startTx(tx);
        Assert.assertEquals(new Long(readless ? 3L : 2L), table.get(new Get(R1, C1)).getLong(C1));
    } finally {
        txClient.commitOrThrow(tx);
    }
    // drop table
    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) HashMap(java.util.HashMap) TransactionAware(org.apache.tephra.TransactionAware) DatasetProperties(co.cask.cdap.api.dataset.DatasetProperties) Increment(co.cask.cdap.api.dataset.table.Increment) Get(co.cask.cdap.api.dataset.table.Get) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin)

Example 17 with Transaction

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

the class TableTest method testConflictDetection.

private void testConflictDetection(ConflictDetection level) throws Exception {
    // we use tableX_Y format for variable names which means "tableX that is used in tx Y"
    String table1 = "table1";
    String table2 = "table2";
    DatasetProperties props = TableProperties.builder().setConflictDetection(level).build();
    DatasetAdmin admin1 = getTableAdmin(CONTEXT1, table1, props);
    DatasetAdmin admin2 = getTableAdmin(CONTEXT1, table2, props);
    admin1.create();
    admin2.create();
    try {
        // 1) Test conflicts when using different tables
        Transaction tx1 = txClient.startShort();
        Table table11 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table11).startTx(tx1);
        // write r1->c1,v1 but not commit
        table11.put(R1, a(C1), a(V1));
        // start new tx
        Transaction tx2 = txClient.startShort();
        Table table22 = getTable(CONTEXT1, table2, props);
        ((TransactionAware) table22).startTx(tx2);
        // change in tx2 same data but in different table
        table22.put(R1, a(C1), a(V2));
        // start new tx
        Transaction tx3 = txClient.startShort();
        Table table13 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table13).startTx(tx3);
        // change in tx3 same data in same table as tx1
        table13.put(R1, a(C1), a(V2));
        // committing tx1
        txClient.canCommitOrThrow(tx1, ((TransactionAware) table11).getTxChanges());
        Assert.assertTrue(((TransactionAware) table11).commitTx());
        txClient.commitOrThrow(tx1);
        // no conflict should be when committing tx2
        txClient.canCommitOrThrow(tx2, ((TransactionAware) table22).getTxChanges());
        // but conflict should be when committing tx3
        if (level != ConflictDetection.NONE) {
            try {
                txClient.canCommitOrThrow(tx3, ((TransactionAware) table13).getTxChanges());
                Assert.fail("Conflict not detected!");
            } catch (TransactionConflictException e) {
            // expected
            }
            ((TransactionAware) table13).rollbackTx();
            txClient.abort(tx3);
        } else {
            txClient.canCommitOrThrow(tx3, ((TransactionAware) table13).getTxChanges());
        }
        // 2) Test conflicts when using different rows
        Transaction tx4 = txClient.startShort();
        Table table14 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table14).startTx(tx4);
        // write r1->c1,v1 but not commit
        table14.put(R1, a(C1), a(V1));
        // start new tx
        Transaction tx5 = txClient.startShort();
        Table table15 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table15).startTx(tx5);
        // change in tx5 same data but in different row
        table15.put(R2, a(C1), a(V2));
        // start new tx
        Transaction tx6 = txClient.startShort();
        Table table16 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table16).startTx(tx6);
        // change in tx6 in same row as tx1
        table16.put(R1, a(C2), a(V2));
        // committing tx4
        txClient.canCommitOrThrow(tx4, ((TransactionAware) table14).getTxChanges());
        Assert.assertTrue(((TransactionAware) table14).commitTx());
        txClient.commitOrThrow(tx4);
        // no conflict should be when committing tx5
        txClient.canCommitOrThrow(tx5, ((TransactionAware) table15).getTxChanges());
        // but conflict should be when committing tx6 iff we resolve on row level
        if (level == ConflictDetection.ROW) {
            try {
                txClient.canCommitOrThrow(tx6, ((TransactionAware) table16).getTxChanges());
                Assert.fail("Conflict not detected!");
            } catch (TransactionConflictException e) {
            // expected
            }
            ((TransactionAware) table16).rollbackTx();
            txClient.abort(tx6);
        } else {
            txClient.canCommitOrThrow(tx6, ((TransactionAware) table16).getTxChanges());
        }
        // 3) Test conflicts when using different columns
        Transaction tx7 = txClient.startShort();
        Table table17 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table17).startTx(tx7);
        // write r1->c1,v1 but not commit
        table17.put(R1, a(C1), a(V1));
        // start new tx
        Transaction tx8 = txClient.startShort();
        Table table18 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table18).startTx(tx8);
        // change in tx8 same data but in different column
        table18.put(R1, a(C2), a(V2));
        // start new tx
        Transaction tx9 = txClient.startShort();
        Table table19 = getTable(CONTEXT1, table1, props);
        ((TransactionAware) table19).startTx(tx9);
        // change in tx9 same column in same column as tx1
        table19.put(R1, a(C1), a(V2));
        // committing tx7
        txClient.canCommitOrThrow(tx7, ((TransactionAware) table17).getTxChanges());
        Assert.assertTrue(((TransactionAware) table17).commitTx());
        txClient.commitOrThrow(tx7);
        // no conflict should be when committing tx8 iff we resolve on column level
        if (level == ConflictDetection.COLUMN || level == ConflictDetection.NONE) {
            txClient.canCommitOrThrow(tx8, ((TransactionAware) table18).getTxChanges());
        } else {
            try {
                txClient.canCommitOrThrow(tx8, ((TransactionAware) table18).getTxChanges());
                Assert.fail("Conflict not detected!");
            } catch (TransactionConflictException e) {
            // expected
            }
            ((TransactionAware) table18).rollbackTx();
            txClient.abort(tx8);
        }
        // but conflict should be when committing tx9
        if (level != ConflictDetection.NONE) {
            try {
                txClient.canCommitOrThrow(tx9, ((TransactionAware) table19).getTxChanges());
                Assert.fail("Conflict not detected!");
            } catch (TransactionConflictException e) {
            // expected
            }
            ((TransactionAware) table19).rollbackTx();
            txClient.abort(tx9);
        } else {
            txClient.canCommitOrThrow(tx9, ((TransactionAware) table19).getTxChanges());
        }
    } finally {
        // NOTE: we are doing our best to cleanup junk between tests to isolate errors, but we are not going to be
        // crazy about it
        admin1.drop();
        admin2.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 Transaction

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

the class TableTest method testMultiGetWithTx.

@Test
public void testMultiGetWithTx() throws Exception {
    String testMultiGet = "testMultiGet";
    DatasetAdmin admin = getTableAdmin(CONTEXT1, testMultiGet);
    admin.create();
    try {
        Transaction tx = txClient.startShort();
        Table table = getTable(CONTEXT1, testMultiGet);
        ((TransactionAware) table).startTx(tx);
        for (int i = 0; i < 100; i++) {
            table.put(new Put(Bytes.toBytes("r" + i)).add(C1, V1).add(C2, V2));
        }
        txClient.canCommitOrThrow(tx, ((TransactionAware) table).getTxChanges());
        Assert.assertTrue(((TransactionAware) table).commitTx());
        txClient.commitOrThrow(tx);
        Transaction tx2 = txClient.startShort();
        ((TransactionAware) table).startTx(tx2);
        List<Get> gets = Lists.newArrayListWithCapacity(100);
        for (int i = 0; i < 100; i++) {
            gets.add(new Get(Bytes.toBytes("r" + i)));
        }
        List<Row> results = table.get(gets);
        txClient.commitOrThrow(tx2);
        for (int i = 0; i < 100; i++) {
            Row row = results.get(i);
            Assert.assertArrayEquals(Bytes.toBytes("r" + i), row.getRow());
            byte[] val = row.get(C1);
            Assert.assertNotNull(val);
            Assert.assertArrayEquals(V1, val);
            byte[] val2 = row.get(C2);
            Assert.assertNotNull(val2);
            Assert.assertArrayEquals(V2, val2);
        }
        Transaction tx3 = txClient.startShort();
        ((TransactionAware) table).startTx(tx3);
        gets = Lists.newArrayListWithCapacity(100);
        for (int i = 0; i < 100; i++) {
            gets.add(new Get("r" + i).add(C1));
        }
        results = table.get(gets);
        txClient.commitOrThrow(tx3);
        for (int i = 0; i < 100; i++) {
            Row row = results.get(i);
            Assert.assertArrayEquals(Bytes.toBytes("r" + i), row.getRow());
            byte[] val = row.get(C1);
            Assert.assertNotNull(val);
            Assert.assertArrayEquals(V1, val);
            // should have only returned column 1
            byte[] val2 = row.get(C2);
            Assert.assertNull(val2);
        }
        // retrieve different columns per row
        Transaction tx4 = txClient.startShort();
        ((TransactionAware) table).startTx(tx4);
        gets = Lists.newArrayListWithCapacity(100);
        for (int i = 0; i < 100; i++) {
            Get get = new Get("r" + i);
            // evens get C1, odds get C2
            get.add(i % 2 == 0 ? C1 : C2);
            gets.add(get);
        }
        results = table.get(gets);
        txClient.commitOrThrow(tx4);
        for (int i = 0; i < 100; i++) {
            Row row = results.get(i);
            Assert.assertArrayEquals(Bytes.toBytes("r" + i), row.getRow());
            byte[] val1 = row.get(C1);
            byte[] val2 = row.get(C2);
            if (i % 2 == 0) {
                Assert.assertNotNull(val1);
                Assert.assertArrayEquals(V1, val1);
                Assert.assertNull(val2);
            } else {
                Assert.assertNull(val1);
                Assert.assertNotNull(val2);
                Assert.assertArrayEquals(V2, val2);
            }
        }
    } 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) Get(co.cask.cdap.api.dataset.table.Get) DatasetAdmin(co.cask.cdap.api.dataset.DatasetAdmin) Row(co.cask.cdap.api.dataset.table.Row) Put(co.cask.cdap.api.dataset.table.Put) Test(org.junit.Test)

Example 19 with Transaction

use of org.apache.tephra.Transaction 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 20 with Transaction

use of org.apache.tephra.Transaction 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)

Aggregations

Transaction (org.apache.tephra.Transaction)99 Test (org.junit.Test)54 TransactionAware (org.apache.tephra.TransactionAware)34 Table (co.cask.cdap.api.dataset.table.Table)29 DatasetAdmin (co.cask.cdap.api.dataset.DatasetAdmin)27 HBaseTable (co.cask.cdap.data2.dataset2.lib.table.hbase.HBaseTable)22 Put (co.cask.cdap.api.dataset.table.Put)12 DatasetProperties (co.cask.cdap.api.dataset.DatasetProperties)11 Get (co.cask.cdap.api.dataset.table.Get)10 TransactionSystemClient (org.apache.tephra.TransactionSystemClient)10 Row (co.cask.cdap.api.dataset.table.Row)8 ConsumerConfig (co.cask.cdap.data2.queue.ConsumerConfig)8 KeyStructValueTableDefinition (co.cask.cdap.explore.service.datasets.KeyStructValueTableDefinition)8 Scan (co.cask.cdap.api.dataset.table.Scan)7 ArrayList (java.util.ArrayList)7 CConfiguration (co.cask.cdap.common.conf.CConfiguration)6 ExploreExecutionResult (co.cask.cdap.explore.client.ExploreExecutionResult)6 DatasetId (co.cask.cdap.proto.id.DatasetId)6 IOException (java.io.IOException)6 BufferingTableTest (co.cask.cdap.data2.dataset2.lib.table.BufferingTableTest)5