Search in sources :

Example 1 with AbortedDueToConcurrentModificationException

use of com.google.cloud.spanner.AbortedDueToConcurrentModificationException in project java-spanner by googleapis.

the class ConnectionAsyncApiAbortedTest method testQueriesAbortedMidway_ResultsChanged.

@Test
public void testQueriesAbortedMidway_ResultsChanged() {
    mockSpanner.setExecuteStreamingSqlExecutionTime(SimulatedExecutionTime.ofStreamException(mockSpanner.createAbortedException(ByteString.copyFromUtf8("test")), RANDOM_RESULT_SET_ROW_COUNT - 1));
    final Statement statement = Statement.of("SELECT * FROM TEST_TABLE");
    final RandomResultSetGenerator generator = new RandomResultSetGenerator(RANDOM_RESULT_SET_ROW_COUNT - 10);
    mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
    final CountDownLatch latch = new CountDownLatch(1);
    final RetryCounter counter = new RetryCounter();
    try (Connection connection = createConnection(counter)) {
        ApiFuture<Void> res1;
        try (AsyncResultSet rs = connection.executeQueryAsync(SELECT_RANDOM_STATEMENT, Options.bufferRows(5))) {
            res1 = rs.setCallback(multiThreadedExecutor, resultSet -> {
                try {
                    latch.await(10L, TimeUnit.SECONDS);
                    while (true) {
                        switch(resultSet.tryNext()) {
                            case OK:
                                break;
                            case DONE:
                                return CallbackResponse.DONE;
                            case NOT_READY:
                                return CallbackResponse.CONTINUE;
                        }
                    }
                } catch (Throwable t) {
                    throw SpannerExceptionFactory.asSpannerException(t);
                }
            });
        }
        try (AsyncResultSet rs = connection.executeQueryAsync(statement, Options.bufferRows(5))) {
            rs.setCallback(multiThreadedExecutor, new ReadyCallback() {

                boolean replaced;

                @Override
                public CallbackResponse cursorReady(AsyncResultSet resultSet) {
                    if (!replaced) {
                        // Replace the result of the query on the server after the first execution.
                        mockSpanner.putStatementResult(StatementResult.query(statement, generator.generate()));
                        replaced = true;
                    }
                    while (true) {
                        switch(resultSet.tryNext()) {
                            case OK:
                                break;
                            case DONE:
                                latch.countDown();
                                return CallbackResponse.DONE;
                            case NOT_READY:
                                return CallbackResponse.CONTINUE;
                        }
                    }
                }
            });
        }
        try {
            get(res1);
            fail("Missing expected exception");
        } catch (AbortedDueToConcurrentModificationException e) {
            assertThat(counter.retryCount).isEqualTo(1);
        }
    }
}
Also used : MoreExecutors(com.google.common.util.concurrent.MoreExecutors) BeforeClass(org.junit.BeforeClass) SpannerExceptionFactory(com.google.cloud.spanner.SpannerExceptionFactory) Timestamp(com.google.cloud.Timestamp) Collections2(com.google.common.collect.Collections2) StatementResult(com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) ImmutableList(com.google.common.collect.ImmutableList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) After(org.junit.After) Assert.fail(org.junit.Assert.fail) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) SimulatedExecutionTime(com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime) ExecutorService(java.util.concurrent.ExecutorService) Before(org.junit.Before) AsyncResultSet(com.google.cloud.spanner.AsyncResultSet) AfterClass(org.junit.AfterClass) CallbackResponse(com.google.cloud.spanner.AsyncResultSet.CallbackResponse) AbstractMessage(com.google.protobuf.AbstractMessage) Executor(java.util.concurrent.Executor) SpannerApiFutures.get(com.google.cloud.spanner.SpannerApiFutures.get) ITConnection(com.google.cloud.spanner.connection.ITAbstractSpannerTest.ITConnection) Test(org.junit.Test) ReadyCallback(com.google.cloud.spanner.AsyncResultSet.ReadyCallback) Truth.assertThat(com.google.common.truth.Truth.assertThat) Options(com.google.cloud.spanner.Options) Executors(java.util.concurrent.Executors) ApiFuture(com.google.api.core.ApiFuture) SettableApiFuture(com.google.api.core.SettableApiFuture) Statement(com.google.cloud.spanner.Statement) ByteString(com.google.protobuf.ByteString) TimeUnit(java.util.concurrent.TimeUnit) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) ExecuteSqlRequest(com.google.spanner.v1.ExecuteSqlRequest) AsyncResultSet(com.google.cloud.spanner.AsyncResultSet) CallbackResponse(com.google.cloud.spanner.AsyncResultSet.CallbackResponse) Statement(com.google.cloud.spanner.Statement) ITConnection(com.google.cloud.spanner.connection.ITAbstractSpannerTest.ITConnection) CountDownLatch(java.util.concurrent.CountDownLatch) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) ReadyCallback(com.google.cloud.spanner.AsyncResultSet.ReadyCallback) Test(org.junit.Test)

