@Override public void commitOrThrow(Transaction tx) throws TransactionFailureException { delegate.commitOrThrow(tx); }
@Override public boolean invalidate(long tx) { return delegate.invalidate(tx); }
@Override public void abort(Transaction tx) { delegate.abort(tx); }
@Test public void testTruncateInvalidTxBefore() throws Exception { TransactionSystemClient txClient = getTxClient(); // Reset state, and assert no invalid transactions are present txClient.resetState(); Assert.assertEquals(0, txClient.getInvalidSize()); // Start few transactions and invalidate them Transaction tx1 = txClient.startShort(); Transaction tx2 = txClient.startLong(); // Sleep so that transaction ids get generated a millisecond apart for assertion // TEPHRA-63 should eliminate the need to sleep TimeUnit.MILLISECONDS.sleep(1); long beforeTx3 = System.currentTimeMillis(); Transaction tx3 = txClient.startLong(); Assert.assertTrue(txClient.invalidate(tx1.getWritePointer())); Assert.assertTrue(txClient.invalidate(tx2.getWritePointer())); Assert.assertTrue(txClient.invalidate(tx3.getWritePointer())); Assert.assertEquals(3, txClient.getInvalidSize()); // Remove all transactions in invalid list beforeTx3 HttpResponse response = doPost("/v3/transactions/invalid/remove/until", GSON.toJson(ImmutableMap.of("time", beforeTx3))); Assert.assertEquals(200, response.getResponseCode()); Assert.assertEquals(1, txClient.getInvalidSize()); }
@Test public void testBatchWritableKeyIsIgnored() throws Exception { String tableName = "batchWritableTable"; getTableAdmin(CONTEXT1, tableName).create(); try { // write in a transaction, three times, with key = null, a, q, always Put with row = a Transaction tx = txClient.startShort(); Table table = getTable(CONTEXT1, tableName); ((TransactionAware) table).startTx(tx); table.write(null, new Put("a").add("x", "x")); table.write(new byte[]{'q'}, new Put("a").add("y", "y")); table.write(new byte[]{'a'}, new Put("a").add("z", "z")); txClient.canCommitOrThrow(tx, ((TransactionAware) table).getTxChanges()); ((TransactionAware) table).commitTx(); txClient.commitOrThrow(tx); // validate that all writes went to row a, and row q was not written tx = txClient.startShort(); ((TransactionAware) table).startTx(tx); Assert.assertTrue(table.get(new Get("q")).isEmpty()); Row row = table.get(new Get("a")); Assert.assertEquals(3, row.getColumns().size()); Assert.assertEquals("x", row.getString("x")); Assert.assertEquals("y", row.getString("y")); Assert.assertEquals("z", row.getString("z")); ((TransactionAware) table).commitTx(); txClient.abort(tx); } finally { getTableAdmin(CONTEXT1, tableName).drop(); } }
private Transaction startTx(Iterable<TransactionAware> txAwares) throws TransactionFailureException { Transaction transaction = txClient.startLong(); for (TransactionAware txAware : txAwares) { try { txAware.startTx(transaction); } catch (Throwable t) { txClient.abort(transaction); throw new TransactionFailureException( String.format("Unable to start transaction-aware '%s' for transaction %d. ", txAware.getTransactionAwareName(), transaction.getTransactionId()), t); } } return transaction; }
@Override public Transaction startLong() { return delegate.startLong(); }
@Path("/transactions/invalid") @GET public void invalidList(HttpRequest request, HttpResponder responder, @QueryParam("limit") @DefaultValue("-1") int limit) { Transaction tx = txClient.startShort(); txClient.abort(tx); long[] invalids = tx.getInvalids(); if (limit == -1) { responder.sendJson(HttpResponseStatus.OK, GSON.toJson(invalids)); return; } responder.sendJson(HttpResponseStatus.OK, GSON.toJson(Arrays.copyOf(invalids, Math.min(limit, invalids.length)))); }
/** * Tests invalidating a transaction. */ @Test public void testInvalidateTx() throws Exception { TransactionSystemClient txClient = getTxClient(); Transaction tx1 = txClient.startShort(); HttpResponse response = doPost("/v3/transactions/" + tx1.getWritePointer() + "/invalidate"); Assert.assertEquals(200, response.getResponseCode()); Transaction tx2 = txClient.startShort(); txClient.commitOrThrow(tx2); response = doPost("/v3/transactions/" + tx2.getWritePointer() + "/invalidate"); Assert.assertEquals(409, response.getResponseCode()); Assert.assertEquals(400, doPost("/v3/transactions/foobar/invalidate").getResponseCode()); }
@Override public Transaction startShort() { return delegate.startShort(); }
private void commitAndAssertSuccess(Transaction tx, TransactionAware txAware) throws Exception { txClient.canCommitOrThrow(tx, txAware.getTxChanges()); Assert.assertTrue(txAware.commitTx()); txClient.commitOrThrow(tx); }
@Override public void checkpoint(boolean hasUncommittedData) throws SQLException { if (hasUncommittedData) { try { if (txContext == null) { tx = txServiceClient.checkpoint(tx); } else { assert (txContext != null); txContext.checkpoint(); tx = txContext.getCurrentTransaction(); } } catch (TransactionFailureException e) { throw new SQLException(e); } } // Since we're querying our own table while mutating it, we must exclude // see our current mutations, otherwise we can get erroneous results // (for DELETE) // or get into an infinite loop (for UPSERT SELECT). if (txContext == null) { tx.setVisibility(VisibilityLevel.SNAPSHOT_EXCLUDE_CURRENT); } else { assert (txContext != null); txContext.getCurrentTransaction().setVisibility( VisibilityLevel.SNAPSHOT_EXCLUDE_CURRENT); } }
@Override public int getInvalidSize() { return delegate.getInvalidSize(); }
@Override public void canCommitOrThrow(Transaction tx, Collection<byte[]> changeIds) throws TransactionFailureException { delegate.canCommitOrThrow(tx, changeIds); }
@Test public void testTruncateInvalidTx() throws Exception { TransactionSystemClient txClient = getTxClient(); // Reset state, and assert no invalid transactions are present txClient.resetState(); Assert.assertEquals(0, txClient.getInvalidSize()); // Start few transactions and invalidate them Transaction tx1 = txClient.startShort(); Transaction tx2 = txClient.startLong(); Transaction tx3 = txClient.startLong(); Assert.assertTrue(txClient.invalidate(tx1.getWritePointer())); Assert.assertTrue(txClient.invalidate(tx2.getWritePointer())); Assert.assertTrue(txClient.invalidate(tx3.getWritePointer())); Assert.assertEquals(3, txClient.getInvalidSize()); // Remove tx1 and tx3 from invalid list HttpResponse response = doPost("/v3/transactions/invalid/remove/ids", GSON.toJson(ImmutableMap.of("ids", ImmutableSet.of(tx1.getWritePointer(), tx3.getWritePointer())))); Assert.assertEquals(200, response.getResponseCode()); Assert.assertEquals(1, txClient.getInvalidSize()); }
private Transaction startTx(Iterable<TransactionAware> txAwares) throws TransactionFailureException { Transaction transaction = txClient.startLong(); for (TransactionAware txAware : txAwares) { try { txAware.startTx(transaction); } catch (Throwable t) { txClient.abort(transaction); throw new TransactionFailureException( String.format("Unable to start transaction-aware '%s' for transaction %d. ", txAware.getTransactionAwareName(), transaction.getTransactionId()), t); } } return transaction; }
@Override public Transaction startLong() { return delegate.startLong(); }
@Path("/transactions/invalid") @GET public void invalidList(HttpRequest request, HttpResponder responder, @QueryParam("limit") @DefaultValue("-1") int limit) { Transaction tx = txClient.startShort(); txClient.abort(tx); long[] invalids = tx.getInvalids(); if (limit == -1) { responder.sendJson(HttpResponseStatus.OK, GSON.toJson(invalids)); return; } responder.sendJson(HttpResponseStatus.OK, GSON.toJson(Arrays.copyOf(invalids, Math.min(limit, invalids.length)))); }
@Test public void testReadOwnWrite() throws Exception { final String tableName = "readOwnWrite"; DatasetAdmin admin = getTableAdmin(CONTEXT1, tableName); admin.create(); Table table = getTable(CONTEXT1, tableName); Transaction tx = txClient.startShort(); try { ((TransactionAware) table).startTx(tx); // Write some data, then flush it by calling commitTx. table.put(new Put(R1, C1, V1)); ((TransactionAware) table).commitTx(); // Try to read the previous write. Assert.assertArrayEquals(V1, table.get(new Get(R1, C1)).get(C1)); } finally { txClient.commitOrThrow(tx); } // drop table admin.drop(); }
@Override public void start(int timeout) throws TransactionFailureException { Preconditions.checkState(currentTx == null, "Already have an active transaction."); currentTx = txClient.startShort(timeout); startAllTxAwares(); }