use of com.google.cloud.spanner.AsyncTransactionManager in project java-spanner by googleapis.
the class ITAsyncAPITest method testAsyncTransactionManagerReturnsCommitStats.
@Test
public void testAsyncTransactionManagerReturnsCommitStats() throws InterruptedException {
assumeFalse("Emulator does not return commit statistics", isUsingEmulator());
try (AsyncTransactionManager manager = client.transactionManagerAsync(Options.commitStats())) {
TransactionContextFuture context = manager.beginAsync();
while (true) {
try {
get(context.then((transaction, ignored) -> {
transaction.buffer(Mutation.newInsertOrUpdateBuilder(TABLE_NAME).set("Key").to("k_commit_stats").set("StringValue").to("Should return commit stats").build());
return ApiFutures.immediateFuture(null);
}, executor).commitAsync());
assertNotNull(get(manager.getCommitResponse()).getCommitStats());
assertEquals(4L, get(manager.getCommitResponse()).getCommitStats().getMutationCount());
break;
} catch (AbortedException e) {
Thread.sleep(e.getRetryDelayInMillis());
context = manager.resetForRetryAsync();
}
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager 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 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 in project java-spanner by googleapis.
the class ITTransactionManagerAsyncTest method testInvalidInsert.
@Test
public void testInvalidInsert() throws InterruptedException {
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture txn = manager.beginAsync();
while (true) {
try {
txn.then((transaction, ignored) -> {
transaction.buffer(Mutation.newInsertBuilder("InvalidTable").set("K").to("Key1").set("BoolValue").to(true).build());
return ApiFutures.immediateFuture(null);
}, executor).commitAsync().get();
fail("Expected exception");
} catch (AbortedException e) {
Thread.sleep(e.getRetryDelayInMillis());
txn = manager.resetForRetryAsync();
} catch (ExecutionException e) {
assertThat(e.getCause()).isInstanceOf(SpannerException.class);
SpannerException se = (SpannerException) e.getCause();
assertThat(se.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND);
// expected
break;
}
}
assertThat(manager.getState()).isEqualTo(TransactionState.COMMIT_FAILED);
// We cannot retry for non aborted errors.
try {
manager.resetForRetryAsync();
fail("Expected exception");
} catch (IllegalStateException ex) {
assertNotNull(ex.getMessage());
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager in project java-spanner by googleapis.
the class ITTransactionManagerAsyncTest method testRollback.
@Test
public void testRollback() throws InterruptedException {
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
TransactionContextFuture txn = manager.beginAsync();
while (true) {
txn.then((transaction, ignored) -> {
transaction.buffer(Mutation.newInsertBuilder("T").set("K").to("Key2").set("BoolValue").to(true).build());
return ApiFutures.immediateFuture(null);
}, executor);
try {
manager.rollbackAsync();
break;
} catch (AbortedException e) {
Thread.sleep(e.getRetryDelayInMillis());
txn = manager.resetForRetryAsync();
}
}
assertThat(manager.getState()).isEqualTo(TransactionState.ROLLED_BACK);
// Row should not have been inserted.
assertThat(client.singleUse().readRow("T", Key.of("Key2"), Arrays.asList("K", "BoolValue"))).isNull();
}
}
Aggregations