Example 2 with AbortedDueToConcurrentModificationException

use of com.google.cloud.spanner.AbortedDueToConcurrentModificationException in project java-spanner by googleapis.

the class ConnectionAsyncApiAbortedTest method testBlindUpdateAborted_WithConcurrentModification.

@Test
public void testBlindUpdateAborted_WithConcurrentModification() {
    Statement update1 = Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=100");
    mockSpanner.putStatementResult(StatementResult.update(update1, 100));
    RetryCounter counter = new RetryCounter();
    try (Connection connection = createConnection(counter)) {
        // Execute an update statement and then change the result for the next time it is executed.
        get(connection.executeUpdateAsync(update1));
        mockSpanner.putStatementResult(StatementResult.update(update1, 200));
        // Abort on the next statement. The retry should now fail because of the changed result of the
        // first update.
        mockSpanner.abortNextStatement();
        connection.executeUpdateAsync(INSERT_STATEMENT);
        try {
            get(connection.commitAsync());
            fail("Missing expected exception");
        } catch (AbortedDueToConcurrentModificationException e) {
            assertThat(counter.retryCount).isEqualTo(1);
        }
    }
}
Also used : Statement(com.google.cloud.spanner.Statement) ITConnection(com.google.cloud.spanner.connection.ITAbstractSpannerTest.ITConnection) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) Test(org.junit.Test)

Example 3 with AbortedDueToConcurrentModificationException

use of com.google.cloud.spanner.AbortedDueToConcurrentModificationException in project java-spanner by googleapis.

the class ITTransactionRetryTest method testAbortWithConcurrentInsert.

@Test
public void testAbortWithConcurrentInsert() {
    assumeFalse("concurrent transactions are not supported on the emulator", isUsingEmulator());
    AbortInterceptor interceptor = new AbortInterceptor(0);
    try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) {
        // insert two test records
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (1, 'test 1')"));
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (2, 'test 2')"));
        // select the test records and consume the entire result set
        try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM TEST ORDER BY ID"))) {
            while (rs.next()) {
            // do nothing
            }
        }
        // open a new connection and transaction and do an additional insert
        try (ITConnection connection2 = createConnection()) {
            connection2.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (3, 'test 3')"));
            connection2.commit();
        }
        // now try to do an insert that will abort. The retry should now fail as there has been a
        // concurrent modification
        interceptor.setProbability(1.0);
        interceptor.setOnlyInjectOnce(true);
        boolean expectedException = false;
        try {
            connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (4, 'test 4')"));
        } catch (AbortedDueToConcurrentModificationException e) {
            expectedException = true;
        }
        assertThat(expectedException, is(true));
        assertRetryStatistics(1, 1, 0);
    }
}
Also used : ResultSet(com.google.cloud.spanner.ResultSet) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) ParallelIntegrationTest(com.google.cloud.spanner.ParallelIntegrationTest) Test(org.junit.Test) ITAbstractSpannerTest(com.google.cloud.spanner.connection.ITAbstractSpannerTest)

