use of com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture 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.CommitTimestampFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerChainWithErrorInTheMiddle.
@Test
public void asyncTransactionManagerChainWithErrorInTheMiddle() throws Exception {
try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
CommitTimestampFuture commitTimestampFuture = transactionContextFuture.then((transactionContext, ignored) -> transactionContext.executeUpdateAsync(INVALID_UPDATE_STATEMENT), executor).then((ignored1, ignored2) -> {
throw new IllegalStateException("this should not be executed");
}, executor).commitAsync();
SpannerException e = assertThrows(SpannerException.class, () -> get(commitTimestampFuture));
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerUpdateAbortedWithoutGettingResult.
@Test
public void asyncTransactionManagerUpdateAbortedWithoutGettingResult() throws Exception {
final AtomicInteger attempt = new AtomicInteger();
try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
CommitTimestampFuture commitTimestampFuture = transactionContextFuture.then((transaction, ignored) -> {
if (attempt.incrementAndGet() == 1) {
mockSpanner.abortNextStatement();
}
// This update statement will be aborted, but the error will not
// propagated to the transaction runner and cause the transaction to
// retry. Instead, the commit call will do that.
transaction.executeUpdateAsync(UPDATE_STATEMENT);
// has actually finished successfully.
return ApiFutures.immediateFuture(null);
}, executor).commitAsync();
assertThat(commitTimestampFuture.get()).isNotNull();
assertThat(attempt.get()).isEqualTo(2);
// The server may receive 1 or 2 commit requests depending on whether the call to
// commitAsync() already knows that the transaction has aborted. If it does, it will not
// attempt to call the Commit RPC and instead directly propagate the Aborted error.
assertThat(mockSpanner.getRequestTypes()).containsAtLeast(BatchCreateSessionsRequest.class, ExecuteSqlRequest.class, // The retry will use a BeginTransaction RPC.
BeginTransactionRequest.class, ExecuteSqlRequest.class, CommitRequest.class);
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerInvalidUpdate.
@Test
public void asyncTransactionManagerInvalidUpdate() throws Exception {
try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
CommitTimestampFuture commitTimestamp = transactionContextFuture.then((transaction, ignored) -> transaction.executeUpdateAsync(INVALID_UPDATE_STATEMENT), executor).commitAsync();
SpannerException e = assertThrows(SpannerException.class, () -> get(commitTimestamp));
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
assertThat(e.getMessage()).contains("invalid statement");
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method testAsyncTransactionManager_returnsCommitStats.
@Test
public void testAsyncTransactionManager_returnsCommitStats() throws Exception {
try (AsyncTransactionManager manager = client().transactionManagerAsync(Options.commitStats())) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
CommitTimestampFuture commitTimestamp = transactionContextFuture.then((transactionContext, ignored) -> transactionContext.bufferAsync(Collections.singleton(Mutation.delete("FOO", Key.of("foo")))), executor).commitAsync();
assertNotNull(commitTimestamp.get());
assertNotNull(manager.getCommitResponse().get());
assertNotNull(manager.getCommitResponse().get().getCommitStats());
assertEquals(1L, manager.getCommitResponse().get().getCommitStats().getMutationCount());
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
}
Aggregations