use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManager_shouldPropagateStatementFailure.
@Test
public void asyncTransactionManager_shouldPropagateStatementFailure() throws ExecutionException, InterruptedException, TimeoutException {
DatabaseClient dbClient = client();
try (AsyncTransactionManager transactionManager = dbClient.transactionManagerAsync()) {
TransactionContextFuture txnContextFuture = transactionManager.beginAsync();
AsyncTransactionStep<Void, Long> updateFuture = txnContextFuture.then((transaction, ignored) -> transaction.executeUpdateAsync(INVALID_UPDATE_STATEMENT), executor);
final SettableApiFuture<Void> res = SettableApiFuture.create();
ApiFutures.addCallback(updateFuture, new ApiFutureCallback<Long>() {
@Override
public void onFailure(Throwable throwable) {
// Check that we got the expected failure.
try {
assertThat(throwable).isInstanceOf(SpannerException.class);
SpannerException e = (SpannerException) throwable;
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
assertThat(e.getMessage()).contains("invalid statement");
res.set(null);
} catch (Throwable t) {
res.setException(t);
}
}
@Override
public void onSuccess(Long aLong) {
res.setException(new AssertionError("Statement should not succeed."));
}
}, executor);
assertThat(res.get(10L, TimeUnit.SECONDS)).isNull();
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture 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.TransactionContextFuture 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.TransactionContextFuture 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();
}
}
}
}
use of com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture in project java-spanner by googleapis.
the class AsyncTransactionManagerTest method asyncTransactionManagerBatchUpdateAbortedWithoutGettingResult.
@Test
public void asyncTransactionManagerBatchUpdateAbortedWithoutGettingResult() throws Exception {
final AtomicInteger attempt = new AtomicInteger();
try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) {
TransactionContextFuture transactionContextFuture = manager.beginAsync();
while (true) {
try {
transactionContextFuture.then((transactionContext, ignored) -> {
if (attempt.incrementAndGet() == 1) {
mockSpanner.abortNextStatement();
}
// This update statement will be aborted, but the error will not propagated
// to the transaction manager and cause the transaction to retry. Instead,
// the commit call will do that. Depending on the timing, that will happen
// directly in the transaction manager if the ABORTED error has already been
// returned by the batch update call before the commit call starts.
// Otherwise, the backend will return an ABORTED error for the commit call.
transactionContext.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT));
return ApiFutures.immediateFuture(null);
}, executor).commitAsync().get();
break;
} catch (AbortedException e) {
transactionContextFuture = manager.resetForRetryAsync();
}
}
}
assertThat(attempt.get()).isEqualTo(2);
Iterable<Class<? extends AbstractMessage>> requests = mockSpanner.getRequestTypes();
int size = Iterables.size(requests);
assertThat(size).isIn(Range.closed(5, 6));
if (size == 5) {
assertThat(requests).containsExactly(BatchCreateSessionsRequest.class, ExecuteBatchDmlRequest.class, BeginTransactionRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class);
} else {
assertThat(requests).containsExactly(BatchCreateSessionsRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class, BeginTransactionRequest.class, ExecuteBatchDmlRequest.class, CommitRequest.class);
}
}
Aggregations