Example 4 with AbortedDueToConcurrentModificationException

use of com.google.cloud.spanner.AbortedDueToConcurrentModificationException in project java-spanner by googleapis.

the class ITTransactionRetryTest method testAbortWithCursorHalfwayDroppedTableConcurrentModification.

/**
 * Test that shows the following:
 *
 * <ol>
 *   <li>Insert two records into table TEST and commit.
 *   <li>Create the table FOO and insert two test records and commit.
 *   <li>Query all the records from the TEST table and consume the result set.
 *   <li>Query all the records from the FOO table and consume only part of the result set.
 *   <li>Open another connection and drop the table FOO.
 *   <li>Try to consume the rest of the FOO result set. This aborts.
 *   <li>The transaction is internally retried. The retry fails as the SELECT statement on FOO
 *       will now fail.
 * </ol>
 */
@Test
public void testAbortWithCursorHalfwayDroppedTableConcurrentModification() {
    assumeFalse("concurrent transactions are not supported on the emulator", isUsingEmulator());
    boolean abortedDueToConcurrentModification = false;
    AbortInterceptor interceptor = new AbortInterceptor(0);
    // first insert two test records
    try (ITConnection connection = createConnection()) {
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (1, 'test 1')"));
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (2, 'test 2')"));
        connection.commit();
    }
    // CREATE FOO
    try (ITConnection connection2 = createConnection()) {
        connection2.setAutocommit(true);
        connection2.execute(Statement.of("CREATE TABLE FOO (ID INT64, NAME STRING(100)) PRIMARY KEY (ID)"));
        connection2.executeUpdate(Statement.of("INSERT INTO FOO (ID, NAME) VALUES (1, 'test 1')"));
        connection2.executeUpdate(Statement.of("INSERT INTO FOO (ID, NAME) VALUES (2, 'test 2')"));
    }
    try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) {
        try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM TEST"))) {
            while (rs.next()) {
            // do nothing
            }
        }
        // SELECT FROM FOO and consume part of the result set
        ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM FOO"));
        assertThat(rs.next(), is(true));
        // DROP FOO using a different connection
        try (ITConnection connection2 = createConnection()) {
            connection2.setAutocommit(true);
            connection2.execute(Statement.of("DROP TABLE FOO"));
        }
        // try to continue to consume the result set, but this will now abort.
        interceptor.setProbability(1.0);
        interceptor.setOnlyInjectOnce(true);
        try {
            // This will fail as the retry will not succeed.
            rs.next();
        } catch (AbortedDueToConcurrentModificationException e) {
            abortedDueToConcurrentModification = true;
        } finally {
            rs.close();
        }
    }
    assertThat(abortedDueToConcurrentModification, is(true));
    assertRetryStatistics(1, 1, 0);
}
Also used : ResultSet(com.google.cloud.spanner.ResultSet) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) ParallelIntegrationTest(com.google.cloud.spanner.ParallelIntegrationTest) Test(org.junit.Test) ITAbstractSpannerTest(com.google.cloud.spanner.connection.ITAbstractSpannerTest)

Example 5 with AbortedDueToConcurrentModificationException

use of com.google.cloud.spanner.AbortedDueToConcurrentModificationException in project java-spanner by googleapis.

the class ITTransactionRetryTest method testAbortWithDroppedTableConcurrentModification.

/**
 * Test that shows the following:
 *
 * <ol>
 *   <li>Insert two records into table TEST and commit.
 *   <li>Create the table FOO and insert a test record.
 *   <li>Query the table FOO.
 *   <li>Query all the records from the TEST table and consume the result set.
 *   <li>Open another connection and drop the table FOO.
 *   <li>Insert another record into TEST that aborts.
 *   <li>The transaction is internally retried. The retry fails as the SELECT statement on FOO
 *       will now fail.
 * </ol>
 */
