use of com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerReadRow.
@Test
public void asyncTransactionManagerReadRow() throws Exception {
try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
AsyncTransactionStep<Struct, String> value = transactionContextFuture.then((transactionContext, ignored) -> transactionContext.readRowAsync(READ_TABLE_NAME, Key.of(1L), READ_COLUMN_NAMES), executor).then((ignored, input) -> ApiFutures.immediateFuture(input.getString("Value")), executor);
value.commitAsync().get();
assertThat(value.get()).isEqualTo("v1");
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep in project java-spanner by googleapis.
the class ITTransactionManagerAsyncTest method testAbortAndRetry.
@Ignore("Cloud Spanner now seems to return CANCELLED instead of ABORTED when a transaction is invalidated by a later transaction in the same session")
@Test
public void testAbortAndRetry() throws InterruptedException, ExecutionException {
assumeFalse("Emulator does not support more than 1 simultaneous transaction. " + "This test would therefore loop indefinitely on the emulator.", isUsingEmulator());
client.write(Collections.singletonList(Mutation.newInsertBuilder("T").set("K").to("Key3").set("BoolValue").to(true).build()));
try (AsyncTransactionManager manager1 = client.transactionManagerAsync()) {
TransactionContextFuture txn1 = manager1.beginAsync();
AsyncTransactionManager manager2;
TransactionContextFuture txn2;
AsyncTransactionStep<Void, Struct> txn2Step1;
while (true) {
try {
AsyncTransactionStep<Void, Struct> txn1Step1 = txn1.then((transaction, ignored) -> transaction.readRowAsync("T", Key.of("Key3"), Arrays.asList("K", "BoolValue")), executor);
manager2 = client.transactionManagerAsync();
txn2 = manager2.beginAsync();
txn2Step1 = txn2.then((transaction, ignored) -> transaction.readRowAsync("T", Key.of("Key3"), Arrays.asList("K", "BoolValue")), executor);
AsyncTransactionStep<Struct, Void> txn1Step2 = txn1Step1.then((transaction, ignored) -> {
transaction.buffer(Mutation.newUpdateBuilder("T").set("K").to("Key3").set("BoolValue").to(false).build());
return ApiFutures.immediateFuture(null);
}, executor);
txn2Step1.get();
txn1Step2.commitAsync().get();
break;
} catch (AbortedException e) {
Thread.sleep(e.getRetryDelayInMillis());
// In that case we should just retry without resetting anything.
if (manager1.getState() == TransactionState.ABORTED) {
txn1 = manager1.resetForRetryAsync();
}
}
}
// txn2 should have been aborted.
try {
txn2Step1.commitAsync().get();
fail("Expected to abort");
} catch (AbortedException e) {
assertThat(manager2.getState()).isEqualTo(TransactionState.ABORTED);
txn2 = manager2.resetForRetryAsync();
}
AsyncTransactionStep<Void, Void> txn2Step2 = txn2.then((transaction, ignored) -> {
transaction.buffer(Mutation.newUpdateBuilder("T").set("K").to("Key3").set("BoolValue").to(true).build());
return ApiFutures.immediateFuture(null);
}, executor);
txn2Step2.commitAsync().get();
Struct row = client.singleUse().readRow("T", Key.of("Key3"), Arrays.asList("K", "BoolValue"));
assertThat(row.getString(0)).isEqualTo("Key3");
assertThat(row.getBoolean(1)).isTrue();
manager2.close();
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep in project java-spanner by googleapis.
the class AsyncTransactionManagerExample method asyncTransactionManager.
static void asyncTransactionManager(DatabaseClient client) throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService executor = Executors.newSingleThreadExecutor();
AsyncTransactionStep<List<Struct>, long[]> updateCounts;
try (AsyncTransactionManager mgr = client.transactionManagerAsync()) {
TransactionContextFuture txn = mgr.beginAsync();
// Loop to retry aborted errors.
while (true) {
try {
updateCounts = txn.then((transaction, v) -> {
// Execute two reads in parallel and return the result of these as the input
// for the next step of the transaction.
ApiFuture<Struct> album1BudgetFut = transaction.readRowAsync("Albums", Key.of(1, 1), ImmutableList.of("MarketingBudget"));
ApiFuture<Struct> album2BudgetFut = transaction.readRowAsync("Albums", Key.of(2, 2), ImmutableList.of("MarketingBudget"));
return ApiFutures.allAsList(Arrays.asList(album1BudgetFut, album2BudgetFut));
}, executor).then((transaction, budgets) -> {
long album1Budget = budgets.get(0).getLong(0);
long album2Budget = budgets.get(1).getLong(0);
long transfer = 200_000;
if (album2Budget >= transfer) {
album1Budget += transfer;
album2Budget -= transfer;
Statement updateStatement1 = Statement.newBuilder("UPDATE Albums " + "SET MarketingBudget = @AlbumBudget " + "WHERE SingerId = 1 and AlbumId = 1").bind("AlbumBudget").to(album1Budget).build();
Statement updateStatement2 = Statement.newBuilder("UPDATE Albums " + "SET MarketingBudget = @AlbumBudget " + "WHERE SingerId = 2 and AlbumId = 2").bind("AlbumBudget").to(album2Budget).build();
return transaction.batchUpdateAsync(ImmutableList.of(updateStatement1, updateStatement2));
} else {
return ApiFutures.immediateFuture(new long[] { 0L, 0L });
}
}, executor);
// Commit after the updates.
CommitTimestampFuture commitTsFut = updateCounts.commitAsync();
// Wait for the transaction to finish and execute a retry if necessary.
commitTsFut.get();
break;
} catch (AbortedException e) {
txn = mgr.resetForRetryAsync();
}
}
}
// Calculate the total update count.
ApiFuture<Long> totalUpdateCount = ApiFutures.transform(updateCounts, new ApiFunction<long[], Long>() {
@SuppressFBWarnings("UVA_USE_VAR_ARGS")
@Override
public Long apply(long[] input) {
return Arrays.stream(input).sum();
}
}, MoreExecutors.directExecutor());
System.out.printf("%d records updated.%n", totalUpdateCount.get(30L, TimeUnit.SECONDS));
executor.shutdown();
}
use of com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerFireAndForgetInvalidBatchUpdate.
@Test
public void asyncTransactionManagerFireAndForgetInvalidBatchUpdate() throws Exception {
try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
AsyncTransactionStep<Void, long[]> updateCounts = transactionContextFuture.then((transactionContext, ignored) -> {
transactionContext.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT));
return ApiFutures.<Void>immediateFuture(null);
}, executor).then((transactionContext, ignored) -> transactionContext.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)), executor);
updateCounts.commitAsync().get();
assertThat(updateCounts.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT);
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
assertThat(mockSpanner.getRequestTypes()).containsExactly(BatchCreateSessionsRequest.class, ExecuteBatchDmlRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class);
}
use of com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerWithBatchUpdateCommitAborted.
@Test
public void asyncTransactionManagerWithBatchUpdateCommitAborted() throws Exception {
try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) {
// Temporarily set the result of the update to 2 rows.
mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT + 1L));
final AtomicInteger attempt = new AtomicInteger();
TransactionContextFuture txn = manager.beginAsync();
while (true) {
try {
AsyncTransactionStep<Void, long[]> updateCounts = txn.then((ignored1, ignored2) -> {
if (attempt.get() > 0) {
// Set the result of the update statement back to 1 row.
mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
}
return ApiFutures.<Void>immediateFuture(null);
}, executor).then((transactionContext, ignored) -> transactionContext.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)), executor);
updateCounts.then((transaction, ignored) -> {
if (attempt.incrementAndGet() == 1) {
mockSpanner.abortTransaction(transaction);
}
return ApiFutures.immediateFuture(null);
}, executor).commitAsync().get();
assertThat(updateCounts.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT);
assertThat(attempt.get()).isEqualTo(2);
break;
} catch (AbortedException e) {
txn = manager.resetForRetryAsync();
}
}
} finally {
mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
}
assertThat(mockSpanner.getRequestTypes()).containsExactly(BatchCreateSessionsRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class, BeginTransactionRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class);
}
Aggregations