use of org.apache.tephra.TransactionAware in project cdap by caskdata.
the class TableTest method testTxUsingMultipleTables.
@Test
public void testTxUsingMultipleTables() throws Exception {
String table1 = "table1";
String table2 = "table2";
String table3 = "table3";
String table4 = "table4";
getTableAdmin(CONTEXT1, table1).create();
getTableAdmin(CONTEXT1, table2).create();
getTableAdmin(CONTEXT1, table3).create();
getTableAdmin(CONTEXT1, table4).create();
try {
// We will be changing:
// * table1 and table2 in tx1
// * table2 and table3 in tx2 << will conflict with first one
// * table3 and table4 in tx3
Transaction tx1 = txClient.startShort();
Transaction tx2 = txClient.startShort();
Transaction tx3 = txClient.startShort();
// Write data in tx1 and commit
Table table11 = getTable(CONTEXT1, table1);
((TransactionAware) table11).startTx(tx1);
// write r1->c1,v1 but not commit
table11.put(R1, a(C1), a(V1));
Table table21 = getTable(CONTEXT1, table2);
((TransactionAware) table21).startTx(tx1);
// write r1->c1,v2 but not commit
table21.put(R1, a(C1), a(V2));
// TableAssert.verify writes inside same tx
TableAssert.assertRow(a(C1, V1), table11.get(R1, a(C1)));
TableAssert.assertRow(a(C1, V2), table21.get(R1, a(C1)));
// commit tx1
txClient.canCommitOrThrow(tx1, ImmutableList.copyOf(Iterables.concat(((TransactionAware) table11).getTxChanges(), ((TransactionAware) table21).getTxChanges())));
Assert.assertTrue(((TransactionAware) table11).commitTx());
Assert.assertTrue(((TransactionAware) table21).commitTx());
txClient.commitOrThrow(tx1);
// Write data in tx2 and check that cannot commit because of conflicts
Table table22 = getTable(CONTEXT1, table2);
((TransactionAware) table22).startTx(tx2);
// write r1->c1,v1 but not commit
table22.put(R1, a(C1), a(V2));
Table table32 = getTable(CONTEXT1, table3);
((TransactionAware) table32).startTx(tx2);
// write r1->c1,v2 but not commit
table32.put(R1, a(C1), a(V3));
// TableAssert.verify writes inside same tx
TableAssert.assertRow(a(C1, V2), table22.get(R1, a(C1)));
TableAssert.assertRow(a(C1, V3), table32.get(R1, a(C1)));
// try commit tx2
try {
txClient.canCommitOrThrow(tx2, ImmutableList.copyOf(Iterables.concat(((TransactionAware) table22).getTxChanges(), ((TransactionAware) table32).getTxChanges())));
Assert.fail("Conflict not detected!");
} catch (TransactionConflictException e) {
// expected
}
Assert.assertTrue(((TransactionAware) table22).rollbackTx());
Assert.assertTrue(((TransactionAware) table32).rollbackTx());
txClient.abort(tx2);
// Write data in tx3 and check that can commit (no conflicts)
Table table33 = getTable(CONTEXT1, table3);
((TransactionAware) table33).startTx(tx3);
// write r1->c1,v1 but not commit
table33.put(R1, a(C1), a(V3));
Table table43 = getTable(CONTEXT1, table4);
((TransactionAware) table43).startTx(tx3);
// write r1->c1,v2 but not commit
table43.put(R1, a(C1), a(V4));
// TableAssert.verify writes inside same tx
TableAssert.assertRow(a(C1, V3), table33.get(R1, a(C1)));
TableAssert.assertRow(a(C1, V4), table43.get(R1, a(C1)));
// commit tx3
txClient.canCommitOrThrow(tx3, ImmutableList.copyOf(Iterables.concat(((TransactionAware) table33).getTxChanges(), ((TransactionAware) table43).getTxChanges())));
Assert.assertTrue(((TransactionAware) table33).commitTx());
Assert.assertTrue(((TransactionAware) table43).commitTx());
txClient.commitOrThrow(tx3);
} finally {
getTableAdmin(CONTEXT1, table1).drop();
getTableAdmin(CONTEXT1, table2).drop();
getTableAdmin(CONTEXT1, table3).drop();
getTableAdmin(CONTEXT1, table4).drop();
}
}
use of org.apache.tephra.TransactionAware 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();
}
use of org.apache.tephra.TransactionAware 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();
}
}
use of org.apache.tephra.TransactionAware 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();
}
}
use of org.apache.tephra.TransactionAware 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();
}
}
Aggregations