@Test
public void testAbortWithDroppedTableConcurrentModification() {
    assumeFalse("concurrent transactions are not supported on the emulator", isUsingEmulator());
    boolean abortedDueToConcurrentModification = false;
    AbortInterceptor interceptor = new AbortInterceptor(0);
    // first insert two test records
    try (ITConnection connection = createConnection()) {
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (1, 'test 1')"));
        connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (2, 'test 2')"));
        connection.commit();
    }
    // CREATE FOO
    try (ITConnection connection2 = createConnection()) {
        connection2.setAutocommit(true);
        connection2.execute(Statement.of("CREATE TABLE FOO (ID INT64, NAME STRING(100)) PRIMARY KEY (ID)"));
        connection2.executeUpdate(Statement.of("INSERT INTO FOO (ID, NAME) VALUES (1, 'test 1')"));
    }
    try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) {
        try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM FOO"))) {
            while (rs.next()) {
            // do nothing
            }
        }
        try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM TEST"))) {
            while (rs.next()) {
            // do nothing
            }
        }
        // DROP FOO using a different connection
        try (ITConnection connection2 = createConnection()) {
            connection2.setAutocommit(true);
            connection2.execute(Statement.of("DROP TABLE FOO"));
        }
        // Now try to do an insert that will abort. The subsequent retry will fail as the SELECT *
        // FROM FOO now fails.
        interceptor.setProbability(1.0);
        interceptor.setOnlyInjectOnce(true);
        try {
            connection.executeUpdate(Statement.of("INSERT INTO TEST (ID, NAME) VALUES (3, 'test 3')"));
        } catch (AbortedDueToConcurrentModificationException e) {
            abortedDueToConcurrentModification = true;
        }
    }
    assertThat(abortedDueToConcurrentModification, is(true));
    assertRetryStatistics(1, 1, 0);
}
Also used : ResultSet(com.google.cloud.spanner.ResultSet) AbortedDueToConcurrentModificationException(com.google.cloud.spanner.AbortedDueToConcurrentModificationException) ParallelIntegrationTest(com.google.cloud.spanner.ParallelIntegrationTest) Test(org.junit.Test) ITAbstractSpannerTest(com.google.cloud.spanner.connection.ITAbstractSpannerTest)

Aggregations

AbortedDueToConcurrentModificationException (com.google.cloud.spanner.AbortedDueToConcurrentModificationException)21 Test (org.junit.Test)21 ParallelIntegrationTest (com.google.cloud.spanner.ParallelIntegrationTest)15 ResultSet (com.google.cloud.spanner.ResultSet)15 ITAbstractSpannerTest (com.google.cloud.spanner.connection.ITAbstractSpannerTest)15 Statement (com.google.cloud.spanner.Statement)9 AsyncResultSet (com.google.cloud.spanner.AsyncResultSet)7 ApiFuture (com.google.api.core.ApiFuture)6 SettableApiFuture (com.google.api.core.SettableApiFuture)6 ITConnection (com.google.cloud.spanner.connection.ITAbstractSpannerTest.ITConnection)6 Timestamp (com.google.cloud.Timestamp)5 CallbackResponse (com.google.cloud.spanner.AsyncResultSet.CallbackResponse)5 Options (com.google.cloud.spanner.Options)5 SpannerApiFutures.get (com.google.cloud.spanner.SpannerApiFutures.get)5 SpannerExceptionFactory (com.google.cloud.spanner.SpannerExceptionFactory)5 Truth.assertThat (com.google.common.truth.Truth.assertThat)5 CountDownLatch (java.util.concurrent.CountDownLatch)5 ExecutorService (java.util.concurrent.ExecutorService)5 Executors (java.util.concurrent.Executors)5 TimeUnit (java.util.concurrent.TimeUnit)5