use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture 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.TransactionContextFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerInvalidBatchUpdate.
@Test
public void asyncTransactionManagerInvalidBatchUpdate() throws Exception {
try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
SpannerException e = assertThrows(SpannerException.class, () -> get(transactionContextFuture.then((transactionContext, ignored) -> transactionContext.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT)), executor).commitAsync()));
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
assertThat(e.getMessage()).contains("invalid statement");
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture 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.TransactionContextFuture 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);
}
use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture 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();
}
}
}
}
Aggregations