From e256d22f33d5f091ea90ed81c0b0f8600beae96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 11 Jun 2020 13:54:53 +0200 Subject: [PATCH 01/55] fix: include an explicit version for javax-annotations-api (#261) The Maven flatten plugin transforms the pom of the project from a set of imports and transitive dependencies into a pom that contains all dependencies and versions explicitly. This process did however miss the javax-annotations-api dependency that is only included for JDK9 and higher. Fixes https://github.com/GoogleCloudPlatform/java-docs-samples/issues/3139 --- google-cloud-spanner-bom/pom.xml | 2 +- google-cloud-spanner/pom.xml | 1 + grpc-google-cloud-spanner-v1/pom.xml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 53e8fac348..ccb065a4af 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -90,7 +90,7 @@ com.google.cloud google-cloud-spanner test-jar - 1.55.1 + 1.55.2-SNAPSHOT com.google.api.grpc diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 9aec315b34..6bff001cfa 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -336,6 +336,7 @@ javax.annotation javax.annotation-api + 1.3.2 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index ac288a3444..124d4db6cf 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -53,6 +53,7 @@ javax.annotation javax.annotation-api + 1.3.2 From 3b4d4603aecce44648de4840039013832421bb62 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 11 Jun 2020 10:58:41 -0700 Subject: [PATCH 02/55] chore: regenerate README versions (#262) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/e66d5b32-5d3a-4216-853d-260a1b0f526f/targets - [ ] To automatically regenerate this PR, check this box. --- README.md | 4 ++-- synth.metadata | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e10d846e4c..d0334a6260 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file com.google.cloud libraries-bom - 5.4.0 + 5.7.0 pom import @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 1.55.0 + 1.55.1 ``` diff --git a/synth.metadata b/synth.metadata index eacf03a5f7..6c1d47215c 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "13e47c305c1f546e0ae54ca1deb7faabd6eb9ea9" + "sha": "22ed45816098f5e50104935b66bc55297ea7f7b7" } }, { From 52ca90d46cd600783f8714788fdf4ce4e3891e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 12 Jun 2020 07:22:09 +0200 Subject: [PATCH 03/55] test: get write sessions in one call (#265) The test case SessionPoolTest.testMaintainerKeepsWriteProportion could fail as it queried the session pool for the number of write sessions by doing two calls; one for available write sessions and one for sessions being prepared. If one of the sessions that was being prepared was returned to the pool between the two calls, the test case would fail because it calculated the wrong number. Fixes #264 --- .../main/java/com/google/cloud/spanner/SessionPool.java | 7 +++++++ .../java/com/google/cloud/spanner/SessionPoolTest.java | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java index 776c3df1c9..2286c3b34b 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java @@ -1323,6 +1323,13 @@ int getNumberOfSessionsInPool() { } } + @VisibleForTesting + int getNumberOfWriteSessionsInPool() { + synchronized (lock) { + return writePreparedSessions.size() + numSessionsBeingPrepared; + } + } + @VisibleForTesting int getNumberOfSessionsBeingCreated() { synchronized (lock) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index 395a60ade3..b833719009 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -1058,9 +1058,7 @@ public void run() { verify(session, times(options.getMinSessions())).singleUse(any(TimestampBound.class)); // Verify that all sessions are still in the pool, and that the write fraction is maintained. assertThat(pool.getNumberOfSessionsInPool()).isEqualTo(options.getMinSessions()); - assertThat( - pool.getNumberOfAvailableWritePreparedSessions() - + pool.getNumberOfSessionsBeingPrepared()) + assertThat(pool.getNumberOfWriteSessionsInPool()) .isEqualTo( (int) Math.ceil(pool.getNumberOfSessionsInPool() * options.getWriteSessionsFraction())); From f89da6a1f4f8a86c136a23dfd2f5b073dd65407a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 12 Jun 2020 07:23:33 +0200 Subject: [PATCH 04/55] test: try to workaround sleep bug in windows (#266) --- .../cloud/spanner/SpannerRetryHelperTest.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java index 8991691bff..e5a427bff8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.fail; import com.google.common.base.Stopwatch; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.protobuf.Duration; import com.google.rpc.RetryInfo; import io.grpc.Context; @@ -188,6 +189,24 @@ public Integer call() throws Exception { @Test public void testExceptionWithRetryInfo() { + // Workaround from https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6435126. + // See also https://stackoverflow.com/questions/824110/accurate-sleep-for-java-on-windows + // Note that this is a daemon thread, so it will not prevent the JVM from shutting down. + new ThreadFactoryBuilder() + .setDaemon(true) + .build() + .newThread( + new Runnable() { + @Override + public void run() { + while (true) { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + } + } + } + }); final int RETRY_DELAY_MILLIS = 100; Metadata.Key key = ProtoUtils.keyForProto(RetryInfo.getDefaultInstance()); Status status = Status.fromCodeValue(Status.Code.ABORTED.value()); @@ -220,7 +239,8 @@ public Integer call() throws Exception { Stopwatch watch = Stopwatch.createStarted(); assertThat(SpannerRetryHelper.runTxWithRetriesOnAborted(callable)).isEqualTo(2); long elapsed = watch.elapsed(TimeUnit.MILLISECONDS); - assertThat(elapsed >= RETRY_DELAY_MILLIS).isTrue(); + // Allow 1ms difference as that should be the accuracy of the sleep method. + assertThat(elapsed).isAtLeast(RETRY_DELAY_MILLIS - 1); } private SpannerException abortedWithRetryInfo(int nanos) { From 00eadd34d03a52ad39a070dee55a6118d9473b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 12 Jun 2020 12:01:53 +0200 Subject: [PATCH 05/55] tests: prevent multiple retries quickly after each other (#268) --- .../java/com/google/cloud/spanner/InstanceAdminGaxTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java index 66ae5ab0bd..309c45bf03 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java @@ -224,10 +224,10 @@ public void setUp() throws Exception { RetrySettings retrySettingsWithLowTimeout = RetrySettings.newBuilder() .setInitialRetryDelay(Duration.ofMillis(1L)) - .setMaxRetryDelay(Duration.ofMillis(1L)) + .setMaxRetryDelay(Duration.ofMillis(1000L)) .setInitialRpcTimeout(Duration.ofMillis(20L)) .setMaxRpcTimeout(Duration.ofMillis(200L)) - .setRetryDelayMultiplier(1.3) + .setRetryDelayMultiplier(1000.0d) .setMaxAttempts(10) .setTotalTimeout(Duration.ofMillis(200L)) .build(); From 867dd33120a150ebc58bf6be39a00e8d6901d797 Mon Sep 17 00:00:00 2001 From: Suraj Dhamecha <48670070+suraj-qlogic@users.noreply.github.com> Date: Fri, 12 Jun 2020 15:33:35 +0530 Subject: [PATCH 06/55] chore: remove usage of deprecated ExpectedException none() method (#247) --- .../AbstractStructReaderTypesTest.java | 20 +- .../google/cloud/spanner/BackupIdTest.java | 3 - .../com/google/cloud/spanner/BackupTest.java | 38 ++- .../google/cloud/spanner/DatabaseIdTest.java | 13 +- .../google/cloud/spanner/DatabaseTest.java | 3 - .../cloud/spanner/GrpcResultSetTest.java | 31 +- .../cloud/spanner/InstanceConfigIdTest.java | 13 +- .../google/cloud/spanner/InstanceIdTest.java | 13 +- .../google/cloud/spanner/KeyRangeTest.java | 22 +- .../google/cloud/spanner/MutationTest.java | 52 +-- .../google/cloud/spanner/OperationTest.java | 27 +- .../com/google/cloud/spanner/OptionsTest.java | 37 +- .../cloud/spanner/PartitionOptionsTest.java | 21 +- .../google/cloud/spanner/ResultSetsTest.java | 32 +- .../spanner/ResumableStreamIteratorTest.java | 24 +- .../google/cloud/spanner/SessionImplTest.java | 157 +++++---- .../spanner/SessionPoolIntegrationTest.java | 3 - .../cloud/spanner/SessionPoolOptionsTest.java | 31 +- .../google/cloud/spanner/SessionPoolTest.java | 45 ++- .../com/google/cloud/spanner/SpanTest.java | 14 +- .../cloud/spanner/SpannerGaxRetryTest.java | 64 ++-- .../cloud/spanner/SpannerOptionsTest.java | 29 +- .../google/cloud/spanner/StatementTest.java | 39 ++- .../com/google/cloud/spanner/StructTest.java | 4 - .../cloud/spanner/TimestampBoundTest.java | 21 +- .../spanner/TransactionManagerImplTest.java | 69 ++-- .../com/google/cloud/spanner/TypeTest.java | 41 ++- .../com/google/cloud/spanner/ValueTest.java | 322 +++++++++++------- .../spanner/connection/DdlBatchTest.java | 77 +++-- .../spanner/connection/DmlBatchTest.java | 71 ++-- .../connection/ReadOnlyTransactionTest.java | 61 +++- .../connection/ReadWriteTransactionTest.java | 48 ++- .../connection/StatementResultImplTest.java | 38 ++- .../connection/StatementTimeoutTest.java | 178 +++++++--- .../connection/it/ITReadOnlySpannerTest.java | 21 +- .../it/ITReadWriteAutocommitSpannerTest.java | 4 - .../connection/it/ITTransactionModeTest.java | 52 +-- .../google/cloud/spanner/it/ITBackupTest.java | 3 - .../cloud/spanner/it/ITClosedSessionTest.java | 45 ++- .../cloud/spanner/it/ITDatabaseAdminTest.java | 23 +- .../cloud/spanner/it/ITDatabaseTest.java | 16 +- .../cloud/spanner/it/ITInstanceAdminTest.java | 3 - .../cloud/spanner/it/ITQueryOptionsTest.java | 3 - .../google/cloud/spanner/it/ITQueryTest.java | 80 +++-- .../cloud/spanner/it/ITReadOnlyTxnTest.java | 21 +- .../google/cloud/spanner/it/ITReadTest.java | 51 +-- .../spanner/it/ITTransactionManagerTest.java | 12 +- .../google/cloud/spanner/it/ITWriteTest.java | 79 +++-- 48 files changed, 1312 insertions(+), 762 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java index 04b6183148..3e6da2a296 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java @@ -19,6 +19,7 @@ import static com.google.cloud.spanner.Type.StructField; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.junit.runners.Parameterized.Parameter; @@ -33,9 +34,7 @@ import java.util.List; import javax.annotation.Nullable; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.mockito.Mockito; @@ -274,7 +273,6 @@ public static Collection parameters() { @Nullable public List otherAllowedGetters; - @Rule public ExpectedException expectedException = ExpectedException.none(); private TestStructReader reader; @Before @@ -372,15 +370,23 @@ public void getterForIncorrectType() throws Exception { public void getterWhenNull() throws Exception { Mockito.when(reader.getType()).thenReturn(Type.struct(StructField.of("F1", type))); Mockito.when(reader.isNull(0)).thenReturn(true); - expectedException.expect(NullPointerException.class); - getterByIndex(0); + try { + getterByIndex(0); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void getterByNameWhenNull() throws Exception { Mockito.when(reader.getType()).thenReturn(Type.struct(StructField.of("F1", type))); Mockito.when(reader.isNull(0)).thenReturn(true); - expectedException.expect(NullPointerException.class); - getterByName("F1"); + try { + getterByName("F1"); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertNotNull(ex.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupIdTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupIdTest.java index c3405a05a0..629d026143 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupIdTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupIdTest.java @@ -19,16 +19,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.BackupId}. */ @RunWith(JUnit4.class) public class BackupIdTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basics() { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 0e5e1afd39..50eaf1fd09 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -17,6 +17,9 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -29,9 +32,7 @@ import com.google.cloud.spanner.BackupInfo.State; import java.util.Arrays; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; @@ -46,7 +47,6 @@ public class BackupTest { private static final String DB = "projects/test-project/instances/test-instance/databases/db-1"; private static final Timestamp EXP_TIME = Timestamp.ofTimeSecondsAndNanos(1000L, 1000); - @Rule public ExpectedException expectedException = ExpectedException.none(); @Mock DatabaseAdminClient dbClient; @Before @@ -102,8 +102,12 @@ public void createWithoutSource() { .newBackupBuilder(BackupId.of("test-project", "dest-instance", "backup-id")) .setExpireTime(expireTime) .build(); - expectedException.expect(IllegalStateException.class); - backup.create(); + try { + backup.create(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertNotNull(e.getMessage()); + } } @Test @@ -113,8 +117,12 @@ public void createWithoutExpireTime() { .newBackupBuilder(BackupId.of("test-project", "instance-id", "backup-id")) .setDatabase(DatabaseId.of("test-project", "instance-id", "src-database")) .build(); - expectedException.expect(IllegalStateException.class); - backup.create(); + try { + backup.create(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertNotNull(e.getMessage()); + } } @Test @@ -207,8 +215,12 @@ public void updateExpireTimeWithoutExpireTime() { dbClient .newBackupBuilder(BackupId.of("test-project", "test-instance", "test-backup")) .build(); - expectedException.expect(IllegalStateException.class); - backup.updateExpireTime(); + try { + backup.updateExpireTime(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertNotNull(e.getMessage()); + } } @Test @@ -228,8 +240,12 @@ public void restoreWithoutDestination() { dbClient .newBackupBuilder(BackupId.of("test-project", "test-instance", "test-backup")) .build(); - expectedException.expect(NullPointerException.class); - backup.restore(null); + try { + backup.restore(null); + fail("Expected exception"); + } catch (NullPointerException e) { + assertNull(e.getMessage()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseIdTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseIdTest.java index a740f40424..7db3c6cef4 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseIdTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseIdTest.java @@ -17,17 +17,15 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.DatabaseId}. */ @RunWith(JUnit4.class) public class DatabaseIdTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basics() { @@ -44,8 +42,11 @@ public void basics() { @Test public void badName() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("projects"); // Expect conforming pattern in output. - DatabaseId.of("bad name"); + try { + DatabaseId.of("bad name"); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage()).contains("projects"); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 14b93d7413..74703609d9 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -28,9 +28,7 @@ import com.google.cloud.spanner.DatabaseInfo.State; import java.util.Arrays; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; @@ -44,7 +42,6 @@ public class DatabaseTest { private static final String NAME = "projects/test-project/instances/test-instance/databases/database-1"; - @Rule public ExpectedException expectedException = ExpectedException.none(); @Mock DatabaseAdminClient dbClient; @Before diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java index da3e81a9bb..5bad5b5541 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java @@ -16,9 +16,9 @@ package com.google.cloud.spanner; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.testing.SerializableTester.reserialize; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import com.google.cloud.ByteArray; import com.google.cloud.Date; @@ -40,16 +40,13 @@ import java.util.Map; import javax.annotation.Nullable; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.SpannerImpl.GrpcResultSet}. */ @RunWith(JUnit4.class) public class GrpcResultSetTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); private AbstractResultSet.GrpcResultSet resultSet; private SpannerRpc.ResultStreamConsumer consumer; @@ -107,16 +104,24 @@ public void metadataFailure() { SpannerException t = SpannerExceptionFactory.newSpannerException(ErrorCode.DEADLINE_EXCEEDED, "outatime"); consumer.onError(t); - expectedException.expect(isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); - expectedException.expectMessage("outatime"); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.DEADLINE_EXCEEDED); + assertThat(ex.getMessage()).contains("outatime"); + } } @Test public void noMetadata() { consumer.onCompleted(); - expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -195,8 +200,12 @@ public void multiResponseChunkingStreamClosed() { .setChunkedValue(true) .build()); consumer.onCompleted(); - expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigIdTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigIdTest.java index 3266333d37..4110cbe676 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigIdTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceConfigIdTest.java @@ -17,17 +17,16 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link InstanceConfigId}. */ @RunWith(JUnit4.class) public class InstanceConfigIdTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basic() { @@ -43,7 +42,11 @@ public void basic() { @Test public void badName() { - expectedException.expect(IllegalArgumentException.class); - InstanceConfigId.of("bad name"); + try { + InstanceConfigId.of("bad name"); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceIdTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceIdTest.java index 7d6ff2a2fe..2e921257f9 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceIdTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceIdTest.java @@ -17,17 +17,16 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; -import org.junit.Rule; +import org.junit.Assert; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link InstanceId}. */ @RunWith(JUnit4.class) public class InstanceIdTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basic() { @@ -43,7 +42,11 @@ public void basic() { @Test public void badName() { - expectedException.expect(IllegalArgumentException.class); - InstanceId.of("bad name"); + try { + InstanceId.of("bad name"); + Assert.fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertNotNull(e.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java index ba8c8eeed5..393138c604 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java @@ -20,18 +20,16 @@ import static com.google.cloud.spanner.KeyRange.Endpoint.OPEN; import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import com.google.common.testing.EqualsTester; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.KeyRange}. */ @RunWith(JUnit4.class) public class KeyRangeTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basics() { @@ -104,16 +102,22 @@ public void toBuilder() { @Test public void builderRequiresStart() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("start(Key)"); - KeyRange.newBuilder().setEnd(Key.of("z")).build(); + try { + KeyRange.newBuilder().setEnd(Key.of("z")).build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("start(Key)"); + } } @Test public void builderRequiresEnd() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("end(Key)"); - KeyRange.newBuilder().setStart(Key.of("a")).build(); + try { + KeyRange.newBuilder().setStart(Key.of("a")).build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("end(Key)"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java index f857f08f0a..a6f1049f08 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java @@ -18,6 +18,7 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import com.google.cloud.ByteArray; import com.google.cloud.Date; @@ -30,16 +31,13 @@ import java.util.List; import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.Mutation}. */ @RunWith(JUnit4.class) public class MutationTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void insertEmpty() { @@ -123,16 +121,22 @@ public void replace() { @Test public void duplicateColumn() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Duplicate column"); - Mutation.newInsertBuilder("T1").set("C1").to(true).set("C1").to(false).build(); + try { + Mutation.newInsertBuilder("T1").set("C1").to(true).set("C1").to(false).build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("Duplicate column"); + } } @Test public void duplicateColumnCaseInsensitive() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Duplicate column"); - Mutation.newInsertBuilder("T1").set("C1").to(true).set("c1").to(false).build(); + try { + Mutation.newInsertBuilder("T1").set("C1").to(true).set("c1").to(false).build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("Duplicate column"); + } } @Test @@ -149,30 +153,36 @@ public void asMap() { public void unfinishedBindingV1() { Mutation.WriteBuilder b = Mutation.newInsertBuilder("T1"); b.set("C1"); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Incomplete binding for column C1"); - b.build(); + try { + b.build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("Incomplete binding for column C1"); + } } @Test public void unfinishedBindingV2() { Mutation.WriteBuilder b = Mutation.newInsertBuilder("T1"); b.set("C1"); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Incomplete binding for column C1"); - b.set("C2"); + try { + b.set("C2"); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("Incomplete binding for column C1"); + } } @Test public void notInBinding() { ValueBinder binder = Mutation.newInsertBuilder("T1").set("C1"); binder.to(1234); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("No binding currently active"); - binder.to(5678); + try { + binder.to(5678); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("No binding currently active"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java index 8f0da8c6ff..f958c85330 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java @@ -16,9 +16,9 @@ package com.google.cloud.spanner; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; import static com.google.longrunning.Operation.newBuilder; +import static org.junit.Assert.fail; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -31,9 +31,7 @@ import com.google.rpc.Status; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; @@ -49,8 +47,6 @@ public class OperationTest { @Mock private DatabaseAdminClient dbClient; @Mock private ApiClock clock; - @Rule public ExpectedException expectedException = ExpectedException.none(); - private class ParserImpl implements Operation.Parser { @Override @@ -91,8 +87,12 @@ public void failedOperation() { assertThat(op.isDone()).isTrue(); assertThat(op.isSuccessful()).isFalse(); assertThat(op.getMetadata()).isNull(); - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - op.getResult(); + try { + op.getResult(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test @@ -179,10 +179,13 @@ public void waitForTimesout() throws Exception { Operation op = Operation.create(rpc, proto, new ParserImpl(), clock); when(rpc.getOperation("op1")).thenReturn(proto); when(clock.nanoTime()).thenReturn(0L, 50_000_000L, 100_000_000L, 150_000_000L); - - expectedException.expect(isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); - op.waitFor( - RetryOption.totalTimeout(Duration.ofMillis(100L)), - RetryOption.initialRetryDelay(Duration.ZERO)); + try { + op.waitFor( + RetryOption.totalTimeout(Duration.ofMillis(100L)), + RetryOption.initialRetryDelay(Duration.ZERO)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.DEADLINE_EXCEEDED); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java index 70544a661e..0931eba174 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java @@ -17,40 +17,55 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link Options}. */ @RunWith(JUnit4.class) public class OptionsTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void negativeLimitsNotAllowed() { - expectedException.expect(IllegalArgumentException.class); - Options.limit(-1); + try { + Options.limit(-1); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void zeroLimitNotAllowed() { - expectedException.expect(IllegalArgumentException.class); - Options.limit(0); + try { + Options.limit(0); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void negativePrefetchChunksNotAllowed() { - expectedException.expect(IllegalArgumentException.class); - Options.prefetchChunks(-1); + try { + Options.prefetchChunks(-1); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void zeroPrefetchChunksNotAllowed() { - expectedException.expect(IllegalArgumentException.class); - Options.prefetchChunks(0); + try { + Options.prefetchChunks(0); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionOptionsTest.java index 4eb5ba5bfa..e8c8dd001f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/PartitionOptionsTest.java @@ -18,18 +18,17 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import com.google.common.testing.EqualsTester; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.PartitionOptions}. */ @RunWith(JUnit4.class) public class PartitionOptionsTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void builder() { @@ -86,13 +85,21 @@ public void equalAndHashCode() { @Test public void invalidDesiredBytesPerBatch() { - expectedException.expect(IllegalArgumentException.class); - PartitionOptions.newBuilder().setPartitionSizeBytes(-1).build(); + try { + PartitionOptions.newBuilder().setPartitionSizeBytes(-1).build(); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void invalidMaxPartitionCount() { - expectedException.expect(IllegalArgumentException.class); - PartitionOptions.newBuilder().setMaxPartitions(-1).build(); + try { + PartitionOptions.newBuilder().setMaxPartitions(-1).build(); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java index 006e5a62b1..93b6d9f604 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import com.google.cloud.ByteArray; @@ -27,9 +28,7 @@ import com.google.common.primitives.Longs; import java.util.Arrays; import java.util.List; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -37,8 +36,6 @@ @RunWith(JUnit4.class) public class ResultSetsTest { - @Rule public ExpectedException expected = ExpectedException.none(); - @Test public void resultSetIteration() { double doubleVal = 1.2; @@ -234,10 +231,13 @@ public void resultSetIterationWithStructColumns() { Struct value1 = Struct.newBuilder().set("g1").to("abc").build(); Struct struct1 = Struct.newBuilder().set("f1").to(value1).set("f2").to((Long) null).build(); - - expected.expect(UnsupportedOperationException.class); - expected.expectMessage("STRUCT-typed columns are not supported inside ResultSets."); - ResultSets.forRows(type, Arrays.asList(struct1)); + try { + ResultSets.forRows(type, Arrays.asList(struct1)); + fail("Expected exception"); + } catch (UnsupportedOperationException ex) { + assertThat(ex.getMessage()) + .contains("STRUCT-typed columns are not supported inside ResultSets."); + } } @Test @@ -306,8 +306,12 @@ public void closeResultSet() { Type.struct(Type.StructField.of("f1", Type.string())), Arrays.asList(Struct.newBuilder().set("f1").to("x").build())); rs.close(); - expected.expect(IllegalStateException.class); - rs.getCurrentRowAsStruct(); + try { + rs.getCurrentRowAsStruct(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -316,7 +320,11 @@ public void exceptionIfNextIsNotCalled() { ResultSets.forRows( Type.struct(Type.StructField.of("f1", Type.string())), Arrays.asList(Struct.newBuilder().set("f1").to("x").build())); - expected.expect(IllegalStateException.class); - rs.getCurrentRowAsStruct(); + try { + rs.getCurrentRowAsStruct(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java index ca3e621ff9..6c387f0d48 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResumableStreamIteratorTest.java @@ -16,8 +16,8 @@ package com.google.cloud.spanner; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -40,15 +40,13 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; import org.mockito.internal.util.reflection.Whitebox; -/** Unit tests for {@link SpannerImpl.ResumableStreamIterator}. */ +/** Unit tests for {@link AbstractResultSet.ResumableStreamIterator}. */ @RunWith(JUnit4.class) public class ResumableStreamIteratorTest { interface Starter { @@ -112,8 +110,6 @@ public void close(@Nullable String message) { } } - @Rule public ExpectedException expectedException = ExpectedException.none(); - Starter starter = Mockito.mock(Starter.class); AbstractResultSet.ResumableStreamIterator resumableStreamIterator; @@ -237,8 +233,12 @@ public void nonRetryableError() { Iterator strings = stringIterator(resumableStreamIterator); assertThat(strings.next()).isEqualTo("a"); assertThat(strings.next()).isEqualTo("b"); - expectedException.expect(isSpannerException(ErrorCode.FAILED_PRECONDITION)); - assertThat(strings.next()).isNotEqualTo("X"); + try { + assertThat(strings.next()).isNotEqualTo("X"); + fail("Expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); + } } @Test @@ -341,8 +341,12 @@ public void bufferLimitMissingTokensUnsafeToRetry() { .thenThrow(new RetryableException(ErrorCode.UNAVAILABLE, "failed by test")); assertThat(consumeAtMost(3, resumableStreamIterator)).containsExactly("a", "b", "c").inOrder(); - expectedException.expect(isSpannerException(ErrorCode.UNAVAILABLE)); - resumableStreamIterator.next(); + try { + resumableStreamIterator.next(); + fail("Expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.UNAVAILABLE); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java index f3f205a529..fcc36d2b1b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -50,9 +51,7 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; @@ -63,11 +62,9 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -/** Unit tests for {@link com.google.cloud.spanner.SpannerImpl.SessionImpl}. */ +/** Unit tests for {@link com.google.cloud.spanner.SessionImpl}. */ @RunWith(JUnit4.class) public class SessionImplTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Mock private SpannerRpc rpc; @Mock private SpannerOptions spannerOptions; private com.google.cloud.spanner.Session session; @@ -245,50 +242,60 @@ private static long utcTimeSeconds(int year, int month, int day, int hour, int m public void newSingleUseContextClosesOldSingleUseContext() { ReadContext ctx = session.singleUse(TimestampBound.strong()); session.singleUse(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test public void newSingleUseContextClosesOldSingleUseReadOnlyTransactionContext() { ReadContext ctx = session.singleUseReadOnlyTransaction(TimestampBound.strong()); session.singleUse(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test public void newSingleUseContextClosesOldMultiUseReadOnlyTransactionContext() { ReadContext ctx = session.singleUseReadOnlyTransaction(TimestampBound.strong()); session.singleUse(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test public void newSingleUseReadOnlyTransactionContextClosesOldSingleUseContext() { ReadContext ctx = session.singleUse(TimestampBound.strong()); session.singleUseReadOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test public void newMultiUseReadOnlyTransactionContextClosesOldSingleUseContext() { ReadContext ctx = session.singleUse(TimestampBound.strong()); session.readOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test @@ -301,10 +308,12 @@ public void writeClosesOldSingleUseContext() throws ParseException { .setCommitTimestamp(Timestamps.parse("2015-10-01T10:54:20.021Z")) .build()); session.writeAtLeastOnce(Arrays.asList()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test @@ -313,10 +322,12 @@ public void transactionClosesOldSingleUseContext() { // Note that we don't even run the transaction - just preparing the runner is sufficient. session.readWriteTransaction(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test @@ -324,18 +335,20 @@ public void singleUseContextClosesTransaction() { TransactionRunner runner = session.readWriteTransaction(); session.singleUse(TimestampBound.strong()); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - runner.run( - new TransactionRunner.TransactionCallable() { - @Nullable - @Override - public Void run(TransactionContext transaction) throws SpannerException { - fail("Unexpected call to transaction body"); - return null; - } - }); + try { + runner.run( + new TransactionRunner.TransactionCallable() { + @Nullable + @Override + public Void run(TransactionContext transaction) throws SpannerException { + fail("Unexpected call to transaction body"); + return null; + } + }); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } @Test @@ -345,10 +358,12 @@ public void prepareClosesOldSingleUseContext() { Mockito.when(rpc.beginTransaction(Mockito.any(), Mockito.eq(options))) .thenReturn(Transaction.newBuilder().setId(ByteString.copyFromUtf8("t1")).build()); session.prepareReadWriteTransaction(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("invalidated"); - ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + try { + ctx.read("Dummy", KeySet.all(), Arrays.asList("C")); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("invalidated"); + } } private static ResultSetMetadata newMetadata(Type type) { @@ -370,8 +385,12 @@ public void singleUseReadOnlyTransactionDoesntReturnTransactionMetadata() { // be better for the read to fail with an INTERNAL error, but we can't do that until txn // metadata is returned for failed reads (e.g., table-not-found) as well as successful ones. // TODO(user): Fix this. - expectedException.expect(IllegalStateException.class); - txn.getReadTimestamp(); + try { + txn.getReadTimestamp(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -386,9 +405,12 @@ public void singleUseReadOnlyTransactionReturnsEmptyTransactionMetadata() { mockRead(resultSet); ReadOnlyTransaction txn = session.singleUseReadOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.INTERNAL)); - txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + try { + txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } private static class NoOpStreamingCall implements SpannerRpc.StreamingCall { @@ -426,9 +448,12 @@ public void multiUseReadOnlyTransactionReturnsEmptyTransactionMetadata() { mockRead(resultSet); ReadOnlyTransaction txn = session.readOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.INTERNAL)); - txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + try { + txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + fail("Expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -443,9 +468,12 @@ public void multiUseReadOnlyTransactionReturnsMissingTimestamp() { mockRead(resultSet); ReadOnlyTransaction txn = session.readOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.INTERNAL)); - txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + try { + txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + fail("Expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -461,8 +489,11 @@ public void multiUseReadOnlyTransactionReturnsMissingTransactionId() throws Pars mockRead(resultSet); ReadOnlyTransaction txn = session.readOnlyTransaction(TimestampBound.strong()); - - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.INTERNAL)); - txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + try { + txn.readRow("Dummy", Key.of(), Arrays.asList("C")); + fail("Expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java index 5492957106..353dbdfe46 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java @@ -28,10 +28,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -48,7 +46,6 @@ public class SessionPoolIntegrationTest { private static final String TABLE_NAME = "TestTable"; private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private SessionPool pool; @BeforeClass diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolOptionsTest.java index b529a2737f..9cdabfac68 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolOptionsTest.java @@ -16,13 +16,13 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; @@ -31,7 +31,6 @@ /** Unit tests for {@link com.google.cloud.spanner.SessionPoolOptions} */ @RunWith(Parameterized.class) public class SessionPoolOptionsTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Parameter public int minSessions; @Parameter(1) @@ -49,17 +48,23 @@ public static Collection data() { @Test public void setMinMaxSessions() { - if (minSessions > maxSessions) { - expectedException.expect(IllegalArgumentException.class); + try { + SessionPoolOptions options = + SessionPoolOptions.newBuilder() + .setMinSessions(minSessions) + .setMaxSessions(maxSessions) + .build(); + if (minSessions > maxSessions) { + fail("Expected exception"); + } + assertThat(minSessions).isEqualTo(options.getMinSessions()); + assertThat(maxSessions).isEqualTo(options.getMaxSessions()); + } catch (IllegalArgumentException ex) { + if (minSessions <= maxSessions) { + throw ex; + } + assertNotNull(ex.getMessage()); } - SessionPoolOptions options = - SessionPoolOptions.newBuilder() - .setMinSessions(minSessions) - .setMaxSessions(maxSessions) - .build(); - - assertThat(minSessions).isEqualTo(options.getMinSessions()); - assertThat(maxSessions).isEqualTo(options.getMaxSessions()); } /** diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index b833719009..99cffbaec7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -22,8 +22,8 @@ import static com.google.cloud.spanner.MetricRegistryConstants.NUM_WRITE_SESSIONS; import static com.google.cloud.spanner.MetricRegistryConstants.SPANNER_LABEL_KEYS; import static com.google.cloud.spanner.MetricRegistryConstants.SPANNER_LABEL_KEYS_WITH_TYPE; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -81,9 +81,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; @@ -96,7 +94,6 @@ /** Tests for SessionPool that mock out the underlying stub. */ @RunWith(Parameterized.class) public class SessionPoolTest extends BaseSessionPoolTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); private final ExecutorService executor = Executors.newSingleThreadExecutor(); @Parameter public int minSessions; @@ -517,8 +514,12 @@ public void run() { // Suppress expected leakedSession warning. leakedSession.clearLeakedException(); pool.closeAsync(new SpannerImpl.ClosedException()); - expectedException.expect(IllegalStateException.class); - pool.getReadSession(); + try { + pool.getReadSession(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -560,8 +561,12 @@ public Void call() throws Exception { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); - pool.getReadSession(); + try { + pool.getReadSession(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -587,8 +592,12 @@ public Void call() throws Exception { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); - pool.getReadWriteSession(); + try { + pool.getReadWriteSession(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -616,8 +625,12 @@ public void run() { .when(session) .prepareReadWriteTransaction(); pool = createPool(); - expectedException.expect(isSpannerException(ErrorCode.INTERNAL)); - pool.getReadWriteSession(); + try { + pool.getReadWriteSession(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); + } } @Test @@ -851,8 +864,12 @@ public void run() { .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); Session session1 = pool.getReadSession(); - expectedException.expect(isSpannerException(ErrorCode.RESOURCE_EXHAUSTED)); - pool.getReadSession(); + try { + pool.getReadSession(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + } session1.close(); session1 = pool.getReadSession(); assertThat(session1).isNotNull(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java index eb1bb67e89..dc4652a1b4 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java @@ -44,10 +44,8 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.threeten.bp.Duration; @@ -119,8 +117,6 @@ public class SpanTest { .withDescription("Non-retryable test exception.") .asRuntimeException(); - @Rule public ExpectedException expectedException = ExpectedException.none(); - @BeforeClass public static void startStaticServer() throws Exception { mockSpanner = new MockSpannerServiceImpl(); @@ -231,23 +227,29 @@ public void tearDown() { @Test public void singleUseNonRetryableErrorOnNext() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.FAILED_PRECONDITION)); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { mockSpanner.addException(FAILED_PRECONDITION); while (rs.next()) { // Just consume the result set. + fail("Expected exception"); } + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); } } @Test public void singleUseExecuteStreamingSqlTimeout() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); try (ResultSet rs = clientWithTimeout.singleUse().executeQuery(SELECT1AND2)) { mockSpanner.setExecuteStreamingSqlExecutionTime(ONE_SECOND); while (rs.next()) { // Just consume the result set. + fail("Expected exception"); } + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.DEADLINE_EXCEEDED); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java index 54d7ad5a12..ad7ee39b35 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import com.google.api.core.ApiFunction; @@ -45,9 +46,7 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.threeten.bp.Duration; @@ -101,8 +100,6 @@ public class SpannerGaxRetryTest { private Spanner spannerWithTimeout; private DatabaseClient clientWithTimeout; - @Rule public ExpectedException expectedException = ExpectedException.none(); - @BeforeClass public static void startStaticServer() throws IOException { mockSpanner = new MockSpannerServiceImpl(); @@ -224,10 +221,13 @@ public Long run(TransactionContext transaction) throws Exception { @Test public void singleUseTimeout() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); mockSpanner.setBatchCreateSessionsExecutionTime(ONE_SECOND); try (ResultSet rs = clientWithTimeout.singleUse().executeQuery(SELECT1AND2)) { - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } @@ -241,38 +241,50 @@ public void singleUseUnavailable() { @Test public void singleUseNonRetryableError() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.FAILED_PRECONDITION)); mockSpanner.addException(FAILED_PRECONDITION); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); } } @Test public void singleUseNonRetryableErrorOnNext() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.FAILED_PRECONDITION)); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { mockSpanner.addException(FAILED_PRECONDITION); - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); } } @Test public void singleUseInternal() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.INTERNAL)); mockSpanner.addException(new IllegalArgumentException()); try (ResultSet rs = client.singleUse().executeQuery(SELECT1AND2)) { - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.INTERNAL, ex.getErrorCode()); } } @Test public void singleUseReadOnlyTransactionTimeout() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); mockSpanner.setBatchCreateSessionsExecutionTime(ONE_SECOND); try (ResultSet rs = clientWithTimeout.singleUseReadOnlyTransaction().executeQuery(SELECT1AND2)) { - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } @@ -286,10 +298,13 @@ public void singleUseReadOnlyTransactionUnavailable() { @Test public void singleUseExecuteStreamingSqlTimeout() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); try (ResultSet rs = clientWithTimeout.singleUse().executeQuery(SELECT1AND2)) { mockSpanner.setExecuteStreamingSqlExecutionTime(ONE_SECOND); - while (rs.next()) {} + while (rs.next()) { + fail("Expected exception"); + } + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } @@ -303,18 +318,13 @@ public void singleUseExecuteStreamingSqlUnavailable() { @Test public void readWriteTransactionTimeout() { - expectedException.expect(SpannerMatchers.isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); mockSpanner.setBeginTransactionExecutionTime(ONE_SECOND); - TransactionRunner runner = clientWithTimeout.readWriteTransaction(); - long updateCount = - runner.run( - new TransactionCallable() { - @Override - public Long run(TransactionContext transaction) throws Exception { - return transaction.executeUpdate(UPDATE_STATEMENT); - } - }); - assertThat(updateCount, is(equalTo(UPDATE_COUNT))); + try { + TransactionRunner runner = clientWithTimeout.readWriteTransaction(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java index f03def2e33..96490b94fd 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.ServerStreamingCallSettings; @@ -35,9 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; @@ -47,8 +46,6 @@ @RunWith(JUnit4.class) public class SpannerOptionsTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void defaultBuilder() { // We need to set the project id since in test environment we cannot obtain a default project @@ -346,22 +343,34 @@ public void testInstanceAdminCustomRetrySettings() { @Test public void testInvalidTransport() { - thrown.expect(IllegalArgumentException.class); - SpannerOptions.newBuilder().setTransportOptions(Mockito.mock(TransportOptions.class)); + try { + SpannerOptions.newBuilder().setTransportOptions(Mockito.mock(TransportOptions.class)); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test public void testInvalidSessionLabels() { - thrown.expect(NullPointerException.class); Map labels = new HashMap<>(); labels.put("env", null); - SpannerOptions.newBuilder().setSessionLabels(labels); + try { + SpannerOptions.newBuilder().setSessionLabels(labels); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test public void testNullSessionLabels() { - thrown.expect(NullPointerException.class); - SpannerOptions.newBuilder().setSessionLabels(null); + try { + SpannerOptions.newBuilder().setSessionLabels(null); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java index 116781c582..f41a659df2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java @@ -18,20 +18,19 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import com.google.cloud.ByteArray; import com.google.common.collect.ImmutableMap; import com.google.common.testing.EqualsTester; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.Statement}. */ @RunWith(JUnit4.class) public class StatementTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void basic() { @@ -103,33 +102,47 @@ public void bindReplacement() { public void incompleteBinding() { Statement.Builder builder = Statement.newBuilder("SELECT @v"); builder.bind("v"); - expectedException.expect(IllegalStateException.class); - builder.build(); + try { + builder.build(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test public void bindingInProgress() { Statement.Builder builder = Statement.newBuilder("SELECT @v"); builder.bind("v"); - - expectedException.expect(IllegalStateException.class); - builder.bind("y"); + try { + builder.bind("y"); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test public void alreadyBound() { ValueBinder binder = Statement.newBuilder("SELECT @v").bind("v"); binder.to("abc"); - - expectedException.expect(IllegalStateException.class); - binder.to("xyz"); + try { + binder.to("xyz"); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).isNotNull(); + } } @Test public void bindCommitTimestampFails() { ValueBinder binder = Statement.newBuilder("SELECT @v").bind("v"); - expectedException.expect(IllegalArgumentException.class); - binder.to(Value.COMMIT_TIMESTAMP); + try { + binder.to(Value.COMMIT_TIMESTAMP); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java index 503723df0b..61d2f900cb 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java @@ -23,9 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -33,8 +31,6 @@ @RunWith(JUnit4.class) public class StructTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test public void builder() { // These tests are basic: AbstractStructReaderTypesTest already covers all type getters. diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java index 231831128b..1298e05292 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java @@ -19,6 +19,8 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import com.google.cloud.Timestamp; import com.google.cloud.spanner.TimestampBound.Mode; @@ -26,9 +28,7 @@ import com.google.spanner.v1.TransactionOptions; import java.util.concurrent.TimeUnit; import org.hamcrest.MatcherAssert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -37,7 +37,6 @@ public class TimestampBoundTest { private static final long TEST_TIME_SECONDS = 1444662894L; private static final String TEST_TIME_ISO = "2015-10-12T15:14:54Z"; - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void serialization() throws Exception { @@ -90,8 +89,12 @@ public void exactStaleness() { @Test public void exactStalenessNegative() { - expectedException.expect(IllegalArgumentException.class); - TimestampBound.ofExactStaleness(-1, TimeUnit.SECONDS); + try { + TimestampBound.ofExactStaleness(-1, TimeUnit.SECONDS); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -119,8 +122,12 @@ public void stalenessSourceUnits() { @Test public void maxStalenessNegative() { - expectedException.expect(IllegalArgumentException.class); - TimestampBound.ofMaxStaleness(-1, TimeUnit.SECONDS); + try { + TimestampBound.ofMaxStaleness(-1, TimeUnit.SECONDS); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java index cd94d82800..85bb69181a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -44,9 +45,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; @@ -69,8 +68,6 @@ public void release(ScheduledExecutorService exec) { } } - @Rule public ExpectedException exception = ExpectedException.none(); - @Mock private SessionImpl session; @Mock TransactionRunnerImpl.TransactionContextImpl txn; private TransactionManagerImpl manager; @@ -86,26 +83,42 @@ public void beginCalledTwiceFails() { when(session.newTransaction()).thenReturn(txn); assertThat(manager.begin()).isEqualTo(txn); assertThat(manager.getState()).isEqualTo(TransactionState.STARTED); - exception.expect(IllegalStateException.class); - manager.begin(); + try { + manager.begin(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void commitBeforeBeginFails() { - exception.expect(IllegalStateException.class); - manager.commit(); + try { + manager.commit(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void rollbackBeforeBeginFails() { - exception.expect(IllegalStateException.class); - manager.rollback(); + try { + manager.rollback(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void resetBeforeBeginFails() { - exception.expect(IllegalStateException.class); - manager.resetForRetry(); + try { + manager.resetForRetry(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -133,8 +146,12 @@ public void resetAfterSuccessfulCommitFails() { when(session.newTransaction()).thenReturn(txn); manager.begin(); manager.commit(); - exception.expect(IllegalStateException.class); - manager.resetForRetry(); + try { + manager.resetForRetry(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -165,8 +182,12 @@ public void resetAfterErrorFails() { } catch (SpannerException e) { assertThat(e.getErrorCode()).isEqualTo(ErrorCode.UNKNOWN); } - exception.expect(IllegalStateException.class); - manager.resetForRetry(); + try { + manager.resetForRetry(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -174,8 +195,12 @@ public void rollbackAfterCommitFails() { when(session.newTransaction()).thenReturn(txn); manager.begin(); manager.commit(); - exception.expect(IllegalStateException.class); - manager.rollback(); + try { + manager.rollback(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -183,8 +208,12 @@ public void commitAfterRollbackFails() { when(session.newTransaction()).thenReturn(txn); manager.begin(); manager.rollback(); - exception.expect(IllegalStateException.class); - manager.commit(); + try { + manager.commit(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } @SuppressWarnings("unchecked") diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java index 4665b119fd..db83c1ba66 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java @@ -19,19 +19,18 @@ import static com.google.cloud.spanner.Type.StructField; import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import com.google.spanner.v1.TypeCode; import org.hamcrest.MatcherAssert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link com.google.cloud.spanner.Type}. */ @RunWith(JUnit4.class) public class TypeTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); private abstract static class ScalarTypeTester { final Type.Code expectedCode; @@ -289,34 +288,46 @@ public void emptyStruct() { @Test public void structFieldIndexNotFound() { Type t = Type.struct(StructField.of("f1", Type.int64())); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Field not found: f2"); - t.getFieldIndex("f2"); + try { + t.getFieldIndex("f2"); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage().contains("Field not found: f2")); + } } @Test public void structFieldIndexAmbiguous() { Type t = Type.struct(StructField.of("f1", Type.int64()), StructField.of("f1", Type.string())); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Ambiguous field name: f1"); - t.getFieldIndex("f1"); + try { + t.getFieldIndex("f1"); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage().contains("Ambiguous field name: f1")); + } } @Test public void parseErrorMissingTypeCode() { com.google.spanner.v1.Type proto = com.google.spanner.v1.Type.newBuilder().build(); - expectedException.expect(IllegalArgumentException.class); - Type.fromProto(proto); + try { + Type.fromProto(proto); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test public void parseErrorMissingArrayElementTypeProto() { com.google.spanner.v1.Type proto = com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.ARRAY).build(); - expectedException.expect(IllegalArgumentException.class); - Type.fromProto(proto); + try { + Type.fromProto(proto); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } private static void assertProtoEquals(com.google.spanner.v1.Type proto, String expected) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java index 58b9bb05dd..22c8261db9 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java @@ -19,6 +19,7 @@ import static com.google.common.testing.SerializableTester.reserializeAndAssert; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; import com.google.cloud.ByteArray; import com.google.cloud.Date; @@ -33,9 +34,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -43,7 +42,6 @@ @RunWith(JUnit4.class) public class ValueTest { private static final String NULL_STRING = "NULL"; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static ByteArray newByteArray(String data) { return ByteArray.copyFrom(data); @@ -85,10 +83,12 @@ public void boolWrapperNull() { assertThat(v.getType()).isEqualTo(Type.bool()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getBool(); + try { + v.getBool(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertThat(ex.getMessage()).contains("null value"); + } } @Test @@ -103,28 +103,34 @@ public void int64() { @Test public void int64TryGetBool() { Value value = Value.int64(1234); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: BOOL actual: INT64"); - value.getBool(); + try { + value.getBool(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Expected: BOOL actual: INT64"); + } } @Test public void int64NullTryGetBool() { Value value = Value.int64(null); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: BOOL actual: INT64"); - value.getBool(); + try { + value.getBool(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Expected: BOOL actual: INT64"); + } } @Test public void int64TryGetInt64Array() { Value value = Value.int64(1234); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: ARRAY actual: INT64"); - value.getInt64Array(); + try { + value.getInt64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Expected: ARRAY actual: INT64"); + } } @Test @@ -142,10 +148,12 @@ public void int64WrapperNull() { assertThat(v.getType()).isEqualTo(Type.int64()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getInt64(); + try { + v.getInt64(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("null value"); + } } @Test @@ -172,10 +180,12 @@ public void float64WrapperNull() { assertThat(v.getType()).isEqualTo(Type.float64()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getFloat64(); + try { + v.getFloat64(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("null value"); + } } @Test @@ -192,10 +202,12 @@ public void stringNull() { assertThat(v.getType()).isEqualTo(Type.string()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getString(); + try { + v.getString(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -232,10 +244,12 @@ public void bytesNull() { assertThat(v.getType()).isEqualTo(Type.bytes()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getBytes(); + try { + v.getBytes(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -257,9 +271,12 @@ public void timestampNull() { assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); assertThat(v.isCommitTimestamp()).isFalse(); - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getTimestamp(); + try { + v.getTimestamp(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -274,9 +291,12 @@ public void commitTimestamp() { com.google.protobuf.Value.newBuilder() .setStringValue("spanner.commit_timestamp()") .build()); - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Commit timestamp value"); - v.getTimestamp(); + try { + v.getTimestamp(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Commit timestamp value")); + } } @Test @@ -296,10 +316,12 @@ public void dateNull() { assertThat(v.getType()).isEqualTo(Type.date()); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getDate(); + try { + v.getDate(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -323,10 +345,12 @@ public void boolArrayNull() { Value v = Value.boolArray((boolean[]) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getBoolArray(); + try { + v.getBoolArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -342,10 +366,12 @@ public void boolArrayFromListNull() { Value v = Value.boolArray((Iterable) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getBoolArray(); + try { + v.getBoolArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -368,10 +394,12 @@ public void boolArrayFromPlainIterable() { @Test public void boolArrayTryGetInt64Array() { Value value = Value.boolArray(Arrays.asList(true)); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: ARRAY actual: ARRAY"); - value.getInt64Array(); + try { + value.getInt64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: ARRAY actual: ARRAY")); + } } @Test @@ -395,10 +423,12 @@ public void int64ArrayNull() { Value v = Value.int64Array((long[]) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getInt64Array(); + try { + v.getInt64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -414,28 +444,34 @@ public void int64ArrayWrapperNull() { Value v = Value.int64Array((Iterable) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getInt64Array(); + try { + v.getInt64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test public void int64ArrayTryGetBool() { Value value = Value.int64Array(Arrays.asList(1234L)); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: BOOL actual: ARRAY"); - value.getBool(); + try { + value.getBool(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: BOOL actual: ARRAY")); + } } @Test public void int64ArrayNullTryGetBool() { Value value = Value.int64Array((Iterable) null); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: BOOL actual: ARRAY"); - value.getBool(); + try { + value.getBool(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: BOOL actual: ARRAY")); + } } @Test @@ -459,10 +495,12 @@ public void float64ArrayNull() { Value v = Value.float64Array((double[]) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getFloat64Array(); + try { + v.getFloat64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -478,19 +516,23 @@ public void float64ArrayWrapperNull() { Value v = Value.float64Array((Iterable) null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getFloat64Array(); + try { + v.getFloat64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test public void float64ArrayTryGetInt64Array() { Value value = Value.float64Array(Arrays.asList(.1)); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: ARRAY actual: ARRAY"); - value.getInt64Array(); + try { + value.getInt64Array(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: ARRAY actual: ARRAY")); + } } @Test @@ -506,19 +548,23 @@ public void stringArrayNull() { Value v = Value.stringArray(null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getStringArray(); + try { + v.getStringArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test public void stringArrayTryGetBytesArray() { Value value = Value.stringArray(Arrays.asList("a")); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: ARRAY actual: ARRAY"); - value.getBytesArray(); + try { + value.getBytesArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: ARRAY actual: ARRAY")); + } } @Test @@ -536,19 +582,23 @@ public void bytesArrayNull() { Value v = Value.bytesArray(null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getBytesArray(); + try { + v.getBytesArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test public void bytesArrayTryGetStringArray() { Value value = Value.bytesArray(Arrays.asList(newByteArray("a"))); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Expected: ARRAY actual: ARRAY"); - value.getStringArray(); + try { + value.getStringArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("Expected: ARRAY actual: ARRAY")); + } } @Test @@ -570,10 +620,12 @@ public void timestampArrayNull() { Value v = Value.timestampArray(null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getTimestampArray(); + try { + v.getTimestampArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -594,10 +646,12 @@ public void dateArrayNull() { Value v = Value.dateArray(null); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("null value"); - v.getDateArray(); + try { + v.getDateArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage().contains("null value")); + } } @Test @@ -611,10 +665,12 @@ public void struct() { Value v2 = Value.struct(struct.getType(), struct); assertThat(v2).isEqualTo(v1); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Mismatch between struct value and type."); - Value.struct(Type.struct(Arrays.asList(StructField.of("f3", Type.string()))), struct); + try { + Value.struct(Type.struct(Arrays.asList(StructField.of("f3", Type.string()))), struct); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage().contains("Mismatch between struct value and type.")); + } } @Test @@ -627,10 +683,12 @@ public void nullStruct() { assertThat(v.getType().getStructFields()).isEqualTo(fieldTypes); assertThat(v.isNull()).isTrue(); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("Illegal call to create a NULL struct value."); - Value.struct(null); + try { + Value.struct(null); + fail("Expected exception"); + } catch (NullPointerException e) { + assertThat(e.getMessage().contains("Illegal call to create a NULL struct value.")); + } } @Test @@ -641,10 +699,12 @@ public void nullStructGetter() { Value v = Value.struct(Type.struct(fieldTypes), null); assertThat(v.isNull()).isTrue(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Illegal call to getter of null value."); - v.getStruct(); + try { + v.getStruct(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Illegal call to getter of null value."); + } } @Test @@ -726,10 +786,12 @@ public void structArrayNull() { assertThat(v.isNull()).isTrue(); assertThat(v.getType().getArrayElementType()).isEqualTo(elementType); assertThat(v.toString()).isEqualTo(NULL_STRING); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Illegal call to getter of null value"); - v.getStructArray(); + try { + v.getStructArray(); + fail("Expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Illegal call to getter of null value"); + } } @Test @@ -744,10 +806,12 @@ public void structArrayInvalidType() { Arrays.asList( Struct.newBuilder().set("ff1").to("1").set("ff2").to(1).build(), Struct.newBuilder().set("ff1").to(2).set("ff2").to(3).build()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("must have type STRUCT"); - Value.structArray(elementType, arrayElements); + try { + Value.structArray(elementType, arrayElements); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("must have type STRUCT"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java index 50f576fe69..4f02fb9a36 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlBatchTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyListOf; import static org.mockito.Matchers.anyString; @@ -53,9 +54,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentMatcher; @@ -65,8 +64,6 @@ @RunWith(JUnit4.class) public class DdlBatchTest { - @Rule public ExpectedException exception = ExpectedException.none(); - private DdlClient createDefaultMockDdlClient() { return createDefaultMockDdlClient(false, 0L); } @@ -139,8 +136,12 @@ private DdlBatch createSubject(DdlClient ddlClient, DatabaseClient dbClient) { @Test public void testExecuteQuery() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.executeQuery(mock(ParsedStatement.class), AnalyzeMode.NONE); + try { + batch.executeQuery(mock(ParsedStatement.class), AnalyzeMode.NONE); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test @@ -165,38 +166,58 @@ public void testExecuteMetadataQuery() { @Test public void testExecuteUpdate() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.executeUpdate(mock(ParsedStatement.class)); + try { + batch.executeUpdate(mock(ParsedStatement.class)); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testGetCommitTimestamp() { DdlBatch batch = createSubject(); batch.runBatch(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.getCommitTimestamp(); + try { + batch.getCommitTimestamp(); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testGetReadTimestamp() { DdlBatch batch = createSubject(); batch.runBatch(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.getReadTimestamp(); + try { + batch.getReadTimestamp(); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testWrite() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.write(Mutation.newInsertBuilder("foo").build()); + try { + batch.write(Mutation.newInsertBuilder("foo").build()); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testWriteIterable() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.write(Arrays.asList(Mutation.newInsertBuilder("foo").build())); + try { + batch.write(Arrays.asList(Mutation.newInsertBuilder("foo").build())); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test @@ -471,22 +492,34 @@ public void run() { }, 100, TimeUnit.MILLISECONDS); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); - batch.runBatch(); + try { + batch.runBatch(); + fail("expected CANCELLED"); + } catch (SpannerException e) { + assertEquals(ErrorCode.CANCELLED, e.getErrorCode()); + } } @Test public void testCommit() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.commit(); + try { + batch.commit(); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testRollback() { DdlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.rollback(); + try { + batch.rollback(); + fail("expected FAILED_PRECONDITION"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DmlBatchTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DmlBatchTest.java index 2ef5709341..e841601db7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DmlBatchTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DmlBatchTest.java @@ -18,6 +18,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Matchers.anyListOf; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -31,21 +33,18 @@ import com.google.cloud.spanner.connection.StatementParser.StatementType; import com.google.cloud.spanner.connection.UnitOfWork.UnitOfWorkState; import java.util.Arrays; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class DmlBatchTest { + private final ParsedStatement statement1 = StatementParser.INSTANCE.parse(Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=2")); private final ParsedStatement statement2 = StatementParser.INSTANCE.parse(Statement.of("UPDATE FOO SET BAR=2 WHERE BAZ=3")); - @Rule public ExpectedException exception = ExpectedException.none(); - private DmlBatch createSubject() { UnitOfWork transaction = mock(UnitOfWork.class); when(transaction.executeBatchUpdate(Arrays.asList(statement1, statement2))) @@ -63,23 +62,35 @@ private DmlBatch createSubject(UnitOfWork transaction) { @Test public void testExecuteQuery() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.executeQuery(mock(ParsedStatement.class), AnalyzeMode.NONE); + try { + batch.executeQuery(mock(ParsedStatement.class), AnalyzeMode.NONE); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testExecuteDdl() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.executeDdl(mock(ParsedStatement.class)); + try { + batch.executeDdl(mock(ParsedStatement.class)); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testGetReadTimestamp() { DmlBatch batch = createSubject(); batch.runBatch(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.getReadTimestamp(); + try { + batch.getReadTimestamp(); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test @@ -92,22 +103,34 @@ public void testIsReadOnly() { public void testGetCommitTimestamp() { DmlBatch batch = createSubject(); batch.runBatch(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.getCommitTimestamp(); + try { + batch.getCommitTimestamp(); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testWrite() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.write(Mutation.newInsertBuilder("foo").build()); + try { + batch.write(Mutation.newInsertBuilder("foo").build()); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testWriteIterable() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.write(Arrays.asList(Mutation.newInsertBuilder("foo").build())); + try { + batch.write(Arrays.asList(Mutation.newInsertBuilder("foo").build())); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test @@ -150,14 +173,22 @@ public void testGetStateAndIsActive() { @Test public void testCommit() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.commit(); + try { + batch.commit(); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } @Test public void testRollback() { DmlBatch batch = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - batch.rollback(); + try { + batch.rollback(); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java index 3fb0e3a04d..aac55bd9f8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java @@ -21,6 +21,8 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -46,15 +48,12 @@ import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class ReadOnlyTransactionTest { - @Rule public ExpectedException exception = ExpectedException.none(); private static final class SimpleReadOnlyTransaction implements com.google.cloud.spanner.ReadOnlyTransaction { @@ -153,44 +152,68 @@ private ReadOnlyTransaction createSubject(TimestampBound staleness) { public void testExecuteDdl() { ParsedStatement ddl = mock(ParsedStatement.class); when(ddl.getType()).thenReturn(StatementType.DDL); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - createSubject().executeDdl(ddl); + try { + createSubject().executeDdl(ddl); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testExecuteUpdate() { ParsedStatement update = mock(ParsedStatement.class); when(update.getType()).thenReturn(StatementType.UPDATE); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - createSubject().executeUpdate(update); + try { + createSubject().executeUpdate(update); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testWrite() { Mutation mutation = Mutation.newInsertBuilder("foo").build(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - createSubject().write(mutation); + try { + createSubject().write(mutation); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testWriteIterable() { Mutation mutation = Mutation.newInsertBuilder("foo").build(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - createSubject().write(Arrays.asList(mutation, mutation)); + try { + createSubject().write(Arrays.asList(mutation, mutation)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testRunBatch() { ReadOnlyTransaction subject = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.runBatch(); + try { + subject.runBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testAbortBatch() { ReadOnlyTransaction subject = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.abortBatch(); + try { + subject.abortBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test @@ -198,8 +221,12 @@ public void testGetCommitTimestamp() { ReadOnlyTransaction transaction = createSubject(); transaction.commit(); assertThat(transaction.getState(), is(UnitOfWorkState.COMMITTED)); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - transaction.getCommitTimestamp(); + try { + transaction.getCommitTimestamp(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java index d244f1d46a..f9a1e7afab 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java @@ -22,6 +22,8 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -49,9 +51,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.concurrent.ExecutionException; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.invocation.InvocationOnMock; @@ -60,8 +60,6 @@ @RunWith(JUnit4.class) public class ReadWriteTransactionTest { - @Rule public final ExpectedException exception = ExpectedException.none(); - private enum CommitBehavior { SUCCEED, FAIL, @@ -173,22 +171,34 @@ public void testExecuteDdl() { when(statement.getType()).thenReturn(StatementType.DDL); ReadWriteTransaction transaction = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - transaction.executeDdl(statement); + try { + transaction.executeDdl(statement); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testRunBatch() { ReadWriteTransaction subject = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.runBatch(); + try { + subject.runBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testAbortBatch() { ReadWriteTransaction subject = createSubject(); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.abortBatch(); + try { + subject.abortBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test @@ -261,9 +271,12 @@ public void testGetCommitTimestampBeforeCommit() { ReadWriteTransaction transaction = createSubject(); assertThat(transaction.executeUpdate(parsedStatement), is(1L)); - - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - transaction.getCommitTimestamp(); + try { + transaction.getCommitTimestamp(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test @@ -291,9 +304,12 @@ public void testGetReadTimestamp() { ReadWriteTransaction transaction = createSubject(); assertThat(transaction.executeQuery(parsedStatement, AnalyzeMode.NONE), is(notNullValue())); - - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - transaction.getReadTimestamp(); + try { + transaction.getReadTimestamp(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java index f641a51ed4..c28d3b75b9 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementResultImplTest.java @@ -20,37 +20,45 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import com.google.cloud.Timestamp; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType; import com.google.cloud.spanner.connection.StatementResult.ResultType; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class StatementResultImplTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Test public void testNoResultGetResultSet() { StatementResult subject = StatementResultImpl.noResult(); assertThat(subject.getResultType(), is(equalTo(ResultType.NO_RESULT))); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.getResultSet(); + try { + subject.getResultSet(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testNoResultGetUpdateCount() { StatementResult subject = StatementResultImpl.noResult(); assertThat(subject.getResultType(), is(equalTo(ResultType.NO_RESULT))); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.getUpdateCount(); + try { + subject.getUpdateCount(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test @@ -64,16 +72,24 @@ public void testResultSetGetResultSet() { public void testResultSetGetUpdateCount() { StatementResult subject = StatementResultImpl.of(mock(ResultSet.class)); assertThat(subject.getResultType(), is(equalTo(ResultType.RESULT_SET))); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.getUpdateCount(); + try { + subject.getUpdateCount(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test public void testUpdateCountGetResultSet() { StatementResult subject = StatementResultImpl.of(1L); assertThat(subject.getResultType(), is(equalTo(ResultType.UPDATE_COUNT))); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - subject.getResultSet(); + try { + subject.getResultSet(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java index d44dc7086d..ae52779912 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java @@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyListOf; import static org.mockito.Mockito.doAnswer; @@ -51,9 +53,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Matchers; @@ -62,6 +62,7 @@ @RunWith(JUnit4.class) public class StatementTimeoutTest { + private static final String URI = "cloudspanner:/projects/test-project-123/instances/test-instance/databases/test-database"; private static final String SLOW_SELECT = "SELECT foo FROM bar"; @@ -100,8 +101,6 @@ private enum CommitRollbackBehavior { SLOW_ROLLBACK; } - @Rule public ExpectedException expected = ExpectedException.none(); - private static final class DelayedQueryExecution implements Answer { @Override public ResultSet answer(InvocationOnMock invocation) throws Throwable { @@ -273,8 +272,12 @@ public void testTimeoutExceptionReadOnlyAutocommit() { .build())) { connection.setReadOnly(true); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -315,8 +318,12 @@ public void testTimeoutExceptionReadOnlyTransactional() { connection.setReadOnly(true); connection.setAutocommit(false); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -359,8 +366,12 @@ public void testTimeoutExceptionReadWriteAutocommit() { .setUri(URI) .build())) { connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -398,8 +409,12 @@ public void testTimeoutExceptionReadWriteAutocommitSlowUpdate() { .setUri(URI) .build())) { connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.execute(Statement.of(SLOW_UPDATE)); + try { + connection.execute(Statement.of(SLOW_UPDATE)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -449,8 +464,12 @@ public void testTimeoutExceptionReadWriteAutocommitSlowCommit() { // gRPC call will be slow. connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); connection.setAutocommit(true); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.execute(Statement.of(FAST_UPDATE)); + try { + connection.execute(Statement.of(FAST_UPDATE)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -494,8 +513,12 @@ public void testTimeoutExceptionReadWriteAutocommitPartitioned() { connection.execute(Statement.of(FAST_UPDATE)); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.execute(Statement.of(SLOW_UPDATE)); + try { + connection.execute(Statement.of(SLOW_UPDATE)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -509,8 +532,12 @@ public void testTimeoutExceptionReadWriteTransactional() { .build())) { connection.setAutocommit(false); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -564,8 +591,12 @@ public void testTimeoutExceptionReadWriteTransactionalSlowCommit() { connection.executeQuery(Statement.of(FAST_SELECT)); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.commit(); + try { + connection.commit(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -583,8 +614,12 @@ public void testTimeoutExceptionReadWriteTransactionalSlowRollback() { connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS); connection.executeQuery(Statement.of(FAST_SELECT)); connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); - connection.rollback(); + try { + connection.rollback(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } @@ -683,9 +718,12 @@ public void testInvalidQueryReadOnlyAutocommit() { .build())) { connection.setReadOnly(true); connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.INVALID_ARGUMENT)); - connection.executeQuery(Statement.of(INVALID_SELECT)); + try { + connection.executeQuery(Statement.of(INVALID_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode()); + } } } @@ -700,9 +738,12 @@ public void testInvalidQueryReadOnlyTransactional() { connection.setReadOnly(true); connection.setAutocommit(false); connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.INVALID_ARGUMENT)); - connection.executeQuery(Statement.of(INVALID_SELECT)); + try { + connection.executeQuery(Statement.of(INVALID_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode()); + } } } @@ -715,9 +756,12 @@ public void testInvalidQueryReadWriteAutocommit() { .setUri(URI) .build())) { connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.INVALID_ARGUMENT)); - connection.executeQuery(Statement.of(INVALID_SELECT)); + try { + connection.executeQuery(Statement.of(INVALID_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode()); + } } } @@ -731,9 +775,12 @@ public void testInvalidQueryReadWriteTransactional() { .build())) { connection.setAutocommit(false); connection.setStatementTimeout(TIMEOUT_FOR_FAST_STATEMENTS, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.INVALID_ARGUMENT)); - connection.executeQuery(Statement.of(INVALID_SELECT)); + try { + connection.executeQuery(Statement.of(INVALID_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.INVALID_ARGUMENT, ex.getErrorCode()); + } } } @@ -756,9 +803,12 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); + } } } @@ -816,9 +866,12 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); + } } } @@ -878,9 +931,12 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); - connection.executeQuery(Statement.of(SLOW_SELECT)); + try { + connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); + } } } @@ -935,9 +991,12 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); - connection.execute(Statement.of(SLOW_UPDATE)); + try { + connection.execute(Statement.of(SLOW_UPDATE)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); + } } } @@ -960,9 +1019,10 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); connection.execute(Statement.of(FAST_UPDATE)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); } } @@ -986,8 +1046,10 @@ public void run() { WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); } } @@ -1014,6 +1076,7 @@ public void run() { boolean cancelled = false; try { connection.executeQuery(Statement.of(SLOW_SELECT)); + fail("Expected exception"); } catch (SpannerException e) { cancelled = e.getErrorCode() == ErrorCode.CANCELLED; } @@ -1048,9 +1111,10 @@ public void run() { }, WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); connection.runBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); } } @@ -1073,8 +1137,10 @@ public void run() { WAIT_BEFORE_CANCEL, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.CANCELLED)); connection.execute(Statement.of(SLOW_DDL)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.CANCELLED, ex.getErrorCode()); } } @@ -1087,8 +1153,10 @@ public void testTimeoutExceptionDdlAutocommit() { .setUri(URI) .build())) { connection.setStatementTimeout(TIMEOUT_FOR_SLOW_STATEMENTS, TimeUnit.MILLISECONDS); - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); connection.execute(Statement.of(SLOW_DDL)); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } @@ -1133,8 +1201,10 @@ public void testTimeoutExceptionDdlBatch() { // the following statement will NOT timeout as the statement is only buffered locally connection.execute(Statement.of(SLOW_DDL)); // the commit sends the statement to the server and should timeout - expected.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); connection.runBatch(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java index a01d533dbd..358bbadcd7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java @@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Mutation; @@ -30,7 +32,6 @@ import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.connection.ITAbstractSpannerTest; -import com.google.cloud.spanner.connection.SpannerExceptionMatcher; import com.google.cloud.spanner.connection.SqlScriptVerifier; import java.math.BigInteger; import java.util.concurrent.ExecutorService; @@ -38,10 +39,8 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -55,8 +54,6 @@ public class ITReadOnlySpannerTest extends ITAbstractSpannerTest { private static final Logger logger = Logger.getLogger(ITReadOnlySpannerTest.class.getName()); private static final long TEST_ROWS_COUNT = 1000L; - @Rule public ExpectedException exception = ExpectedException.none(); - @Override protected void appendConnectionUri(StringBuilder url) { url.append(";readOnly=true"); @@ -112,13 +109,16 @@ public void testStatementTimeoutTransactional() throws Exception { try (ITConnection connection = createConnection()) { connection.beginTransaction(); connection.setStatementTimeout(1L, TimeUnit.MILLISECONDS); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); try (ResultSet rs = connection.executeQuery( Statement.of( - "SELECT (SELECT COUNT(*) FROM PRIME_NUMBERS)/(SELECT COUNT(*) FROM NUMBERS) AS PRIME_NUMBER_RATIO"))) {} + "SELECT (SELECT COUNT(*) FROM PRIME_NUMBERS)/(SELECT COUNT(*) FROM NUMBERS) AS PRIME_NUMBER_RATIO"))) { + fail("Expected exception"); + } // should never be reached connection.commit(); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); } } @@ -155,11 +155,14 @@ public void testStatementTimeoutAutocommit() throws Exception { try (ITConnection connection = createConnection()) { assertThat(connection.isAutocommit(), is(true)); connection.setStatementTimeout(1L, TimeUnit.MILLISECONDS); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.DEADLINE_EXCEEDED)); try (ResultSet rs = connection.executeQuery( Statement.of( - "SELECT (SELECT COUNT(*) FROM PRIME_NUMBERS)/(SELECT COUNT(*) FROM NUMBERS) AS PRIME_NUMBER_RATIO"))) {} + "SELECT (SELECT COUNT(*) FROM PRIME_NUMBERS)/(SELECT COUNT(*) FROM NUMBERS) AS PRIME_NUMBER_RATIO"))) { + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java index bb0b9fb28f..8870afdd95 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java @@ -34,10 +34,8 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.junit.FixMethodOrder; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.junit.runners.MethodSorters; @@ -47,8 +45,6 @@ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ITReadWriteAutocommitSpannerTest extends ITAbstractSpannerTest { - @Rule public ExpectedException exception = ExpectedException.none(); - @Override protected void appendConnectionUri(StringBuilder uri) { uri.append(";autocommit=true"); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java index 07deb7deca..681690e50d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java @@ -19,29 +19,27 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Key; import com.google.cloud.spanner.Mutation; import com.google.cloud.spanner.ParallelIntegrationTest; import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.connection.ITAbstractSpannerTest; -import com.google.cloud.spanner.connection.SpannerExceptionMatcher; import com.google.cloud.spanner.connection.SqlScriptVerifier; import java.util.Arrays; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITTransactionModeTest extends ITAbstractSpannerTest { - @Rule public ExpectedException exception = ExpectedException.none(); - @Override public void appendConnectionUri(StringBuilder uri) { uri.append("?autocommit=false"); @@ -142,8 +140,12 @@ public void testDoNotAllowBufferedWriteInReadOnlyTransaction() { try (ITConnection connection = createConnection()) { connection.execute(Statement.of("SET TRANSACTION READ ONLY")); assertThat(connection.isAutocommit(), is(false)); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - connection.bufferedWrite(Mutation.newInsertBuilder("FOO").set("ID").to(1L).build()); + try { + connection.bufferedWrite(Mutation.newInsertBuilder("FOO").set("ID").to(1L).build()); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } } @@ -152,11 +154,15 @@ public void testDoNotAllowBufferedWriteIterableInReadOnlyTransaction() { try (ITConnection connection = createConnection()) { connection.execute(Statement.of("SET TRANSACTION READ ONLY")); assertThat(connection.isAutocommit(), is(false)); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - connection.bufferedWrite( - Arrays.asList( - Mutation.newInsertBuilder("FOO").set("ID").to(1L).build(), - Mutation.newInsertBuilder("FOO").set("ID").to(2L).build())); + try { + connection.bufferedWrite( + Arrays.asList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).build(), + Mutation.newInsertBuilder("FOO").set("ID").to(2L).build())); + fail("Expected exception"); + } catch (SpannerException ex) { + assertEquals(ErrorCode.FAILED_PRECONDITION, ex.getErrorCode()); + } } } @@ -166,8 +172,12 @@ public void testDoNotAllowBufferedWriteInDdlBatch() { connection.startBatchDdl(); assertThat(connection.isAutocommit(), is(false)); assertThat(connection.isDdlBatchActive(), is(true)); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - connection.bufferedWrite(Mutation.newInsertBuilder("FOO").set("ID").to(1L).build()); + try { + connection.bufferedWrite(Mutation.newInsertBuilder("FOO").set("ID").to(1L).build()); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } } @@ -177,11 +187,15 @@ public void testDoNotAllowBufferedWriteIterableInDdlBatch() { connection.startBatchDdl(); assertThat(connection.isAutocommit(), is(false)); assertThat(connection.isDdlBatchActive(), is(true)); - exception.expect(SpannerExceptionMatcher.matchCode(ErrorCode.FAILED_PRECONDITION)); - connection.bufferedWrite( - Arrays.asList( - Mutation.newInsertBuilder("FOO").set("ID").to(1L).build(), - Mutation.newInsertBuilder("FOO").set("ID").to(2L).build())); + try { + connection.bufferedWrite( + Arrays.asList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).build(), + Mutation.newInsertBuilder("FOO").set("ID").to(2L).build())); + fail("Expected exception"); + } catch (SpannerException e) { + assertEquals(ErrorCode.FAILED_PRECONDITION, e.getErrorCode()); + } } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java index c4cb3e032a..cb954006db 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java @@ -66,10 +66,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -84,7 +82,6 @@ public class ITBackupTest { private static final String EXPECTED_OP_NAME_FORMAT = "%s/backups/%s/operations/"; @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - @Rule public ExpectedException expectedException = ExpectedException.none(); private DatabaseAdminClient dbAdminClient; private InstanceAdminClient instanceAdminClient; private Instance instance; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java index 40913f9f2d..c249859f83 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java @@ -17,6 +17,8 @@ package com.google.cloud.spanner.it; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import com.google.cloud.spanner.AbortedException; @@ -37,10 +39,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -57,7 +57,6 @@ public class ITClosedSessionTest { new IntegrationTestWithClosedSessionsEnv(); private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static DatabaseClientWithClosedSessionImpl client; @BeforeClass @@ -94,9 +93,11 @@ public void testSingleUseNoRecreation() { // This should trigger an exception with code NOT_FOUND and the text 'Session not found'. client.setAllowSessionReplacing(false); client.invalidateNextSession(); - expectedException.expect(SessionNotFoundException.class); try (ResultSet rs = Statement.of("SELECT 1").executeQuery(client.singleUse())) { rs.next(); + fail("Expected exception"); + } catch (SessionNotFoundException ex) { + assertNotNull(ex.getMessage()); } } @@ -169,11 +170,14 @@ public void testReadOnlyTransaction() { public void testReadOnlyTransactionNoRecreation() { client.setAllowSessionReplacing(false); client.invalidateNextSession(); - expectedException.expect(SessionNotFoundException.class); try (ReadOnlyTransaction txn = client.readOnlyTransaction()) { try (ResultSet rs = txn.executeQuery(Statement.of("SELECT 1"))) { rs.next(); + fail("Expected exception"); } + fail("Expected exception"); + } catch (SessionNotFoundException ex) { + assertNotNull(ex.getMessage()); } } @@ -221,18 +225,23 @@ public Void run(TransactionContext transaction) throws Exception { public void testReadWriteTransactionNoRecreation() { client.setAllowSessionReplacing(false); client.invalidateNextSession(); - expectedException.expect(SessionNotFoundException.class); - TransactionRunner txn = client.readWriteTransaction(); - txn.run( - new TransactionCallable() { - @Override - public Void run(TransactionContext transaction) throws Exception { - try (ResultSet rs = transaction.executeQuery(Statement.of("SELECT 1"))) { - rs.next(); + try { + TransactionRunner txn = client.readWriteTransaction(); + txn.run( + new TransactionCallable() { + @Override + public Void run(TransactionContext transaction) throws Exception { + try (ResultSet rs = transaction.executeQuery(Statement.of("SELECT 1"))) { + rs.next(); + fail("Expected exception"); + } + return null; } - return null; - } - }); + }); + fail("Expected exception"); + } catch (SessionNotFoundException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -265,14 +274,16 @@ public void testTransactionManager() throws InterruptedException { public void testTransactionManagerNoRecreation() throws InterruptedException { client.setAllowSessionReplacing(false); client.invalidateNextSession(); - expectedException.expect(SessionNotFoundException.class); try (TransactionManager manager = client.transactionManager()) { TransactionContext txn = manager.begin(); while (true) { try (ResultSet rs = txn.executeQuery(Statement.of("SELECT 1"))) { rs.next(); + fail("Expected exception"); } } + } catch (SessionNotFoundException ex) { + assertNotNull(ex.getMessage()); } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java index 39260122ea..14421c86b4 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java @@ -16,8 +16,8 @@ package com.google.cloud.spanner.it; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import com.google.api.gax.grpc.GrpcInterceptorProvider; @@ -45,7 +45,6 @@ import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.ClientCall; -import io.grpc.ClientCall.Listener; import io.grpc.ClientInterceptor; import io.grpc.ForwardingClientCall.SimpleForwardingClientCall; import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener; @@ -63,10 +62,8 @@ import org.junit.After; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -75,7 +72,6 @@ @RunWith(JUnit4.class) public class ITDatabaseAdminTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - @Rule public ExpectedException expectedException = ExpectedException.none(); private DatabaseAdminClient dbAdminClient; private RemoteSpannerHelper testHelper; private List dbs = new ArrayList<>(); @@ -128,8 +124,12 @@ public void databaseOperations() throws Exception { dbAdminClient.dropDatabase(instanceId, dbId); dbs.clear(); - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - db = dbAdminClient.getDatabase(testHelper.getInstanceId().getInstance(), dbId); + try { + db = dbAdminClient.getDatabase(testHelper.getInstanceId().getInstance(), dbId); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test @@ -170,11 +170,14 @@ public void databaseOperationsViaEntity() throws Exception { op2.get(); Iterable statementsInDb = db.getDdl(); assertThat(statementsInDb).containsExactly(statement1, statement2); - db.drop(); dbs.clear(); - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - db.reload(); + try { + db.reload(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java index af1193f298..fda120bff6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java @@ -16,7 +16,6 @@ package com.google.cloud.spanner.it; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; @@ -33,14 +32,13 @@ import com.google.cloud.spanner.IntegrationTestEnv; import com.google.cloud.spanner.ParallelIntegrationTest; import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import java.util.Collections; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -49,14 +47,16 @@ @RunWith(JUnit4.class) public class ITDatabaseTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void badDdl() { - expectedException.expect(isSpannerException(ErrorCode.INVALID_ARGUMENT)); - expectedException.expectMessage("Syntax error on line 1"); - - env.getTestHelper().createTestDatabase("CREATE TABLE T ( Illegal Way To Define A Table )"); + try { + env.getTestHelper().createTestDatabase("CREATE TABLE T ( Illegal Way To Define A Table )"); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(ex.getMessage()).contains("Syntax error on line 1"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java index 5b9e3a06a9..a3d35ee6c1 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java @@ -34,10 +34,8 @@ import java.util.Random; import org.junit.Before; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -46,7 +44,6 @@ @RunWith(JUnit4.class) public class ITInstanceAdminTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - @Rule public ExpectedException expectedException = ExpectedException.none(); InstanceAdminClient instanceClient; @Before diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java index c60e2ae889..71c7bcd47c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java @@ -34,10 +34,8 @@ import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -46,7 +44,6 @@ public class ITQueryOptionsTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static DatabaseClient client; @BeforeClass diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java index 07e520c8c0..b54984362d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java @@ -16,10 +16,10 @@ package com.google.cloud.spanner.it; -import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.cloud.spanner.Type.StructField; import static com.google.common.truth.Truth.assertThat; import static java.util.Arrays.asList; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import com.google.cloud.ByteArray; @@ -33,6 +33,7 @@ import com.google.cloud.spanner.ParallelIntegrationTest; import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode; import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TimestampBound; @@ -47,10 +48,8 @@ import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -60,7 +59,6 @@ public class ITQueryTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static DatabaseClient client; @BeforeClass @@ -78,9 +76,13 @@ public void simple() { @Test public void badQuery() { - expectedException.expect(isSpannerException(ErrorCode.INVALID_ARGUMENT)); - expectedException.expectMessage("Unrecognized name: Apples"); - execute(Statement.of("SELECT Apples AND Oranges"), Type.int64()); + try { + execute(Statement.of("SELECT Apples AND Oranges"), Type.int64()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(ex.getMessage()).contains("Unrecognized name: Apples"); + } } @Test @@ -494,12 +496,16 @@ public void bindDateArrayNull() { @Test public void unsupportedSelectStructValue() { assumeFalse("The emulator accepts this query", env.getTestHelper().isEmulator()); - Struct p = structValue(); - expectedException.expect(isSpannerException(ErrorCode.UNIMPLEMENTED)); - expectedException.expectMessage( - "Unsupported query shape: " + "A struct value cannot be returned as a column value."); - execute(Statement.newBuilder("SELECT @p").bind("p").to(p).build(), p.getType()); + try { + execute(Statement.newBuilder("SELECT @p").bind("p").to(p).build(), p.getType()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.UNIMPLEMENTED); + assertThat(ex.getMessage()) + .contains( + "Unsupported query shape: A struct value cannot be returned as a column value."); + } } @Test @@ -509,23 +515,31 @@ public void unsupportedSelectArrayStructValue() { env.getTestHelper().isEmulator()); Struct p = structValue(); - expectedException.expect(isSpannerException(ErrorCode.UNIMPLEMENTED)); - expectedException.expectMessage( - "Unsupported query shape: " - + "This query can return a null-valued array of struct, " - + "which is not supported by Spanner."); - execute( - Statement.newBuilder("SELECT @p").bind("p").toStructArray(p.getType(), asList(p)).build(), - p.getType()); + try { + execute( + Statement.newBuilder("SELECT @p").bind("p").toStructArray(p.getType(), asList(p)).build(), + p.getType()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.UNIMPLEMENTED); + assertThat(ex.getMessage()) + .contains( + "Unsupported query shape: " + + "This query can return a null-valued array of struct, " + + "which is not supported by Spanner."); + } } @Test public void invalidAmbiguousFieldAccess() { Struct p = Struct.newBuilder().set("f1").to(20).set("f1").to("abc").build(); - - expectedException.expect(isSpannerException(ErrorCode.INVALID_ARGUMENT)); - expectedException.expectMessage("Struct field name f1 is ambiguous"); - execute(Statement.newBuilder("SELECT @p.f1").bind("p").to(p).build(), Type.int64()); + try { + execute(Statement.newBuilder("SELECT @p.f1").bind("p").to(p).build(), Type.int64()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(ex.getMessage()).contains("Struct field name f1 is ambiguous"); + } } private Struct structValue() { @@ -720,8 +734,12 @@ public void bindStructWithArrayOfStructField() { public void unboundParameter() { ResultSet resultSet = Statement.of("SELECT @v").executeQuery(client.singleUse(TimestampBound.strong())); - expectedException.expect(isSpannerException(ErrorCode.INVALID_ARGUMENT)); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + } } @Test @@ -766,9 +784,13 @@ public void largeErrorText() { .to("(" + veryLongString) .build(); ResultSet resultSet = statement.executeQuery(client.singleUse(TimestampBound.strong())); - expectedException.expect(isSpannerException(ErrorCode.OUT_OF_RANGE)); - expectedException.expectMessage("Cannot parse regular expression"); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.OUT_OF_RANGE); + assertThat(ex.getMessage()).contains("Cannot parse regular expression"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java index e6e473779d..a52a108151 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java @@ -17,6 +17,8 @@ package com.google.cloud.spanner.it; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import com.google.cloud.Timestamp; import com.google.cloud.spanner.Database; @@ -41,10 +43,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -62,7 +62,6 @@ public class ITReadOnlyTxnTest { private static final String TABLE_NAME = "TestTable"; private static DatabaseClient sharedClient; private static List sharedHistory; - @Rule public ExpectedException expectedException = ExpectedException.none(); private List history; private DatabaseClient client; @@ -311,8 +310,12 @@ public void multiReadTimestamp() { @Test public void multiMinReadTimestamp() { // Cannot use bounded modes with multi-read transactions. - expectedException.expect(IllegalArgumentException.class); - client.readOnlyTransaction(TimestampBound.ofMinReadTimestamp(history.get(2).timestamp)); + try { + client.readOnlyTransaction(TimestampBound.ofMinReadTimestamp(history.get(2).timestamp)); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -338,7 +341,11 @@ public void multiExactStaleness() { @Test public void multiMaxStaleness() { // Cannot use bounded modes with multi-read transactions. - expectedException.expect(IllegalArgumentException.class); - client.readOnlyTransaction(TimestampBound.ofMaxStaleness(1, TimeUnit.SECONDS)); + try { + client.readOnlyTransaction(TimestampBound.ofMaxStaleness(1, TimeUnit.SECONDS)); + fail("Expected exception"); + } catch (IllegalArgumentException ex) { + assertNotNull(ex.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java index b06d3ae152..4682ddd1ec 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java @@ -20,6 +20,7 @@ import static com.google.cloud.spanner.Type.StructField; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; @@ -50,10 +51,8 @@ import org.hamcrest.MatcherAssert; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -76,7 +75,6 @@ public class ITReadTest { StructField.of("Key", Type.string()), StructField.of("StringValue", Type.string())); private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static DatabaseClient client; @BeforeClass @@ -292,26 +290,38 @@ public void invalidDatabase() { RemoteSpannerHelper helper = env.getTestHelper(); DatabaseClient invalidClient = helper.getClient().getDatabaseClient(DatabaseId.of(helper.getInstanceId(), "invalid")); - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - invalidClient - .singleUse(TimestampBound.strong()) - .readRow(TABLE_NAME, Key.of("k99"), ALL_COLUMNS); + try { + invalidClient + .singleUse(TimestampBound.strong()) + .readRow(TABLE_NAME, Key.of("k99"), ALL_COLUMNS); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test public void tableNotFound() { - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - expectedException.expectMessage("BadTableName"); - client.singleUse(TimestampBound.strong()).readRow("BadTableName", Key.of("k1"), ALL_COLUMNS); + try { + client.singleUse(TimestampBound.strong()).readRow("BadTableName", Key.of("k1"), ALL_COLUMNS); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(ex.getMessage()).contains("BadTableName"); + } } @Test public void columnNotFound() { - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - expectedException.expectMessage("BadColumnName"); - client - .singleUse(TimestampBound.strong()) - .readRow(TABLE_NAME, Key.of("k1"), Arrays.asList("Key", "BadColumnName")); + try { + client + .singleUse(TimestampBound.strong()) + .readRow(TABLE_NAME, Key.of("k1"), Arrays.asList("Key", "BadColumnName")); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(ex.getMessage()).contains("BadColumnName"); + } } @Test @@ -322,10 +332,13 @@ public void cursorErrorDeferred() { client .singleUse(TimestampBound.strong()) .read("BadTableName", KeySet.singleKey(Key.of("k1")), ALL_COLUMNS); - - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - expectedException.expectMessage("BadTableName"); - resultSet.next(); + try { + resultSet.next(); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(ex.getMessage()).contains("BadTableName"); + } } @Test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerTest.java index b9776363c4..281977af6a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerTest.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner.it; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; @@ -35,10 +36,8 @@ import java.util.Arrays; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -48,7 +47,6 @@ public class ITTransactionManagerTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static Database db; - @Rule public ExpectedException expectedException = ExpectedException.none(); private static DatabaseClient client; @BeforeClass @@ -115,8 +113,12 @@ public void invalidInsert() throws InterruptedException { } assertThat(manager.getState()).isEqualTo(TransactionState.COMMIT_FAILED); // We cannot retry for non aborted errors. - expectedException.expect(IllegalStateException.class); - manager.resetForRetry(); + try { + manager.resetForRetry(); + fail("Expected exception"); + } catch (IllegalStateException ex) { + assertNotNull(ex.getMessage()); + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java index b41a998c65..1f084d5fdb 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java @@ -18,6 +18,7 @@ import static com.google.cloud.spanner.SpannerMatchers.isSpannerException; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import com.google.cloud.ByteArray; @@ -49,10 +50,8 @@ import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -96,7 +95,6 @@ private static String uniqueString() { return String.format("k%04d", seq++); } - @Rule public ExpectedException expectedException = ExpectedException.none(); private String lastKey; private Timestamp write(Mutation m) { @@ -163,8 +161,12 @@ public void writeAlreadyExists() { @Ignore // TODO(user): Fix this - backend currently accepts empty mutation. @Test public void emptyWrite() { - expectedException.expect(isSpannerException(ErrorCode.INVALID_ARGUMENT)); - client.write(Arrays.asList()); + try { + client.write(Arrays.asList()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + } } @Test @@ -373,9 +375,12 @@ public void writeBoolArray() { Struct row = readLastRow("BoolArrayValue"); assertThat(row.isNull(0)).isFalse(); assertThat(row.getBooleanList(0)).containsExactly(true, null, false).inOrder(); - - expectedException.expect(NullPointerException.class); - row.getBooleanArray(0); + try { + row.getBooleanArray(0); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -407,9 +412,12 @@ public void writeInt64Array() { Struct row = readLastRow("Int64ArrayValue"); assertThat(row.isNull(0)).isFalse(); assertThat(row.getLongList(0)).containsExactly(1L, 2L, null).inOrder(); - - expectedException.expect(NullPointerException.class); - row.getLongArray(0); + try { + row.getLongArray(0); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -445,9 +453,12 @@ public void writeFloat64Array() { Struct row = readLastRow("Float64ArrayValue"); assertThat(row.isNull(0)).isFalse(); assertThat(row.getDoubleList(0)).containsExactly(null, 1.0, 2.0).inOrder(); - - expectedException.expect(NullPointerException.class); - row.getDoubleArray(0); + try { + row.getDoubleArray(0); + fail("Expected exception"); + } catch (NullPointerException ex) { + assertNotNull(ex.getMessage()); + } } @Test @@ -570,29 +581,39 @@ public void writeDateArray() { public void tableNotFound() { // TODO(user): More precise matchers! Customer code needs to discern table not found, column // not found, etc. - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - write( - Mutation.newInsertBuilder("TableThatDoesNotExist") - .set("K") - .to(uniqueString()) - .set("StringuniqueString(Value") - .to("V1") - .build()); + try { + write( + Mutation.newInsertBuilder("TableThatDoesNotExist") + .set("K") + .to(uniqueString()) + .set("StringuniqueString(Value") + .to("V1") + .build()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test public void columnNotFound() { - expectedException.expect(isSpannerException(ErrorCode.NOT_FOUND)); - write(baseInsert().set("ColumnThatDoesNotExist").to("V1").build()); + try { + write(baseInsert().set("ColumnThatDoesNotExist").to("V1").build()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } } @Test public void incorrectType() { - expectedException.expect(isSpannerException(ErrorCode.FAILED_PRECONDITION)); - // Attempt to set 'V' to INT64, not STRING. - // NOTE: an interest effect of not sending type metadata is that BYTES and INT64 are accepted - // here... - write(baseInsert().set("StringValue").to(1.234).build()); + try { + write(baseInsert().set("StringValue").to(1.234).build()); + fail("Expected exception"); + } catch (SpannerException ex) { + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); + assertThat(ex.getMessage()).contains("Expected STRING"); + } } @Test From 3427141217038a3d5e3d50c6a8a5343aaaa71daa Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 15 Jun 2020 22:34:53 +0200 Subject: [PATCH 07/55] build(deps): update dependency com.google.cloud:google-cloud-shared-config to v0.8.1 --- google-cloud-spanner-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index ccb065a4af..5f9af594d5 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -8,7 +8,7 @@ com.google.cloud google-cloud-shared-config - 0.8.0 + 0.8.1 Google Cloud Spanner BOM diff --git a/pom.xml b/pom.xml index 0e2274df67..dc998a7aa1 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ com.google.cloud google-cloud-shared-config - 0.8.0 + 0.8.1 From 6ec4c99a9eebe920c8d823bd5ce03668a0d36d32 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 16 Jun 2020 15:40:10 -0700 Subject: [PATCH 08/55] ci: switch to secret manager for sample/integration tests (#271) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/2c593734-539a-435d-8a04-27f04c90082f/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/c4f3059c27591eb24d6942a0e357ec94c80459f2 Source-Link: https://github.com/googleapis/synthtool/commit/6eb80fa9f96433af8dbeb1c8323aa80cda49b374 Source-Link: https://github.com/googleapis/synthtool/commit/6d3eed67a45fd58f9c7bfa173c32e4fd4fed058f Source-Link: https://github.com/googleapis/synthtool/commit/d1addcdf80aa9ddef8c932c89c919024bbad7af3 --- .kokoro/build.sh | 2 +- .kokoro/nightly/integration.cfg | 12 +++------ .kokoro/nightly/samples.cfg | 16 +++++------- .kokoro/populate-secrets.sh | 43 +++++++++++++++++++++++++++++++ .kokoro/presubmit/integration.cfg | 12 +++------ .kokoro/presubmit/samples.cfg | 14 ++++------ .kokoro/trampoline.sh | 2 ++ synth.metadata | 4 +-- 8 files changed, 67 insertions(+), 38 deletions(-) create mode 100755 .kokoro/populate-secrets.sh diff --git a/.kokoro/build.sh b/.kokoro/build.sh index f46042a8f0..112a2cce85 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -39,7 +39,7 @@ retry_with_backoff 3 10 \ # if GOOGLE_APPLICATION_CREDIENTIALS is specified as a relative path prepend Kokoro root directory onto it if [[ ! -z "${GOOGLE_APPLICATION_CREDENTIALS}" && "${GOOGLE_APPLICATION_CREDENTIALS}" != /* ]]; then - export GOOGLE_APPLICATION_CREDENTIALS=$(realpath ${KOKORO_ROOT}/src/${GOOGLE_APPLICATION_CREDENTIALS}) + export GOOGLE_APPLICATION_CREDENTIALS=$(realpath ${KOKORO_GFILE_DIR}/${GOOGLE_APPLICATION_CREDENTIALS}) fi RETURN_CODE=0 diff --git a/.kokoro/nightly/integration.cfg b/.kokoro/nightly/integration.cfg index 40c4abb7bf..0048c8ece7 100644 --- a/.kokoro/nightly/integration.cfg +++ b/.kokoro/nightly/integration.cfg @@ -28,14 +28,10 @@ env_vars: { env_vars: { key: "GOOGLE_APPLICATION_CREDENTIALS" - value: "keystore/73713_java_it_service_account" + value: "secret_manager/java-it-service-account" } -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "java_it_service_account" - } - } +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-it-service-account" } diff --git a/.kokoro/nightly/samples.cfg b/.kokoro/nightly/samples.cfg index 20aabd55de..f25429314f 100644 --- a/.kokoro/nightly/samples.cfg +++ b/.kokoro/nightly/samples.cfg @@ -24,19 +24,15 @@ env_vars: { env_vars: { key: "GOOGLE_APPLICATION_CREDENTIALS" - value: "keystore/73713_java_it_service_account" + value: "secret_manager/java-docs-samples-service-account" } env_vars: { - key: "ENABLE_BUILD_COP" - value: "true" + key: "SECRET_MANAGER_KEYS" + value: "java-docs-samples-service-account" } -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "java_it_service_account" - } - } +env_vars: { + key: "ENABLE_BUILD_COP" + value: "true" } diff --git a/.kokoro/populate-secrets.sh b/.kokoro/populate-secrets.sh new file mode 100755 index 0000000000..f52514257e --- /dev/null +++ b/.kokoro/populate-secrets.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2020 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} +function msg { println "$*" >&2 ;} +function println { printf '%s\n' "$(now) $*" ;} + + +# Populates requested secrets set in SECRET_MANAGER_KEYS from service account: +# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com +SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" +msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" +mkdir -p ${SECRET_LOCATION} +for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") +do + msg "Retrieving secret ${key}" + docker run --entrypoint=gcloud \ + --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ + gcr.io/google.com/cloudsdktool/cloud-sdk \ + secrets versions access latest \ + --project cloud-devrel-kokoro-resources \ + --secret ${key} > \ + "${SECRET_LOCATION}/${key}" + if [[ $? == 0 ]]; then + msg "Secret written to ${SECRET_LOCATION}/${key}" + else + msg "Error retrieving secret ${key}" + fi +done diff --git a/.kokoro/presubmit/integration.cfg b/.kokoro/presubmit/integration.cfg index 522e5b1010..dded67a9d5 100644 --- a/.kokoro/presubmit/integration.cfg +++ b/.kokoro/presubmit/integration.cfg @@ -24,14 +24,10 @@ env_vars: { env_vars: { key: "GOOGLE_APPLICATION_CREDENTIALS" - value: "keystore/73713_java_it_service_account" + value: "secret_manager/java-it-service-account" } -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "java_it_service_account" - } - } +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-it-service-account" } diff --git a/.kokoro/presubmit/samples.cfg b/.kokoro/presubmit/samples.cfg index 1171aead01..01e0960047 100644 --- a/.kokoro/presubmit/samples.cfg +++ b/.kokoro/presubmit/samples.cfg @@ -24,14 +24,10 @@ env_vars: { env_vars: { key: "GOOGLE_APPLICATION_CREDENTIALS" - value: "keystore/73713_java_it_service_account" + value: "secret_manager/java-docs-samples-service-account" } -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "java_it_service_account" - } - } -} +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-docs-samples-service-account" +} \ No newline at end of file diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh index ba17ce0146..9da0f83987 100644 --- a/.kokoro/trampoline.sh +++ b/.kokoro/trampoline.sh @@ -21,4 +21,6 @@ function cleanup() { echo "cleanup"; } trap cleanup EXIT + +$(dirname $0)/populate-secrets.sh # Secret Manager secrets. python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" diff --git a/synth.metadata b/synth.metadata index 6c1d47215c..d92ee33ca3 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "22ed45816098f5e50104935b66bc55297ea7f7b7" + "sha": "3427141217038a3d5e3d50c6a8a5343aaaa71daa" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "987270824bd26f6a8c716d5e2022057b8ae7b26e" + "sha": "c4f3059c27591eb24d6942a0e357ec94c80459f2" } } ], From b7bac19ad4d01152a15031c5ee49d2b7aecff829 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 17 Jun 2020 01:46:08 +0200 Subject: [PATCH 09/55] chore(deps): update dependency com.google.cloud:libraries-bom to v6 (#272) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:libraries-bom](https://togithub.com/GoogleCloudPlatform/cloud-opensource-java) | major | `5.7.0` -> `6.0.0` | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index a585cbae96..00dbc02dc2 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 5.7.0 + 6.0.0 pom import From 5a15f8e22913fb376eb9044e8a77b776cd8baf99 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 17 Jun 2020 19:42:37 +0200 Subject: [PATCH 10/55] chore(deps): update dependency com.google.cloud:libraries-bom to v7 (#275) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:libraries-bom](https://togithub.com/GoogleCloudPlatform/cloud-opensource-java) | major | `6.0.0` -> `7.0.0` | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 00dbc02dc2..cbb1d86790 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 6.0.0 + 7.0.0 pom import From caf75c44c95651c7038a2adbd3ee392950ca63f4 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2020 11:07:27 +1000 Subject: [PATCH 11/55] chore: release 1.56.0 (#259) * updated CHANGELOG.md [ci skip] * updated README.md [ci skip] * updated versions.txt [ci skip] * updated google-cloud-spanner/pom.xml [ci skip] * updated grpc-google-cloud-spanner-v1/pom.xml [ci skip] * updated samples/install-without-bom/pom.xml [ci skip] * updated samples/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-v1/pom.xml [ci skip] * updated samples/snapshot/pom.xml [ci skip] * updated google-cloud-spanner-bom/pom.xml [ci skip] * updated pom.xml [ci skip] * updated samples/snippets/pom.xml Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 22 +++++++++++++++++++ README.md | 4 ++-- google-cloud-spanner-bom/pom.xml | 18 +++++++-------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 +++++++------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 ++++++------ 13 files changed, 63 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa75531c6..48c54d6bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## [1.56.0](https://www.github.com/googleapis/java-spanner/compare/v1.55.1...v1.56.0) (2020-06-17) + + +### Features + +* add num_sessions_in_pool metric ([#128](https://www.github.com/googleapis/java-spanner/issues/128)) ([3a7a8ad](https://www.github.com/googleapis/java-spanner/commit/3a7a8ad79f1de3371d32a1298406990cb7bbf5be)) + + +### Bug Fixes + +* backend now supports optimizer version for DML ([#252](https://www.github.com/googleapis/java-spanner/issues/252)) ([24b986b](https://www.github.com/googleapis/java-spanner/commit/24b986b03a785f4c5ee978dcdc57f51687701e52)) +* include an explicit version for javax-annotations-api ([#261](https://www.github.com/googleapis/java-spanner/issues/261)) ([e256d22](https://www.github.com/googleapis/java-spanner/commit/e256d22f33d5f091ea90ed81c0b0f8600beae96c)) +* inconsistent json and yaml spanner configs ([#238](https://www.github.com/googleapis/java-spanner/issues/238)) ([627fdc1](https://www.github.com/googleapis/java-spanner/commit/627fdc13d64ab7b51934d4866ff753f7b08dabe4)) +* test allowed a too old staleness ([#214](https://www.github.com/googleapis/java-spanner/issues/214)) ([f4fa6bf](https://www.github.com/googleapis/java-spanner/commit/f4fa6bfca4bb821cbda426c4cb7bf32f091a2913)) +* use millis to prevent rounding errors ([#260](https://www.github.com/googleapis/java-spanner/issues/260)) ([22ed458](https://www.github.com/googleapis/java-spanner/commit/22ed45816098f5e50104935b66bc55297ea7f7b7)) + + +### Dependencies + +* include test-jar in bom ([#253](https://www.github.com/googleapis/java-spanner/issues/253)) ([4e86a37](https://www.github.com/googleapis/java-spanner/commit/4e86a374aacbcfc34d64809b7d9606f21176f6b9)) +* update dependency org.json:json to v20200518 ([#239](https://www.github.com/googleapis/java-spanner/issues/239)) ([e3d7921](https://www.github.com/googleapis/java-spanner/commit/e3d79214ac4d6e72992acdddb7ddeb2148b1ae15)) + ### [1.55.1](https://www.github.com/googleapis/java-spanner/compare/v1.55.0...v1.55.1) (2020-05-21) diff --git a/README.md b/README.md index d0334a6260..2a08c9d906 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-spanner:1.55.1' +compile 'com.google.cloud:google-cloud-spanner:1.56.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.55.1" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.56.0" ``` [//]: # ({x-version-update-end}) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 5f9af594d5..adeba195a2 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.55.2-SNAPSHOT + 1.56.0 pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.cloud google-cloud-spanner - 1.55.2-SNAPSHOT + 1.56.0 com.google.cloud google-cloud-spanner test-jar - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 6bff001cfa..e94f9faddf 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.55.2-SNAPSHOT + 1.56.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 6d197be081..8d6123bb42 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 60b6118f53..9eb4be7a81 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 124d4db6cf..2b4953097f 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/pom.xml b/pom.xml index dc998a7aa1..c20135800b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.55.2-SNAPSHOT + 1.56.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 com.google.cloud google-cloud-spanner - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 4a89149a26..f7ae0ac26c 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.55.2-SNAPSHOT + 1.56.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 40fa0553c8..918e36f2c4 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.55.2-SNAPSHOT + 1.56.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 179428c2c5..6e11c5dd9a 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.55.2-SNAPSHOT + 1.56.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 4ac5ce4190..c99a7eb0c5 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.55.2-SNAPSHOT + 1.56.0 diff --git a/versions.txt b/versions.txt index a6a70950eb..4e791c39a3 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.55.1:1.55.2-SNAPSHOT -proto-google-cloud-spanner-v1:1.55.1:1.55.2-SNAPSHOT -proto-google-cloud-spanner-admin-database-v1:1.55.1:1.55.2-SNAPSHOT -grpc-google-cloud-spanner-v1:1.55.1:1.55.2-SNAPSHOT -grpc-google-cloud-spanner-admin-instance-v1:1.55.1:1.55.2-SNAPSHOT -grpc-google-cloud-spanner-admin-database-v1:1.55.1:1.55.2-SNAPSHOT -google-cloud-spanner:1.55.1:1.55.2-SNAPSHOT \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.0 +proto-google-cloud-spanner-v1:1.56.0:1.56.0 +proto-google-cloud-spanner-admin-database-v1:1.56.0:1.56.0 +grpc-google-cloud-spanner-v1:1.56.0:1.56.0 +grpc-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.0 +grpc-google-cloud-spanner-admin-database-v1:1.56.0:1.56.0 +google-cloud-spanner:1.56.0:1.56.0 \ No newline at end of file From 507007cf4b1ce57ac58901429112e436dbabc828 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 22 Jun 2020 13:13:53 -0700 Subject: [PATCH 12/55] chore: regenerate README versions (#279) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/5c193786-fcd8-4a90-b8a2-1d007566f359/targets - [ ] To automatically regenerate this PR, check this box. --- README.md | 2 +- synth.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2a08c9d906..a5fd31f2ef 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file com.google.cloud libraries-bom - 5.7.0 + 7.0.0 pom import diff --git a/synth.metadata b/synth.metadata index d92ee33ca3..cef3df582a 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "3427141217038a3d5e3d50c6a8a5343aaaa71daa" + "sha": "5a15f8e22913fb376eb9044e8a77b776cd8baf99" } }, { From d5fa721c5d8a065c701dbb9cce9d36bcf98f8359 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 22 Jun 2020 23:48:31 +0200 Subject: [PATCH 13/55] chore(deps): update dependency com.google.cloud:libraries-bom to v7.0.1 (#293) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:libraries-bom](https://togithub.com/GoogleCloudPlatform/cloud-opensource-java) | patch | `7.0.0` -> `7.0.1` | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index cbb1d86790..1ae5cf18a3 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 7.0.0 + 7.0.1 pom import From bbcb01dde255eaec87a871bba2fc7028d4bd8258 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2020 22:30:45 +0000 Subject: [PATCH 14/55] chore: release 1.56.1-SNAPSHOT (#292) :robot: I have created a release \*beep\* \*boop\* --- ### Updating meta-information for bleeding-edge SNAPSHOT release. --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). --- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index adeba195a2..be01d7aded 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.56.0 + 1.56.1-SNAPSHOT pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.56.0 + 1.56.1-SNAPSHOT com.google.cloud google-cloud-spanner test-jar - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index e94f9faddf..2523f20e68 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.56.0 + 1.56.1-SNAPSHOT jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 8d6123bb42..62d36cd2fb 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 9eb4be7a81..92fd910baf 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 2b4953097f..1cc1637650 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index c20135800b..fd23c37515 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.56.0 + 1.56.1-SNAPSHOT Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index f7ae0ac26c..ef12a1b97b 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.0 + 1.56.1-SNAPSHOT proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 918e36f2c4..42295de97e 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.0 + 1.56.1-SNAPSHOT proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 6e11c5dd9a..db572f326f 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.0 + 1.56.1-SNAPSHOT proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index c99a7eb0c5..531e9593fe 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.56.0 + 1.56.1-SNAPSHOT diff --git a/versions.txt b/versions.txt index 4e791c39a3..14ce0a2ca2 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.0 -proto-google-cloud-spanner-v1:1.56.0:1.56.0 -proto-google-cloud-spanner-admin-database-v1:1.56.0:1.56.0 -grpc-google-cloud-spanner-v1:1.56.0:1.56.0 -grpc-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.0 -grpc-google-cloud-spanner-admin-database-v1:1.56.0:1.56.0 -google-cloud-spanner:1.56.0:1.56.0 \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.1-SNAPSHOT +proto-google-cloud-spanner-v1:1.56.0:1.56.1-SNAPSHOT +proto-google-cloud-spanner-admin-database-v1:1.56.0:1.56.1-SNAPSHOT +grpc-google-cloud-spanner-v1:1.56.0:1.56.1-SNAPSHOT +grpc-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.1-SNAPSHOT +grpc-google-cloud-spanner-admin-database-v1:1.56.0:1.56.1-SNAPSHOT +google-cloud-spanner:1.56.0:1.56.1-SNAPSHOT \ No newline at end of file From ead0c17c68b3ac5cdf6e0c9c368dec9c45a2b79a Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 23 Jun 2020 01:50:59 +0200 Subject: [PATCH 15/55] build(deps): update dependency org.codehaus.mojo:build-helper-maven-plugin to v3.2.0 (#291) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [org.codehaus.mojo:build-helper-maven-plugin](http://www.mojohaus.org/build-helper-maven-plugin/) ([source](https://togithub.com/mojohaus/build-helper-maven-plugin)) | minor | `3.1.0` -> `3.2.0` | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- samples/install-without-bom/pom.xml | 2 +- samples/snapshot/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index aeebf4a95e..f59ec396f1 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -53,7 +53,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.1.0 + 3.2.0 add-snippets-source diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 531e9593fe..2db2bd7169 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -52,7 +52,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.1.0 + 3.2.0 add-snippets-source From 39826d2d789ab0f9d9046161627ed34969bdef78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 24 Jun 2020 21:44:49 +0200 Subject: [PATCH 16/55] process: prepare to test deps on Java 11 (#281) * process: also test deps on Java 11 * deps: remove unused dependency * tests: run deps test on Java 11 * process: remove changes that comes from autosynth --- google-cloud-spanner/pom.xml | 2 +- grpc-google-cloud-spanner-admin-database-v1/pom.xml | 2 +- grpc-google-cloud-spanner-admin-instance-v1/pom.xml | 2 +- grpc-google-cloud-spanner-v1/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 2523f20e68..23118dd6f0 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -116,7 +116,7 @@ org.apache.maven.plugins maven-dependency-plugin - io.grpc:grpc-protobuf-lite,org.hamcrest:hamcrest,org.hamcrest:hamcrest-core,com.google.errorprone:error_prone_annotations,org.openjdk.jmh:jmh-generator-annprocess,com.google.api.grpc:grpc-google-cloud-spanner-v1,com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1,com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1 + io.grpc:grpc-protobuf-lite,org.hamcrest:hamcrest,org.hamcrest:hamcrest-core,com.google.errorprone:error_prone_annotations,org.openjdk.jmh:jmh-generator-annprocess,com.google.api.grpc:grpc-google-cloud-spanner-v1,com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1,com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1,javax.annotation:javax.annotation-api diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 62d36cd2fb..4a334c1b1f 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -73,7 +73,7 @@ org.apache.maven.plugins maven-dependency-plugin - com.google.auto.value:auto-value-annotations + com.google.auto.value:auto-value-annotations,javax.annotation:javax.annotation-api diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 92fd910baf..b617c08984 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -73,7 +73,7 @@ org.apache.maven.plugins maven-dependency-plugin - com.google.auto.value:auto-value-annotations + com.google.auto.value:auto-value-annotations,javax.annotation:javax.annotation-api diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 1cc1637650..903e53bf94 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -66,7 +66,7 @@ org.apache.maven.plugins maven-dependency-plugin - com.google.auto.value:auto-value-annotations + com.google.auto.value:auto-value-annotations,javax.annotation:javax.annotation-api From 2e8364c81a0bf10134bd571dc2930c10fbadb1dc Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 25 Jun 2020 19:41:40 +1000 Subject: [PATCH 17/55] test: unskip tests passing against the emulator (#304) --- .../java/com/google/cloud/spanner/it/ITBatchDmlTest.java | 5 +---- .../java/com/google/cloud/spanner/it/ITBatchReadTest.java | 4 ---- .../src/test/java/com/google/cloud/spanner/it/ITDMLTest.java | 3 --- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java index a080d1c396..f45fa2c427 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java @@ -195,10 +195,7 @@ public long[] run(TransactionContext transaction) { runner.run(callable); Assert.fail("Expecting an exception."); } catch (SpannerBatchUpdateException e) { - // TODO: Remove if-statement when emulator returns the same error code as Cloud Spanner. - if (!env.getTestHelper().isEmulator()) { - assertThat(e.getErrorCode()).isEqualTo(ErrorCode.ALREADY_EXISTS); - } + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.ALREADY_EXISTS); long[] rowCounts = e.getUpdateCounts(); assertThat(rowCounts.length).isEqualTo(1); for (long rc : rowCounts) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java index a6aa4f715d..9c3f11d3ee 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java @@ -17,7 +17,6 @@ package com.google.cloud.spanner.it; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assume.assumeFalse; import com.google.cloud.ByteArray; import com.google.cloud.Timestamp; @@ -89,9 +88,6 @@ private static List manyRows() { @BeforeClass public static void setUpDatabase() throws Exception { - assumeFalse( - "BatchReadOnlyTransactions are not supported on the emulator", - env.getTestHelper().isEmulator()); db = env.getTestHelper() .createTestDatabase( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDMLTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDMLTest.java index 9af4a22f76..aabf93b3a6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDMLTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDMLTest.java @@ -18,7 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; import com.google.cloud.spanner.AbortedException; import com.google.cloud.spanner.Database; @@ -137,8 +136,6 @@ public void abortOnceShouldSucceedAfterRetry() { @Test public void partitionedDML() { - assumeFalse("The emulator does not support partitioned DML", env.getTestHelper().isEmulator()); - executeUpdate(DML_COUNT, insertDml()); assertThat( client From 33a231430a7dc44fbf9adb72ade216bbc16897e1 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 25 Jun 2020 12:17:37 +0200 Subject: [PATCH 18/55] chore(deps): update dependency com.google.cloud:google-cloud-spanner to v1.56.0 (#285) --- samples/install-without-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index f59ec396f1..9267fb1f98 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-spanner - 1.55.1 + 1.56.0 From 8536a3e05252bfbae6872fc011468ce353f57f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 25 Jun 2020 12:18:21 +0200 Subject: [PATCH 19/55] tests: fix flaky instance admin test (#303) --- .../java/com/google/cloud/spanner/InstanceAdminGaxTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java index 309c45bf03..4041263a10 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java @@ -229,7 +229,7 @@ public void setUp() throws Exception { .setMaxRpcTimeout(Duration.ofMillis(200L)) .setRetryDelayMultiplier(1000.0d) .setMaxAttempts(10) - .setTotalTimeout(Duration.ofMillis(200L)) + .setTotalTimeout(Duration.ofMillis(20000L)) .build(); RetrySettings retrySettingsWithHighTimeout = RetrySettings.newBuilder() From 5aef6c3f6d3e9564cb8728ad51718feb6b64475a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 25 Jun 2020 12:20:21 +0200 Subject: [PATCH 20/55] feat(deps): adopt flatten plugin and google-cloud-shared-dependencies and update ExecutorProvider (#302) * feat(deps): adopt flatten plugin and google-cloud-shared-dependencies * fix: change executor after gax update * tests: create a new Thread to get default group * tests: get threads through Thread.getAllStackTraces() Co-authored-by: yangnuoyu --- google-cloud-spanner/pom.xml | 1 - .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 9 +- ...est.java => SpannerOptionsThreadTest.java} | 122 ++++++++---------- .../connection/AbstractMockServerTest.java | 4 + grpc-google-cloud-spanner-v1/pom.xml | 1 - pom.xml | 17 ++- 6 files changed, 81 insertions(+), 73 deletions(-) rename google-cloud-spanner/src/test/java/com/google/cloud/spanner/{it/ITSpannerOptionsTest.java => SpannerOptionsThreadTest.java} (65%) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 23118dd6f0..206ed5e316 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -336,7 +336,6 @@ javax.annotation javax.annotation-api - 1.3.2 diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 97f4b5c88a..890aebed2d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -163,7 +163,8 @@ public class GapicSpannerRpc implements SpannerRpc { * down when the {@link SpannerRpc} is closed. */ private static final class ManagedInstantiatingExecutorProvider implements ExecutorProvider { - private static final int DEFAULT_THREAD_COUNT = 4; + // 4 Gapic clients * 4 channels per client. + private static final int DEFAULT_MIN_THREAD_COUNT = 16; private final List executors = new LinkedList<>(); private final ThreadFactory threadFactory; @@ -178,8 +179,10 @@ public boolean shouldAutoClose() { @Override public ScheduledExecutorService getExecutor() { + int numCpus = Runtime.getRuntime().availableProcessors(); + int numThreads = Math.max(DEFAULT_MIN_THREAD_COUNT, numCpus); ScheduledExecutorService executor = - new ScheduledThreadPoolExecutor(DEFAULT_THREAD_COUNT, threadFactory); + new ScheduledThreadPoolExecutor(numThreads, threadFactory); synchronized (this) { executors.add(executor); } @@ -298,7 +301,7 @@ public GapicSpannerRpc(final SpannerOptions options) { .setMaxInboundMessageSize(MAX_MESSAGE_SIZE) .setMaxInboundMetadataSize(MAX_METADATA_SIZE) .setPoolSize(options.getNumChannels()) - .setExecutorProvider(executorProvider) + .setExecutor(executorProvider.getExecutor()) // Set a keepalive time of 120 seconds to help long running // commit GRPC calls succeed diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsThreadTest.java similarity index 65% rename from google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java rename to google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsThreadTest.java index 34e6c43944..8626f5cb5c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Google LLC + * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,55 +14,58 @@ * limitations under the License. */ -package com.google.cloud.spanner.it; +package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; -import com.google.cloud.spanner.Database; -import com.google.cloud.spanner.DatabaseAdminClient; -import com.google.cloud.spanner.DatabaseClient; -import com.google.cloud.spanner.InstanceAdminClient; -import com.google.cloud.spanner.IntegrationTestEnv; -import com.google.cloud.spanner.ParallelIntegrationTest; -import com.google.cloud.spanner.ResultSet; -import com.google.cloud.spanner.Spanner; -import com.google.cloud.spanner.SpannerOptions; -import com.google.cloud.spanner.Statement; +import com.google.api.core.ApiFunction; +import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.connection.AbstractMockServerTest; import com.google.common.base.Stopwatch; +import com.google.spanner.admin.database.v1.ListDatabasesResponse; +import com.google.spanner.admin.instance.v1.ListInstancesResponse; +import io.grpc.ManagedChannelBuilder; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -@Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) -public class ITSpannerOptionsTest { - @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - private static Database db; - - @BeforeClass - public static void setUp() throws Exception { - db = env.getTestHelper().createTestDatabase(); - } - - @AfterClass - public static void tearDown() throws Exception { - db.drop(); - } - +public class SpannerOptionsThreadTest extends AbstractMockServerTest { private static final int NUMBER_OF_TEST_RUNS = 2; - private static final int DEFAULT_NUM_CHANNELS = 4; - private static final int NUM_THREADS_PER_CHANNEL = 4; + private static final int DEFAULT_NUM_CHANNELS_PER_GAPIC_CLIENT = 4; + private static final int NUM_GAPIC_CLIENTS = 4; + private static final int NUM_THREADS = + Math.max( + DEFAULT_NUM_CHANNELS_PER_GAPIC_CLIENT * NUM_GAPIC_CLIENTS, + Runtime.getRuntime().availableProcessors()); private static final String SPANNER_THREAD_NAME = "Cloud-Spanner-TransportChannel"; private static final String THREAD_PATTERN = "%s-[0-9]+"; + private final DatabaseId dbId = DatabaseId.of("p", "i", "d"); + + @SuppressWarnings("rawtypes") + private SpannerOptions createOptions() { + return SpannerOptions.newBuilder() + .setProjectId("p") + // Set a custom channel configurator to allow http instead of https. + .setChannelConfigurator( + new ApiFunction() { + @Override + public ManagedChannelBuilder apply(ManagedChannelBuilder input) { + input.usePlaintext(); + return input; + } + }) + .setHost("http://localhost:" + getPort()) + .setCredentials(NoCredentials.getInstance()) + .build(); + } + @Test public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException { int baseThreadCount = getNumberOfThreadsWithName(SPANNER_THREAD_NAME); @@ -72,18 +75,15 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException // Create Spanner instance. // We make a copy of the options instance, as SpannerOptions caches any service object // that has been handed out. - SpannerOptions options = env.getTestHelper().getOptions().toBuilder().build(); + SpannerOptions options = createOptions(); Spanner spanner = options.getService(); // Get a database client and do a query. This should initiate threads for the Spanner service. - DatabaseClient client = spanner.getDatabaseClient(db.getId()); + DatabaseClient client = spanner.getDatabaseClient(dbId); List resultSets = new ArrayList<>(); // SpannerStub affiliates a channel with a session, so we need to use multiple sessions // to ensure we also hit multiple channels. for (int i2 = 0; i2 < options.getSessionPoolOptions().getMaxSessions(); i2++) { - ResultSet rs = - client - .singleUse() - .executeQuery(Statement.of("SELECT 1 AS COL1 UNION ALL SELECT 2 AS COL2")); + ResultSet rs = client.singleUse().executeQuery(SELECT_COUNT_STATEMENT); // Execute ResultSet#next() to send the query to Spanner. rs.next(); // Delay closing the result set in order to force the use of multiple sessions. @@ -91,8 +91,7 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException // sessions should initialize multiple transport channels. resultSets.add(rs); // Check whether the number of expected threads has been reached. - if (getNumberOfThreadsWithName(SPANNER_THREAD_NAME) - == DEFAULT_NUM_CHANNELS * NUM_THREADS_PER_CHANNEL + baseThreadCount) { + if (getNumberOfThreadsWithName(SPANNER_THREAD_NAME) == NUM_THREADS + baseThreadCount) { break; } } @@ -102,25 +101,27 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException // Check the number of threads after the query. Doing a request should initialize a thread // pool for the underlying SpannerClient. assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME)) - .isEqualTo(DEFAULT_NUM_CHANNELS * NUM_THREADS_PER_CHANNEL + baseThreadCount); + .isEqualTo(NUM_THREADS + baseThreadCount); // Then do a request to the InstanceAdmin service and check the number of threads. // Doing a request should initialize a thread pool for the underlying InstanceAdminClient. - for (int i2 = 0; i2 < DEFAULT_NUM_CHANNELS * 2; i2++) { + for (int i2 = 0; i2 < DEFAULT_NUM_CHANNELS_PER_GAPIC_CLIENT * 2; i2++) { InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient(); + mockInstanceAdmin.addResponse(ListInstancesResponse.getDefaultInstance()); instanceAdminClient.listInstances(); } assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME)) - .isEqualTo(2 * DEFAULT_NUM_CHANNELS * NUM_THREADS_PER_CHANNEL + baseThreadCount); + .isEqualTo(NUM_THREADS + baseThreadCount); // Then do a request to the DatabaseAdmin service and check the number of threads. // Doing a request should initialize a thread pool for the underlying DatabaseAdminClient. - for (int i2 = 0; i2 < DEFAULT_NUM_CHANNELS * 2; i2++) { + for (int i2 = 0; i2 < DEFAULT_NUM_CHANNELS_PER_GAPIC_CLIENT * 2; i2++) { DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient(); - databaseAdminClient.listDatabases(db.getId().getInstanceId().getInstance()); + mockDatabaseAdmin.addResponse(ListDatabasesResponse.getDefaultInstance()); + databaseAdminClient.listDatabases(dbId.getInstanceId().getInstance()); } assertThat(getNumberOfThreadsWithName(SPANNER_THREAD_NAME)) - .isEqualTo(3 * DEFAULT_NUM_CHANNELS * NUM_THREADS_PER_CHANNEL + baseThreadCount); + .isEqualTo(NUM_THREADS + baseThreadCount); // Now close the Spanner instance and check whether the threads are shutdown or not. spanner.close(); @@ -138,23 +139,17 @@ public void testCloseAllThreadsWhenClosingSpanner() throws InterruptedException public void testMultipleSpannersFromSameSpannerOptions() throws InterruptedException { waitForStartup(); int baseThreadCount = getNumberOfThreadsWithName(SPANNER_THREAD_NAME); - SpannerOptions options = env.getTestHelper().getOptions().toBuilder().build(); + SpannerOptions options = createOptions(); try (Spanner spanner1 = options.getService()) { // Having both in the try-with-resources block is not possible, as it is the same instance. // One will be closed before the other, and the closing of the second instance would fail. Spanner spanner2 = options.getService(); assertThat(spanner1).isSameInstanceAs(spanner2); - DatabaseClient client1 = spanner1.getDatabaseClient(db.getId()); - DatabaseClient client2 = spanner2.getDatabaseClient(db.getId()); + DatabaseClient client1 = spanner1.getDatabaseClient(dbId); + DatabaseClient client2 = spanner2.getDatabaseClient(dbId); assertThat(client1).isSameInstanceAs(client2); - try (ResultSet rs1 = - client1 - .singleUse() - .executeQuery(Statement.of("SELECT 1 AS COL1 UNION ALL SELECT 2 AS COL2")); - ResultSet rs2 = - client2 - .singleUse() - .executeQuery(Statement.of("SELECT 1 AS COL1 UNION ALL SELECT 2 AS COL2")); ) { + try (ResultSet rs1 = client1.singleUse().executeQuery(SELECT_COUNT_STATEMENT); + ResultSet rs2 = client2.singleUse().executeQuery(SELECT_COUNT_STATEMENT)) { while (rs1.next() && rs2.next()) { // Do nothing, just consume the result sets. } @@ -181,15 +176,10 @@ private void waitForStartup() throws InterruptedException { private int getNumberOfThreadsWithName(String serviceName) { Pattern pattern = Pattern.compile(String.format(THREAD_PATTERN, serviceName)); - ThreadGroup group = Thread.currentThread().getThreadGroup(); - while (group.getParent() != null) { - group = group.getParent(); - } - Thread[] threads = new Thread[100 * NUMBER_OF_TEST_RUNS]; - int numberOfThreads = group.enumerate(threads); + Set threadSet = Thread.getAllStackTraces().keySet(); int res = 0; - for (int i = 0; i < numberOfThreads; i++) { - if (pattern.matcher(threads[i].getName()).matches()) { + for (Thread thread : threadSet) { + if (pattern.matcher(thread.getName()).matches()) { res++; } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java index 3497b42bc7..a54a5b848a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java @@ -170,6 +170,10 @@ protected String getBaseUrl() { server.getPort()); } + protected int getPort() { + return server.getPort(); + } + protected ExecuteSqlRequest getLastExecuteSqlRequest() { List requests = mockSpanner.getRequests(); for (int i = requests.size() - 1; i >= 0; i--) { diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 903e53bf94..aa85115cf4 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -53,7 +53,6 @@ javax.annotation javax.annotation-api - 1.3.2 diff --git a/pom.xml b/pom.xml index fd23c37515..a899259548 100644 --- a/pom.xml +++ b/pom.xml @@ -106,10 +106,23 @@ com.google.cloud google-cloud-shared-dependencies - 0.4.0 + 0.8.1 pom import + + + junit + junit + 4.13 + test + + + com.google.truth + truth + 1.0.1 + test + @@ -187,7 +200,7 @@ https://developers.google.com/protocol-buffers/docs/reference/java/ https://googleapis.dev/java/google-auth-library/latest/ https://googleapis.dev/java/gax/latest/ - https://googleapis.github.io/api-common-java/1.8.1/apidocs/ + https://googleapis.github.io/api-common-java/ From 6a900aab0ab36943f7af483d5362dca6a92973c0 Mon Sep 17 00:00:00 2001 From: kurisumakise2011 <55313644+kurisumakise2011@users.noreply.github.com> Date: Thu, 25 Jun 2020 13:26:26 +0300 Subject: [PATCH 21/55] feature: Increase a length of debug string (#301) Increase length of debug string to 36, due to UUID length. According to https://tools.ietf.org/html/rfc4122#section-3 It provides the formal definition of UUID string representations. It's 36 characters (32 hex digits + 4 dashes) It should be more convenient to debugging statements --- .../src/main/java/com/google/cloud/spanner/Value.java | 2 +- .../src/test/java/com/google/cloud/spanner/ValueTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java index 63b9a3a135..c32b5fde81 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java @@ -71,7 +71,7 @@ public abstract class Value implements Serializable { */ public static final Timestamp COMMIT_TIMESTAMP = Timestamp.ofTimeMicroseconds(0L); - private static final int MAX_DEBUG_STRING_LENGTH = 32; + private static final int MAX_DEBUG_STRING_LENGTH = 36; private static final String ELLIPSIS = "..."; private static final String NULL_STRING = "NULL"; private static final char LIST_SEPERATOR = ','; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java index 22c8261db9..dbc9c8ea61 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java @@ -212,11 +212,11 @@ public void stringNull() { @Test public void stringLong() { - String str = "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"; + String str = "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeee"; Value v = Value.string(str); assertThat(v.getString()).isEqualTo(str); - assertThat(v.toString()).hasLength(32); - assertThat(v.toString()).startsWith(str.substring(0, 32 - 3)); + assertThat(v.toString()).hasLength(36); + assertThat(v.toString()).startsWith(str.substring(0, 36 - 3)); assertThat(v.toString()).endsWith("..."); } From 1e8ec14657dad509de2488cbf28a7500138082a3 Mon Sep 17 00:00:00 2001 From: Suraj Dhamecha <48670070+suraj-qlogic@users.noreply.github.com> Date: Fri, 26 Jun 2020 04:12:38 +0530 Subject: [PATCH 22/55] chore: remove unused throws from test (#299) --- .../spanner/connection/ChecksumResultSet.java | 3 +- .../AbstractStructReaderTypesTest.java | 6 +- .../cloud/spanner/BackendExhaustedTest.java | 4 +- .../com/google/cloud/spanner/BackupTest.java | 2 +- .../cloud/spanner/BatchClientImplTest.java | 2 +- .../spanner/BatchCreateSessionsTest.java | 8 +- .../spanner/DatabaseAdminClientImplTest.java | 2 +- .../spanner/DatabaseAdminClientTest.java | 17 ++-- .../cloud/spanner/DatabaseAdminGaxTest.java | 2 +- .../cloud/spanner/DatabaseClientImplTest.java | 36 ++++---- .../google/cloud/spanner/DatabaseTest.java | 2 +- .../cloud/spanner/GrpcResultSetTest.java | 4 +- .../cloud/spanner/InstanceAdminGaxTest.java | 2 +- .../google/cloud/spanner/KeyRangeTest.java | 2 +- .../com/google/cloud/spanner/KeySetTest.java | 2 +- .../com/google/cloud/spanner/KeyTest.java | 2 +- .../spanner/MockDatabaseAdminServiceImpl.java | 2 +- .../MockDatabaseAdminServiceImplTest.java | 2 +- .../google/cloud/spanner/MutationTest.java | 2 +- .../google/cloud/spanner/OperationTest.java | 4 +- .../RetryOnInvalidatedSessionTest.java | 35 ++++---- .../cloud/spanner/SessionClientTest.java | 12 +-- .../google/cloud/spanner/SessionImplTest.java | 4 +- .../spanner/SessionPoolIntegrationTest.java | 2 +- .../cloud/spanner/SessionPoolLeakTest.java | 8 +- .../spanner/SessionPoolMaintainerTest.java | 6 +- .../cloud/spanner/SessionPoolStressTest.java | 10 +-- .../google/cloud/spanner/SessionPoolTest.java | 90 +++++++++---------- .../com/google/cloud/spanner/SpanTest.java | 4 +- .../cloud/spanner/SpannerGaxRetryTest.java | 12 +-- .../google/cloud/spanner/SpannerImplTest.java | 4 +- .../cloud/spanner/SpannerRetryHelperTest.java | 18 ++-- .../google/cloud/spanner/StatementTest.java | 2 +- .../cloud/spanner/TimestampBoundTest.java | 2 +- .../TransactionManagerAbortedTest.java | 4 +- .../spanner/TransactionManagerImplTest.java | 7 +- .../spanner/TransactionRunnerImplTest.java | 23 +++-- .../com/google/cloud/spanner/ValueTest.java | 7 +- .../database/v1/DatabaseAdminClientTest.java | 2 +- .../instance/v1/InstanceAdminClientTest.java | 2 +- .../connection/ConnectionImplTest.java | 16 ++-- ...nnectionStatementWithNoParametersTest.java | 22 ++--- ...nnectionStatementWithOneParameterTest.java | 14 +-- .../connection/CredentialsServiceTest.java | 4 +- .../DirectExecuteResultSetTest.java | 3 +- .../connection/ITAbstractSpannerTest.java | 6 +- .../connection/ReadWriteTransactionTest.java | 7 +- .../ReplaceableForwardingResultSetTest.java | 3 +- .../connection/SingleUseTransactionTest.java | 2 +- .../spanner/connection/SpannerPoolTest.java | 13 ++- .../connection/StatementTimeoutTest.java | 7 +- .../connection/it/ITBulkConnectionTest.java | 2 +- .../connection/it/ITReadOnlySpannerTest.java | 6 +- .../it/ITReadWriteAutocommitSpannerTest.java | 4 +- .../google/cloud/spanner/it/ITBackupTest.java | 6 +- .../cloud/spanner/it/ITBatchDmlTest.java | 4 +- .../cloud/spanner/it/ITBatchReadTest.java | 2 +- .../cloud/spanner/it/ITClosedSessionTest.java | 6 +- .../spanner/it/ITCommitTimestampTest.java | 2 +- .../cloud/spanner/it/ITDatabaseAdminTest.java | 4 +- .../cloud/spanner/it/ITInstanceAdminTest.java | 2 +- .../cloud/spanner/it/ITQueryOptionsTest.java | 6 +- .../cloud/spanner/it/ITTransactionTest.java | 2 +- .../cloud/spanner/v1/SpannerClientTest.java | 2 +- 64 files changed, 242 insertions(+), 263 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java index 0170a9f572..d8e0e85844 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java @@ -38,7 +38,6 @@ import com.google.common.hash.PrimitiveSink; import java.util.Objects; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; /** * {@link ResultSet} implementation that keeps a running checksum that can be used to determine @@ -117,7 +116,7 @@ public boolean next() { } @VisibleForTesting - HashCode getChecksum() throws InterruptedException, ExecutionException { + HashCode getChecksum() { // HashCode is immutable and can be safely returned. return checksumCalculator.getChecksum(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java index 3e6da2a296..bde868fe55 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java @@ -328,7 +328,7 @@ public void getter() throws Exception { } @Test - public void getterForIncorrectType() throws Exception { + public void getterForIncorrectType() { Mockito.when(reader.getType()).thenReturn(Type.struct(StructField.of("F1", type))); int columnIndex = 0; Mockito.when(reader.isNull(columnIndex)).thenReturn(false); @@ -367,7 +367,7 @@ public void getterForIncorrectType() throws Exception { } @Test - public void getterWhenNull() throws Exception { + public void getterWhenNull() { Mockito.when(reader.getType()).thenReturn(Type.struct(StructField.of("F1", type))); Mockito.when(reader.isNull(0)).thenReturn(true); try { @@ -379,7 +379,7 @@ public void getterWhenNull() throws Exception { } @Test - public void getterByNameWhenNull() throws Exception { + public void getterByNameWhenNull() { Mockito.when(reader.getType()).thenReturn(Type.struct(StructField.of("F1", type))); Mockito.when(reader.isNull(0)).thenReturn(true); try { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackendExhaustedTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackendExhaustedTest.java index f7d6653faf..cb1244f8e3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackendExhaustedTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackendExhaustedTest.java @@ -153,7 +153,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception { + public void tearDown() { mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); // This test case force-closes the Spanner instance as it would otherwise wait @@ -209,7 +209,7 @@ public void run() { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java index 50eaf1fd09..3bdc673838 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BackupTest.java @@ -56,7 +56,7 @@ public void setUp() { .thenAnswer( new Answer() { @Override - public Builder answer(InvocationOnMock invocation) throws Throwable { + public Builder answer(InvocationOnMock invocation) { return new Backup.Builder(dbClient, (BackupId) invocation.getArguments()[0]); } }); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java index 002a992b6f..f53a3ac406 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchClientImplTest.java @@ -102,7 +102,7 @@ public void testBatchReadOnlyTxnWithBound() throws Exception { } @Test - public void testBatchReadOnlyTxnWithTxnId() throws Exception { + public void testBatchReadOnlyTxnWithTxnId() { when(txnID.getSessionId()).thenReturn(SESSION_NAME); when(txnID.getTransactionId()).thenReturn(TXN_ID); Timestamp t = Timestamp.parseTimestamp(TIMESTAMP); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchCreateSessionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchCreateSessionsTest.java index 222b393113..abac3bd134 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchCreateSessionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BatchCreateSessionsTest.java @@ -102,7 +102,7 @@ public static void stopServer() throws InterruptedException { } @Before - public void setUp() throws IOException { + public void setUp() { mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); } @@ -237,7 +237,7 @@ public void testSpannerReturnsResourceExhausted() throws InterruptedException { } @Test - public void testPrepareSessionFailPropagatesToUser() throws InterruptedException { + public void testPrepareSessionFailPropagatesToUser() { // Do not create any sessions by default. // This also means that when a read/write session is requested, the session pool // will start preparing a read session at that time. Any errors that might occur @@ -256,7 +256,7 @@ public void testPrepareSessionFailPropagatesToUser() throws InterruptedException runner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -297,7 +297,7 @@ public void testPrepareSessionFailDoesNotPropagateToUser() throws InterruptedExc runner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index e77fb38439..b2676473cf 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -338,7 +338,7 @@ public void listBackups() { } @Test - public void updateBackup() throws Exception { + public void updateBackup() { Timestamp t = Timestamp.ofTimeMicroseconds( TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java index ea695c3611..8b30df912d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientTest.java @@ -48,7 +48,6 @@ import io.grpc.Server; import io.grpc.Status; import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; -import java.io.IOException; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.Collections; @@ -110,7 +109,7 @@ public static void stopServer() throws Exception { @SuppressWarnings("rawtypes") @Before - public void setUp() throws IOException { + public void setUp() { mockDatabaseAdmin.reset(); mockOperations.reset(); SpannerOptions.Builder builder = SpannerOptions.newBuilder(); @@ -214,7 +213,7 @@ public ManagedChannelBuilder apply(ManagedChannelBuilder input) { } @After - public void tearDown() throws Exception { + public void tearDown() { mockDatabaseAdmin.reset(); mockDatabaseAdmin.removeAllExecutionTimes(); mockOperations.reset(); @@ -311,7 +310,7 @@ public void databaseBackup() throws InterruptedException, ExecutionException { } @Test - public void dbAdminCreateBackupAlreadyExists() throws InterruptedException, ExecutionException { + public void dbAdminCreateBackupAlreadyExists() throws InterruptedException { OperationFuture op = client.createBackup(INSTANCE_ID, BCK_ID, DB_ID, after7Days()); try { @@ -325,7 +324,7 @@ public void dbAdminCreateBackupAlreadyExists() throws InterruptedException, Exec } @Test - public void backupCreateAlreadyExists() throws InterruptedException, ExecutionException { + public void backupCreateAlreadyExists() throws InterruptedException { Backup backup = client .newBackupBuilder(BackupId.of(PROJECT_ID, INSTANCE_ID, BCK_ID)) @@ -343,7 +342,7 @@ public void backupCreateAlreadyExists() throws InterruptedException, ExecutionEx } @Test - public void databaseBackupAlreadyExists() throws InterruptedException, ExecutionException { + public void databaseBackupAlreadyExists() throws InterruptedException { Database db = client.getDatabase(INSTANCE_ID, DB_ID); OperationFuture op = db.backup( @@ -362,7 +361,7 @@ public void databaseBackupAlreadyExists() throws InterruptedException, Execution } @Test - public void dbAdminCreateBackupDbNotFound() throws InterruptedException, ExecutionException { + public void dbAdminCreateBackupDbNotFound() throws InterruptedException { final String backupId = "other-backup-id"; OperationFuture op = client.createBackup(INSTANCE_ID, backupId, "does-not-exist", after7Days()); @@ -376,7 +375,7 @@ public void dbAdminCreateBackupDbNotFound() throws InterruptedException, Executi } @Test - public void backupCreateDbNotFound() throws InterruptedException, ExecutionException { + public void backupCreateDbNotFound() throws InterruptedException { final String backupId = "other-backup-id"; Backup backup = client @@ -394,7 +393,7 @@ public void backupCreateDbNotFound() throws InterruptedException, ExecutionExcep } @Test - public void databaseBackupDbNotFound() throws InterruptedException, ExecutionException { + public void databaseBackupDbNotFound() throws InterruptedException { final String backupId = "other-backup-id"; Database db = new Database( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminGaxTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminGaxTest.java index caeed50da6..7e4dfb699c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminGaxTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminGaxTest.java @@ -294,7 +294,7 @@ public Void apply(Builder input) { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index ac57476c12..7bb05964fb 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -126,7 +126,7 @@ public static void stopServer() throws InterruptedException { } @Before - public void setUp() throws IOException { + public void setUp() { spanner = SpannerOptions.newBuilder() .setProjectId(TEST_PROJECT) @@ -137,7 +137,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); @@ -185,7 +185,7 @@ public void testExecutePartitionedDmlWithException() { } @Test - public void testPartitionedDmlDoesNotTimeout() throws Exception { + public void testPartitionedDmlDoesNotTimeout() { mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(10, 0)); final RetrySettings retrySettings = RetrySettings.newBuilder() @@ -218,7 +218,7 @@ public void testPartitionedDmlDoesNotTimeout() throws Exception { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { transaction.executeUpdate(UPDATE_STATEMENT); return null; } @@ -233,7 +233,7 @@ public Void run(TransactionContext transaction) throws Exception { } @Test - public void testPartitionedDmlWithLowerTimeout() throws Exception { + public void testPartitionedDmlWithLowerTimeout() { mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(1000, 0)); SpannerOptions.Builder builder = SpannerOptions.newBuilder() @@ -265,7 +265,7 @@ public void testPartitionedDmlWithLowerTimeout() throws Exception { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); @@ -274,7 +274,7 @@ public Long run(TransactionContext transaction) throws Exception { } @Test - public void testPartitionedDmlWithHigherTimeout() throws Exception { + public void testPartitionedDmlWithHigherTimeout() { mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(100, 0)); SpannerOptions.Builder builder = SpannerOptions.newBuilder() @@ -313,7 +313,7 @@ public void testPartitionedDmlWithHigherTimeout() throws Exception { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); @@ -326,7 +326,7 @@ public Long run(TransactionContext transaction) throws Exception { } @Test - public void testPartitionedDmlRetriesOnUnavailable() throws Exception { + public void testPartitionedDmlRetriesOnUnavailable() { mockSpanner.setExecuteSqlExecutionTime( SimulatedExecutionTime.ofException(Status.UNAVAILABLE.asRuntimeException())); SpannerOptions.Builder builder = @@ -387,7 +387,7 @@ public void testDatabaseOrInstanceDoesNotExistOnPrepareSession() throws Exceptio .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -440,7 +440,7 @@ public void testDatabaseOrInstanceDoesNotExistOnInitialization() throws Exceptio } @Test - public void testDatabaseOrInstanceDoesNotExistOnCreate() throws Exception { + public void testDatabaseOrInstanceDoesNotExistOnCreate() { StatusRuntimeException[] exceptions = new StatusRuntimeException[] { SpannerExceptionFactoryTest.newStatusResourceNotFoundException( @@ -578,7 +578,7 @@ private void testExceptionOnPrepareSession(StatusRuntimeException exception) .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -594,7 +594,7 @@ public Void run(TransactionContext transaction) throws Exception { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -665,7 +665,7 @@ public void testDatabaseOrInstanceIsDeletedAndThenRecreated() throws Exception { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -690,7 +690,7 @@ public Void run(TransactionContext transaction) throws Exception { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -737,7 +737,7 @@ public void testAllowNestedTransactions() throws InterruptedException { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { assertThat(client.pool.getNumberOfSessionsInPool()).isEqualTo(minSessions - 1); return transaction.executeUpdate(UPDATE_STATEMENT); } @@ -772,7 +772,7 @@ public void testNestedTransactionsUsingTwoDatabases() throws InterruptedExceptio .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { // Client1 should have 1 session checked out. // Client2 should have 0 sessions checked out. assertThat(client1.pool.getNumberOfSessionsInPool()).isEqualTo(minSessions - 1); @@ -783,7 +783,7 @@ public Long run(TransactionContext transaction) throws Exception { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { // Both clients should now have 1 session checked out. assertThat(client1.pool.getNumberOfSessionsInPool()) .isEqualTo(minSessions - 1); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 74703609d9..9557615007 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -51,7 +51,7 @@ public void setUp() { .thenAnswer( new Answer() { @Override - public Backup.Builder answer(InvocationOnMock invocation) throws Throwable { + public Backup.Builder answer(InvocationOnMock invocation) { return new Backup.Builder(dbClient, (BackupId) invocation.getArguments()[0]); } }); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java index 5bad5b5541..2ee73e75d3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java @@ -564,7 +564,7 @@ private static ResultSetMetadata makeMetadata(Type rowType) { } @Test - public void serialization() throws Exception { + public void serialization() { Type structType = Type.struct( Arrays.asList( @@ -605,7 +605,7 @@ public void serialization() throws Exception { } @Test - public void nestedStructSerialization() throws Exception { + public void nestedStructSerialization() { Type structType = Type.struct( Arrays.asList( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java index 4041263a10..5f3063bc7b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminGaxTest.java @@ -300,7 +300,7 @@ public Void apply(Builder input) { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java index 393138c604..c89d08ef26 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyRangeTest.java @@ -130,7 +130,7 @@ public void testToString() { } @Test - public void serialization() throws Exception { + public void serialization() { reserializeAndAssert(KeyRange.closedOpen(Key.of(1), Key.of(2))); reserializeAndAssert(KeyRange.closedClosed(Key.of(1), Key.of(2))); reserializeAndAssert(KeyRange.openOpen(Key.of(1), Key.of(2))); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeySetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeySetTest.java index 2712c84613..7ed74283f3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeySetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeySetTest.java @@ -264,7 +264,7 @@ public void serializationMultiWithAll() { } @Test - public void javaSerialization() throws Exception { + public void javaSerialization() { reserializeAndAssert( KeySet.all() .toBuilder() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyTest.java index 81f3957c28..a135e30888 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyTest.java @@ -179,7 +179,7 @@ public void equalsAndHashCode() { } @Test - public void serialization() throws Exception { + public void serialization() { reserializeAndAssert(Key.of()); reserializeAndAssert(Key.of(new Object[] {null})); reserializeAndAssert(Key.of(true)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java index ff0e7b482f..832dccb14c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java @@ -201,7 +201,7 @@ private CreateDatabaseCallable(String operationName, String name) { } @Override - public Database call() throws Exception { + public Database call() { MockDatabase db = databases.get(name); db.state = State.READY; Database proto = db.toProto(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImplTest.java index 4364bfe26a..c73b79d6e6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImplTest.java @@ -193,7 +193,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { client.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java index a6f1049f08..12edae4479 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java @@ -413,7 +413,7 @@ public void toProtoCoalescingDeleteChanges() { } @Test - public void javaSerialization() throws Exception { + public void javaSerialization() { reserializeAndAssert(appendAllTypes(Mutation.newInsertBuilder("test")).build()); reserializeAndAssert(appendAllTypes(Mutation.newUpdateBuilder("test")).build()); reserializeAndAssert(appendAllTypes(Mutation.newReplaceBuilder("test")).build()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java index f958c85330..169bf481d0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OperationTest.java @@ -149,7 +149,7 @@ public void reload() { } @Test - public void waitForCompletes() throws Exception { + public void waitForCompletes() { com.google.longrunning.Operation proto = newBuilder().setName("op1").setDone(false).build(); Operation op = Operation.create(rpc, proto, new ParserImpl()); com.google.spanner.admin.database.v1.Database db = @@ -174,7 +174,7 @@ public void waitForCompletes() throws Exception { } @Test - public void waitForTimesout() throws Exception { + public void waitForTimesout() { com.google.longrunning.Operation proto = newBuilder().setName("op1").setDone(false).build(); Operation op = Operation.create(rpc, proto, new ParserImpl(), clock); when(rpc.getOperation("op1")).thenReturn(proto); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java index d202f5d5eb..29f442a761 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java @@ -176,7 +176,7 @@ public static void stopServer() throws InterruptedException { } @Before - public void setUp() throws IOException { + public void setUp() { mockSpanner.reset(); SessionPoolOptions.Builder builder = SessionPoolOptions.newBuilder().setWriteSessionsFraction(WRITE_SESSIONS_FRACTION); @@ -195,7 +195,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); } @@ -573,7 +573,7 @@ public void readWriteTransactionReadOnlySessionInPool() throws InterruptedExcept runner.run( new TransactionCallable() { @Override - public Integer run(TransactionContext transaction) throws Exception { + public Integer run(TransactionContext transaction) { int count = 0; try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) { while (rs.next()) { @@ -596,7 +596,7 @@ public void readWriteTransactionSelect() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Integer run(TransactionContext transaction) throws Exception { + public Integer run(TransactionContext transaction) { int count = 0; try (ResultSet rs = transaction.executeQuery(SELECT1AND2)) { while (rs.next()) { @@ -623,7 +623,7 @@ public void readWriteTransactionRead() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Integer run(TransactionContext transaction) throws Exception { + public Integer run(TransactionContext transaction) { int count = 0; try (ResultSet rs = transaction.read("FOO", KeySet.all(), Arrays.asList("BAR"))) { while (rs.next()) { @@ -650,7 +650,7 @@ public void readWriteTransactionReadUsingIndex() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Integer run(TransactionContext transaction) throws Exception { + public Integer run(TransactionContext transaction) { int count = 0; try (ResultSet rs = transaction.readUsingIndex( @@ -679,7 +679,7 @@ public void readWriteTransactionReadRow() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Struct run(TransactionContext transaction) throws Exception { + public Struct run(TransactionContext transaction) { return transaction.readRow("FOO", Key.of(), Arrays.asList("BAR")); } }); @@ -700,7 +700,7 @@ public void readWriteTransactionReadRowUsingIndex() throws InterruptedException runner.run( new TransactionCallable() { @Override - public Struct run(TransactionContext transaction) throws Exception { + public Struct run(TransactionContext transaction) { return transaction.readRowUsingIndex( "FOO", "IDX", Key.of(), Arrays.asList("BAR")); } @@ -722,7 +722,7 @@ public void readWriteTransactionUpdate() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); @@ -743,7 +743,7 @@ public void readWriteTransactionBatchUpdate() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public long[] run(TransactionContext transaction) throws Exception { + public long[] run(TransactionContext transaction) { return transaction.batchUpdate(Arrays.asList(UPDATE_STATEMENT)); } }); @@ -764,7 +764,7 @@ public void readWriteTransactionBuffer() throws InterruptedException { runner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { transaction.buffer(Mutation.newInsertBuilder("FOO").set("BAR").to(1L).build()); return null; } @@ -777,7 +777,7 @@ public Void run(TransactionContext transaction) throws Exception { } @Test - public void readWriteTransactionSelectInvalidatedDuringTransaction() throws InterruptedException { + public void readWriteTransactionSelectInvalidatedDuringTransaction() { try { TransactionRunner runner = client.readWriteTransaction(); int attempts = @@ -814,7 +814,7 @@ public Integer run(TransactionContext transaction) throws Exception { } @Test - public void readWriteTransactionReadInvalidatedDuringTransaction() throws InterruptedException { + public void readWriteTransactionReadInvalidatedDuringTransaction() { try { TransactionRunner runner = client.readWriteTransaction(); int attempts = @@ -851,8 +851,7 @@ public Integer run(TransactionContext transaction) throws Exception { } @Test - public void readWriteTransactionReadUsingIndexInvalidatedDuringTransaction() - throws InterruptedException { + public void readWriteTransactionReadUsingIndexInvalidatedDuringTransaction() { try { TransactionRunner runner = client.readWriteTransaction(); int attempts = @@ -893,8 +892,7 @@ public Integer run(TransactionContext transaction) throws Exception { } @Test - public void readWriteTransactionReadRowInvalidatedDuringTransaction() - throws InterruptedException { + public void readWriteTransactionReadRowInvalidatedDuringTransaction() { try { TransactionRunner runner = client.readWriteTransaction(); int attempts = @@ -922,8 +920,7 @@ public Integer run(TransactionContext transaction) throws Exception { } @Test - public void readWriteTransactionReadRowUsingIndexInvalidatedDuringTransaction() - throws InterruptedException { + public void readWriteTransactionReadRowUsingIndexInvalidatedDuringTransaction() { try { TransactionRunner runner = client.readWriteTransaction(); int attempts = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionClientTest.java index fe68020705..39dfee6a3f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionClientTest.java @@ -151,8 +151,7 @@ public void batchCreateAndCloseSessions() { .then( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { Map options = invocation.getArgumentAt(3, Map.class); Long channelHint = (Long) options.get(SpannerRpc.Option.CHANNEL_HINT); usedChannels.add(channelHint); @@ -215,8 +214,7 @@ public void batchCreateSessionsDistributesMultipleRequestsOverChannels() { .then( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { Map options = invocation.getArgumentAt(3, Map.class); Long channelHint = (Long) options.get(SpannerRpc.Option.CHANNEL_HINT); usedChannelHintss.add(channelHint); @@ -300,8 +298,7 @@ public void batchCreateSessionsWithExceptions() { .then( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { Map options = invocation.getArgumentAt(3, Map.class); Long channelHint = (Long) options.get(SpannerRpc.Option.CHANNEL_HINT); if (errorOnChannels.contains(channelHint)) { @@ -368,8 +365,7 @@ public void batchCreateSessionsServerReturnsLessSessionsPerBatch() { .then( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { int sessionCount = invocation.getArgumentAt(1, Integer.class); List res = new ArrayList<>(); for (int i = 1; i <= Math.min(MAX_SESSIONS_PER_BATCH, sessionCount); i++) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java index fcc36d2b1b..be4179f21b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java @@ -124,7 +124,7 @@ public Void run(TransactionContext transaction) throws SpannerException { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -428,7 +428,7 @@ private void mockRead(final PartialResultSet myResultSet) { .then( new Answer() { @Override - public SpannerRpc.StreamingCall answer(InvocationOnMock invocation) throws Throwable { + public SpannerRpc.StreamingCall answer(InvocationOnMock invocation) { consumer.getValue().onPartialResultSet(myResultSet); consumer.getValue().onCompleted(); return new NoOpStreamingCall(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java index 353dbdfe46..b7ddb19223 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolIntegrationTest.java @@ -74,7 +74,7 @@ public static void setUpDatabase() { } @Before - public void setUp() throws Exception { + public void setUp() { SessionPoolOptions options = SessionPoolOptions.newBuilder().setMinSessions(1).setMaxSessions(2).build(); pool = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolLeakTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolLeakTest.java index dbafb9dd01..2dc31bb28a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolLeakTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolLeakTest.java @@ -72,7 +72,7 @@ public static void stopServer() throws InterruptedException { } @Before - public void setUp() throws Exception { + public void setUp() { mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); SpannerOptions.Builder builder = @@ -95,7 +95,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); } @@ -135,7 +135,7 @@ private void readWriteTransactionTest( .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -161,7 +161,7 @@ public void run() { } @Test - public void testTransactionManagerExceptionOnBegin() throws Exception { + public void testTransactionManagerExceptionOnBegin() { transactionManagerTest( new Runnable() { @Override diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java index 8d1b780432..8007ce8385 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java @@ -56,7 +56,7 @@ public class SessionPoolMaintainerTest extends BaseSessionPoolTest { private Map pingedSessions = new HashMap<>(); @Before - public void setUp() throws Exception { + public void setUp() { initMocks(this); when(client.getOptions()).thenReturn(spannerOptions); when(client.getSessionClient(db)).thenReturn(sessionClient); @@ -78,7 +78,7 @@ private void setupMockSessionCreation() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -107,7 +107,7 @@ private SessionImpl setupMockSession(final SessionImpl session) { .thenAnswer( new Answer() { @Override - public ResultSet answer(InvocationOnMock invocation) throws Throwable { + public ResultSet answer(InvocationOnMock invocation) { Integer currentValue = pingedSessions.get(session.getName()); if (currentValue == null) { currentValue = 0; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java index b059e4f861..e5f5dff463 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java @@ -102,7 +102,7 @@ private void setupSpanner(DatabaseId db) { new Answer() { @Override - public Session answer(InvocationOnMock invocation) throws Throwable { + public Session answer(InvocationOnMock invocation) { synchronized (lock) { SessionImpl session = mockSession(); setupSession(session); @@ -118,7 +118,7 @@ public Session answer(InvocationOnMock invocation) throws Throwable { doAnswer( new Answer() { @Override - public Void answer(InvocationOnMock invocation) throws Throwable { + public Void answer(InvocationOnMock invocation) { int sessionCount = invocation.getArgumentAt(0, Integer.class); for (int s = 0; s < sessionCount; s++) { synchronized (lock) { @@ -151,7 +151,7 @@ private void setupSession(final SessionImpl session) { new Answer() { @Override - public ResultSet answer(InvocationOnMock invocation) throws Throwable { + public ResultSet answer(InvocationOnMock invocation) { resetTransaction(session); return mockResult; } @@ -161,7 +161,7 @@ public ResultSet answer(InvocationOnMock invocation) throws Throwable { new Answer>() { @Override - public ApiFuture answer(InvocationOnMock invocation) throws Throwable { + public ApiFuture answer(InvocationOnMock invocation) { synchronized (lock) { if (expiredSessions.contains(session.getName())) { return ApiFutures.immediateFailedFuture( @@ -184,7 +184,7 @@ public ApiFuture answer(InvocationOnMock invocation) throws Throwable { doAnswer( new Answer() { @Override - public Void answer(InvocationOnMock invocation) throws Throwable { + public Void answer(InvocationOnMock invocation) { if (random.nextInt(100) < 10) { expireSession(session); throw SpannerExceptionFactoryTest.newSessionNotFoundException(session.getName()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index 99cffbaec7..db56c8ff82 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -132,7 +132,7 @@ private SessionPool createPool( } @Before - public void setUp() throws Exception { + public void setUp() { initMocks(this); when(client.getOptions()).thenReturn(spannerOptions); when(client.getSessionClient(db)).thenReturn(sessionClient); @@ -150,7 +150,7 @@ private void setupMockSessionCreation() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -241,7 +241,7 @@ public void poolClosureClosesLeakedSessions() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -299,7 +299,7 @@ public void poolClosureFailsPendingReadWaiters() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -315,7 +315,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Callable() { @Override @@ -357,7 +357,7 @@ public void poolClosureFailsPendingWriteWaiters() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -373,7 +373,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Callable() { @Override @@ -413,7 +413,7 @@ public void poolClosesEvenIfCreationFails() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Callable() { @Override @@ -449,7 +449,7 @@ public void poolClosesEvenIfPreparationFails() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -489,12 +489,12 @@ public Session answer(InvocationOnMock invocation) throws Throwable { } @Test - public void poolClosureFailsNewRequests() throws Exception { + public void poolClosureFailsNewRequests() { final SessionImpl session = mockSession(); doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -543,11 +543,11 @@ public void creationExceptionPropagatesToReadSession() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Callable() { @Override - public Void call() throws Exception { + public Void call() { SessionConsumerImpl consumer = invocation.getArgumentAt(2, SessionConsumerImpl.class); consumer.onSessionCreateFailure( @@ -574,11 +574,11 @@ public void creationExceptionPropagatesToReadWriteSession() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Callable() { @Override - public Void call() throws Exception { + public Void call() { SessionConsumerImpl consumer = invocation.getArgumentAt(2, SessionConsumerImpl.class); consumer.onSessionCreateFailure( @@ -606,7 +606,7 @@ public void prepareExceptionPropagatesToReadWriteSession() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -639,7 +639,7 @@ public void getReadWriteSession() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -670,7 +670,7 @@ public void getMultipleReadWriteSessions() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -701,7 +701,7 @@ public void getMultipleConcurrentReadWriteSessions() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -735,7 +735,7 @@ public void sessionIsPrePrepared() { new Answer() { @Override - public Void answer(InvocationOnMock arg0) throws Throwable { + public Void answer(InvocationOnMock arg0) { prepareLatch.countDown(); return null; } @@ -746,7 +746,7 @@ public Void answer(InvocationOnMock arg0) throws Throwable { new Answer() { @Override - public Void answer(InvocationOnMock arg0) throws Throwable { + public Void answer(InvocationOnMock arg0) { prepareLatch.countDown(); return null; } @@ -756,7 +756,7 @@ public Void answer(InvocationOnMock arg0) throws Throwable { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -797,7 +797,7 @@ public void getReadSessionFallsBackToWritePreparedSession() throws Exception { doAnswer( new Answer() { @Override - public Void answer(InvocationOnMock arg0) throws Throwable { + public Void answer(InvocationOnMock arg0) { prepareLatch.countDown(); return null; } @@ -807,7 +807,7 @@ public Void answer(InvocationOnMock arg0) throws Throwable { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -847,7 +847,7 @@ public void failOnPoolExhaustion() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -888,7 +888,7 @@ public void poolWorksWhenSessionNotFound() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -924,7 +924,7 @@ public void idleSessionCleanup() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -984,7 +984,7 @@ public void keepAlive() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1040,7 +1040,7 @@ public void testMaintainerKeepsWriteProportion() throws Exception { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1142,7 +1142,7 @@ public void blockAndTimeoutOnPoolExhaustion() throws Exception { executor.submit( new Callable() { @Override - public Void call() throws Exception { + public Void call() { Session session; latch.countDown(); if (finWrite) { @@ -1198,7 +1198,7 @@ public void testSessionNotFoundSingleUse() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1214,7 +1214,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1254,7 +1254,7 @@ public void testSessionNotFoundReadOnlyTransaction() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1270,7 +1270,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1376,7 +1376,7 @@ public void testSessionNotFoundReadWriteTransaction() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1392,7 +1392,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1430,7 +1430,7 @@ public void run() { private int callNumber = 0; @Override - public Integer run(TransactionContext transaction) throws Exception { + public Integer run(TransactionContext transaction) { callNumber++; if (hasPreparedTransaction) { // If the session had a prepared read/write transaction, that transaction will @@ -1512,7 +1512,7 @@ public void testSessionNotFoundOnPrepareTransaction() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1528,7 +1528,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1563,7 +1563,7 @@ public void testSessionNotFoundWrite() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1579,7 +1579,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1615,7 +1615,7 @@ public void testSessionNotFoundWriteAtLeastOnce() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1631,7 +1631,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1666,7 +1666,7 @@ public void testSessionNotFoundPartitionedUpdate() { doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override @@ -1682,7 +1682,7 @@ public void run() { .doAnswer( new Answer() { @Override - public Void answer(final InvocationOnMock invocation) throws Throwable { + public Void answer(final InvocationOnMock invocation) { executor.submit( new Runnable() { @Override diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java index dc4652a1b4..9bbbdcea82 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java @@ -292,7 +292,7 @@ public void transactionRunner() { runner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { transaction.executeUpdate(UPDATE_STATEMENT); return null; } @@ -313,7 +313,7 @@ public void transactionRunnerWithError() { runner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { transaction.executeUpdate(INVALID_UPDATE_STATEMENT); return null; } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java index ad7ee39b35..05729d6f53 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java @@ -186,7 +186,7 @@ public Void apply(Builder input) { } @After - public void tearDown() throws Exception { + public void tearDown() { spannerWithTimeout.close(); spanner.close(); } @@ -201,7 +201,7 @@ private void warmUpSessionPool(DatabaseClient client) { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); @@ -336,7 +336,7 @@ public void readWriteTransactionUnavailable() { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate(UPDATE_STATEMENT); } }); @@ -351,7 +351,7 @@ public void readWriteTransactionStatementAborted() { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { if (attempts.getAndIncrement() == 0) { mockSpanner.abortTransaction(transaction); } @@ -370,7 +370,7 @@ public void readWriteTransactionCommitAborted() { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { long res = transaction.executeUpdate(UPDATE_STATEMENT); if (attempts.getAndIncrement() == 0) { mockSpanner.abortTransaction(transaction); @@ -401,7 +401,7 @@ public void readWriteTransactionUncheckedException() { runner.run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { transaction.executeUpdate(UPDATE_STATEMENT); throw SpannerExceptionFactory.newSpannerException(ErrorCode.INVALID_ARGUMENT, "test"); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerImplTest.java index f2546f838d..aafd88390c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerImplTest.java @@ -168,7 +168,7 @@ public void getDbclientAfterCloseThrows() { } @Test - public void testSpannerClosed() throws InterruptedException { + public void testSpannerClosed() { SpannerOptions options = createSpannerOptions(); Spanner spanner1 = options.getService(); Spanner spanner2 = options.getService(); @@ -199,7 +199,7 @@ public void testSpannerClosed() throws InterruptedException { } @Test - public void testClientId() throws Exception { + public void testClientId() { // Create a unique database id to be sure it has not yet been used in the lifetime of this JVM. String dbName = String.format("projects/p1/instances/i1/databases/%s", UUID.randomUUID().toString()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java index e5a427bff8..415145120f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerRetryHelperTest.java @@ -50,7 +50,7 @@ public void testCancelledContext() { final Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { latch.countDown(); throw SpannerExceptionFactory.newSpannerException(ErrorCode.ABORTED, "test"); } @@ -85,12 +85,12 @@ public void run() { } @Test - public void testTimedoutContext() throws InterruptedException { + public void testTimedoutContext() { ScheduledExecutorService service = Executors.newScheduledThreadPool(1); final Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { throw SpannerExceptionFactory.newSpannerException(ErrorCode.ABORTED, "test"); } }; @@ -120,7 +120,7 @@ public void noException() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { return 1 + 1; } }; @@ -132,7 +132,7 @@ public void propagateUncheckedException() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { throw new IllegalStateException("test"); } }; @@ -145,7 +145,7 @@ public void retryOnAborted() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { if (attempts.getAndIncrement() == 0) { throw abortedWithRetryInfo((int) TimeUnit.MILLISECONDS.toNanos(1L)); } @@ -161,7 +161,7 @@ public void retryMultipleTimesOnAborted() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { if (attempts.getAndIncrement() < 2) { throw abortedWithRetryInfo((int) TimeUnit.MILLISECONDS.toNanos(1)); } @@ -177,7 +177,7 @@ public void retryOnAbortedAndThenPropagateUnchecked() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { if (attempts.getAndIncrement() == 0) { throw abortedWithRetryInfo((int) TimeUnit.MILLISECONDS.toNanos(1L)); } @@ -227,7 +227,7 @@ public void run() { Callable callable = new Callable() { @Override - public Integer call() throws Exception { + public Integer call() { if (attempts.getAndIncrement() == 0) { throw e; } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java index f41a659df2..4e39d1271d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StatementTest.java @@ -43,7 +43,7 @@ public void basic() { } @Test - public void serialization() throws Exception { + public void serialization() { Statement stmt = Statement.newBuilder("SELECT * FROM table WHERE ") .append("bool_field = @bool_field ") diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java index 1298e05292..955485da5d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TimestampBoundTest.java @@ -39,7 +39,7 @@ public class TimestampBoundTest { private static final String TEST_TIME_ISO = "2015-10-12T15:14:54Z"; @Test - public void serialization() throws Exception { + public void serialization() { reserializeAndAssert(TimestampBound.strong()); reserializeAndAssert(TimestampBound.ofExactStaleness(10, TimeUnit.NANOSECONDS)); reserializeAndAssert(TimestampBound.ofMaxStaleness(100, TimeUnit.DAYS)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerAbortedTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerAbortedTest.java index 8272ac4aa8..dec674bd6c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerAbortedTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerAbortedTest.java @@ -167,7 +167,7 @@ public static void stopServer() throws InterruptedException { } @Before - public void setUp() throws Exception { + public void setUp() { mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); SpannerOptions.Builder builder = @@ -179,7 +179,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception { + public void tearDown() { spanner.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java index 85bb69181a..ba569653c3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java @@ -236,8 +236,7 @@ public void usesPreparedTransaction() { .thenAnswer( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { return Arrays.asList( com.google.spanner.v1.Session.newBuilder() .setName((String) invocation.getArguments()[0] + "/sessions/1") @@ -251,7 +250,7 @@ public List answer(InvocationOnMock invocation) .thenAnswer( new Answer() { @Override - public Transaction answer(InvocationOnMock invocation) throws Throwable { + public Transaction answer(InvocationOnMock invocation) { return Transaction.newBuilder() .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) .build(); @@ -261,7 +260,7 @@ public Transaction answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public CommitResponse answer(InvocationOnMock invocation) throws Throwable { + public CommitResponse answer(InvocationOnMock invocation) { return CommitResponse.newBuilder() .setCommitTimestamp( com.google.protobuf.Timestamp.newBuilder() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java index c45f46fbd1..074f0a905c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java @@ -90,7 +90,7 @@ public void release(ScheduledExecutorService exec) { private boolean firstRun; @Before - public void setUp() throws Exception { + public void setUp() { MockitoAnnotations.initMocks(this); firstRun = true; when(session.newTransaction()).thenReturn(txn); @@ -117,8 +117,7 @@ public void usesPreparedTransaction() { .thenAnswer( new Answer>() { @Override - public List answer(InvocationOnMock invocation) - throws Throwable { + public List answer(InvocationOnMock invocation) { return Arrays.asList( com.google.spanner.v1.Session.newBuilder() .setName((String) invocation.getArguments()[0] + "/sessions/1") @@ -131,7 +130,7 @@ public List answer(InvocationOnMock invocation) .thenAnswer( new Answer() { @Override - public Transaction answer(InvocationOnMock invocation) throws Throwable { + public Transaction answer(InvocationOnMock invocation) { return Transaction.newBuilder() .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) .build(); @@ -141,7 +140,7 @@ public Transaction answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public CommitResponse answer(InvocationOnMock invocation) throws Throwable { + public CommitResponse answer(InvocationOnMock invocation) { return CommitResponse.newBuilder() .setCommitTimestamp( Timestamp.newBuilder().setSeconds(System.currentTimeMillis() * 1000)) @@ -156,7 +155,7 @@ public CommitResponse answer(InvocationOnMock invocation) throws Throwable { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); @@ -171,7 +170,7 @@ public void commitSucceeds() { transactionRunner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { numCalls.incrementAndGet(); return null; } @@ -197,7 +196,7 @@ public void commitAbort() { transactionRunner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { numCalls.incrementAndGet(); return null; } @@ -217,7 +216,7 @@ public void commitFailsWithNonAbort() { transactionRunner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { numCalls.incrementAndGet(); return null; } @@ -232,7 +231,7 @@ public Void run(TransactionContext transaction) throws Exception { } @Test - public void runResourceExhaustedNoRetry() throws Exception { + public void runResourceExhaustedNoRetry() { try { runTransaction( new StatusRuntimeException(Status.fromCodeValue(Status.Code.RESOURCE_EXHAUSTED.value()))); @@ -308,7 +307,7 @@ private long[] batchDmlException(int status) { runner.run( new TransactionCallable() { @Override - public long[] run(TransactionContext transaction) throws Exception { + public long[] run(TransactionContext transaction) { numCalls.incrementAndGet(); return transaction.batchUpdate(Arrays.asList(statement, statement)); } @@ -324,7 +323,7 @@ private void runTransaction(final Exception exception) { transactionRunner.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { if (firstRun) { firstRun = false; throw SpannerExceptionFactory.newSpannerException(exception); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java index dbc9c8ea61..a7b99d313e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java @@ -28,7 +28,6 @@ import com.google.common.collect.ForwardingList; import com.google.common.collect.Lists; import com.google.common.testing.EqualsTester; -import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -1008,13 +1007,11 @@ protected List delegate() { return delegate; } - private void readObject(@SuppressWarnings("unused") java.io.ObjectInputStream unusedStream) - throws IOException, ClassNotFoundException { + private void readObject(@SuppressWarnings("unused") java.io.ObjectInputStream unusedStream) { throw new IllegalStateException("Serialization disabled"); } - private void writeObject(@SuppressWarnings("unused") java.io.ObjectOutputStream unusedStream) - throws IOException { + private void writeObject(@SuppressWarnings("unused") java.io.ObjectOutputStream unusedStream) { throw new IllegalStateException("Serialization disabled"); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java index 78efb14466..a20872cc51 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java @@ -115,7 +115,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { client.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java index 406171d3aa..72e9d59379 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java @@ -103,7 +103,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { client.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java index e13e1d0c15..f5295ef96b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java @@ -216,7 +216,7 @@ public static ConnectionImpl createConnection(ConnectionOptions options) { .thenAnswer( new Answer() { @Override - public ResultSet answer(InvocationOnMock invocation) throws Throwable { + public ResultSet answer(InvocationOnMock invocation) { if (select1ResultSet.nextCalled) { // create a new mock return new SimpleResultSet(createSelect1MockResultSet()); @@ -232,7 +232,7 @@ public ResultSet answer(InvocationOnMock invocation) throws Throwable { .then( new Answer() { @Override - public Timestamp answer(InvocationOnMock invocation) throws Throwable { + public Timestamp answer(InvocationOnMock invocation) { if (select1ResultSet.isNextCalled() || select1ResultSetWithStats.isNextCalled()) { return Timestamp.now(); } @@ -247,13 +247,13 @@ public Timestamp answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public TransactionManager answer(InvocationOnMock invocation) throws Throwable { + public TransactionManager answer(InvocationOnMock invocation) { TransactionContext txContext = mock(TransactionContext.class); when(txContext.executeQuery(Statement.of(SELECT))) .thenAnswer( new Answer() { @Override - public ResultSet answer(InvocationOnMock invocation) throws Throwable { + public ResultSet answer(InvocationOnMock invocation) { if (select1ResultSet.nextCalled) { // create a new mock return new SimpleResultSet(createSelect1MockResultSet()); @@ -274,13 +274,13 @@ public ResultSet answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public ReadOnlyTransaction answer(InvocationOnMock invocation) throws Throwable { + public ReadOnlyTransaction answer(InvocationOnMock invocation) { ReadOnlyTransaction tx = mock(ReadOnlyTransaction.class); when(tx.executeQuery(Statement.of(SELECT))) .thenAnswer( new Answer() { @Override - public ResultSet answer(InvocationOnMock invocation) throws Throwable { + public ResultSet answer(InvocationOnMock invocation) { if (select1ResultSet.nextCalled) { // create a new mock return new SimpleResultSet(createSelect1MockResultSet()); @@ -296,7 +296,7 @@ public ResultSet answer(InvocationOnMock invocation) throws Throwable { .then( new Answer() { @Override - public Timestamp answer(InvocationOnMock invocation) throws Throwable { + public Timestamp answer(InvocationOnMock invocation) { if (select1ResultSet.isNextCalled() || select1ResultSetWithStats.isNextCalled()) { return Timestamp.now(); @@ -314,7 +314,7 @@ public Timestamp answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public TransactionRunner answer(InvocationOnMock invocation) throws Throwable { + public TransactionRunner answer(InvocationOnMock invocation) { TransactionRunner runner = new TransactionRunner() { private Timestamp commitTimestamp; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithNoParametersTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithNoParametersTest.java index 8012f255dc..e3be3cfeae 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithNoParametersTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithNoParametersTest.java @@ -32,7 +32,7 @@ public class ConnectionStatementWithNoParametersTest { private final StatementParser parser = StatementParser.INSTANCE; @Test - public void testExecuteGetAutocommit() throws Exception { + public void testExecuteGetAutocommit() { ParsedStatement statement = parser.parse(Statement.of("show variable autocommit")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -43,7 +43,7 @@ public void testExecuteGetAutocommit() throws Exception { } @Test - public void testExecuteGetReadOnly() throws Exception { + public void testExecuteGetReadOnly() { ParsedStatement statement = parser.parse(Statement.of("show variable readonly")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -54,7 +54,7 @@ public void testExecuteGetReadOnly() throws Exception { } @Test - public void testExecuteGetAutocommitDmlMode() throws Exception { + public void testExecuteGetAutocommitDmlMode() { ParsedStatement statement = parser.parse(Statement.of("show variable autocommit_dml_mode")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -66,7 +66,7 @@ public void testExecuteGetAutocommitDmlMode() throws Exception { } @Test - public void testExecuteGetStatementTimeout() throws Exception { + public void testExecuteGetStatementTimeout() { ParsedStatement statement = parser.parse(Statement.of("show variable statement_timeout")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -79,7 +79,7 @@ public void testExecuteGetStatementTimeout() throws Exception { } @Test - public void testExecuteGetReadTimestamp() throws Exception { + public void testExecuteGetReadTimestamp() { ParsedStatement statement = parser.parse(Statement.of("show variable read_timestamp")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -91,7 +91,7 @@ public void testExecuteGetReadTimestamp() throws Exception { } @Test - public void testExecuteGetCommitTimestamp() throws Exception { + public void testExecuteGetCommitTimestamp() { ParsedStatement statement = parser.parse(Statement.of("show variable commit_timestamp")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -103,7 +103,7 @@ public void testExecuteGetCommitTimestamp() throws Exception { } @Test - public void testExecuteGetReadOnlyStaleness() throws Exception { + public void testExecuteGetReadOnlyStaleness() { ParsedStatement statement = parser.parse(Statement.of("show variable read_only_staleness")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -115,7 +115,7 @@ public void testExecuteGetReadOnlyStaleness() throws Exception { } @Test - public void testExecuteGetOptimizerVersion() throws Exception { + public void testExecuteGetOptimizerVersion() { ParsedStatement statement = parser.parse(Statement.of("show variable optimizer_version")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -127,7 +127,7 @@ public void testExecuteGetOptimizerVersion() throws Exception { } @Test - public void testExecuteBegin() throws Exception { + public void testExecuteBegin() { ParsedStatement subject = parser.parse(Statement.of("begin")); for (String statement : subject.getClientSideStatement().getExampleStatements()) { ConnectionImpl connection = mock(ConnectionImpl.class); @@ -140,7 +140,7 @@ public void testExecuteBegin() throws Exception { } @Test - public void testExecuteCommit() throws Exception { + public void testExecuteCommit() { ParsedStatement subject = parser.parse(Statement.of("commit")); for (String statement : subject.getClientSideStatement().getExampleStatements()) { ConnectionImpl connection = mock(ConnectionImpl.class); @@ -153,7 +153,7 @@ public void testExecuteCommit() throws Exception { } @Test - public void testExecuteRollback() throws Exception { + public void testExecuteRollback() { ParsedStatement subject = parser.parse(Statement.of("rollback")); for (String statement : subject.getClientSideStatement().getExampleStatements()) { ConnectionImpl connection = mock(ConnectionImpl.class); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithOneParameterTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithOneParameterTest.java index b07c308a0e..56c5c689b0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithOneParameterTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionStatementWithOneParameterTest.java @@ -34,7 +34,7 @@ public class ConnectionStatementWithOneParameterTest { private final StatementParser parser = StatementParser.INSTANCE; @Test - public void testExecuteSetAutcommit() throws Exception { + public void testExecuteSetAutcommit() { ParsedStatement subject = parser.parse(Statement.of("set autocommit = true")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -49,7 +49,7 @@ public void testExecuteSetAutcommit() throws Exception { } @Test - public void testExecuteSetReadOnly() throws Exception { + public void testExecuteSetReadOnly() { ParsedStatement subject = parser.parse(Statement.of("set readonly = true")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -64,7 +64,7 @@ public void testExecuteSetReadOnly() throws Exception { } @Test - public void testExecuteSetAutcommitDmlMode() throws Exception { + public void testExecuteSetAutcommitDmlMode() { ParsedStatement subject = parser.parse(Statement.of("set autocommit_dml_mode='foo'")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -79,7 +79,7 @@ public void testExecuteSetAutcommitDmlMode() throws Exception { } @Test - public void testExecuteSetStatementTimeout() throws Exception { + public void testExecuteSetStatementTimeout() { ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); when(executor.statementSetStatementTimeout(any(Duration.class))).thenCallRealMethod(); ConnectionImpl connection = mock(ConnectionImpl.class); @@ -109,7 +109,7 @@ public void testExecuteSetStatementTimeout() throws Exception { } @Test - public void testExecuteSetReadOnlyStaleness() throws Exception { + public void testExecuteSetReadOnlyStaleness() { ParsedStatement subject = parser.parse(Statement.of("set read_only_staleness='foo'")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -149,7 +149,7 @@ private String timestampBoundToString(TimestampBound staleness) { } @Test - public void testExecuteSetOptimizerVersion() throws Exception { + public void testExecuteSetOptimizerVersion() { ParsedStatement subject = parser.parse(Statement.of("set optimizer_version='foo'")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); @@ -164,7 +164,7 @@ public void testExecuteSetOptimizerVersion() throws Exception { } @Test - public void testExecuteSetTransaction() throws Exception { + public void testExecuteSetTransaction() { ParsedStatement subject = parser.parse(Statement.of("set transaction read_only")); ConnectionImpl connection = mock(ConnectionImpl.class); ConnectionStatementExecutorImpl executor = mock(ConnectionStatementExecutorImpl.class); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/CredentialsServiceTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/CredentialsServiceTest.java index 7a48c577c2..e8dc7a4f87 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/CredentialsServiceTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/CredentialsServiceTest.java @@ -54,14 +54,14 @@ GoogleCredentials internalGetApplicationDefault() throws IOException { }; @Test - public void testCreateCredentialsDefault() throws Exception { + public void testCreateCredentialsDefault() { ServiceAccountCredentials credentials = (ServiceAccountCredentials) service.createCredentials(null); assertThat(credentials.getProjectId(), is(equalTo(APP_DEFAULT_PROJECT_ID))); } @Test - public void testCreateCredentialsFile() throws IOException { + public void testCreateCredentialsFile() { ServiceAccountCredentials credentials = (ServiceAccountCredentials) service.createCredentials(FILE_TEST_PATH); assertThat(credentials.getProjectId(), is(equalTo(TEST_PROJECT_ID))); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java index 477c872179..237c6af718 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java @@ -144,8 +144,7 @@ private void callMethods( } @Test - public void testValidMethodCall() - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + public void testValidMethodCall() throws IllegalArgumentException { ResultSet delegate = mock(ResultSet.class); when(delegate.next()).thenReturn(true, true, false); DirectExecuteResultSet subject = DirectExecuteResultSet.ofResultSet(delegate); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java index a14b9aa4a7..99fd3d7a10 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java @@ -33,7 +33,6 @@ import com.google.cloud.spanner.connection.StatementParser.ParsedStatement; import com.google.common.base.Preconditions; import com.google.common.base.Strings; -import java.io.IOException; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; @@ -41,7 +40,6 @@ import java.util.Collections; import java.util.List; import java.util.Random; -import java.util.concurrent.ExecutionException; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -186,7 +184,7 @@ public static StringBuilder extractConnectionUrl(SpannerOptions options, Databas } @BeforeClass - public static void setup() throws IOException, InterruptedException, ExecutionException { + public static void setup() { database = env.getTestHelper().createTestDatabase(); } @@ -268,7 +266,7 @@ protected boolean doCreateDefaultTestTable() { } @Before - public void createTestTable() throws Exception { + public void createTestTable() { if (doCreateDefaultTestTable()) { try (Connection connection = createConnection()) { connection.setAutocommit(true); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java index f9a1e7afab..e0cd8db9a6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java @@ -50,7 +50,6 @@ import com.google.spanner.v1.ResultSetStats; import java.util.Arrays; import java.util.Collections; -import java.util.concurrent.ExecutionException; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -145,7 +144,7 @@ private ReadWriteTransaction createSubject( .thenAnswer( new Answer() { @Override - public TransactionManager answer(InvocationOnMock invocation) throws Throwable { + public TransactionManager answer(InvocationOnMock invocation) { TransactionContext txContext = mock(TransactionContext.class); when(txContext.executeQuery(any(Statement.class))) .thenReturn(mock(ResultSet.class)); @@ -470,7 +469,7 @@ public void testRetry() { } @Test - public void testChecksumResultSet() throws InterruptedException, ExecutionException { + public void testChecksumResultSet() { DatabaseClient client = mock(DatabaseClient.class); ReadWriteTransaction transaction = ReadWriteTransaction.newBuilder() @@ -534,7 +533,7 @@ public void testChecksumResultSet() throws InterruptedException, ExecutionExcept } @Test - public void testChecksumResultSetWithArray() throws InterruptedException, ExecutionException { + public void testChecksumResultSetWithArray() { DatabaseClient client = mock(DatabaseClient.class); ReadWriteTransaction transaction = ReadWriteTransaction.newBuilder() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSetTest.java index e95f23a865..a30b15e6c2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSetTest.java @@ -195,8 +195,7 @@ private void callMethods( } @Test - public void testValidMethodCall() - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + public void testValidMethodCall() throws IllegalArgumentException { ResultSet delegate = mock(ResultSet.class); when(delegate.next()).thenReturn(true, true, false); try (ReplaceableForwardingResultSet subject = new ReplaceableForwardingResultSet(delegate)) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java index 7286b426d4..27ee1903fa 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java @@ -346,7 +346,7 @@ public Long answer(InvocationOnMock invocation) throws Throwable { .thenAnswer( new Answer() { @Override - public TransactionRunner answer(InvocationOnMock invocation) throws Throwable { + public TransactionRunner answer(InvocationOnMock invocation) { TransactionRunner runner = new TransactionRunner() { private Timestamp commitTimestamp; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java index bfd413001b..c0145203ce 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java @@ -35,7 +35,6 @@ import com.google.cloud.spanner.connection.ConnectionImpl.LeakedConnectionException; import com.google.cloud.spanner.connection.SpannerPool.CheckAndCloseSpannersMode; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.OutputStream; import java.util.logging.Handler; import java.util.logging.Logger; @@ -174,13 +173,13 @@ private void attachLogCapturer() { log.addHandler(customLogHandler); } - public String getTestCapturedLog() throws IOException { + public String getTestCapturedLog() { customLogHandler.flush(); return logCapturingStream.toString(); } @Test - public void testRemoveConnectionOptionsNotRegistered() throws IOException { + public void testRemoveConnectionOptionsNotRegistered() { attachLogCapturer(); final String expectedLogPart = "There is no Spanner registered for ConnectionOptions"; SpannerPool pool = createSubjectAndMocks(); @@ -191,7 +190,7 @@ public void testRemoveConnectionOptionsNotRegistered() throws IOException { } @Test - public void testRemoveConnectionConnectionNotRegistered() throws IOException { + public void testRemoveConnectionConnectionNotRegistered() { attachLogCapturer(); final String expectedLogPart = "There are no connections registered for ConnectionOptions"; SpannerPool pool = createSubjectAndMocks(); @@ -202,7 +201,7 @@ public void testRemoveConnectionConnectionNotRegistered() throws IOException { } @Test - public void testRemoveConnectionConnectionAlreadyRemoved() throws IOException { + public void testRemoveConnectionConnectionAlreadyRemoved() { attachLogCapturer(); final String expectedLogPart = "There are no connections registered for ConnectionOptions"; SpannerPool pool = createSubjectAndMocks(); @@ -214,7 +213,7 @@ public void testRemoveConnectionConnectionAlreadyRemoved() throws IOException { } @Test - public void testCloseSpanner() throws IOException { + public void testCloseSpanner() { SpannerPool pool = createSubjectAndMocks(); Spanner spanner = pool.getSpanner(options1, connection1); // verify that closing is not possible until all connections have been removed @@ -246,7 +245,7 @@ public void testCloseSpanner() throws IOException { } @Test - public void testLeakedConnection() throws IOException { + public void testLeakedConnection() { ConnectionOptions options = ConnectionOptions.newBuilder() .setCredentials(NoCredentials.getInstance()) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java index ae52779912..e483a50279 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/StatementTimeoutTest.java @@ -191,15 +191,14 @@ private ConnectionImpl createConnection( .thenAnswer( new Answer() { @Override - public TransactionManager answer(InvocationOnMock invocation) throws Throwable { + public TransactionManager answer(InvocationOnMock invocation) { TransactionManager txManager = mock(TransactionManager.class); when(txManager.getState()).thenReturn(null, TransactionState.STARTED); when(txManager.begin()) .thenAnswer( new Answer() { @Override - public TransactionContext answer(InvocationOnMock invocation) - throws Throwable { + public TransactionContext answer(InvocationOnMock invocation) { TransactionContext txContext = mock(TransactionContext.class); when(txContext.executeQuery(Statement.of(SLOW_SELECT))) .thenAnswer(new DelayedQueryExecution()); @@ -681,7 +680,7 @@ private void testInterruptedException(final ConnectionConsumer consumer) executor.submit( new Callable() { @Override - public Boolean call() throws Exception { + public Boolean call() { try (Connection connection = createConnection( ConnectionOptions.newBuilder() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java index fc86864929..7a8091e0d4 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java @@ -68,7 +68,7 @@ public void testBulkCreateConnectionsMultiThreaded() throws InterruptedException executor.submit( new Callable() { @Override - public Void call() throws Exception { + public Void call() { try (ITConnection connection = createConnection()) { try (ResultSet rs = connection.executeQuery(Statement.of("select 1"))) { assertThat(rs.next(), is(true)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java index 358bbadcd7..ae94e9781b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java @@ -105,7 +105,7 @@ public void testSqlScript() throws Exception { } @Test - public void testStatementTimeoutTransactional() throws Exception { + public void testStatementTimeoutTransactional() { try (ITConnection connection = createConnection()) { connection.beginTransaction(); connection.setStatementTimeout(1L, TimeUnit.MILLISECONDS); @@ -123,7 +123,7 @@ public void testStatementTimeoutTransactional() throws Exception { } @Test - public void testStatementTimeoutTransactionalMultipleStatements() throws Exception { + public void testStatementTimeoutTransactionalMultipleStatements() { long startTime = System.currentTimeMillis(); try (ITConnection connection = createConnection()) { connection.beginTransaction(); @@ -151,7 +151,7 @@ public void testStatementTimeoutTransactionalMultipleStatements() throws Excepti } @Test - public void testStatementTimeoutAutocommit() throws Exception { + public void testStatementTimeoutAutocommit() { try (ITConnection connection = createConnection()) { assertThat(connection.isAutocommit(), is(true)); connection.setStatementTimeout(1L, TimeUnit.MILLISECONDS); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java index 8870afdd95..928fc8869f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java @@ -63,7 +63,7 @@ public void test01_SqlScript() throws Exception { } @Test - public void test02_WriteMutation() throws Exception { + public void test02_WriteMutation() { try (ITConnection connection = createConnection()) { connection.write( Mutation.newInsertBuilder("TEST").set("ID").to(9999L).set("NAME").to("FOO").build()); @@ -72,7 +72,7 @@ public void test02_WriteMutation() throws Exception { } @Test - public void test03_MultipleStatements_WithTimeouts() throws InterruptedException { + public void test03_MultipleStatements_WithTimeouts() { try (ITConnection connection = createConnection()) { // do an insert that should succeed assertThat( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java index cb954006db..2a35a17083 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java @@ -97,7 +97,7 @@ public static void doNotRunOnEmulator() { } @Before - public void setUp() throws Exception { + public void setUp() { logger.info("Setting up tests"); testHelper = env.getTestHelper(); dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); @@ -474,7 +474,7 @@ private void testGetBackup(Database db, String backupId, Timestamp expireTime) { assertThat(backup.getDatabase()).isEqualTo(db.getId()); } - private void testUpdateBackup(Backup backup) throws InterruptedException, ExecutionException { + private void testUpdateBackup(Backup backup) { // Update the expire time. Timestamp tomorrow = tomorrow(); backup = backup.toBuilder().setExpireTime(tomorrow).build(); @@ -525,7 +525,7 @@ private void testPagination(int expectedMinimumTotalBackups) { assertThat(numBackups).isAtLeast(expectedMinimumTotalBackups); } - private void testDelete(String backupId) throws InterruptedException, ExecutionException { + private void testDelete(String backupId) throws InterruptedException { waitForDbOperations(backupId); // Get the backup. logger.info(String.format("Fetching backup %s", backupId)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java index f45fa2c427..b2cf021445 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchDmlTest.java @@ -108,7 +108,7 @@ public void batchDml() { final TransactionCallable callable = new TransactionCallable() { @Override - public long[] run(TransactionContext transaction) throws Exception { + public long[] run(TransactionContext transaction) { List stmts = new ArrayList<>(); stmts.add(Statement.of(INSERT_DML)); stmts.add(Statement.of(UPDATE_DML)); @@ -129,7 +129,7 @@ public void mixedBatchDmlAndDml() { final TransactionCallable callable = new TransactionCallable() { @Override - public long[] run(TransactionContext transaction) throws Exception { + public long[] run(TransactionContext transaction) { long rowCount = transaction.executeUpdate(Statement.of(INSERT_DML)); List stmts = new ArrayList<>(); stmts.add(Statement.of(UPDATE_DML)); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java index 9c3f11d3ee..e682dd685e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBatchReadTest.java @@ -173,7 +173,7 @@ public void readUsingIndex() { } @After - public void tearDown() throws Exception { + public void tearDown() { if (batchTxn != null) { batchTxn.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java index c249859f83..3031b0edd8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITClosedSessionTest.java @@ -207,7 +207,7 @@ public void testReadWriteTransaction() { txn.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { for (int i = 0; i < 2; i++) { try (ResultSet rs = transaction.executeQuery(Statement.of("SELECT 1"))) { assertThat(rs.next()).isTrue(); @@ -230,7 +230,7 @@ public void testReadWriteTransactionNoRecreation() { txn.run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { try (ResultSet rs = transaction.executeQuery(Statement.of("SELECT 1"))) { rs.next(); fail("Expected exception"); @@ -271,7 +271,7 @@ public void testTransactionManager() throws InterruptedException { } @Test - public void testTransactionManagerNoRecreation() throws InterruptedException { + public void testTransactionManagerNoRecreation() { client.setAllowSessionReplacing(false); client.invalidateNextSession(); try (TransactionManager manager = client.transactionManager()) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java index c2cba6cb54..92d5aa3c6e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java @@ -61,7 +61,7 @@ public class ITCommitTimestampTest { private static String databaseId; @BeforeClass - public static void setUp() throws Exception { + public static void setUp() { testHelper = env.getTestHelper(); db = testHelper.createTestDatabase( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java index 14421c86b4..f66154d66c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseAdminTest.java @@ -77,13 +77,13 @@ public class ITDatabaseAdminTest { private List dbs = new ArrayList<>(); @Before - public void setUp() throws Exception { + public void setUp() { testHelper = env.getTestHelper(); dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); } @After - public void tearDown() throws Exception { + public void tearDown() { for (Database db : dbs) { db.drop(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java index a3d35ee6c1..68e4e615a3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITInstanceAdminTest.java @@ -64,7 +64,7 @@ public void instanceConfigOperations() { } @Test - public void listInstances() throws Exception { + public void listInstances() { Instance instance = Iterators.getOnlyElement( instanceClient diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java index 71c7bcd47c..30cfa80c45 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryOptionsTest.java @@ -111,7 +111,7 @@ public void executeUpdate() { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate( Statement.newBuilder("INSERT INTO TEST (ID, NAME) VALUES (@id, @name)") .bind("id") @@ -132,7 +132,7 @@ public Long run(TransactionContext transaction) throws Exception { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate( Statement.newBuilder("INSERT INTO TEST (ID, NAME) VALUES (@id, @name)") .bind("id") @@ -153,7 +153,7 @@ public Long run(TransactionContext transaction) throws Exception { .run( new TransactionCallable() { @Override - public Long run(TransactionContext transaction) throws Exception { + public Long run(TransactionContext transaction) { return transaction.executeUpdate( Statement.newBuilder("INSERT INTO TEST (ID, NAME) VALUES (@id, @name)") .bind("id") diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java index cc87023be0..a05029ad99 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java @@ -397,7 +397,7 @@ public Void run(TransactionContext transaction) throws SpannerException { .run( new TransactionCallable() { @Override - public Void run(TransactionContext transaction) throws Exception { + public Void run(TransactionContext transaction) { return null; } }); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java index 1977873f96..b0de897cf9 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java @@ -108,7 +108,7 @@ public void setUp() throws IOException { } @After - public void tearDown() throws Exception { + public void tearDown() { client.close(); } From b4e04014c9f2d9556b0e25c3542f946496272890 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 26 Jun 2020 05:03:38 +0200 Subject: [PATCH 23/55] chore(deps): update dependency com.google.cloud:libraries-bom to v8 (#307) --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 1ae5cf18a3..60797f3fca 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 7.0.1 + 8.0.0 pom import From 0fb3c2b0c38036231225d641d482ca9216cd48db Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 25 Jun 2020 20:04:34 -0700 Subject: [PATCH 24/55] ci(java): run dependency test on Java 8 and 11 (#289) * ci(java): run dependency test on Java 8 and 11 Redo fix in #633 with proper jinja templating format Source-Author: Jeff Ching Source-Date: Fri Jun 19 16:52:15 2020 -0700 Source-Repo: googleapis/synthtool Source-Sha: 4f2c9f752a94042472fc03c5bd9e06e89817d2bd Source-Link: https://github.com/googleapis/synthtool/commit/4f2c9f752a94042472fc03c5bd9e06e89817d2bd --- .github/workflows/ci.yaml | 5 ++++- .kokoro/dependencies.sh | 4 +++- README.md | 2 +- synth.metadata | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 445b4bf82f..6830220756 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -36,11 +36,14 @@ jobs: JOB_TYPE: test dependencies: runs-on: ubuntu-latest + strategy: + matrix: + java: [8, 11] steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: 8 + java-version: ${{matrix.java}} - run: java -version - run: .kokoro/dependencies.sh linkage-monitor: diff --git a/.kokoro/dependencies.sh b/.kokoro/dependencies.sh index cf3bb4347e..cee4f11e75 100755 --- a/.kokoro/dependencies.sh +++ b/.kokoro/dependencies.sh @@ -41,8 +41,10 @@ echo "****************** DEPENDENCY LIST COMPLETENESS CHECK *******************" ## Run dependency list completeness check function completenessCheck() { # Output dep list with compile scope generated using the original pom + # Running mvn dependency:list on Java versions that support modules will also include the module of the dependency. + # This is stripped from the output as it is not present in the flattened pom. msg "Generating dependency list using original pom..." - mvn dependency:list -f pom.xml -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' | grep -v ':test$' >.org-list.txt + mvn dependency:list -f pom.xml -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' | sed -e s/\\s--\\smodule.*// | grep -v ':test$' >.org-list.txt # Output dep list generated using the flattened pom (test scope deps are ommitted) msg "Generating dependency list using flattened pom..." diff --git a/README.md b/README.md index a5fd31f2ef..b433e3accb 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file com.google.cloud libraries-bom - 7.0.0 + 7.0.1 pom import diff --git a/synth.metadata b/synth.metadata index cef3df582a..075a723b25 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "5a15f8e22913fb376eb9044e8a77b776cd8baf99" + "sha": "39826d2d789ab0f9d9046161627ed34969bdef78" } }, { @@ -19,7 +19,7 @@ "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "c4f3059c27591eb24d6942a0e357ec94c80459f2" + "sha": "4f2c9f752a94042472fc03c5bd9e06e89817d2bd" } } ], From 3d479e4ac478b8a46bbb77c74ca0d08876d74db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 26 Jun 2020 12:17:07 +0200 Subject: [PATCH 25/55] tests: enable Connection API ITs (#309) * tests: enable Connection API ITs The abstract base class for all Connection API integration tests were marked with category IntegrationTest, while all concrete subclasses were marked with ParallelIntegrationTest. This caused them to be excluded from the CI builds. * chore: run formatter --- .../google/cloud/spanner/connection/ITAbstractSpannerTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java index 99fd3d7a10..216ab5ca0d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java @@ -19,7 +19,6 @@ import com.google.cloud.spanner.Database; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.GceTestEnvConfig; -import com.google.cloud.spanner.IntegrationTest; import com.google.cloud.spanner.IntegrationTestEnv; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SpannerExceptionFactory; @@ -43,13 +42,11 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.experimental.categories.Category; /** * Base class for integration tests. This class is located in this package to be able to access * package-private methods of the Connection API */ -@Category(IntegrationTest.class) public abstract class ITAbstractSpannerTest { protected class ITConnectionProvider implements GenericConnectionProvider { public ITConnectionProvider() {} From d0d29f38b39a8d28b4605ac56411839f48142e09 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Fri, 26 Jun 2020 22:43:29 -0700 Subject: [PATCH 26/55] chore: regenerate README versions (#311) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/1b8e3777-2a8a-43ca-858f-1e4587d9e4d1/targets - [ ] To automatically regenerate this PR, check this box. --- README.md | 4 ++-- .../spanner/admin/database/v1/DatabaseAdminClientTest.java | 2 +- .../spanner/admin/instance/v1/InstanceAdminClientTest.java | 2 +- .../java/com/google/cloud/spanner/v1/SpannerClientTest.java | 2 +- synth.metadata | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b433e3accb..3473fc2bb1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file com.google.cloud libraries-bom - 7.0.1 + 8.0.0 pom import @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 1.55.1 + 1.56.0 ``` diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java index a20872cc51..78efb14466 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java @@ -115,7 +115,7 @@ public void setUp() throws IOException { } @After - public void tearDown() { + public void tearDown() throws Exception { client.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java index 72e9d59379..406171d3aa 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java @@ -103,7 +103,7 @@ public void setUp() throws IOException { } @After - public void tearDown() { + public void tearDown() throws Exception { client.close(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java index b0de897cf9..1977873f96 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/v1/SpannerClientTest.java @@ -108,7 +108,7 @@ public void setUp() throws IOException { } @After - public void tearDown() { + public void tearDown() throws Exception { client.close(); } diff --git a/synth.metadata b/synth.metadata index 075a723b25..37d62fcdba 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "39826d2d789ab0f9d9046161627ed34969bdef78" + "sha": "3d479e4ac478b8a46bbb77c74ca0d08876d74db6" } }, { From 5806a814c323537ba236ce32d5ba3c44a8d01a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 30 Jun 2020 01:33:47 +0200 Subject: [PATCH 27/55] test: run integration tests against emulator (#310) * test: run integration tests against emulator * tests: close Spanner after test finishes * tests: do not close Spanner twice * chore: run formatter --- .../integration-tests-against-emulator.sh | 47 +++++++++++++++++ .../integration-tests-against-emulator.yaml | 19 +++++++ .../spanner/testing/RemoteSpannerHelper.java | 1 - .../cloud/spanner/IntegrationTestEnv.java | 25 +++++---- .../connection/ITAbstractSpannerTest.java | 10 ++++ .../connection/it/ITBulkConnectionTest.java | 10 ++-- .../connection/it/ITReadOnlySpannerTest.java | 2 + .../connection/it/ITSqlMusicScriptTest.java | 5 ++ .../connection/it/ITSqlScriptTest.java | 13 +++++ .../connection/it/ITTransactionModeTest.java | 2 +- .../connection/it/ITTransactionRetryTest.java | 51 ++++++++++++++++++- .../spanner/it/ITCommitTimestampTest.java | 7 +++ .../google/cloud/spanner/it/ITWriteTest.java | 2 +- 13 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/integration-tests-against-emulator.sh create mode 100644 .github/workflows/integration-tests-against-emulator.yaml diff --git a/.github/workflows/integration-tests-against-emulator.sh b/.github/workflows/integration-tests-against-emulator.sh new file mode 100644 index 0000000000..2125d5f308 --- /dev/null +++ b/.github/workflows/integration-tests-against-emulator.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.. + +# Fail on any error +set -e + +# Display commands being run +set -x + +export SPANNER_EMULATOR_HOST=localhost:9010 +export GOOGLE_CLOUD_PROJECT=emulator-test-project +echo "Running the Cloud Spanner emulator: $SPANNER_EMULATOR_HOST"; + +# Download the emulator +EMULATOR_VERSION=0.8.0 +wget https://storage.googleapis.com/cloud-spanner-emulator/releases/${EMULATOR_VERSION}/cloud-spanner-emulator_linux_amd64-${EMULATOR_VERSION}.tar.gz +tar zxvf cloud-spanner-emulator_linux_amd64-${EMULATOR_VERSION}.tar.gz +chmod u+x emulator_main + +# Start the emulator +./emulator_main --host_port $SPANNER_EMULATOR_HOST & + +EMULATOR_PID=$! + +# Stop the emulator & clean the environment variable +trap "kill -15 $EMULATOR_PID; unset SPANNER_EMULATOR_HOST; unset GOOGLE_CLOUD_PROJECT; echo \"Cleanup the emulator\";" EXIT + +mvn -B -Dspanner.testenv.instance="" \ + -Penable-integration-tests \ + -DtrimStackTrace=false \ + -Dclirr.skip=true \ + -Denforcer.skip=true \ + -fae \ + verify diff --git a/.github/workflows/integration-tests-against-emulator.yaml b/.github/workflows/integration-tests-against-emulator.yaml new file mode 100644 index 0000000000..ac27f8e17e --- /dev/null +++ b/.github/workflows/integration-tests-against-emulator.yaml @@ -0,0 +1,19 @@ +on: + push: + branches: + - master + pull_request: +name: integration-tests-against-emulator +jobs: + units: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: 8 + - run: java -version + - run: .kokoro/build.sh + - run: sh .github/workflows/integration-tests-against-emulator.sh + env: + JOB_TYPE: test diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/RemoteSpannerHelper.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/RemoteSpannerHelper.java index 2ab5635431..f20354950f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/RemoteSpannerHelper.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/RemoteSpannerHelper.java @@ -129,7 +129,6 @@ public void cleanUp() { } } logger.log(Level.INFO, "Dropped {0} test database(s)", numDropped); - client.close(); } /** diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index f643c6021e..b67f970273 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -162,17 +162,22 @@ private void initializeInstance(InstanceId instanceId) { } private void cleanUpInstance() { - if (isOwnedInstance) { - // Delete the instance, which implicitly drops all databases in it. - try { - logger.log(Level.FINE, "Deleting test instance {0}", testHelper.getInstanceId()); - instanceAdminClient.deleteInstance(testHelper.getInstanceId().getInstance()); - logger.log(Level.INFO, "Deleted test instance {0}", testHelper.getInstanceId()); - } catch (SpannerException e) { - logger.log(Level.SEVERE, "Failed to delete test instance " + testHelper.getInstanceId(), e); + try { + if (isOwnedInstance) { + // Delete the instance, which implicitly drops all databases in it. + try { + logger.log(Level.FINE, "Deleting test instance {0}", testHelper.getInstanceId()); + instanceAdminClient.deleteInstance(testHelper.getInstanceId().getInstance()); + logger.log(Level.INFO, "Deleted test instance {0}", testHelper.getInstanceId()); + } catch (SpannerException e) { + logger.log( + Level.SEVERE, "Failed to delete test instance " + testHelper.getInstanceId(), e); + } + } else { + testHelper.cleanUp(); } - } else { - testHelper.cleanUp(); + } finally { + testHelper.getClient().close(); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java index 216ab5ca0d..fae463ceb1 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ITAbstractSpannerTest.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner.connection; +import com.google.cloud.NoCredentials; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.GceTestEnvConfig; @@ -39,6 +40,7 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -177,6 +179,9 @@ public static StringBuilder extractConnectionUrl(SpannerOptions options, Databas url.append(options.getHost().substring(options.getHost().indexOf(':') + 1)); } url.append("/").append(database.getId().getName()); + if (options.getCredentials() == NoCredentials.getInstance()) { + url.append(";usePlainText=true"); + } return url; } @@ -185,6 +190,11 @@ public static void setup() { database = env.getTestHelper().createTestDatabase(); } + @AfterClass + public static void teardown() { + ConnectionOptions.closeSpanner(); + } + /** * Creates a new default connection to a test database. Use the method {@link * ITAbstractSpannerTest#appendConnectionUri(StringBuilder)} to append additional connection diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java index 7a8091e0d4..dac9efc6b8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITBulkConnectionTest.java @@ -20,7 +20,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; -import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.IntegrationTest; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.connection.ITAbstractSpannerTest; @@ -35,8 +35,12 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Test opening multiple generic (not JDBC) Spanner connections. */ -@Category(ParallelIntegrationTest.class) +/** + * Test opening multiple generic (not JDBC) Spanner connections. This test should not be run in + * parallel with other tests, as it tries to close all active connections, and should not try to + * close connections of other integration tests. + */ +@Category(IntegrationTest.class) @RunWith(JUnit4.class) public class ITBulkConnectionTest extends ITAbstractSpannerTest { private static final int NUMBER_OF_TEST_CONNECTIONS = 250; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java index ae94e9781b..db83349232 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Mutation; @@ -168,6 +169,7 @@ public void testStatementTimeoutAutocommit() { @Test public void testAnalyzeQuery() { + assumeFalse("analyze query is not supported on the emulator", env.getTestHelper().isEmulator()); try (ITConnection connection = createConnection()) { for (QueryAnalyzeMode mode : QueryAnalyzeMode.values()) { try (ResultSet rs = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java index b213ed3536..5f239f2c9e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlMusicScriptTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assume.assumeFalse; import com.google.cloud.spanner.AbortedDueToConcurrentModificationException; import com.google.cloud.spanner.Mutation; @@ -58,6 +59,10 @@ public void test01_RunScript() throws Exception { @Test public void test02_RunAbortedTest() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); + final long SINGER_ID = 2L; final long VENUE_ID = 68L; final long NUMBER_OF_SINGERS = 30L; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java index 6f343d29d5..9ff245ffe5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITSqlScriptTest.java @@ -16,7 +16,9 @@ package com.google.cloud.spanner.connection.it; +import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.connection.ITAbstractSpannerTest; import com.google.cloud.spanner.connection.SqlScriptVerifier; import com.google.cloud.spanner.connection.SqlScriptVerifier.SpannerGenericConnection; @@ -73,6 +75,12 @@ public void test02_InsertTestData() throws Exception { SpannerGenericConnection.of(connection), INSERT_AND_VERIFY_TEST_DATA, SqlScriptVerifier.class); + } catch (SpannerException e) { + if (env.getTestHelper().isEmulator() && e.getErrorCode() == ErrorCode.ALREADY_EXISTS) { + // Errors in a transaction are 'sticky' on the emulator, so any query in the same + // transaction will return the same error as the error generated by a previous (update) + // statement. + } } } @@ -93,6 +101,11 @@ public void test04_TestGetCommitTimestamp() throws Exception { SpannerGenericConnection.of(connection), TEST_GET_COMMIT_TIMESTAMP, SqlScriptVerifier.class); + } catch (SpannerException e) { + if (env.getTestHelper().isEmulator() && e.getErrorCode() == ErrorCode.INVALID_ARGUMENT) { + // Errors in a transaction are 'sticky' on the emulator, so any query in the same + // transaction will return the same error as the error generated by a previous statement. + } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java index 681690e50d..3874f595ba 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionModeTest.java @@ -42,7 +42,7 @@ public class ITTransactionModeTest extends ITAbstractSpannerTest { @Override public void appendConnectionUri(StringBuilder uri) { - uri.append("?autocommit=false"); + uri.append(";autocommit=false"); } @Override diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java index 05fb54a791..60e85c7858 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assume.assumeFalse; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AbortedDueToConcurrentModificationException; @@ -315,7 +316,7 @@ public void testNextCallAborted() { 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')")); // do a query - try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM TEST"))) { + try (ResultSet rs = connection.executeQuery(Statement.of("SELECT * FROM TEST ORDER BY ID"))) { // the first record should be accessible without any problems assertThat(rs.next(), is(true)); assertThat(rs.getLong("ID"), is(equalTo(1L))); @@ -490,6 +491,9 @@ public void testAbortWithResultSetFullyConsumed() { @Test public void testAbortWithConcurrentInsert() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) { @@ -524,6 +528,9 @@ public void testAbortWithConcurrentInsert() { @Test public void testAbortWithConcurrentDelete() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records try (ITConnection connection = createConnection()) { @@ -562,6 +569,9 @@ public void testAbortWithConcurrentDelete() { @Test public void testAbortWithConcurrentUpdate() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records try (ITConnection connection = createConnection()) { @@ -605,6 +615,9 @@ public void testAbortWithConcurrentUpdate() { */ @Test public void testAbortWithUnseenConcurrentInsert() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) { @@ -652,6 +665,9 @@ public void testAbortWithUnseenConcurrentInsert() { */ @Test public void testAbortWithUnseenConcurrentInsertAbortOnNext() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); // no calls to next(), this should succeed assertThat(testAbortWithUnseenConcurrentInsertAbortOnNext(0) >= 1, is(true)); // 1 call to next() should also succeed, as there were 2 records in the original result set @@ -673,6 +689,9 @@ public void testAbortWithUnseenConcurrentInsertAbortOnNext() { private int testAbortWithUnseenConcurrentInsertAbortOnNext(int callsToNext) throws AbortedDueToConcurrentModificationException { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); int retries = 0; clearTable(); clearStatistics(); @@ -732,6 +751,9 @@ private int testAbortWithUnseenConcurrentInsertAbortOnNext(int callsToNext) */ @Test public void testAbortWithConcurrentInsertAndContinue() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) { @@ -941,6 +963,9 @@ protected boolean shouldAbort(String statement, ExecutionStep step) { */ @Test public void testNestedAbortWithConcurrentInsert() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0) { private boolean alreadyAborted = false; @@ -1003,6 +1028,9 @@ protected boolean shouldAbort(String statement, ExecutionStep step) { */ @Test public void testAbortWithDifferentUpdateCount() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records try (ITConnection connection = createConnection()) { @@ -1048,6 +1076,9 @@ public void testAbortWithDifferentUpdateCount() { */ @Test public void testAbortWithExceptionOnSelect() { + assumeFalse( + "resume after error in transaction is not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records try (ITConnection connection = createConnection()) { @@ -1097,6 +1128,9 @@ public void testAbortWithExceptionOnSelect() { */ @Test public void testAbortWithExceptionOnSelectAndConcurrentModification() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); boolean abortedDueToConcurrentModification = false; AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records @@ -1164,6 +1198,9 @@ public void testAbortWithExceptionOnSelectAndConcurrentModification() { */ @Test public void testAbortWithExceptionOnInsertAndConcurrentModification() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); boolean abortedDueToConcurrentModification = false; AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records @@ -1230,6 +1267,9 @@ public void testAbortWithExceptionOnInsertAndConcurrentModification() { */ @Test public void testAbortWithDroppedTableConcurrentModification() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); boolean abortedDueToConcurrentModification = false; AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records @@ -1292,6 +1332,9 @@ public void testAbortWithDroppedTableConcurrentModification() { */ @Test public void testAbortWithInsertOnDroppedTableConcurrentModification() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); boolean abortedDueToConcurrentModification = false; AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records @@ -1351,6 +1394,9 @@ public void testAbortWithInsertOnDroppedTableConcurrentModification() { */ @Test public void testAbortWithCursorHalfwayDroppedTableConcurrentModification() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); boolean abortedDueToConcurrentModification = false; AbortInterceptor interceptor = new AbortInterceptor(0); // first insert two test records @@ -1503,6 +1549,9 @@ public void testRetryHighAbortRate() { @Test public void testAbortWithConcurrentInsertOnEmptyTable() { + assumeFalse( + "concurrent transactions are not supported on the emulator", + env.getTestHelper().isEmulator()); AbortInterceptor interceptor = new AbortInterceptor(0); try (ITConnection connection = createConnection(interceptor, new CountTransactionRetryListener())) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java index 92d5aa3c6e..84d1a67559 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCommitTimestampTest.java @@ -34,11 +34,13 @@ import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TimestampBound; import com.google.cloud.spanner.Value; +import com.google.cloud.spanner.connection.ConnectionOptions; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.concurrent.ExecutionException; import org.junit.After; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -77,6 +79,11 @@ public static void setUp() { databaseId = db.getId().getDatabase(); } + @AfterClass + public static void teardown() { + ConnectionOptions.closeSpanner(); + } + @After public void deleteAllTestRecords() { client.write(ImmutableList.of(Mutation.delete("T", KeySet.all()))); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java index 1f084d5fdb..d7a007eaf6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITWriteTest.java @@ -612,7 +612,7 @@ public void incorrectType() { fail("Expected exception"); } catch (SpannerException ex) { assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); - assertThat(ex.getMessage()).contains("Expected STRING"); + assertThat(ex.getMessage()).contains("STRING"); } } From 948392583233797486f3731468c091e8fb0848b1 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2020 14:25:48 +1000 Subject: [PATCH 28/55] chore: release 1.57.0 (#306) * updated CHANGELOG.md [ci skip] * updated README.md [ci skip] * updated versions.txt [ci skip] * updated samples/pom.xml [ci skip] * updated google-cloud-spanner-bom/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-v1/pom.xml [ci skip] * updated samples/snapshot/pom.xml [ci skip] * updated google-cloud-spanner/pom.xml [ci skip] * updated grpc-google-cloud-spanner-v1/pom.xml [ci skip] * updated pom.xml [ci skip] * updated samples/install-without-bom/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated samples/snippets/pom.xml Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 13 files changed, 48 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c54d6bfd..9c172a8492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.57.0](https://www.github.com/googleapis/java-spanner/compare/v1.56.0...v1.57.0) (2020-06-29) + + +### Features + +* **deps:** adopt flatten plugin and google-cloud-shared-dependencies and update ExecutorProvider ([#302](https://www.github.com/googleapis/java-spanner/issues/302)) ([5aef6c3](https://www.github.com/googleapis/java-spanner/commit/5aef6c3f6d3e9564cb8728ad51718feb6b64475a)) + ## [1.56.0](https://www.github.com/googleapis/java-spanner/compare/v1.55.1...v1.56.0) (2020-06-17) diff --git a/README.md b/README.md index 3473fc2bb1..bb5b4b043b 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-spanner:1.56.0' +compile 'com.google.cloud:google-cloud-spanner:1.57.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.56.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.57.0" ``` [//]: # ({x-version-update-end}) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index be01d7aded..9e94ad8c5d 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.56.1-SNAPSHOT + 1.57.0 pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.cloud google-cloud-spanner - 1.56.1-SNAPSHOT + 1.57.0 com.google.cloud google-cloud-spanner test-jar - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 206ed5e316..060cb88ced 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.56.1-SNAPSHOT + 1.57.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 4a334c1b1f..fa9c667359 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index b617c08984..07c1cb53eb 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index aa85115cf4..7baf5c3120 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/pom.xml b/pom.xml index a899259548..45003534c0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.56.1-SNAPSHOT + 1.57.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 com.google.cloud google-cloud-spanner - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index ef12a1b97b..49d8cf6b52 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.56.1-SNAPSHOT + 1.57.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 42295de97e..998b7594ec 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.56.1-SNAPSHOT + 1.57.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index db572f326f..2ef621ce2c 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.56.1-SNAPSHOT + 1.57.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 2db2bd7169..833c082962 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.56.1-SNAPSHOT + 1.57.0 diff --git a/versions.txt b/versions.txt index 14ce0a2ca2..ba2b2e5e35 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.1-SNAPSHOT -proto-google-cloud-spanner-v1:1.56.0:1.56.1-SNAPSHOT -proto-google-cloud-spanner-admin-database-v1:1.56.0:1.56.1-SNAPSHOT -grpc-google-cloud-spanner-v1:1.56.0:1.56.1-SNAPSHOT -grpc-google-cloud-spanner-admin-instance-v1:1.56.0:1.56.1-SNAPSHOT -grpc-google-cloud-spanner-admin-database-v1:1.56.0:1.56.1-SNAPSHOT -google-cloud-spanner:1.56.0:1.56.1-SNAPSHOT \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.0 +proto-google-cloud-spanner-v1:1.57.0:1.57.0 +proto-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 +grpc-google-cloud-spanner-v1:1.57.0:1.57.0 +grpc-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.0 +grpc-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 +google-cloud-spanner:1.57.0:1.57.0 \ No newline at end of file From df47c13a4c00bdf5e6eafa01bbb64c12a96d7fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 30 Jun 2020 17:25:29 +0200 Subject: [PATCH 29/55] perf: use streaming RPC for PDML (#287) * perf: use streaming RPC for PDML * fix: reset resume token for each tx * cleanup: remove test code * fix: retry depening on resume token * fix: remove unused attempt param * fix: fix check for resume token * fix: keep track of total timeout * fix: clirr build failure * cleanup: add comments + remove unused code * tests: add missing exec time * chore: run formatter * chore: remove unnecessary null check * tests: add missing exec time --- .../clirr-ignored-differences.xml | 6 + .../spanner/PartitionedDMLTransaction.java | 119 +++++++++++++----- .../com/google/cloud/spanner/SessionImpl.java | 3 +- .../spanner/SpannerExceptionFactory.java | 10 +- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 25 ++++ .../cloud/spanner/spi/v1/SpannerRpc.java | 5 + .../cloud/spanner/DatabaseClientImplTest.java | 16 ++- .../cloud/spanner/MockSpannerServiceImpl.java | 36 +++++- 8 files changed, 177 insertions(+), 43 deletions(-) diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 4a089a5682..a10e096af4 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -176,4 +176,10 @@ com.google.api.gax.retrying.RetrySettings getPartitionedDmlRetrySettings() + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.gax.rpc.ServerStream executeStreamingPartitionedDml(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, org.threeten.bp.Duration) + diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java index fdde68989f..638c567a03 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java @@ -18,20 +18,32 @@ import static com.google.common.base.Preconditions.checkState; +import com.google.api.gax.grpc.GrpcStatusCode; +import com.google.api.gax.rpc.ServerStream; +import com.google.api.gax.rpc.UnavailableException; import com.google.cloud.spanner.SessionImpl.SessionTransaction; import com.google.cloud.spanner.spi.v1.SpannerRpc; +import com.google.common.base.Stopwatch; import com.google.protobuf.ByteString; import com.google.spanner.v1.BeginTransactionRequest; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryMode; +import com.google.spanner.v1.PartialResultSet; import com.google.spanner.v1.Transaction; import com.google.spanner.v1.TransactionOptions; import com.google.spanner.v1.TransactionSelector; +import io.grpc.Status.Code; import java.util.Map; -import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.threeten.bp.Duration; +import org.threeten.bp.temporal.ChronoUnit; /** Partitioned DML transaction for bulk updates and deletes. */ class PartitionedDMLTransaction implements SessionTransaction { + private static final Logger log = Logger.getLogger(PartitionedDMLTransaction.class.getName()); + private final SessionImpl session; private final SpannerRpc rpc; private volatile boolean isValid = true; @@ -60,41 +72,88 @@ private ByteString initTransaction() { /** * Executes the {@link Statement} using a partitioned dml transaction with automatic retry if the - * transaction was aborted. + * transaction was aborted. The update method uses the ExecuteStreamingSql RPC to execute the + * statement, and will retry the stream if an {@link UnavailableException} is thrown, using the + * last seen resume token if the server returns any. */ - long executePartitionedUpdate(final Statement statement) { + long executeStreamingPartitionedUpdate(final Statement statement, Duration timeout) { checkState(isValid, "Partitioned DML has been invalidated by a new operation on the session"); - Callable callable = - new Callable() { - @Override - public com.google.spanner.v1.ResultSet call() throws Exception { - ByteString transactionId = initTransaction(); - final ExecuteSqlRequest.Builder builder = - ExecuteSqlRequest.newBuilder() - .setSql(statement.getSql()) - .setQueryMode(QueryMode.NORMAL) - .setSession(session.getName()) - .setTransaction(TransactionSelector.newBuilder().setId(transactionId).build()); - Map stmtParameters = statement.getParameters(); - if (!stmtParameters.isEmpty()) { - com.google.protobuf.Struct.Builder paramsBuilder = builder.getParamsBuilder(); - for (Map.Entry param : stmtParameters.entrySet()) { - paramsBuilder.putFields(param.getKey(), param.getValue().toProto()); - builder.putParamTypes(param.getKey(), param.getValue().getType().toProto()); + log.log(Level.FINER, "Starting PartitionedUpdate statement"); + boolean foundStats = false; + long updateCount = 0L; + Duration remainingTimeout = timeout; + Stopwatch stopWatch = Stopwatch.createStarted(); + try { + // Loop to catch AbortedExceptions. + while (true) { + ByteString resumeToken = ByteString.EMPTY; + try { + ByteString transactionId = initTransaction(); + final ExecuteSqlRequest.Builder builder = + ExecuteSqlRequest.newBuilder() + .setSql(statement.getSql()) + .setQueryMode(QueryMode.NORMAL) + .setSession(session.getName()) + .setTransaction(TransactionSelector.newBuilder().setId(transactionId).build()); + Map stmtParameters = statement.getParameters(); + if (!stmtParameters.isEmpty()) { + com.google.protobuf.Struct.Builder paramsBuilder = builder.getParamsBuilder(); + for (Map.Entry param : stmtParameters.entrySet()) { + paramsBuilder.putFields(param.getKey(), param.getValue().toProto()); + builder.putParamTypes(param.getKey(), param.getValue().getType().toProto()); + } + } + while (true) { + remainingTimeout = + remainingTimeout.minus(stopWatch.elapsed(TimeUnit.MILLISECONDS), ChronoUnit.MILLIS); + try { + builder.setResumeToken(resumeToken); + ServerStream stream = + rpc.executeStreamingPartitionedDml( + builder.build(), session.getOptions(), remainingTimeout); + for (PartialResultSet rs : stream) { + if (rs.getResumeToken() != null && !ByteString.EMPTY.equals(rs.getResumeToken())) { + resumeToken = rs.getResumeToken(); + } + if (rs.hasStats()) { + foundStats = true; + updateCount += rs.getStats().getRowCountLowerBound(); + } + } + break; + } catch (UnavailableException e) { + // Retry the stream in the same transaction if the stream breaks with + // UnavailableException and we have a resume token. Otherwise, we just retry the + // entire transaction. + if (!ByteString.EMPTY.equals(resumeToken)) { + log.log( + Level.FINER, + "Retrying PartitionedDml stream using resume token '" + + resumeToken.toStringUtf8() + + "' because of broken stream", + e); + } else { + throw new com.google.api.gax.rpc.AbortedException( + e, GrpcStatusCode.of(Code.ABORTED), true); } } - return rpc.executePartitionedDml(builder.build(), session.getOptions()); } - }; - com.google.spanner.v1.ResultSet resultSet = - SpannerRetryHelper.runTxWithRetriesOnAborted( - callable, rpc.getPartitionedDmlRetrySettings()); - if (!resultSet.hasStats()) { - throw new IllegalArgumentException( - "Partitioned DML response missing stats possibly due to non-DML statement as input"); + break; + } catch (com.google.api.gax.rpc.AbortedException e) { + // Retry using a new transaction but with the same session if the transaction is aborted. + log.log(Level.FINER, "Retrying PartitionedDml transaction after AbortedException", e); + } + } + if (!foundStats) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, + "Partitioned DML response missing stats possibly due to non-DML statement as input"); + } + log.log(Level.FINER, "Finished PartitionedUpdate statement"); + return updateCount; + } catch (Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); } - // For partitioned DML, using the row count lower bound. - return resultSet.getStats().getRowCountLowerBound(); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java index d1de6e204f..b865efa2d9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java @@ -105,7 +105,8 @@ public String getName() { public long executePartitionedUpdate(Statement stmt) { setActive(null); PartitionedDMLTransaction txn = new PartitionedDMLTransaction(this, spanner.getRpc()); - return txn.executePartitionedUpdate(stmt); + return txn.executeStreamingPartitionedUpdate( + stmt, spanner.getOptions().getPartitionedDmlTimeout()); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerExceptionFactory.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerExceptionFactory.java index e9ca06e233..a86d5463c9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerExceptionFactory.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerExceptionFactory.java @@ -18,6 +18,7 @@ import com.google.api.gax.grpc.GrpcStatusCode; import com.google.api.gax.rpc.ApiException; +import com.google.api.gax.rpc.WatchdogTimeoutException; import com.google.cloud.spanner.SpannerException.DoNotConstructDirectly; import com.google.common.base.MoreObjects; import com.google.common.base.Predicate; @@ -212,7 +213,14 @@ private static SpannerException newSpannerExceptionPreformatted( } private static SpannerException fromApiException(ApiException exception) { - Status.Code code = ((GrpcStatusCode) exception.getStatusCode()).getTransportCode(); + Status.Code code; + if (exception.getStatusCode() instanceof GrpcStatusCode) { + code = ((GrpcStatusCode) exception.getStatusCode()).getTransportCode(); + } else if (exception instanceof WatchdogTimeoutException) { + code = Status.Code.DEADLINE_EXCEEDED; + } else { + code = Status.Code.UNKNOWN; + } ErrorCode errorCode = ErrorCode.fromGrpcStatus(Status.fromCode(code)); if (exception.getCause() != null) { return SpannerExceptionFactory.newSpannerException( diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 890aebed2d..164d3ab7e1 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -38,6 +38,7 @@ import com.google.api.gax.rpc.InstantiatingWatchdogProvider; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.ResponseObserver; +import com.google.api.gax.rpc.ServerStream; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.StreamController; import com.google.api.gax.rpc.TransportChannelProvider; @@ -54,6 +55,7 @@ import com.google.cloud.spanner.admin.database.v1.stub.GrpcDatabaseAdminStub; import com.google.cloud.spanner.admin.instance.v1.stub.GrpcInstanceAdminStub; import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStub; +import com.google.cloud.spanner.spi.v1.SpannerRpc.Option; import com.google.cloud.spanner.v1.stub.GrpcSpannerStub; import com.google.cloud.spanner.v1.stub.SpannerStub; import com.google.cloud.spanner.v1.stub.SpannerStubSettings; @@ -359,6 +361,21 @@ public GapicSpannerRpc(final SpannerOptions options) { .setStreamWatchdogProvider(watchdogProvider) .executeSqlSettings() .setRetrySettings(partitionedDmlRetrySettings); + // The stream watchdog will by default only check for a timeout every 10 seconds, so if the + // timeout is less than 10 seconds, it would be ignored for the first 10 seconds unless we + // also change the StreamWatchdogCheckInterval. + if (options + .getPartitionedDmlTimeout() + .dividedBy(10L) + .compareTo(pdmlSettings.getStreamWatchdogCheckInterval()) + < 0) { + pdmlSettings.setStreamWatchdogCheckInterval( + options.getPartitionedDmlTimeout().dividedBy(10)); + pdmlSettings.setStreamWatchdogProvider( + pdmlSettings + .getStreamWatchdogProvider() + .withCheckInterval(pdmlSettings.getStreamWatchdogCheckInterval())); + } this.partitionedDmlStub = GrpcSpannerStub.create(pdmlSettings.build()); this.instanceAdminStub = @@ -1073,6 +1090,14 @@ public RetrySettings getPartitionedDmlRetrySettings() { return partitionedDmlRetrySettings; } + @Override + public ServerStream executeStreamingPartitionedDml( + ExecuteSqlRequest request, Map options, Duration timeout) { + GrpcCallContext context = newCallContext(options, request.getSession()); + context = context.withStreamWaitTimeout(timeout); + return partitionedDmlStub.executeStreamingSqlCallable().call(request, context); + } + @Override public StreamingCall executeQuery( ExecuteSqlRequest request, ResultStreamConsumer consumer, @Nullable Map options) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 31dc209c91..5b6c6756d9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -20,6 +20,7 @@ import com.google.api.core.InternalApi; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ServerStream; import com.google.cloud.ServiceRpc; import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.admin.database.v1.stub.DatabaseAdminStub; @@ -58,6 +59,7 @@ import java.util.List; import java.util.Map; import javax.annotation.Nullable; +import org.threeten.bp.Duration; /** * Abstracts remote calls to the Cloud Spanner service. Typically end-consumer code will never use @@ -286,6 +288,9 @@ StreamingCall read( RetrySettings getPartitionedDmlRetrySettings(); + ServerStream executeStreamingPartitionedDml( + ExecuteSqlRequest request, @Nullable Map options, Duration timeout); + StreamingCall executeQuery( ExecuteSqlRequest request, ResultStreamConsumer consumer, @Nullable Map options); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index 7bb05964fb..4f98f59104 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -169,7 +169,7 @@ public void testExecutePartitionedDmlAborted() { * A valid query that returns a {@link ResultSet} should not be accepted by a partitioned dml * transaction. */ - @Test(expected = IllegalArgumentException.class) + @Test(expected = SpannerException.class) public void testExecutePartitionedDmlWithQuery() { DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); @@ -234,20 +234,22 @@ public Void run(TransactionContext transaction) { @Test public void testPartitionedDmlWithLowerTimeout() { - mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(1000, 0)); + mockSpanner.setExecuteStreamingSqlExecutionTime( + SimulatedExecutionTime.ofMinimumAndRandomTime(1000, 0)); SpannerOptions.Builder builder = SpannerOptions.newBuilder() .setProjectId(TEST_PROJECT) .setChannelProvider(channelProvider) .setCredentials(NoCredentials.getInstance()); // Set PDML timeout value. - builder.setPartitionedDmlTimeout(Duration.ofMillis(100L)); + builder.setPartitionedDmlTimeout(Duration.ofMillis(10L)); try (Spanner spanner = builder.build().getService()) { DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); - assertThat(spanner.getOptions().getPartitionedDmlTimeout()) - .isEqualTo(Duration.ofMillis(100L)); + assertThat(spanner.getOptions().getPartitionedDmlTimeout()).isEqualTo(Duration.ofMillis(10L)); // PDML should timeout with these settings. + mockSpanner.setExecuteSqlExecutionTime( + SimulatedExecutionTime.ofMinimumAndRandomTime(1000, 0)); try { client.executePartitionedUpdate(UPDATE_STATEMENT); fail("expected DEADLINE_EXCEEDED"); @@ -275,7 +277,8 @@ public Long run(TransactionContext transaction) { @Test public void testPartitionedDmlWithHigherTimeout() { - mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(100, 0)); + mockSpanner.setExecuteStreamingSqlExecutionTime( + SimulatedExecutionTime.ofMinimumAndRandomTime(100, 0)); SpannerOptions.Builder builder = SpannerOptions.newBuilder() .setProjectId(TEST_PROJECT) @@ -307,6 +310,7 @@ public void testPartitionedDmlWithHigherTimeout() { long updateCount = client.executePartitionedUpdate(UPDATE_STATEMENT); // Normal DML should timeout as it should use the ExecuteSQL RPC settings. + mockSpanner.setExecuteSqlExecutionTime(SimulatedExecutionTime.ofMinimumAndRandomTime(100, 0)); try { client .readWriteTransaction() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java index 069242d5a7..164a8842c7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java @@ -994,10 +994,27 @@ public void executeStreamingSql( } sessionLastUsed.put(session.getName(), Instant.now()); try { + Statement statement = + buildStatement(request.getSql(), request.getParamTypesMap(), request.getParams()); + ByteString transactionId = getTransactionId(session, request.getTransaction()); + boolean isPartitioned = isPartitionedDmlTransaction(transactionId); + if (isPartitioned) { + StatementResult firstRes = getResult(statement); + switch (firstRes.getType()) { + case EXCEPTION: + throw firstRes.getException(); + case UPDATE_COUNT: + returnPartialResultSet( + session, 0L, !isPartitioned, responseObserver, request.getTransaction(), false); + break; + case RESULT_SET: + default: + break; + } + } executeStreamingSqlExecutionTime.simulateExecutionTime( exceptions, stickyGlobalExceptions, freezeLock); // Get or start transaction - ByteString transactionId = getTransactionId(session, request.getTransaction()); if (!request.getPartitionToken().isEmpty()) { List tokens = partitionTokens.get(partitionKey(session.getName(), transactionId)); @@ -1009,8 +1026,6 @@ public void executeStreamingSql( } } simulateAbort(session, transactionId); - Statement statement = - buildStatement(request.getSql(), request.getParamTypesMap(), request.getParams()); StatementResult res = getResult(statement); switch (res.getType()) { case EXCEPTION: @@ -1020,7 +1035,6 @@ public void executeStreamingSql( res.getResultSet(), transactionId, request.getTransaction(), responseObserver); break; case UPDATE_COUNT: - boolean isPartitioned = isPartitionedDmlTransaction(transactionId); if (isPartitioned) { commitTransaction(transactionId); } @@ -1281,6 +1295,16 @@ private void returnPartialResultSet( boolean exact, StreamObserver responseObserver, TransactionSelector transaction) { + returnPartialResultSet(session, updateCount, exact, responseObserver, transaction, true); + } + + private void returnPartialResultSet( + Session session, + Long updateCount, + boolean exact, + StreamObserver responseObserver, + TransactionSelector transaction, + boolean complete) { Field field = Field.newBuilder() .setName("UPDATE_COUNT") @@ -1307,7 +1331,9 @@ private void returnPartialResultSet( .setStats(ResultSetStats.newBuilder().setRowCountLowerBound(updateCount).build()) .build()); } - responseObserver.onCompleted(); + if (complete) { + responseObserver.onCompleted(); + } } private boolean isPartitionedDmlTransaction(ByteString transactionId) { From 965e95e70ccd9c62abd6513b0011aab136e48e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 30 Jun 2020 17:25:57 +0200 Subject: [PATCH 30/55] feat: support setting compression option (#192) * feat: support setting compression option * fix: use correct encoding header * fix: add project id * docs: fix typo + missing end tag * chore: resolve merge conflicts * tests: fix test failure on emulator --- .../google/cloud/spanner/SpannerOptions.java | 33 +++++++++ .../spanner/spi/v1/EncodingInterceptor.java | 50 ++++++++++++++ .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 10 ++- .../spi/v1/SpannerInterceptorProvider.java | 11 +++ .../cloud/spanner/SpannerOptionsTest.java | 31 +++++++++ .../spanner/it/ITSpannerOptionsTest.java | 68 +++++++++++++++++++ 6 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/EncodingInterceptor.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 7e895524dc..edeadb7b90 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -49,6 +49,8 @@ import com.google.spanner.admin.database.v1.RestoreDatabaseRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; import io.grpc.CallCredentials; +import io.grpc.CompressorRegistry; +import io.grpc.ExperimentalApi; import io.grpc.ManagedChannelBuilder; import java.io.IOException; import java.net.MalformedURLException; @@ -58,6 +60,7 @@ import java.util.Map.Entry; import java.util.Set; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.threeten.bp.Duration; /** Options for the Cloud Spanner service. */ @@ -104,6 +107,7 @@ public class SpannerOptions extends ServiceOptions { private final Map mergedQueryOptions; private final CallCredentialsProvider callCredentialsProvider; + private final String compressorName; /** * Interface that can be used to provide {@link CallCredentials} instead of {@link Credentials} to @@ -174,6 +178,7 @@ private SpannerOptions(Builder builder) { this.mergedQueryOptions = ImmutableMap.copyOf(merged); } callCredentialsProvider = builder.callCredentialsProvider; + compressorName = builder.compressorName; } /** @@ -238,6 +243,7 @@ public static class Builder private boolean autoThrottleAdministrativeRequests = false; private Map defaultQueryOptions = new HashMap<>(); private CallCredentialsProvider callCredentialsProvider; + private String compressorName; private String emulatorHost = System.getenv("SPANNER_EMULATOR_HOST"); private Builder() { @@ -309,6 +315,7 @@ private Builder() { this.autoThrottleAdministrativeRequests = options.autoThrottleAdministrativeRequests; this.defaultQueryOptions = options.defaultQueryOptions; this.callCredentialsProvider = options.callCredentialsProvider; + this.compressorName = options.compressorName; this.channelProvider = options.channelProvider; this.channelConfigurator = options.channelConfigurator; this.interceptorProvider = options.interceptorProvider; @@ -558,6 +565,28 @@ public Builder setCallCredentialsProvider(CallCredentialsProvider callCredential return this; } + /** + * Sets the compression to use for all gRPC calls. The compressor must be a valid name known in + * the {@link CompressorRegistry}. + * + *

Supported values are: + * + *

    + *
  • gzip: Enable gzip compression + *
  • identity: Disable compression + *
  • null: Use default compression + *
+ */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1704") + public Builder setCompressorName(@Nullable String compressorName) { + Preconditions.checkArgument( + compressorName == null + || CompressorRegistry.getDefaultInstance().lookupCompressor(compressorName) != null, + String.format("%s is not a known compressor", compressorName)); + this.compressorName = compressorName; + return this; + } + /** * Specifying this will allow the client to prefetch up to {@code prefetchChunks} {@code * PartialResultSet} chunks for each read and query. The data size of each chunk depends on the @@ -690,6 +719,10 @@ public CallCredentialsProvider getCallCredentialsProvider() { return callCredentialsProvider; } + public String getCompressorName() { + return compressorName; + } + /** Returns the default query options to use for the specific database. */ public QueryOptions getDefaultQueryOptions(DatabaseId databaseId) { // Use the specific query options for the database if any have been specified. These have diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/EncodingInterceptor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/EncodingInterceptor.java new file mode 100644 index 0000000000..a30135533a --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/EncodingInterceptor.java @@ -0,0 +1,50 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.spanner.spi.v1; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.Metadata.Key; +import io.grpc.MethodDescriptor; + +class EncodingInterceptor implements ClientInterceptor { + private static final String RESPONSE_ENCODING_KEY_NAME = "x-response-encoding"; + private static final Key RESPONSE_ENCODING_KEY = + Metadata.Key.of(RESPONSE_ENCODING_KEY_NAME, Metadata.ASCII_STRING_MARSHALLER); + + private final String encoding; + + EncodingInterceptor(String encoding) { + this.encoding = encoding; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor method, CallOptions callOptions, Channel next) { + return new ForwardingClientCall.SimpleForwardingClientCall( + next.newCall(method, callOptions)) { + @Override + public void start(Listener responseListener, Metadata headers) { + headers.put(RESPONSE_ENCODING_KEY, encoding); + super.start(responseListener, headers); + } + }; + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 164d3ab7e1..6f383b1f79 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -231,6 +231,7 @@ private void awaitTermination() throws InterruptedException { private final String projectName; private final SpannerMetadataProvider metadataProvider; private final CallCredentialsProvider callCredentialsProvider; + private final String compressorName; private final Duration waitTimeout = systemProperty(PROPERTY_TIMEOUT_SECONDS, DEFAULT_TIMEOUT_SECONDS); private final Duration idleTimeout = @@ -284,6 +285,7 @@ public GapicSpannerRpc(final SpannerOptions options) { mergedHeaderProvider.getHeaders(), internalHeaderProviderBuilder.getResourceHeaderKey()); this.callCredentialsProvider = options.getCallCredentialsProvider(); + this.compressorName = options.getCompressorName(); // Create a managed executor provider. this.executorProvider = @@ -312,9 +314,11 @@ public GapicSpannerRpc(final SpannerOptions options) { // Then check if SpannerOptions provides an InterceptorProvider. Create a default // SpannerInterceptorProvider if none is provided .setInterceptorProvider( - MoreObjects.firstNonNull( - options.getInterceptorProvider(), - SpannerInterceptorProvider.createDefault())) + SpannerInterceptorProvider.create( + MoreObjects.firstNonNull( + options.getInterceptorProvider(), + SpannerInterceptorProvider.createDefault())) + .withEncoding(compressorName)) .setHeaderProvider(mergedHeaderProvider) .build()); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerInterceptorProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerInterceptorProvider.java index 060f4ca9d1..c262780935 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerInterceptorProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerInterceptorProvider.java @@ -45,6 +45,10 @@ public static SpannerInterceptorProvider createDefault() { return new SpannerInterceptorProvider(defaultInterceptors); } + static SpannerInterceptorProvider create(GrpcInterceptorProvider provider) { + return new SpannerInterceptorProvider(ImmutableList.copyOf(provider.getInterceptors())); + } + public SpannerInterceptorProvider with(ClientInterceptor clientInterceptor) { List interceptors = ImmutableList.builder() @@ -54,6 +58,13 @@ public SpannerInterceptorProvider with(ClientInterceptor clientInterceptor) { return new SpannerInterceptorProvider(interceptors); } + SpannerInterceptorProvider withEncoding(String encoding) { + if (encoding != null) { + return with(new EncodingInterceptor(encoding)); + } + return this; + } + @Override public List getInterceptors() { return clientInterceptors; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java index 96490b94fd..a7538c4ee4 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerOptionsTest.java @@ -505,4 +505,35 @@ public String getOptimizerVersion() { assertThat(options.getDefaultQueryOptions(DatabaseId.of("p", "i", "o"))) .isEqualTo(QueryOptions.newBuilder().setOptimizerVersion("2").build()); } + + @Test + public void testCompressorName() { + assertThat( + SpannerOptions.newBuilder() + .setProjectId("p") + .setCompressorName("gzip") + .build() + .getCompressorName()) + .isEqualTo("gzip"); + assertThat( + SpannerOptions.newBuilder() + .setProjectId("p") + .setCompressorName("identity") + .build() + .getCompressorName()) + .isEqualTo("identity"); + assertThat( + SpannerOptions.newBuilder() + .setProjectId("p") + .setCompressorName(null) + .build() + .getCompressorName()) + .isNull(); + try { + SpannerOptions.newBuilder().setCompressorName("foo"); + fail("missing expected exception"); + } catch (IllegalArgumentException e) { + // ignore, this is the expected exception. + } + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java new file mode 100644 index 0000000000..db8c725fc5 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITSpannerOptionsTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.it; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.Statement; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@Category(ParallelIntegrationTest.class) +@RunWith(JUnit4.class) +public class ITSpannerOptionsTest { + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static Database db; + + @BeforeClass + public static void setUp() throws Exception { + db = env.getTestHelper().createTestDatabase(); + } + + @AfterClass + public static void tearDown() throws Exception { + db.drop(); + } + + @Test + public void testCompression() { + for (String compressorName : new String[] {"gzip", "identity", null}) { + SpannerOptions options = + env.getTestHelper().getOptions().toBuilder().setCompressorName(compressorName).build(); + try (Spanner spanner = options.getService()) { + DatabaseClient client = spanner.getDatabaseClient(db.getId()); + try (ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1 AS COL1"))) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + } + } +} From 462839b625e58e235581b8ba10b398e1d222eaaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 30 Jun 2020 20:45:21 +0200 Subject: [PATCH 31/55] feat: add async api (#81) * feat: add async api * feat: session pool is non-blocking * tests: fix integration tests that assumed tx was blocking Some integration tests started transactions without executing a query, and expected these transactions to fail. However, as the client is now non-blocking up until the first call to ResultSet#next(), no exception would occur. * feat: add read methods support * tests: test async runner * feat: create async runner * tests: centralize some commonly used test objects * feat: keep session checked out until async finishes * fix: fix span test cases after rebase * fix: fix async runner tests * fix: make async runner wait for async operations * examples: add example integration test * examples: add more examples * tests: fix flaky tests * rebase: rebase on current master * fix: run code formatter * feat: add support for poller * tests: support more param types * fix: fix race conditions * feat: return ApiFuture to monitor end of AsyncResultSet * feat: add helper method for create test result sets * feat: add batchUpdateAsync * fix: add ignored interface differences * refactor: use future as waiter in SessionPool * format: run code formatter * tests: fix test case + remove commented code * fix: AsyncResultSet should throw Cancelled * feat: expose DatabaseId.of(String name) * deps: set version to 1.53 to match bom * feat: steps to add async support for tx manager * review: process review comments * chore: remove unused code * clirr: add ignored differences to clirr * fix: call listeners after all rows have been consumed * feat: towards AsyncTransactionManager * fix: session leaks + code format * fix: more session leak fixes * feat: further work on AsyncTransactionManager * fix: fix test failures * fix: fix several race conditions * tests: increase test timeout * feat: further towards AsyncTransactionManager * feat: require executor for transaction functions * revert: remove async connection api from branch * chore: run code formatter * chore: fix flaky test case * tests: fix ITs for emulator * fix: SpannerOptions.toBuilder().host should override emulatorHost * tests: fix potentially hanging test --- .../clirr-ignored-differences.xml | 83 +- .../cloud/spanner/AbstractReadContext.java | 157 ++- .../cloud/spanner/AbstractResultSet.java | 12 +- .../google/cloud/spanner/AsyncResultSet.java | 226 ++++ .../cloud/spanner/AsyncResultSetImpl.java | 586 ++++++++ .../com/google/cloud/spanner/AsyncRunner.java | 59 + .../google/cloud/spanner/AsyncRunnerImpl.java | 81 ++ .../spanner/AsyncTransactionManager.java | 203 +++ .../spanner/AsyncTransactionManagerImpl.java | 167 +++ .../google/cloud/spanner/BatchClientImpl.java | 5 + .../google/cloud/spanner/DatabaseClient.java | 121 ++ .../cloud/spanner/DatabaseClientImpl.java | 30 +- .../com/google/cloud/spanner/DatabaseId.java | 2 +- .../spanner/ForwardingAsyncResultSet.java | 65 + .../cloud/spanner/ForwardingResultSet.java | 21 +- .../cloud/spanner/ForwardingStructReader.java | 146 +- .../com/google/cloud/spanner/Options.java | 34 + .../spanner/PartitionedDMLTransaction.java | 5 + .../com/google/cloud/spanner/ReadContext.java | 31 + .../com/google/cloud/spanner/ResultSets.java | 27 + .../com/google/cloud/spanner/SessionImpl.java | 113 +- .../com/google/cloud/spanner/SessionPool.java | 1176 ++++++++++++----- .../SessionPoolAsyncTransactionManager.java | 216 +++ .../cloud/spanner/SessionPoolOptions.java | 19 + .../com/google/cloud/spanner/Spanner.java | 4 + .../com/google/cloud/spanner/SpannerImpl.java | 17 + .../google/cloud/spanner/SpannerOptions.java | 82 ++ .../com/google/cloud/spanner/TraceUtil.java | 2 +- .../cloud/spanner/TransactionContext.java | 24 + .../spanner/TransactionContextFutureImpl.java | 258 ++++ .../cloud/spanner/TransactionManagerImpl.java | 15 +- .../cloud/spanner/TransactionRunnerImpl.java | 418 +++++- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 44 +- .../cloud/spanner/spi/v1/SpannerRpc.java | 14 + .../spanner/AbstractAsyncTransactionTest.java | 140 ++ .../spanner/AbstractReadContextTest.java | 2 + .../spanner/AsyncResultSetImplStressTest.java | 464 +++++++ .../cloud/spanner/AsyncResultSetImplTest.java | 443 +++++++ .../google/cloud/spanner/AsyncRunnerTest.java | 618 +++++++++ .../spanner/AsyncTransactionManagerTest.java | 1045 +++++++++++++++ .../cloud/spanner/BaseSessionPoolTest.java | 2 +- .../cloud/spanner/DatabaseClientImplTest.java | 551 +++++++- .../IntegrationTestWithClosedSessionsEnv.java | 29 +- .../spanner/MockDatabaseAdminServiceImpl.java | 5 +- .../cloud/spanner/MockSpannerServiceImpl.java | 331 ++++- .../cloud/spanner/MockSpannerTestUtil.java | 151 +++ .../spanner/RandomResultSetGenerator.java | 166 +++ .../google/cloud/spanner/ReadAsyncTest.java | 510 +++++++ .../RetryOnInvalidatedSessionTest.java | 35 +- .../google/cloud/spanner/SessionImplTest.java | 11 +- .../spanner/SessionPoolMaintainerTest.java | 21 +- .../cloud/spanner/SessionPoolStressTest.java | 93 +- .../google/cloud/spanner/SessionPoolTest.java | 99 +- .../com/google/cloud/spanner/SpanTest.java | 1 + .../spanner/SpannerExceptionFactoryTest.java | 5 + .../cloud/spanner/SpannerGaxRetryTest.java | 7 + .../google/cloud/spanner/SpannerMatchers.java | 37 + .../spanner/TransactionManagerImplTest.java | 37 +- .../spanner/TransactionRunnerImplTest.java | 49 +- .../connection/ReadOnlyTransactionTest.java | 30 + .../connection/SingleUseTransactionTest.java | 30 + .../cloud/spanner/it/ITAsyncAPITest.java | 309 +++++ .../cloud/spanner/it/ITAsyncExamplesTest.java | 550 ++++++++ .../cloud/spanner/it/ITDatabaseTest.java | 1 + .../cloud/spanner/it/ITReadOnlyTxnTest.java | 18 +- .../google/cloud/spanner/it/ITReadTest.java | 2 + .../it/ITTransactionManagerAsyncTest.java | 318 +++++ .../cloud/spanner/it/ITTransactionTest.java | 7 +- versions.txt | 2 +- 69 files changed, 9895 insertions(+), 687 deletions(-) create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSet.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunner.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolAsyncTransactionManager.java create mode 100644 google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContextFutureImpl.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractAsyncTransactionTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplStressTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerTestUtil.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncAPITest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerAsyncTest.java diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index a10e096af4..13462a986c 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -93,7 +93,6 @@ com/google/cloud/spanner/DatabaseAdminClient com.google.cloud.spanner.Backup updateBackup(java.lang.String, java.lang.String, com.google.cloud.Timestamp) - 7012 com/google/cloud/spanner/spi/v1/SpannerRpc @@ -147,6 +146,88 @@ com.google.api.gax.paging.Page listDatabases() + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.core.ApiFuture executeQueryAsync(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map) + + + 7012 + com/google/cloud/spanner/DatabaseClient + * runAsync(*) + + + 7012 + com/google/cloud/spanner/DatabaseClient + * transactionManagerAsync(*) + + + 7012 + com/google/cloud/spanner/Spanner + * getAsyncExecutorProvider(*) + + + 7012 + com/google/cloud/spanner/ReadContext + * executeQueryAsync(*) + + + 7012 + com/google/cloud/spanner/ReadContext + * readAsync(*) + + + 7012 + com/google/cloud/spanner/ReadContext + * readRowAsync(*) + + + 7012 + com/google/cloud/spanner/ReadContext + * readUsingIndexAsync(*) + + + 7012 + com/google/cloud/spanner/ReadContext + * readRowUsingIndexAsync(*) + + + 7012 + com/google/cloud/spanner/TransactionContext + * batchUpdateAsync(*) + + + 7012 + com/google/cloud/spanner/TransactionContext + * executeUpdateAsync(*) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + * beginTransactionAsync(*) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + * commitAsync(*) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + * rollbackAsync(*) + + + 7012 + com/google/cloud/spanner/spi/v1/SpannerRpc + * executeBatchDmlAsync(*) + + + 7012 + com/google/cloud/spanner/connection/Connection + * executeQueryAsync(*) + + 7012 diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java index 685e9a1e31..bc4a868564 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java @@ -21,16 +21,24 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.api.gax.core.ExecutorProvider; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AbstractResultSet.CloseableIterator; import com.google.cloud.spanner.AbstractResultSet.GrpcResultSet; import com.google.cloud.spanner.AbstractResultSet.GrpcStreamIterator; import com.google.cloud.spanner.AbstractResultSet.ResumableStreamIterator; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; import com.google.cloud.spanner.Options.QueryOption; import com.google.cloud.spanner.Options.ReadOption; import com.google.cloud.spanner.SessionImpl.SessionTransaction; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.common.annotations.VisibleForTesting; +import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import com.google.spanner.v1.BeginTransactionRequest; import com.google.spanner.v1.ExecuteBatchDmlRequest; @@ -62,6 +70,7 @@ abstract static class Builder, T extends AbstractReadCon private Span span = Tracing.getTracer().getCurrentSpan(); private int defaultPrefetchChunks = SpannerOptions.Builder.DEFAULT_PREFETCH_CHUNKS; private QueryOptions defaultQueryOptions = SpannerOptions.Builder.DEFAULT_QUERY_OPTIONS; + private ExecutorProvider executorProvider; Builder() {} @@ -95,9 +104,25 @@ B setDefaultQueryOptions(QueryOptions defaultQueryOptions) { return self(); } + B setExecutorProvider(ExecutorProvider executorProvider) { + this.executorProvider = executorProvider; + return self(); + } + abstract T build(); } + /** + * {@link AsyncResultSet} that supports adding listeners that are called when all rows from the + * underlying result stream have been fetched. + */ + interface ListenableAsyncResultSet extends AsyncResultSet { + /** Adds a listener to this {@link AsyncResultSet}. */ + void addListener(Runnable listener); + + void removeListener(Runnable listener); + } + /** * A {@code ReadContext} for standalone reads. This can only be used for a single operation, since * each standalone read may see a different timestamp of Cloud Spanner data. @@ -350,7 +375,8 @@ void initTransaction() { final Object lock = new Object(); final SessionImpl session; final SpannerRpc rpc; - final Span span; + final ExecutorProvider executorProvider; + Span span; private final int defaultPrefetchChunks; private final QueryOptions defaultQueryOptions; @@ -374,6 +400,12 @@ void initTransaction() { this.defaultPrefetchChunks = builder.defaultPrefetchChunks; this.defaultQueryOptions = builder.defaultQueryOptions; this.span = builder.span; + this.executorProvider = builder.executorProvider; + } + + @Override + public void setSpan(Span span) { + this.span = span; } long getSeqNo() { @@ -386,12 +418,38 @@ public final ResultSet read( return readInternal(table, null, keys, columns, options); } + @Override + public ListenableAsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + Options readOptions = Options.fromReadOptions(options); + final int bufferRows = + readOptions.hasBufferRows() + ? readOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AsyncResultSetImpl( + executorProvider, readInternal(table, null, keys, columns, options), bufferRows); + } + @Override public final ResultSet readUsingIndex( String table, String index, KeySet keys, Iterable columns, ReadOption... options) { return readInternal(table, checkNotNull(index), keys, columns, options); } + @Override + public ListenableAsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + Options readOptions = Options.fromReadOptions(options); + final int bufferRows = + readOptions.hasBufferRows() + ? readOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AsyncResultSetImpl( + executorProvider, + readInternal(table, checkNotNull(index), keys, columns, options), + bufferRows); + } + @Nullable @Override public final Struct readRow(String table, Key key, Iterable columns) { @@ -400,6 +458,13 @@ public final Struct readRow(String table, Key key, Iterable columns) { } } + @Override + public final ApiFuture readRowAsync(String table, Key key, Iterable columns) { + try (AsyncResultSet resultSet = readAsync(table, KeySet.singleKey(key), columns)) { + return consumeSingleRowAsync(resultSet); + } + } + @Nullable @Override public final Struct readRowUsingIndex( @@ -409,12 +474,35 @@ public final Struct readRowUsingIndex( } } + @Override + public final ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + try (AsyncResultSet resultSet = + readUsingIndexAsync(table, index, KeySet.singleKey(key), columns)) { + return consumeSingleRowAsync(resultSet); + } + } + @Override public final ResultSet executeQuery(Statement statement, QueryOption... options) { return executeQueryInternal( statement, com.google.spanner.v1.ExecuteSqlRequest.QueryMode.NORMAL, options); } + @Override + public ListenableAsyncResultSet executeQueryAsync(Statement statement, QueryOption... options) { + Options readOptions = Options.fromQueryOptions(options); + final int bufferRows = + readOptions.hasBufferRows() + ? readOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AsyncResultSetImpl( + executorProvider, + executeQueryInternal( + statement, com.google.spanner.v1.ExecuteSqlRequest.QueryMode.NORMAL, options), + bufferRows); + } + @Override public final ResultSet analyzeQuery(Statement statement, QueryAnalyzeMode readContextQueryMode) { switch (readContextQueryMode) { @@ -666,4 +754,71 @@ private Struct consumeSingleRow(ResultSet resultSet) { } return row; } + + static ApiFuture consumeSingleRowAsync(AsyncResultSet resultSet) { + final SettableApiFuture result = SettableApiFuture.create(); + // We can safely use a directExecutor here, as we will only be consuming one row, and we will + // not be doing any blocking stuff in the handler. + final SettableApiFuture row = SettableApiFuture.create(); + ApiFutures.addCallback( + resultSet.setCallback(MoreExecutors.directExecutor(), ConsumeSingleRowCallback.create(row)), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + result.setException(t); + } + + @Override + public void onSuccess(Void input) { + try { + result.set(row.get()); + } catch (Throwable t) { + result.setException(t); + } + } + }, + MoreExecutors.directExecutor()); + return result; + } + + /** + * {@link ReadyCallback} for returning the first row in a result set as a future {@link Struct}. + */ + private static class ConsumeSingleRowCallback implements ReadyCallback { + private final SettableApiFuture result; + private Struct row; + + static ConsumeSingleRowCallback create(SettableApiFuture result) { + return new ConsumeSingleRowCallback(result); + } + + private ConsumeSingleRowCallback(SettableApiFuture result) { + this.result = result; + } + + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + switch (resultSet.tryNext()) { + case DONE: + result.set(row); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + if (row != null) { + throw newSpannerException( + ErrorCode.INTERNAL, "Multiple rows returned for single key"); + } + row = resultSet.getCurrentRowAsStruct(); + return CallbackResponse.CONTINUE; + default: + throw new IllegalStateException(); + } + } catch (Throwable t) { + result.setException(t); + return CallbackResponse.DONE; + } + } + } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java index 7b248bfb9d..6b0681b588 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java @@ -495,7 +495,7 @@ private static Struct decodeStructValue(Type structType, ListValue structValue) return new GrpcStruct(structType, fields); } - private static Object decodeArrayValue(Type elementType, ListValue listValue) { + static Object decodeArrayValue(Type elementType, ListValue listValue) { switch (elementType.getCode()) { case BOOL: // Use a view: element conversion is virtually free. @@ -1009,7 +1009,7 @@ protected PartialResultSet computeNext() { } } - private static double valueProtoToFloat64(com.google.protobuf.Value proto) { + static double valueProtoToFloat64(com.google.protobuf.Value proto) { if (proto.getKindCase() == KindCase.STRING_VALUE) { switch (proto.getStringValue()) { case "-Infinity": @@ -1037,7 +1037,7 @@ private static double valueProtoToFloat64(com.google.protobuf.Value proto) { return proto.getNumberValue(); } - private static NullPointerException throwNotNull(int columnIndex) { + static NullPointerException throwNotNull(int columnIndex) { throw new NullPointerException( "Cannot call array getter for column " + columnIndex + " with null elements"); } @@ -1048,7 +1048,7 @@ private static NullPointerException throwNotNull(int columnIndex) { * {@code BigDecimal} respectively. Rather than construct new wrapper objects for each array * element, we use primitive arrays and a {@code BitSet} to track nulls. */ - private abstract static class PrimitiveArray extends AbstractList { + abstract static class PrimitiveArray extends AbstractList { private final A data; private final BitSet nulls; private final int size; @@ -1103,7 +1103,7 @@ A toPrimitiveArray(int columnIndex) { } } - private static class Int64Array extends PrimitiveArray { + static class Int64Array extends PrimitiveArray { Int64Array(ListValue protoList) { super(protoList); } @@ -1128,7 +1128,7 @@ Long get(long[] array, int i) { } } - private static class Float64Array extends PrimitiveArray { + static class Float64Array extends PrimitiveArray { Float64Array(ListValue protoList) { super(protoList); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSet.java new file mode 100644 index 0000000000..c44a42994e --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSet.java @@ -0,0 +1,226 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +/** Interface for result sets returned by async query methods. */ +public interface AsyncResultSet extends ResultSet { + + /** Response code from {@code tryNext()}. */ + enum CursorState { + /** Cursor has been moved to a new row. */ + OK, + /** Read is complete, all rows have been consumed, and there are no more. */ + DONE, + /** No further information known at this time, thus current row not available. */ + NOT_READY + } + + /** + * Non-blocking call that attempts to step the cursor to the next position in the stream. The + * cursor may be inspected only if the cursor returns {@code CursorState.OK}. + * + *

A caller will typically call {@link #tryNext()} in a loop inside the ReadyCallback, + * consuming all results available. For more information see {@link #setCallback(Executor, + * ReadyCallback)}. + * + *

Currently this method may only be called if a ReadyCallback has been registered. This is for + * safety purposes only, and may be relaxed in future. + * + * @return current cursor readiness state + * @throws SpannerException When an unrecoverable problem downstream occurs. Once this occurs you + * will get no further callbacks. You should return CallbackResponse.DONE back from callback. + */ + CursorState tryNext() throws SpannerException; + + enum CallbackResponse { + /** + * Tell the cursor to continue issuing callbacks when data is available. This is the standard + * "I'm ready for more" response. If cursor is not completely drained of all ready results the + * callback will be called again immediately. + */ + CONTINUE, + + /** + * Tell the cursor to suspend all callbacks until application calls {@link RowCursor#resume()}. + */ + PAUSE, + + /** + * Tell the cursor you are done receiving results, even if there are more results sitting in the + * buffer. Once you return DONE, you will receive no further callbacks. + * + *

Approximately equivalent to calling {@link RowCursor#cancel()}, and then returning {@code + * PAUSE}, but more clear, immediate, and idiomatic. + * + *

It is legal to commit a transaction that owns this read before actually returning {@code + * DONE}. + */ + DONE, + } + + /** + * Interface for receiving asynchronous callbacks when new data is ready. See {@link + * AsyncResultSet#setCallback(Executor, ReadyCallback)}. + */ + interface ReadyCallback { + CallbackResponse cursorReady(AsyncResultSet resultSet); + } + + /** + * Register a callback with the ResultSet to be made aware when more data is available, changing + * the usage pattern from sync to async. Details: + * + *

    + *
  • The callback will be called at least once. + *
  • The callback is run each time more results are available, or when we discover that there + * will be no more results. (unless paused, see below). Spurious callbacks are possible, see + * below. + *
  • Spanner guarantees that one callback is ever outstanding at a time. Also, future + * callbacks guarantee the "happens before" property with previous callbacks. + *
  • A callback normally consumes all available data in the ResultSet, and then returns {@link + * CallbackResponse#CONTINUE}. + *
  • If a callback returns {@link CallbackResponse#CONTINUE} with data still in the ResultSet, + * the callback is invoked again immediately! + *
  • Once a callback has returned {@link CallbackResponse#PAUSE} on the cursor no more + * callbacks will be run until a corresponding {@link #resume()}. + *
  • Callback will stop being called once any of the following occurs: + *
      + *
    1. Callback returns {@link CallbackResponse#DONE}. + *
    2. {@link ResultSet#tryNext()} returns {@link CursorState#DONE}. + *
    3. {@link ResultSet#tryNext()} throws an exception. + *
    + *
  • Callback may possibly be invoked after a call to {@link ResultSet#cancel()} call, but the + * subsequent call to {@link #tryNext()} will yield a SpannerException. + *
  • Spurious callbacks are possible where cursors are not actually ready. Typically callback + * should return {@link CallbackResponse#CONTINUE} any time it sees {@link + * CursorState#NOT_READY}. + *
+ * + *

Flow Control

+ * + * If no flow control is needed (say because result sizes are known in advance to be finite in + * size) then async processing is simple. The following is a code example that transfers work from + * the cursor to an upstream sink: + * + *
{@code
+   * @Override
+   * public CallbackResponse cursorReady(ResultSet cursor) {
+   *   try {
+   *     while (true) {
+   *       switch (cursor.tryNext()) {
+   *         case OK:    upstream.emit(cursor.getRow()); break;
+   *         case DONE:  upstream.done(); return CallbackResponse.DONE;
+   *         case NOT_READY:  return CallbackResponse.CONTINUE;
+   *       }
+   *     }
+   *   } catch (SpannerException e) {
+   *     upstream.doneWithError(e);
+   *     return CallbackResponse.DONE;
+   *   }
+   * }
+   * }
+ * + * Flow control may be needed if for example the upstream system may not always be ready to handle + * more data. In this case the app developer has two main options: + * + *
    + *
  • Semi-async: make {@code upstream.emit()} a blocking call. This will block the callback + * thread until progress is possible. When coding in this way the threads in the Executor + * provided to {@link #setCallback(Executor, ReadyCallback)} must be blockable without + * causing harm to progress in your system. + *
  • Full-async: call {@code cursor.pause()} and return from the callback with data still in + * the Cursor. Once in this state cursor waits until resume() is called before calling + * callback again. + *
+ * + * @param exec executor on which to run all callbacks. Typically use a threadpool. If the executor + * is one that runs the work on the submitting thread, you must be very careful not to throw + * RuntimeException up the stack, lest you do damage to calling components. For example, it + * may cause an event dispatcher thread to crash. + * @param cb ready callback + * @return An {@link ApiFuture} that returns null when the consumption of the {@link + * AsyncResultSet} has finished successfully. No more calls to the {@link ReadyCallback} will + * follow and all resources used by the {@link AsyncResultSet} have been cleaned up. The + * {@link ApiFuture} throws an {@link ExecutionException} if the consumption of the {@link + * AsyncResultSet} finished with an error. + */ + ApiFuture setCallback(Executor exec, ReadyCallback cb); + + /** + * Attempt to cancel this operation and free all resources. Non-blocking. This is a no-op for + * child row cursors and does not cancel the parent cursor. + */ + void cancel(); + + /** + * Resume callbacks from the cursor. If there is more data available, a callback will be + * dispatched immediately. This can be called from any thread. + */ + void resume(); + + /** + * Transforms the row cursor into an immutable list using the given transformer function. {@code + * transformer} will be called once per row, thus the returned list will contain one entry per + * row. The returned future will throw a {@link SpannerException} if the row cursor encountered + * any error or if the transformer threw an exception on any row. + * + *

The transformer will be run on the supplied executor. The implementation may batch multiple + * transformer invocations together into a single {@code Runnable} when possible to increase + * efficiency. At any point in time, there will be at most one invocation of the transformer in + * progress. + * + *

WARNING: This will result in materializing the entire list so this should be used + * judiciously after considering the memory requirements of the returned list. + * + *

WARNING: The {@code RowBase} object passed to transformer function is not immutable and is + * not guaranteed to remain valid after the transformer function returns. The same {@code RowBase} + * object might be passed multiple times to the transformer with different underlying data each + * time. So *NEVER* keep a reference to the {@code RowBase} outside of the transformer. + * Specifically do not use {@link com.google.common.base.Functions#identity()} function. + * + * @param transformer function which will be used to transform the row. It should not return null. + * @param executor executor on which the transformer will be run. This should ideally not be an + * inline executor such as {@code MoreExecutors.directExecutor()}; using such an executor may + * degrade the performance of the Spanner library. + */ + ApiFuture> toListAsync( + Function transformer, Executor executor); + + /** + * Transforms the row cursor into an immutable list using the given transformer function. {@code + * transformer} will be called once per row, thus the returned list will contain one entry per + * row. This method will block until all the rows have been yielded by the cursor. + * + *

WARNING: This will result in consuming the entire list so this should be used judiciously + * after considering the memory requirements of the returned list. + * + *

WARNING: The {@code RowBase} object passed to transformer function is not immutable and is + * not guaranteed to remain valid after the transformer function returns. The same {@code RowBase} + * object might be passed multiple times to the transformer with different underlying data each + * time. So *NEVER* keep a reference to the {@code RowBase} outside of the transformer. + * Specifically do not use {@link com.google.common.base.Functions#identity()} function. + * + * @param transformer function which will be used to transform the row. It should not return null. + */ + ImmutableList toList(Function transformer) throws SpannerException; +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java new file mode 100644 index 0000000000..f277388b0b --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java @@ -0,0 +1,586 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiAsyncFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.ListenableFutureToApiFuture; +import com.google.api.core.SettableApiFuture; +import com.google.api.gax.core.ExecutorProvider; +import com.google.cloud.spanner.AbstractReadContext.ListenableAsyncResultSet; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.ListeningScheduledExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.spanner.v1.ResultSetStats; +import java.util.Collection; +import java.util.LinkedList; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** Default implementation for {@link AsyncResultSet}. */ +class AsyncResultSetImpl extends ForwardingStructReader implements ListenableAsyncResultSet { + private static final Logger log = Logger.getLogger(AsyncResultSetImpl.class.getName()); + + /** State of an {@link AsyncResultSetImpl}. */ + private enum State { + INITIALIZED, + /** SYNC indicates that the {@link ResultSet} is used in sync pattern. */ + SYNC, + CONSUMING, + RUNNING, + PAUSED, + CANCELLED(true), + DONE(true); + + /** Does this state mean that the result set should permanently stop producing rows. */ + private final boolean shouldStop; + + private State() { + shouldStop = false; + } + + private State(boolean shouldStop) { + this.shouldStop = shouldStop; + } + } + + static final int DEFAULT_BUFFER_SIZE = 10; + private static final int MAX_WAIT_FOR_BUFFER_CONSUMPTION = 10; + private static final SpannerException CANCELLED_EXCEPTION = + SpannerExceptionFactory.newSpannerException( + ErrorCode.CANCELLED, "This AsyncResultSet has been cancelled"); + + private final Object monitor = new Object(); + private boolean closed; + + /** + * {@link ExecutorProvider} provides executor services that are used to fetch data from the + * backend and put these into the buffer for further consumption by the callback. + */ + private final ExecutorProvider executorProvider; + + private final ListeningScheduledExecutorService service; + + private final BlockingDeque buffer; + private Struct currentRow; + /** The underlying synchronous {@link ResultSet} that is producing the rows. */ + private final ResultSet delegateResultSet; + + /** + * Any exception that occurs while executing the query and iterating over the result set will be + * stored in this variable and propagated to the user through {@link #tryNext()}. + */ + private volatile SpannerException executionException; + + /** + * Executor for callbacks. Regardless of the type of executor that is provided, the {@link + * AsyncResultSetImpl} will ensure that at most 1 callback call will be active at any one time. + */ + private Executor executor; + + private ReadyCallback callback; + + /** + * Listeners that will be called when the {@link AsyncResultSetImpl} has finished fetching all + * rows and any underlying transaction or session can be closed. + */ + private Collection listeners = new LinkedList<>(); + + private State state = State.INITIALIZED; + + /** + * {@link #finished} indicates whether all the results from the underlying result set have been + * read. + */ + private volatile boolean finished; + + private volatile ApiFuture result; + + /** + * {@link #cursorReturnedDoneOrException} indicates whether {@link #tryNext()} has returned {@link + * CursorState#DONE} or a {@link SpannerException}. + */ + private volatile boolean cursorReturnedDoneOrException; + + /** + * {@link #pausedLatch} is used to pause the producer when the {@link AsyncResultSet} is paused. + * The production of rows that are put into the buffer is only paused once the buffer is full. + */ + private volatile CountDownLatch pausedLatch = new CountDownLatch(1); + /** + * {@link #bufferConsumptionLatch} is used to pause the producer when the buffer is full and the + * consumer needs some time to catch up. + */ + private volatile CountDownLatch bufferConsumptionLatch = new CountDownLatch(0); + /** + * {@link #consumingLatch} is used to pause the producer when all rows have been put into the + * buffer, but the consumer (the callback) has not yet received and processed all rows. + */ + private volatile CountDownLatch consumingLatch = new CountDownLatch(0); + + AsyncResultSetImpl(ExecutorProvider executorProvider, ResultSet delegate, int bufferSize) { + super(delegate); + this.executorProvider = Preconditions.checkNotNull(executorProvider); + this.delegateResultSet = Preconditions.checkNotNull(delegate); + this.service = MoreExecutors.listeningDecorator(executorProvider.getExecutor()); + this.buffer = new LinkedBlockingDeque<>(bufferSize); + } + + /** + * Closes the {@link AsyncResultSet}. {@link #close()} is non-blocking and may be called multiple + * times without side effects. An {@link AsyncResultSet} may be closed before all rows have been + * returned to the callback, and calling {@link #tryNext()} on a closed {@link AsyncResultSet} is + * allowed as long as this is done from within a {@link ReadyCallback}. Calling {@link #resume()} + * on a closed {@link AsyncResultSet} is also allowed. + */ + @Override + public void close() { + synchronized (monitor) { + if (this.closed) { + return; + } + if (state == State.INITIALIZED || state == State.SYNC) { + delegateResultSet.close(); + } + this.closed = true; + } + } + + /** + * Adds a listener that will be called when no more rows will be read from the underlying {@link + * ResultSet}, either because all rows have been read, or because {@link + * ReadyCallback#cursorReady(AsyncResultSet)} returned {@link CallbackResponse#DONE}. + */ + @Override + public void addListener(Runnable listener) { + Preconditions.checkState(state == State.INITIALIZED); + listeners.add(listener); + } + + @Override + public void removeListener(Runnable listener) { + Preconditions.checkState(state == State.INITIALIZED); + listeners.remove(listener); + } + + /** + * Tries to advance this {@link AsyncResultSet} to the next row. This method may only be called + * from within a {@link ReadyCallback}. + */ + @Override + public CursorState tryNext() throws SpannerException { + synchronized (monitor) { + if (state == State.CANCELLED) { + cursorReturnedDoneOrException = true; + throw CANCELLED_EXCEPTION; + } + if (buffer.isEmpty() && executionException != null) { + cursorReturnedDoneOrException = true; + throw executionException; + } + Preconditions.checkState( + this.callback != null, "tryNext may only be called after a callback has been set."); + Preconditions.checkState( + this.state == State.CONSUMING, + "tryNext may only be called from a DataReady callback. Current state: " + + this.state.name()); + + if (finished && buffer.isEmpty()) { + cursorReturnedDoneOrException = true; + return CursorState.DONE; + } + } + if (!buffer.isEmpty()) { + // Set the next row from the buffer as the current row of the StructReader. + replaceDelegate(currentRow = buffer.pop()); + synchronized (monitor) { + bufferConsumptionLatch.countDown(); + } + return CursorState.OK; + } + return CursorState.NOT_READY; + } + + private void closeDelegateResultSet() { + try { + delegateResultSet.close(); + } catch (Throwable t) { + log.log(Level.FINE, "Ignoring error from closing delegate result set", t); + } + } + + /** + * {@link CallbackRunnable} calls the {@link ReadyCallback} registered for this {@link + * AsyncResultSet}. + */ + private class CallbackRunnable implements Runnable { + @Override + public void run() { + try { + while (true) { + synchronized (monitor) { + if (cursorReturnedDoneOrException) { + break; + } + } + CallbackResponse response; + try { + response = callback.cursorReady(AsyncResultSetImpl.this); + } catch (Throwable e) { + synchronized (monitor) { + if (cursorReturnedDoneOrException + && state == State.CANCELLED + && e instanceof SpannerException + && ((SpannerException) e).getErrorCode() == ErrorCode.CANCELLED) { + // The callback did not catch the cancelled exception (which it should have), but + // we'll keep the cancelled state. + return; + } + executionException = SpannerExceptionFactory.newSpannerException(e); + cursorReturnedDoneOrException = true; + } + return; + } + synchronized (monitor) { + if (state == State.CANCELLED) { + if (cursorReturnedDoneOrException) { + return; + } + } else { + switch (response) { + case DONE: + state = State.DONE; + closeDelegateResultSet(); + return; + case PAUSE: + state = State.PAUSED; + // Make sure no-one else is waiting on the current pause latch and create a new + // one. + pausedLatch.countDown(); + pausedLatch = new CountDownLatch(1); + return; + case CONTINUE: + if (buffer.isEmpty()) { + // Call the callback once more if the entire result set has been processed but + // the callback has not yet received a CursorState.DONE or a CANCELLED error. + if (finished && !cursorReturnedDoneOrException) { + break; + } + state = State.RUNNING; + return; + } + break; + default: + throw new IllegalStateException("Unknown response: " + response); + } + } + } + } + } finally { + synchronized (monitor) { + // Count down all latches that the producer might be waiting on. + consumingLatch.countDown(); + while (bufferConsumptionLatch.getCount() > 0L) { + bufferConsumptionLatch.countDown(); + } + } + } + } + } + + private final CallbackRunnable callbackRunnable = new CallbackRunnable(); + + /** + * {@link ProduceRowsCallable} reads data from the underlying {@link ResultSet}, places these in + * the buffer and dispatches the {@link CallbackRunnable} when data is ready to be consumed. + */ + private class ProduceRowsCallable implements Callable { + @Override + public Void call() throws Exception { + boolean stop = false; + boolean hasNext = false; + try { + hasNext = delegateResultSet.next(); + } catch (Throwable e) { + synchronized (monitor) { + executionException = SpannerExceptionFactory.newSpannerException(e); + } + } + try { + while (!stop && hasNext) { + try { + synchronized (monitor) { + stop = state.shouldStop; + } + if (!stop) { + while (buffer.remainingCapacity() == 0 && !stop) { + waitIfPaused(); + // The buffer is full and we should let the callback consume a number of rows before + // we proceed with producing any more rows to prevent us from potentially waiting on + // a full buffer repeatedly. + // Wait until at least half of the buffer is available, or if it's a bigger buffer, + // wait until at least 10 rows can be placed in it. + // TODO: Make this more dynamic / configurable? + startCallbackWithBufferLatchIfNecessary( + Math.min( + Math.min(buffer.size() / 2 + 1, buffer.size()), + MAX_WAIT_FOR_BUFFER_CONSUMPTION)); + bufferConsumptionLatch.await(); + synchronized (monitor) { + stop = state.shouldStop; + } + } + } + if (!stop) { + buffer.put(delegateResultSet.getCurrentRowAsStruct()); + startCallbackIfNecessary(); + hasNext = delegateResultSet.next(); + } + } catch (Throwable e) { + synchronized (monitor) { + executionException = SpannerExceptionFactory.newSpannerException(e); + stop = true; + } + } + } + // We don't need any more data from the underlying result set, so we close it as soon as + // possible. Any error that might occur during this will be ignored. + closeDelegateResultSet(); + + // Ensure that the callback has been called at least once, even if the result set was + // cancelled. + synchronized (monitor) { + finished = true; + stop = cursorReturnedDoneOrException; + } + // Call the callback if there are still rows in the buffer that need to be processed. + while (!stop) { + waitIfPaused(); + startCallbackIfNecessary(); + synchronized (monitor) { + stop = state.shouldStop || cursorReturnedDoneOrException; + } + // Make sure we wait until the callback runner has actually finished. + consumingLatch.await(); + } + } finally { + if (executorProvider.shouldAutoClose()) { + service.shutdown(); + } + for (Runnable listener : listeners) { + listener.run(); + } + synchronized (monitor) { + if (executionException != null) { + throw executionException; + } + if (state == State.CANCELLED) { + throw CANCELLED_EXCEPTION; + } + } + } + return null; + } + + private void waitIfPaused() throws InterruptedException { + CountDownLatch pause; + synchronized (monitor) { + pause = pausedLatch; + } + pause.await(); + } + + private void startCallbackIfNecessary() { + startCallbackWithBufferLatchIfNecessary(0); + } + + private void startCallbackWithBufferLatchIfNecessary(int bufferLatch) { + synchronized (monitor) { + if ((state == State.RUNNING || state == State.CANCELLED) + && !cursorReturnedDoneOrException) { + consumingLatch = new CountDownLatch(1); + if (bufferLatch > 0) { + bufferConsumptionLatch = new CountDownLatch(bufferLatch); + } + if (state == State.RUNNING) { + state = State.CONSUMING; + } + executor.execute(callbackRunnable); + } + } + } + } + + /** Sets the callback for this {@link AsyncResultSet}. */ + @Override + public ApiFuture setCallback(Executor exec, ReadyCallback cb) { + synchronized (monitor) { + Preconditions.checkState(!closed, "This AsyncResultSet has been closed"); + Preconditions.checkState( + this.state == State.INITIALIZED, "callback may not be set multiple times"); + + // Start to fetch data and buffer these. + this.result = + new ListenableFutureToApiFuture<>(this.service.submit(new ProduceRowsCallable())); + this.executor = MoreExecutors.newSequentialExecutor(Preconditions.checkNotNull(exec)); + this.callback = Preconditions.checkNotNull(cb); + this.state = State.RUNNING; + pausedLatch.countDown(); + return result; + } + } + + Future getResult() { + return result; + } + + @Override + public void cancel() { + synchronized (monitor) { + Preconditions.checkState( + state != State.INITIALIZED && state != State.SYNC, + "cannot cancel a result set without a callback"); + state = State.CANCELLED; + pausedLatch.countDown(); + } + } + + @Override + public void resume() { + synchronized (monitor) { + Preconditions.checkState( + state != State.INITIALIZED && state != State.SYNC, + "cannot resume a result set without a callback"); + if (state == State.PAUSED) { + state = State.RUNNING; + pausedLatch.countDown(); + } + } + } + + private static class CreateListCallback implements ReadyCallback { + private final SettableApiFuture> future; + private final Function transformer; + private final ImmutableList.Builder builder = ImmutableList.builder(); + + private CreateListCallback( + SettableApiFuture> future, Function transformer) { + this.future = future; + this.transformer = transformer; + } + + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + future.set(builder.build()); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + builder.add(transformer.apply(resultSet)); + break; + } + } + } catch (Throwable t) { + future.setException(t); + return CallbackResponse.DONE; + } + } + } + + @Override + public ApiFuture> toListAsync( + Function transformer, Executor executor) { + synchronized (monitor) { + Preconditions.checkState(!closed, "This AsyncResultSet has been closed"); + Preconditions.checkState( + this.state == State.INITIALIZED, "This AsyncResultSet has already been used."); + final SettableApiFuture> res = SettableApiFuture.>create(); + CreateListCallback callback = new CreateListCallback(res, transformer); + ApiFuture finished = setCallback(executor, callback); + return ApiFutures.transformAsync( + finished, + new ApiAsyncFunction>() { + @Override + public ApiFuture> apply(Void input) throws Exception { + return res; + } + }, + MoreExecutors.directExecutor()); + } + } + + @Override + public ImmutableList toList(Function transformer) + throws SpannerException { + ApiFuture> future = toListAsync(transformer, MoreExecutors.directExecutor()); + try { + return future.get(); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (Throwable e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + } + + @Override + public boolean next() throws SpannerException { + synchronized (monitor) { + Preconditions.checkState( + this.state == State.INITIALIZED || this.state == State.SYNC, + "Cannot call next() on a result set with a callback."); + this.state = State.SYNC; + } + boolean res = delegateResultSet.next(); + currentRow = delegateResultSet.getCurrentRowAsStruct(); + return res; + } + + @Override + public ResultSetStats getStats() { + return delegateResultSet.getStats(); + } + + @Override + protected void checkValidState() { + synchronized (monitor) { + Preconditions.checkState( + state == State.SYNC || state == State.CONSUMING || state == State.CANCELLED, + "only allowed after a next() call or from within a ReadyCallback#cursorReady callback"); + Preconditions.checkState(state != State.SYNC || !closed, "ResultSet is closed"); + } + } + + @Override + public Struct getCurrentRowAsStruct() { + checkValidState(); + return currentRow; + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunner.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunner.java new file mode 100644 index 0000000000..3cae49e65b --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunner.java @@ -0,0 +1,59 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.cloud.Timestamp; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +public interface AsyncRunner { + + /** + * Functional interface for executing a read/write transaction asynchronously that returns a + * result of type R. + */ + interface AsyncWork { + /** + * Performs a single transaction attempt. All reads/writes should be performed using {@code + * txn}. + * + *

Implementations of this method should not attempt to commit the transaction directly: + * returning normally will result in the runner attempting to commit the transaction once the + * returned future completes, retrying on abort. + * + *

In most cases, the implementation will not need to catch {@code SpannerException}s from + * Spanner operations, instead letting these propagate to the framework. The transaction runner + * will take appropriate action based on the type of exception. In particular, implementations + * should never catch an exception of type {@link SpannerErrors#isAborted}: these indicate that + * some reads may have returned inconsistent data and the transaction attempt must be aborted. + * + * @param txn the transaction + * @return future over the result of the work + */ + ApiFuture doWorkAsync(TransactionContext txn); + } + + /** Executes a read/write transaction asynchronously using the given executor. */ + ApiFuture runAsync(AsyncWork work, Executor executor); + + /** + * Returns the timestamp at which the transaction committed. {@link ApiFuture#get()} will throw an + * {@link ExecutionException} if the transaction did not commit. + */ + ApiFuture getCommitTimestamp(); +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java new file mode 100644 index 0000000000..5b83402919 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.TransactionRunner.TransactionCallable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; + +class AsyncRunnerImpl implements AsyncRunner { + private final TransactionRunnerImpl delegate; + private final SettableApiFuture commitTimestamp = SettableApiFuture.create(); + + AsyncRunnerImpl(TransactionRunnerImpl delegate) { + this.delegate = delegate; + } + + @Override + public ApiFuture runAsync(final AsyncWork work, Executor executor) { + final SettableApiFuture res = SettableApiFuture.create(); + executor.execute( + new Runnable() { + @Override + public void run() { + try { + res.set(runTransaction(work)); + } catch (Throwable t) { + res.setException(t); + } finally { + setCommitTimestamp(); + } + } + }); + return res; + } + + private R runTransaction(final AsyncWork work) { + return delegate.run( + new TransactionCallable() { + @Override + public R run(TransactionContext transaction) throws Exception { + try { + return work.doWorkAsync(transaction).get(); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } + }); + } + + private void setCommitTimestamp() { + try { + commitTimestamp.set(delegate.getCommitTimestamp()); + } catch (Throwable t) { + commitTimestamp.setException(t); + } + } + + @Override + public ApiFuture getCommitTimestamp() { + return commitTimestamp; + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java new file mode 100644 index 0000000000..d519c68013 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java @@ -0,0 +1,203 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionFunction; +import com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture; +import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture; +import com.google.cloud.spanner.TransactionManager.TransactionState; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * An interface for managing the life cycle of a read write transaction including all its retries. + * See {@link TransactionContext} for a description of transaction semantics. + * + *

At any point in time there can be at most one active transaction in this manager. When that + * transaction is committed, if it fails with an {@code ABORTED} error, calling {@link + * #resetForRetryAsync()} would create a new {@link TransactionContextFuture}. The newly created + * transaction would use the same session thus increasing its lock priority. If the transaction is + * committed successfully, or is rolled back or commit fails with any error other than {@code + * ABORTED}, the manager is considered complete and no further transactions are allowed to be + * created in it. + * + *

Every {@code AsyncTransactionManager} should either be committed or rolled back. Failure to do + * so can cause resources to be leaked and deadlocks. Easiest way to guarantee this is by calling + * {@link #close()} in a finally block. + * + * @see DatabaseClient#transactionManagerAsync() + */ +public interface AsyncTransactionManager extends AutoCloseable { + /** + * {@link ApiFuture} that returns a {@link TransactionContext} and that supports chaining of + * multiple {@link TransactionContextFuture}s to form a transaction. + */ + public interface TransactionContextFuture extends ApiFuture { + /** + * Sets the first step to execute as part of this transaction after the transaction has started + * using the specified executor. {@link MoreExecutors#directExecutor()} can be be used for + * lightweight functions, but should be avoided for heavy or blocking operations. See also + * {@link ListenableFuture#addListener(Runnable, Executor)} for further information. + */ + AsyncTransactionStep then( + AsyncTransactionFunction function, Executor executor); + } + + /** + * {@link ApiFuture} that returns the commit {@link Timestamp} of a Cloud Spanner transaction that + * is executed using an {@link AsyncTransactionManager}. This future is returned by the call to + * {@link AsyncTransactionStep#commitAsync()} of the last step in the transaction. + */ + public interface CommitTimestampFuture extends ApiFuture { + /** + * Returns the commit timestamp of the transaction. Getting this value should always be done in + * order to ensure that the transaction succeeded. If any of the steps in the transaction fails + * with an uncaught exception, this method will automatically stop the transaction at that point + * and the exception will be returned as the cause of the {@link ExecutionException} that is + * thrown by this method. + * + * @throws AbortedException if the transaction was aborted by Cloud Spanner and needs to be + * retried. + */ + @Override + Timestamp get() throws AbortedException, InterruptedException, ExecutionException; + + /** + * Same as {@link #get()}, but will throw a {@link TimeoutException} if the transaction does not + * finish within the timeout. + */ + @Override + Timestamp get(long timeout, TimeUnit unit) + throws AbortedException, InterruptedException, ExecutionException, TimeoutException; + } + + /** + * {@link AsyncTransactionStep} is returned by {@link + * TransactionContextFuture#then(AsyncTransactionFunction)} and {@link + * AsyncTransactionStep#then(AsyncTransactionFunction)} and allows transaction steps that should + * be executed serially to be chained together. Each step can contain one or more statements that + * may execute in parallel. + * + *

Example usage: + * + *

{@code
+   * TransactionContextFuture txnFuture = manager.beginAsync();
+   * final String column = "FirstName";
+   * txnFuture.then(
+   *         new AsyncTransactionFunction() {
+   *           @Override
+   *           public ApiFuture apply(TransactionContext txn, Void input)
+   *               throws Exception {
+   *             return txn.readRowAsync(
+   *                 "Singers", Key.of(singerId), Collections.singleton(column));
+   *           }
+   *         })
+   *     .then(
+   *         new AsyncTransactionFunction() {
+   *           @Override
+   *           public ApiFuture apply(TransactionContext txn, Struct input)
+   *               throws Exception {
+   *             String name = input.getString(column);
+   *             txn.buffer(
+   *                 Mutation.newUpdateBuilder("Singers")
+   *                     .set(column)
+   *                     .to(name.toUpperCase())
+   *                     .build());
+   *             return ApiFutures.immediateFuture(null);
+   *           }
+   *         })
+   * }
+ */ + public interface AsyncTransactionStep extends ApiFuture { + /** + * Adds a step to the transaction chain that should be executed using the specified executor. + * This step is guaranteed to be executed only after the previous step executed successfully. + * {@link MoreExecutors#directExecutor()} can be be used for lightweight functions, but should + * be avoided for heavy or blocking operations. See also {@link + * ListenableFuture#addListener(Runnable, Executor)} for further information. + */ + AsyncTransactionStep then( + AsyncTransactionFunction next, Executor executor); + + /** + * Commits the transaction and returns a {@link CommitTimestampFuture} that will return the + * commit timestamp of the transaction, or throw the first uncaught exception in the transaction + * chain as an {@link ExecutionException}. + */ + CommitTimestampFuture commitAsync(); + } + + /** + * Each step in a transaction chain is defined by an {@link AsyncTransactionFunction}. It receives + * a {@link TransactionContext} and the output value of the previous transaction step as its input + * parameters. The method should return an {@link ApiFuture} that will return the result of this + * step. + */ + public interface AsyncTransactionFunction { + /** + * {@link #apply(TransactionContext, Object)} is called when this transaction step is executed. + * The input value is the result of the previous step, and this method will only be called if + * the previous step executed successfully. + * + * @param txn the {@link TransactionContext} that can be used to execute statements. + * @param input the result of the previous transaction step. + * @return an {@link ApiFuture} that will return the result of this step, and that will be the + * input of the next transaction step. This method should never return null. + * Instead, if the method does not have a return value, the method should return {@link + * ApiFutures#immediateFuture(null)}. + */ + ApiFuture apply(TransactionContext txn, I input) throws Exception; + } + + /** + * Creates a new read write transaction. This must be called before doing any other operation and + * can only be called once. To create a new transaction for subsequent retries, see {@link + * #resetForRetry()}. + */ + TransactionContextFuture beginAsync(); + + /** + * Rolls back the currently active transaction. In most cases there should be no need to call this + * explicitly since {@link #close()} would automatically roll back any active transaction. + */ + ApiFuture rollbackAsync(); + + /** + * Creates a new transaction for retry. This should only be called if the previous transaction + * failed with {@code ABORTED}. In all other cases, this will throw an {@link + * IllegalStateException}. Users should backoff before calling this method. Backoff delay is + * specified by {@link SpannerException#getRetryDelayInMillis()} on the {@code SpannerException} + * throw by the previous commit call. + */ + TransactionContextFuture resetForRetryAsync(); + + /** Returns the state of the transaction. */ + TransactionState getState(); + + /** + * Closes the manager. If there is an active transaction, it will be rolled back. Underlying + * session will be released back to the session pool. + */ + @Override + void close(); +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java new file mode 100644 index 0000000000..082fa827e7 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java @@ -0,0 +1,167 @@ +/* + * Copyright 2017 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.SessionImpl.SessionTransaction; +import com.google.cloud.spanner.TransactionContextFutureImpl.CommittableAsyncTransactionManager; +import com.google.cloud.spanner.TransactionManager.TransactionState; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.MoreExecutors; +import io.opencensus.trace.Span; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracing; + +/** Implementation of {@link AsyncTransactionManager}. */ +final class AsyncTransactionManagerImpl + implements CommittableAsyncTransactionManager, SessionTransaction { + private static final Tracer tracer = Tracing.getTracer(); + + private final SessionImpl session; + private Span span; + + private TransactionRunnerImpl.TransactionContextImpl txn; + private TransactionState txnState; + private final SettableApiFuture commitTimestamp = SettableApiFuture.create(); + + AsyncTransactionManagerImpl(SessionImpl session, Span span) { + this.session = session; + this.span = span; + } + + @Override + public void setSpan(Span span) { + this.span = span; + } + + @Override + public void close() { + txn.close(); + } + + @Override + public TransactionContextFutureImpl beginAsync() { + Preconditions.checkState(txn == null, "begin can only be called once"); + TransactionContextFutureImpl begin = + new TransactionContextFutureImpl(this, internalBeginAsync(true)); + return begin; + } + + private ApiFuture internalBeginAsync(boolean setActive) { + txnState = TransactionState.STARTED; + txn = session.newTransaction(); + if (setActive) { + session.setActive(this); + } + final SettableApiFuture res = SettableApiFuture.create(); + final ApiFuture fut = txn.ensureTxnAsync(); + ApiFutures.addCallback( + fut, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + res.setException(SpannerExceptionFactory.newSpannerException(t)); + } + + @Override + public void onSuccess(Void result) { + res.set(txn); + } + }, + MoreExecutors.directExecutor()); + return res; + } + + @Override + public void onError(Throwable t) { + if (t instanceof AbortedException) { + txnState = TransactionState.ABORTED; + } + } + + @Override + public ApiFuture commitAsync() { + Preconditions.checkState( + txnState == TransactionState.STARTED, + "commit can only be invoked if the transaction is in progress. Current state: " + txnState); + if (txn.isAborted()) { + txnState = TransactionState.ABORTED; + return ApiFutures.immediateFailedFuture( + SpannerExceptionFactory.newSpannerException( + ErrorCode.ABORTED, "Transaction already aborted")); + } + ApiFuture res = txn.commitAsync(); + txnState = TransactionState.COMMITTED; + ApiFutures.addCallback( + res, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + if (t instanceof AbortedException) { + txnState = TransactionState.ABORTED; + } else { + txnState = TransactionState.COMMIT_FAILED; + commitTimestamp.setException(t); + } + } + + @Override + public void onSuccess(Timestamp result) { + commitTimestamp.set(result); + } + }, + MoreExecutors.directExecutor()); + return res; + } + + @Override + public ApiFuture rollbackAsync() { + Preconditions.checkState( + txnState == TransactionState.STARTED, + "rollback can only be called if the transaction is in progress"); + try { + return txn.rollbackAsync(); + } finally { + txnState = TransactionState.ROLLED_BACK; + } + } + + @Override + public TransactionContextFuture resetForRetryAsync() { + if (txn == null || !txn.isAborted() && txnState != TransactionState.ABORTED) { + throw new IllegalStateException( + "resetForRetry can only be called if the previous attempt aborted"); + } + return new TransactionContextFutureImpl(this, internalBeginAsync(false)); + } + + @Override + public TransactionState getState() { + return txnState; + } + + @Override + public void invalidate() { + if (txnState == TransactionState.STARTED || txnState == null) { + txnState = TransactionState.ROLLED_BACK; + } + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java index 43de2be092..c84bef77cf 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java @@ -30,6 +30,7 @@ import com.google.spanner.v1.PartitionReadRequest; import com.google.spanner.v1.PartitionResponse; import com.google.spanner.v1.TransactionSelector; +import io.opencensus.trace.Tracing; import java.util.List; import java.util.Map; @@ -51,6 +52,7 @@ public BatchReadOnlyTransaction batchReadOnlyTransaction(TimestampBound bound) { .setTimestampBound(bound) .setDefaultQueryOptions( sessionClient.getSpanner().getDefaultQueryOptions(sessionClient.getDatabaseId())) + .setExecutorProvider(sessionClient.getSpanner().getAsyncExecutorProvider()) .setDefaultPrefetchChunks(sessionClient.getSpanner().getDefaultPrefetchChunks()), checkNotNull(bound)); } @@ -67,6 +69,7 @@ public BatchReadOnlyTransaction batchReadOnlyTransaction(BatchTransactionId batc .setTimestamp(batchTransactionId.getTimestamp()) .setDefaultQueryOptions( sessionClient.getSpanner().getDefaultQueryOptions(sessionClient.getDatabaseId())) + .setExecutorProvider(sessionClient.getSpanner().getAsyncExecutorProvider()) .setDefaultPrefetchChunks(sessionClient.getSpanner().getDefaultPrefetchChunks()), batchTransactionId); } @@ -81,6 +84,7 @@ private static class BatchReadOnlyTransactionImpl extends MultiUseReadOnlyTransa super(builder.setTimestampBound(bound)); this.sessionName = session.getName(); this.options = session.getOptions(); + setSpan(Tracing.getTracer().getCurrentSpan()); initTransaction(); } @@ -89,6 +93,7 @@ private static class BatchReadOnlyTransactionImpl extends MultiUseReadOnlyTransa super(builder.setTransactionId(batchTransactionId.getTransactionId())); this.sessionName = session.getName(); this.options = session.getOptions(); + setSpan(Tracing.getTracer().getCurrentSpan()); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java index ac29ba2b37..d52d1d892e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClient.java @@ -278,6 +278,127 @@ public interface DatabaseClient { */ TransactionManager transactionManager(); + /** + * Returns an asynchronous transaction runner for executing a single logical transaction with + * retries. The returned runner can only be used once. + * + *

Example of a read write transaction. + * + *

 
+   * Executor executor = Executors.newSingleThreadExecutor();
+   * final long singerId = my_singer_id;
+   * AsyncRunner runner = client.runAsync();
+   * ApiFuture rowCount =
+   *     runner.runAsync(
+   *         new AsyncWork() {
+   *           @Override
+   *           public ApiFuture doWorkAsync(TransactionContext txn) {
+   *             String column = "FirstName";
+   *             Struct row =
+   *                 txn.readRow("Singers", Key.of(singerId), Collections.singleton("Name"));
+   *             String name = row.getString("Name");
+   *             return txn.executeUpdateAsync(
+   *                 Statement.newBuilder("UPDATE Singers SET Name=@name WHERE SingerId=@id")
+   *                     .bind("id")
+   *                     .to(singerId)
+   *                     .bind("name")
+   *                     .to(name.toUpperCase())
+   *                     .build());
+   *           }
+   *         },
+   *         executor);
+   * 
+ */ + AsyncRunner runAsync(); + + /** + * Returns an asynchronous transaction manager which allows manual management of transaction + * lifecycle. This API is meant for advanced users. Most users should instead use the {@link + * #runAsync()} API instead. + * + *

Example of using {@link AsyncTransactionManager} with lambda expressions (Java 8 and + * higher). + * + *

{@code
+   * long singerId = 1L;
+   * try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
+   *   TransactionContextFuture txnFut = manager.beginAsync();
+   *   while (true) {
+   *     String column = "FirstName";
+   *     CommitTimestampFuture commitTimestamp =
+   *         txnFut
+   *             .then(
+   *                 (txn, __) ->
+   *                     txn.readRowAsync(
+   *                         "Singers", Key.of(singerId), Collections.singleton(column)))
+   *             .then(
+   *                 (txn, row) -> {
+   *                   String name = row.getString(column);
+   *                   txn.buffer(
+   *                       Mutation.newUpdateBuilder("Singers")
+   *                           .set(column)
+   *                           .to(name.toUpperCase())
+   *                           .build());
+   *                   return ApiFutures.immediateFuture(null);
+   *                 })
+   *             .commitAsync();
+   *     try {
+   *       commitTimestamp.get();
+   *       break;
+   *     } catch (AbortedException e) {
+   *       Thread.sleep(e.getRetryDelayInMillis() / 1000);
+   *       txnFut = manager.resetForRetryAsync();
+   *     }
+   *   }
+   * }
+   * }
+ * + *

Example of using {@link AsyncTransactionManager} (Java 7). + * + *

{@code
+   * final long singerId = 1L;
+   * try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
+   *   TransactionContextFuture txn = manager.beginAsync();
+   *   while (true) {
+   *     final String column = "FirstName";
+   *     CommitTimestampFuture commitTimestamp =
+   *         txn.then(
+   *                 new AsyncTransactionFunction() {
+   *                   @Override
+   *                   public ApiFuture apply(TransactionContext txn, Void input)
+   *                       throws Exception {
+   *                     return txn.readRowAsync(
+   *                         "Singers", Key.of(singerId), Collections.singleton(column));
+   *                   }
+   *                 })
+   *             .then(
+   *                 new AsyncTransactionFunction() {
+   *                   @Override
+   *                   public ApiFuture apply(TransactionContext txn, Struct input)
+   *                       throws Exception {
+   *                     String name = input.getString(column);
+   *                     txn.buffer(
+   *                         Mutation.newUpdateBuilder("Singers")
+   *                             .set(column)
+   *                             .to(name.toUpperCase())
+   *                             .build());
+   *                     return ApiFutures.immediateFuture(null);
+   *                   }
+   *                 })
+   *             .commitAsync();
+   *     try {
+   *       commitTimestamp.get();
+   *       break;
+   *     } catch (AbortedException e) {
+   *       Thread.sleep(e.getRetryDelayInMillis() / 1000);
+   *       txn = manager.resetForRetryAsync();
+   *     }
+   *   }
+   * }
+   * }
+ */ + AsyncTransactionManager transactionManagerAsync(); + /** * Returns the lower bound of rows modified by this DML statement. * diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java index ec83d06335..4dd10001c7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java @@ -17,7 +17,7 @@ package com.google.cloud.spanner; import com.google.cloud.Timestamp; -import com.google.cloud.spanner.SessionPool.PooledSession; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; import com.google.cloud.spanner.SpannerImpl.ClosedException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; @@ -52,12 +52,12 @@ private enum SessionMode { } @VisibleForTesting - PooledSession getReadSession() { + PooledSessionFuture getReadSession() { return pool.getReadSession(); } @VisibleForTesting - PooledSession getReadWriteSession() { + PooledSessionFuture getReadWriteSession() { return pool.getReadWriteSession(); } @@ -191,6 +191,28 @@ public TransactionManager transactionManager() { } } + @Override + public AsyncRunner runAsync() { + Span span = tracer.spanBuilder(READ_WRITE_TRANSACTION).startSpan(); + try (Scope s = tracer.withSpan(span)) { + return getReadWriteSession().runAsync(); + } catch (RuntimeException e) { + TraceUtil.endSpanWithFailure(span, e); + throw e; + } + } + + @Override + public AsyncTransactionManager transactionManagerAsync() { + Span span = tracer.spanBuilder(READ_WRITE_TRANSACTION).startSpan(); + try (Scope s = tracer.withSpan(span)) { + return getReadWriteSession().transactionManagerAsync(); + } catch (RuntimeException e) { + TraceUtil.endSpanWithFailure(span, e); + throw e; + } + } + @Override public long executePartitionedUpdate(final Statement stmt) { Span span = tracer.spanBuilder(PARTITION_DML_TRANSACTION).startSpan(); @@ -212,7 +234,7 @@ public Long apply(Session session) { } private T runWithSessionRetry(SessionMode mode, Function callable) { - PooledSession session = + PooledSessionFuture session = mode == SessionMode.READ_WRITE ? getReadWriteSession() : getReadSession(); while (true) { try { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseId.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseId.java index d2c732750e..dd13df65e8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseId.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseId.java @@ -81,7 +81,7 @@ public String toString() { * projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID} * @throws IllegalArgumentException if {@code name} does not conform to the expected pattern */ - static DatabaseId of(String name) { + public static DatabaseId of(String name) { Preconditions.checkNotNull(name); Map parts = NAME_TEMPLATE.match(name); Preconditions.checkArgument( diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java new file mode 100644 index 0000000000..78e3505998 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingAsyncResultSet.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import java.util.concurrent.Executor; + +/** Forwarding implementation of {@link AsyncResultSet} that forwards all calls to a delegate. */ +public class ForwardingAsyncResultSet extends ForwardingResultSet implements AsyncResultSet { + final AsyncResultSet delegate; + + public ForwardingAsyncResultSet(AsyncResultSet delegate) { + super(Preconditions.checkNotNull(delegate)); + this.delegate = delegate; + } + + @Override + public CursorState tryNext() throws SpannerException { + return delegate.tryNext(); + } + + @Override + public ApiFuture setCallback(Executor exec, ReadyCallback cb) { + return delegate.setCallback(exec, cb); + } + + @Override + public void cancel() { + delegate.cancel(); + } + + @Override + public void resume() { + delegate.resume(); + } + + @Override + public ApiFuture> toListAsync( + Function transformer, Executor executor) { + return delegate.toListAsync(transformer, executor); + } + + @Override + public ImmutableList toList(Function transformer) + throws SpannerException { + return delegate.toList(transformer); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java index 753c3f6f39..4cc0ab9b9e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingResultSet.java @@ -17,16 +17,23 @@ package com.google.cloud.spanner; import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.spanner.v1.ResultSetStats; /** Forwarding implementation of ResultSet that forwards all calls to a delegate. */ public class ForwardingResultSet extends ForwardingStructReader implements ResultSet { - private ResultSet delegate; + private Supplier delegate; public ForwardingResultSet(ResultSet delegate) { super(delegate); - this.delegate = Preconditions.checkNotNull(delegate); + this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(delegate)); + } + + public ForwardingResultSet(Supplier supplier) { + super(supplier); + this.delegate = supplier; } /** @@ -39,26 +46,26 @@ public ForwardingResultSet(ResultSet delegate) { void replaceDelegate(ResultSet newDelegate) { Preconditions.checkNotNull(newDelegate); super.replaceDelegate(newDelegate); - this.delegate = newDelegate; + this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(newDelegate)); } @Override public boolean next() throws SpannerException { - return delegate.next(); + return delegate.get().next(); } @Override public Struct getCurrentRowAsStruct() { - return delegate.getCurrentRowAsStruct(); + return delegate.get().getCurrentRowAsStruct(); } @Override public void close() { - delegate.close(); + delegate.get().close(); } @Override public ResultSetStats getStats() { - return delegate.getStats(); + return delegate.get().getStats(); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java index 9b30b89985..67e546ad5a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java @@ -20,14 +20,20 @@ import com.google.cloud.Date; import com.google.cloud.Timestamp; import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import java.util.List; /** Forwarding implements of StructReader */ public class ForwardingStructReader implements StructReader { - private StructReader delegate; + private Supplier delegate; public ForwardingStructReader(StructReader delegate) { + this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(delegate)); + } + + public ForwardingStructReader(Supplier delegate) { this.delegate = Preconditions.checkNotNull(delegate); } @@ -39,221 +45,271 @@ public ForwardingStructReader(StructReader delegate) { * returned to the user. */ void replaceDelegate(StructReader newDelegate) { - this.delegate = Preconditions.checkNotNull(newDelegate); + this.delegate = Suppliers.ofInstance(Preconditions.checkNotNull(newDelegate)); } + /** + * Called before each forwarding call to allow sub classes to do additional state checking. Sub + * classes should throw an {@link Exception} if the current state is not valid for reading data + * from this {@link ForwardingStructReader}. The default implementation does nothing. + */ + protected void checkValidState() {} + @Override public Type getType() { - return delegate.getType(); + checkValidState(); + return delegate.get().getType(); } @Override public int getColumnCount() { - return delegate.getColumnCount(); + checkValidState(); + return delegate.get().getColumnCount(); } @Override public int getColumnIndex(String columnName) { - return delegate.getColumnIndex(columnName); + checkValidState(); + return delegate.get().getColumnIndex(columnName); } @Override public Type getColumnType(int columnIndex) { - return delegate.getColumnType(columnIndex); + checkValidState(); + return delegate.get().getColumnType(columnIndex); } @Override public Type getColumnType(String columnName) { - return delegate.getColumnType(columnName); + checkValidState(); + return delegate.get().getColumnType(columnName); } @Override public boolean isNull(int columnIndex) { - return delegate.isNull(columnIndex); + checkValidState(); + return delegate.get().isNull(columnIndex); } @Override public boolean isNull(String columnName) { - return delegate.isNull(columnName); + checkValidState(); + return delegate.get().isNull(columnName); } @Override public boolean getBoolean(int columnIndex) { - return delegate.getBoolean(columnIndex); + checkValidState(); + return delegate.get().getBoolean(columnIndex); } @Override public boolean getBoolean(String columnName) { - return delegate.getBoolean(columnName); + checkValidState(); + return delegate.get().getBoolean(columnName); } @Override public long getLong(int columnIndex) { - return delegate.getLong(columnIndex); + checkValidState(); + return delegate.get().getLong(columnIndex); } @Override public long getLong(String columnName) { - return delegate.getLong(columnName); + checkValidState(); + return delegate.get().getLong(columnName); } @Override public double getDouble(int columnIndex) { - return delegate.getDouble(columnIndex); + checkValidState(); + return delegate.get().getDouble(columnIndex); } @Override public double getDouble(String columnName) { - return delegate.getDouble(columnName); + checkValidState(); + return delegate.get().getDouble(columnName); } @Override public String getString(int columnIndex) { - return delegate.getString(columnIndex); + checkValidState(); + return delegate.get().getString(columnIndex); } @Override public String getString(String columnName) { - return delegate.getString(columnName); + checkValidState(); + return delegate.get().getString(columnName); } @Override public ByteArray getBytes(int columnIndex) { - return delegate.getBytes(columnIndex); + checkValidState(); + return delegate.get().getBytes(columnIndex); } @Override public ByteArray getBytes(String columnName) { - return delegate.getBytes(columnName); + checkValidState(); + return delegate.get().getBytes(columnName); } @Override public Timestamp getTimestamp(int columnIndex) { - return delegate.getTimestamp(columnIndex); + checkValidState(); + return delegate.get().getTimestamp(columnIndex); } @Override public Timestamp getTimestamp(String columnName) { - return delegate.getTimestamp(columnName); + checkValidState(); + return delegate.get().getTimestamp(columnName); } @Override public Date getDate(int columnIndex) { - return delegate.getDate(columnIndex); + checkValidState(); + return delegate.get().getDate(columnIndex); } @Override public Date getDate(String columnName) { - return delegate.getDate(columnName); + checkValidState(); + return delegate.get().getDate(columnName); } @Override public boolean[] getBooleanArray(int columnIndex) { - return delegate.getBooleanArray(columnIndex); + checkValidState(); + return delegate.get().getBooleanArray(columnIndex); } @Override public boolean[] getBooleanArray(String columnName) { - return delegate.getBooleanArray(columnName); + checkValidState(); + return delegate.get().getBooleanArray(columnName); } @Override public List getBooleanList(int columnIndex) { - return delegate.getBooleanList(columnIndex); + checkValidState(); + return delegate.get().getBooleanList(columnIndex); } @Override public List getBooleanList(String columnName) { - return delegate.getBooleanList(columnName); + checkValidState(); + return delegate.get().getBooleanList(columnName); } @Override public long[] getLongArray(int columnIndex) { - return delegate.getLongArray(columnIndex); + checkValidState(); + return delegate.get().getLongArray(columnIndex); } @Override public long[] getLongArray(String columnName) { - return delegate.getLongArray(columnName); + checkValidState(); + return delegate.get().getLongArray(columnName); } @Override public List getLongList(int columnIndex) { - return delegate.getLongList(columnIndex); + checkValidState(); + return delegate.get().getLongList(columnIndex); } @Override public List getLongList(String columnName) { - return delegate.getLongList(columnName); + checkValidState(); + return delegate.get().getLongList(columnName); } @Override public double[] getDoubleArray(int columnIndex) { - return delegate.getDoubleArray(columnIndex); + checkValidState(); + return delegate.get().getDoubleArray(columnIndex); } @Override public double[] getDoubleArray(String columnName) { - return delegate.getDoubleArray(columnName); + checkValidState(); + return delegate.get().getDoubleArray(columnName); } @Override public List getDoubleList(int columnIndex) { - return delegate.getDoubleList(columnIndex); + checkValidState(); + return delegate.get().getDoubleList(columnIndex); } @Override public List getDoubleList(String columnName) { - return delegate.getDoubleList(columnName); + checkValidState(); + return delegate.get().getDoubleList(columnName); } @Override public List getStringList(int columnIndex) { - return delegate.getStringList(columnIndex); + checkValidState(); + return delegate.get().getStringList(columnIndex); } @Override public List getStringList(String columnName) { - return delegate.getStringList(columnName); + checkValidState(); + return delegate.get().getStringList(columnName); } @Override public List getBytesList(int columnIndex) { - return delegate.getBytesList(columnIndex); + checkValidState(); + return delegate.get().getBytesList(columnIndex); } @Override public List getBytesList(String columnName) { - return delegate.getBytesList(columnName); + checkValidState(); + return delegate.get().getBytesList(columnName); } @Override public List getTimestampList(int columnIndex) { - return delegate.getTimestampList(columnIndex); + checkValidState(); + return delegate.get().getTimestampList(columnIndex); } @Override public List getTimestampList(String columnName) { - return delegate.getTimestampList(columnName); + checkValidState(); + return delegate.get().getTimestampList(columnName); } @Override public List getDateList(int columnIndex) { - return delegate.getDateList(columnIndex); + checkValidState(); + return delegate.get().getDateList(columnIndex); } @Override public List getDateList(String columnName) { - return delegate.getDateList(columnName); + checkValidState(); + return delegate.get().getDateList(columnName); } @Override public List getStructList(int columnIndex) { - return delegate.getStructList(columnIndex); + checkValidState(); + return delegate.get().getStructList(columnIndex); } @Override public List getStructList(String columnName) { - return delegate.getStructList(columnName); + checkValidState(); + return delegate.get().getStructList(columnName); } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java index d193ad1c75..879b632d17 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java @@ -59,6 +59,11 @@ public static ReadAndQueryOption prefetchChunks(int prefetchChunks) { return new FlowControlOption(prefetchChunks); } + public static ReadAndQueryOption bufferRows(int bufferRows) { + Preconditions.checkArgument(bufferRows > 0, "bufferRows should be greater than 0"); + return new BufferRowsOption(bufferRows); + } + /** * Specifying this will cause the list operations to fetch at most this many records in a page. */ @@ -115,8 +120,22 @@ void appendToOptions(Options options) { } } + static final class BufferRowsOption extends InternalOption implements ReadAndQueryOption { + final int bufferRows; + + BufferRowsOption(int bufferRows) { + this.bufferRows = bufferRows; + } + + @Override + void appendToOptions(Options options) { + options.bufferRows = bufferRows; + } + } + private Long limit; private Integer prefetchChunks; + private Integer bufferRows; private Integer pageSize; private String pageToken; private String filter; @@ -140,6 +159,14 @@ int prefetchChunks() { return prefetchChunks; } + boolean hasBufferRows() { + return bufferRows != null; + } + + int bufferRows() { + return bufferRows; + } + boolean hasPageSize() { return pageSize != null; } @@ -203,6 +230,10 @@ public boolean equals(Object o) { || hasPrefetchChunks() && that.hasPrefetchChunks() && Objects.equals(prefetchChunks(), that.prefetchChunks())) + && (!hasBufferRows() && !that.hasBufferRows() + || hasBufferRows() + && that.hasBufferRows() + && Objects.equals(bufferRows(), that.bufferRows())) && (!hasPageSize() && !that.hasPageSize() || hasPageSize() && that.hasPageSize() && Objects.equals(pageSize(), that.pageSize())) && Objects.equals(pageToken(), that.pageToken()) @@ -218,6 +249,9 @@ public int hashCode() { if (prefetchChunks != null) { result = 31 * result + prefetchChunks.hashCode(); } + if (bufferRows != null) { + result = 31 * result + bufferRows.hashCode(); + } if (pageSize != null) { result = 31 * result + pageSize.hashCode(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java index 638c567a03..96ae390dd6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDMLTransaction.java @@ -33,6 +33,7 @@ import com.google.spanner.v1.TransactionOptions; import com.google.spanner.v1.TransactionSelector; import io.grpc.Status.Code; +import io.opencensus.trace.Span; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -160,4 +161,8 @@ long executeStreamingPartitionedUpdate(final Statement statement, Duration timeo public void invalidate() { isValid = false; } + + // No-op method needed to implement SessionTransaction interface. + @Override + public void setSpan(Span span) {} } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ReadContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ReadContext.java index 16f40769fa..e87d40fb20 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ReadContext.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ReadContext.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner; +import com.google.api.core.ApiFuture; import com.google.cloud.spanner.Options.QueryOption; import com.google.cloud.spanner.Options.ReadOption; import javax.annotation.Nullable; @@ -65,6 +66,13 @@ enum QueryAnalyzeMode { */ ResultSet read(String table, KeySet keys, Iterable columns, ReadOption... options); + /** + * Same as {@link #read(String, KeySet, Iterable, ReadOption...)}, but is guaranteed to be + * non-blocking and will return the results as an {@link AsyncResultSet}. + */ + AsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options); + /** * Reads zero or more rows from a database using an index. * @@ -93,6 +101,13 @@ enum QueryAnalyzeMode { ResultSet readUsingIndex( String table, String index, KeySet keys, Iterable columns, ReadOption... options); + /** + * Same as {@link #readUsingIndex(String, String, KeySet, Iterable, ReadOption...)}, but is + * guaranteed to be non-blocking and will return its results as an {@link AsyncResultSet}. + */ + AsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options); + /** * Reads a single row from a database, returning {@code null} if the row does not exist. * @@ -112,6 +127,9 @@ ResultSet readUsingIndex( @Nullable Struct readRow(String table, Key key, Iterable columns); + /** Same as {@link #readRow(String, Key, Iterable)}, but is guaranteed to be non-blocking. */ + ApiFuture readRowAsync(String table, Key key, Iterable columns); + /** * Reads a single row from a database using an index, returning {@code null} if the row does not * exist. @@ -134,6 +152,13 @@ ResultSet readUsingIndex( @Nullable Struct readRowUsingIndex(String table, String index, Key key, Iterable columns); + /** + * Same as {@link #readRowUsingIndex(String, String, Key, Iterable)}, but is guaranteed to be + * non-blocking. + */ + ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns); + /** * Executes a query against the database. * @@ -160,6 +185,12 @@ ResultSet readUsingIndex( */ ResultSet executeQuery(Statement statement, QueryOption... options); + /** + * Same as {@link #executeQuery(Statement, QueryOption...)}, but is guaranteed to be non-blocking + * and returns its results as an {@link AsyncResultSet}. + */ + AsyncResultSet executeQueryAsync(Statement statement, QueryOption... options); + /** * Analyzes a query and returns query plan and/or query execution statistics information. * diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java index 29c3e52c6a..278b15d967 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java @@ -16,6 +16,8 @@ package com.google.cloud.spanner; +import com.google.api.gax.core.ExecutorProvider; +import com.google.api.gax.core.InstantiatingExecutorProvider; import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; @@ -23,6 +25,7 @@ import com.google.cloud.spanner.Type.StructField; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.spanner.v1.ResultSetStats; import java.util.List; @@ -41,6 +44,30 @@ public static ResultSet forRows(Type type, Iterable rows) { return new PrePopulatedResultSet(type, rows); } + /** Converts the given {@link ResultSet} to an {@link AsyncResultSet}. */ + public static AsyncResultSet toAsyncResultSet(ResultSet delegate) { + return new AsyncResultSetImpl( + InstantiatingExecutorProvider.newBuilder() + .setExecutorThreadCount(1) + .setThreadFactory( + new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("test-async-resultset-%d") + .build()) + .build(), + delegate, + 100); + } + + /** + * Converts the given {@link ResultSet} to an {@link AsyncResultSet} using the given {@link + * ExecutorProvider}. + */ + public static AsyncResultSet toAsyncResultSet( + ResultSet delegate, ExecutorProvider executorProvider) { + return new AsyncResultSetImpl(executorProvider, delegate, 100); + } + private static class PrePopulatedResultSet implements ResultSet { private final List rows; private final Type type; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java index b865efa2d9..ce4d27e94e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.api.core.ApiFuture; +import com.google.api.core.SettableApiFuture; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AbstractReadContext.MultiUseReadOnlyTransaction; import com.google.cloud.spanner.AbstractReadContext.SingleReadContext; @@ -28,6 +29,7 @@ import com.google.cloud.spanner.TransactionRunnerImpl.TransactionContextImpl; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.spanner.v1.BeginTransactionRequest; @@ -43,6 +45,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; /** @@ -76,14 +79,17 @@ static void throwIfTransactionsPending() { static interface SessionTransaction { /** Invalidates the transaction, generally because a new one has been started on the session. */ void invalidate(); + /** Registers the current span on the transaction. */ + void setSpan(Span span); } private final SpannerImpl spanner; private final String name; private final DatabaseId databaseId; private SessionTransaction activeTransaction; - private ByteString readyTransactionId; + ByteString readyTransactionId; private final Map options; + private Span currentSpan; SessionImpl(SpannerImpl spanner, String name, Map options) { this.spanner = spanner; @@ -101,6 +107,10 @@ public String getName() { return options; } + void setCurrentSpan(Span span) { + currentSpan = span; + } + @Override public long executePartitionedUpdate(Statement stmt) { setActive(null); @@ -170,6 +180,8 @@ public ReadContext singleUse(TimestampBound bound) { .setRpc(spanner.getRpc()) .setDefaultQueryOptions(spanner.getDefaultQueryOptions(databaseId)) .setDefaultPrefetchChunks(spanner.getDefaultPrefetchChunks()) + .setSpan(currentSpan) + .setExecutorProvider(spanner.getAsyncExecutorProvider()) .build()); } @@ -187,6 +199,8 @@ public ReadOnlyTransaction singleUseReadOnlyTransaction(TimestampBound bound) { .setRpc(spanner.getRpc()) .setDefaultQueryOptions(spanner.getDefaultQueryOptions(databaseId)) .setDefaultPrefetchChunks(spanner.getDefaultPrefetchChunks()) + .setSpan(currentSpan) + .setExecutorProvider(spanner.getAsyncExecutorProvider()) .buildSingleUseReadOnlyTransaction()); } @@ -204,6 +218,8 @@ public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) { .setRpc(spanner.getRpc()) .setDefaultQueryOptions(spanner.getDefaultQueryOptions(databaseId)) .setDefaultPrefetchChunks(spanner.getDefaultPrefetchChunks()) + .setSpan(currentSpan) + .setExecutorProvider(spanner.getAsyncExecutorProvider()) .build()); } @@ -213,6 +229,23 @@ public TransactionRunner readWriteTransaction() { new TransactionRunnerImpl(this, spanner.getRpc(), spanner.getDefaultPrefetchChunks())); } + @Override + public AsyncRunner runAsync() { + return new AsyncRunnerImpl( + setActive( + new TransactionRunnerImpl(this, spanner.getRpc(), spanner.getDefaultPrefetchChunks()))); + } + + @Override + public TransactionManager transactionManager() { + return new TransactionManagerImpl(this, currentSpan); + } + + @Override + public AsyncTransactionManagerImpl transactionManagerAsync() { + return new AsyncTransactionManagerImpl(this, currentSpan); + } + @Override public void prepareReadWriteTransaction() { setActive(null); @@ -238,27 +271,59 @@ public void close() { } ByteString beginTransaction() { - Span span = tracer.spanBuilder(SpannerImpl.BEGIN_TRANSACTION).startSpan(); - try (Scope s = tracer.withSpan(span)) { - final BeginTransactionRequest request = - BeginTransactionRequest.newBuilder() - .setSession(name) - .setOptions( - TransactionOptions.newBuilder() - .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance())) - .build(); - Transaction txn = spanner.getRpc().beginTransaction(request, options); - if (txn.getId().isEmpty()) { - throw newSpannerException(ErrorCode.INTERNAL, "Missing id in transaction\n" + getName()); - } - span.end(TraceUtil.END_SPAN_OPTIONS); - return txn.getId(); - } catch (RuntimeException e) { - TraceUtil.endSpanWithFailure(span, e); - throw e; + try { + return beginTransactionAsync().get(); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause() == null ? e : e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); } } + ApiFuture beginTransactionAsync() { + final SettableApiFuture res = SettableApiFuture.create(); + final Span span = tracer.spanBuilder(SpannerImpl.BEGIN_TRANSACTION).startSpan(); + final BeginTransactionRequest request = + BeginTransactionRequest.newBuilder() + .setSession(name) + .setOptions( + TransactionOptions.newBuilder() + .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance())) + .build(); + final ApiFuture requestFuture = + spanner.getRpc().beginTransactionAsync(request, options); + requestFuture.addListener( + tracer.withSpan( + span, + new Runnable() { + @Override + public void run() { + try { + Transaction txn = requestFuture.get(); + if (txn.getId().isEmpty()) { + throw newSpannerException( + ErrorCode.INTERNAL, "Missing id in transaction\n" + getName()); + } + span.end(TraceUtil.END_SPAN_OPTIONS); + res.set(txn.getId()); + } catch (ExecutionException e) { + TraceUtil.endSpanWithFailure(span, e); + res.setException( + SpannerExceptionFactory.newSpannerException( + e.getCause() == null ? e : e.getCause())); + } catch (InterruptedException e) { + TraceUtil.endSpanWithFailure(span, e); + res.setException(SpannerExceptionFactory.propagateInterrupt(e)); + } catch (Exception e) { + TraceUtil.endSpanWithFailure(span, e); + res.setException(e); + } + } + }), + MoreExecutors.directExecutor()); + return res; + } + TransactionContextImpl newTransaction() { return TransactionContextImpl.newBuilder() .setSession(this) @@ -266,6 +331,8 @@ TransactionContextImpl newTransaction() { .setRpc(spanner.getRpc()) .setDefaultQueryOptions(spanner.getDefaultQueryOptions(databaseId)) .setDefaultPrefetchChunks(spanner.getDefaultPrefetchChunks()) + .setSpan(currentSpan) + .setExecutorProvider(spanner.getAsyncExecutorProvider()) .build(); } @@ -277,11 +344,13 @@ T setActive(@Nullable T ctx) { } activeTransaction = ctx; readyTransactionId = null; + if (activeTransaction != null) { + activeTransaction.setSpan(currentSpan); + } return ctx; } - @Override - public TransactionManager transactionManager() { - return new TransactionManagerImpl(this); + boolean hasReadyTransaction() { + return readyTransactionId != null; } } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java index 2286c3b34b..90e399fad6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java @@ -40,6 +40,8 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.api.gax.core.ExecutorProvider; import com.google.cloud.Timestamp; import com.google.cloud.grpc.GrpcTransportOptions; import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory; @@ -48,6 +50,7 @@ import com.google.cloud.spanner.SessionClient.SessionConsumer; import com.google.cloud.spanner.SpannerException.ResourceNotFoundException; import com.google.cloud.spanner.SpannerImpl.ClosedException; +import com.google.cloud.spanner.TransactionManager.TransactionState; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.MoreObjects; @@ -56,11 +59,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.ForwardingListenableFuture; +import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.google.common.util.concurrent.Uninterruptibles; import com.google.protobuf.Empty; import io.opencensus.common.Scope; import io.opencensus.common.ToLongFunction; @@ -85,12 +89,17 @@ import java.util.Queue; import java.util.Random; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; @@ -132,53 +141,115 @@ Instant instant() { } } + private abstract static class CachedResultSetSupplier implements Supplier { + private ResultSet cached; + + abstract ResultSet load(); + + ResultSet reload() { + return cached = load(); + } + + @Override + public ResultSet get() { + if (cached == null) { + cached = load(); + } + return cached; + } + } + /** * Wrapper around {@code ReadContext} that releases the session to the pool once the call is * finished, if it is a single use context. */ private static class AutoClosingReadContext implements ReadContext { - private final Function readContextDelegateSupplier; + /** + * {@link AsyncResultSet} implementation that keeps track of the async operations that are still + * running for this {@link ReadContext} and that should finish before the {@link ReadContext} + * releases its session back into the pool. + */ + private class AutoClosingReadContextAsyncResultSetImpl extends AsyncResultSetImpl { + private AutoClosingReadContextAsyncResultSetImpl( + ExecutorProvider executorProvider, ResultSet delegate, int bufferRows) { + super(executorProvider, delegate, bufferRows); + } + + @Override + public ApiFuture setCallback(Executor exec, ReadyCallback cb) { + Runnable listener = + new Runnable() { + @Override + public void run() { + synchronized (lock) { + if (asyncOperationsCount.decrementAndGet() == 0 && closed) { + // All async operations for this read context have finished. + AutoClosingReadContext.this.close(); + } + } + } + }; + try { + asyncOperationsCount.incrementAndGet(); + addListener(listener); + return super.setCallback(exec, cb); + } catch (Throwable t) { + removeListener(listener); + asyncOperationsCount.decrementAndGet(); + throw t; + } + } + } + + private final Function readContextDelegateSupplier; private T readContextDelegate; private final SessionPool sessionPool; - private PooledSession session; private final boolean isSingleUse; - private boolean closed; + private final AtomicInteger asyncOperationsCount = new AtomicInteger(); + + private Object lock = new Object(); + + @GuardedBy("lock") private boolean sessionUsedForQuery = false; + @GuardedBy("lock") + private PooledSessionFuture session; + + @GuardedBy("lock") + private boolean closed; + + @GuardedBy("lock") + private boolean delegateClosed; + private AutoClosingReadContext( - Function delegateSupplier, + Function delegateSupplier, SessionPool sessionPool, - PooledSession session, + PooledSessionFuture session, boolean isSingleUse) { this.readContextDelegateSupplier = delegateSupplier; this.sessionPool = sessionPool; this.session = session; this.isSingleUse = isSingleUse; - while (true) { - try { - this.readContextDelegate = readContextDelegateSupplier.apply(this.session); - break; - } catch (SessionNotFoundException e) { - replaceSessionIfPossible(e); - } - } } T getReadContextDelegate() { + synchronized (lock) { + if (readContextDelegate == null) { + while (true) { + try { + this.readContextDelegate = readContextDelegateSupplier.apply(this.session); + break; + } catch (SessionNotFoundException e) { + replaceSessionIfPossible(e); + } + } + } + } return readContextDelegate; } - private ResultSet wrap(final Supplier resultSetSupplier) { - ResultSet res; - while (true) { - try { - res = resultSetSupplier.get(); - break; - } catch (SessionNotFoundException e) { - replaceSessionIfPossible(e); - } - } - return new ForwardingResultSet(res) { + private ResultSet wrap(final CachedResultSetSupplier resultSetSupplier) { + return new ForwardingResultSet(resultSetSupplier) { private boolean beforeFirst = true; @Override @@ -187,8 +258,18 @@ public boolean next() throws SpannerException { try { return internalNext(); } catch (SessionNotFoundException e) { - replaceSessionIfPossible(e); - replaceDelegate(resultSetSupplier.get()); + while (true) { + // Keep the replace-if-possible outside the try-block to let the exception bubble up + // if it's too late to replace the session. + replaceSessionIfPossible(e); + try { + replaceDelegate(resultSetSupplier.reload()); + break; + } catch (SessionNotFoundException snfe) { + e = snfe; + // retry on yet another session. + } + } } } } @@ -197,9 +278,11 @@ private boolean internalNext() { try { boolean ret = super.next(); if (beforeFirst) { - session.markUsed(); - beforeFirst = false; - sessionUsedForQuery = true; + synchronized (lock) { + session.get().markUsed(); + beforeFirst = false; + sessionUsedForQuery = true; + } } if (!ret && isSingleUse) { close(); @@ -208,9 +291,11 @@ private boolean internalNext() { } catch (SessionNotFoundException e) { throw e; } catch (SpannerException e) { - if (!closed && isSingleUse) { - session.lastException = e; - AutoClosingReadContext.this.close(); + synchronized (lock) { + if (!closed && isSingleUse) { + session.get().lastException = e; + AutoClosingReadContext.this.close(); + } } throw e; } @@ -218,22 +303,27 @@ private boolean internalNext() { @Override public void close() { - super.close(); - if (isSingleUse) { - AutoClosingReadContext.this.close(); + try { + super.close(); + } finally { + if (isSingleUse) { + AutoClosingReadContext.this.close(); + } } } }; } - private void replaceSessionIfPossible(SessionNotFoundException e) { - if (isSingleUse || !sessionUsedForQuery) { - // This class is only used by read-only transactions, so we know that we only need a - // read-only session. - session = sessionPool.replaceReadSession(e, session); - readContextDelegate = readContextDelegateSupplier.apply(session); - } else { - throw e; + private void replaceSessionIfPossible(SessionNotFoundException notFound) { + synchronized (lock) { + if (isSingleUse || !sessionUsedForQuery) { + // This class is only used by read-only transactions, so we know that we only need a + // read-only session. + session = sessionPool.replaceReadSession(notFound, session); + readContextDelegate = readContextDelegateSupplier.apply(session); + } else { + throw notFound; + } } } @@ -244,14 +334,37 @@ public ResultSet read( final Iterable columns, final ReadOption... options) { return wrap( - new Supplier() { + new CachedResultSetSupplier() { @Override - public ResultSet get() { - return readContextDelegate.read(table, keys, columns, options); + ResultSet load() { + return getReadContextDelegate().read(table, keys, columns, options); } }); } + @Override + public AsyncResultSet readAsync( + final String table, + final KeySet keys, + final Iterable columns, + final ReadOption... options) { + Options readOptions = Options.fromReadOptions(options); + final int bufferRows = + readOptions.hasBufferRows() + ? readOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AutoClosingReadContextAsyncResultSetImpl( + sessionPool.sessionClient.getSpanner().getAsyncExecutorProvider(), + wrap( + new CachedResultSetSupplier() { + @Override + ResultSet load() { + return getReadContextDelegate().read(table, keys, columns, options); + } + }), + bufferRows); + } + @Override public ResultSet readUsingIndex( final String table, @@ -260,84 +373,159 @@ public ResultSet readUsingIndex( final Iterable columns, final ReadOption... options) { return wrap( - new Supplier() { + new CachedResultSetSupplier() { @Override - public ResultSet get() { - return readContextDelegate.readUsingIndex(table, index, keys, columns, options); + ResultSet load() { + return getReadContextDelegate().readUsingIndex(table, index, keys, columns, options); } }); } + @Override + public AsyncResultSet readUsingIndexAsync( + final String table, + final String index, + final KeySet keys, + final Iterable columns, + final ReadOption... options) { + Options readOptions = Options.fromReadOptions(options); + final int bufferRows = + readOptions.hasBufferRows() + ? readOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AutoClosingReadContextAsyncResultSetImpl( + sessionPool.sessionClient.getSpanner().getAsyncExecutorProvider(), + wrap( + new CachedResultSetSupplier() { + @Override + ResultSet load() { + return getReadContextDelegate() + .readUsingIndex(table, index, keys, columns, options); + } + }), + bufferRows); + } + @Override @Nullable public Struct readRow(String table, Key key, Iterable columns) { try { while (true) { try { - session.markUsed(); - return readContextDelegate.readRow(table, key, columns); + synchronized (lock) { + session.get().markUsed(); + } + return getReadContextDelegate().readRow(table, key, columns); } catch (SessionNotFoundException e) { replaceSessionIfPossible(e); } } } finally { - sessionUsedForQuery = true; + synchronized (lock) { + sessionUsedForQuery = true; + } if (isSingleUse) { close(); } } } + @Override + public ApiFuture readRowAsync(String table, Key key, Iterable columns) { + try (AsyncResultSet rs = readAsync(table, KeySet.singleKey(key), columns)) { + return AbstractReadContext.consumeSingleRowAsync(rs); + } + } + @Override @Nullable public Struct readRowUsingIndex(String table, String index, Key key, Iterable columns) { try { while (true) { try { - session.markUsed(); - return readContextDelegate.readRowUsingIndex(table, index, key, columns); + synchronized (lock) { + session.get().markUsed(); + } + return getReadContextDelegate().readRowUsingIndex(table, index, key, columns); } catch (SessionNotFoundException e) { replaceSessionIfPossible(e); } } } finally { - sessionUsedForQuery = true; + synchronized (lock) { + sessionUsedForQuery = true; + } if (isSingleUse) { close(); } } } + @Override + public ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + try (AsyncResultSet rs = readUsingIndexAsync(table, index, KeySet.singleKey(key), columns)) { + return AbstractReadContext.consumeSingleRowAsync(rs); + } + } + @Override public ResultSet executeQuery(final Statement statement, final QueryOption... options) { return wrap( - new Supplier() { + new CachedResultSetSupplier() { @Override - public ResultSet get() { - return readContextDelegate.executeQuery(statement, options); + ResultSet load() { + return getReadContextDelegate().executeQuery(statement, options); } }); } + @Override + public AsyncResultSet executeQueryAsync( + final Statement statement, final QueryOption... options) { + Options queryOptions = Options.fromQueryOptions(options); + final int bufferRows = + queryOptions.hasBufferRows() + ? queryOptions.bufferRows() + : AsyncResultSetImpl.DEFAULT_BUFFER_SIZE; + return new AutoClosingReadContextAsyncResultSetImpl( + sessionPool.sessionClient.getSpanner().getAsyncExecutorProvider(), + wrap( + new CachedResultSetSupplier() { + @Override + ResultSet load() { + return getReadContextDelegate().executeQuery(statement, options); + } + }), + bufferRows); + } + @Override public ResultSet analyzeQuery(final Statement statement, final QueryAnalyzeMode queryMode) { return wrap( - new Supplier() { + new CachedResultSetSupplier() { @Override - public ResultSet get() { - return readContextDelegate.analyzeQuery(statement, queryMode); + ResultSet load() { + return getReadContextDelegate().analyzeQuery(statement, queryMode); } }); } @Override public void close() { - if (closed) { - return; + synchronized (lock) { + if (closed && delegateClosed) { + return; + } + closed = true; + if (asyncOperationsCount.get() == 0) { + if (readContextDelegate != null) { + readContextDelegate.close(); + } + session.close(); + delegateClosed = true; + } } - closed = true; - readContextDelegate.close(); - session.close(); } } @@ -345,9 +533,9 @@ private static class AutoClosingReadTransaction extends AutoClosingReadContext implements ReadOnlyTransaction { AutoClosingReadTransaction( - Function txnSupplier, + Function txnSupplier, SessionPool sessionPool, - PooledSession session, + PooledSessionFuture session, boolean isSingleUse) { super(txnSupplier, sessionPool, session, isSingleUse); } @@ -394,6 +582,13 @@ public ResultSet read( return new SessionPoolResultSet(delegate.read(table, keys, columns, options)); } + @Override + public AsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.UNIMPLEMENTED, "not yet implemented"); + } + @Override public ResultSet readUsingIndex( String table, @@ -405,6 +600,17 @@ public ResultSet readUsingIndex( delegate.readUsingIndex(table, index, keys, columns, options)); } + @Override + public AsyncResultSet readUsingIndexAsync( + String table, + String index, + KeySet keys, + Iterable columns, + ReadOption... options) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.UNIMPLEMENTED, "not yet implemented"); + } + @Override public Struct readRow(String table, Key key, Iterable columns) { try { @@ -414,6 +620,13 @@ public Struct readRow(String table, Key key, Iterable columns) { } } + @Override + public ApiFuture readRowAsync(String table, Key key, Iterable columns) { + try (AsyncResultSet rs = readAsync(table, KeySet.singleKey(key), columns)) { + return AbstractReadContext.consumeSingleRowAsync(rs); + } + } + @Override public void buffer(Mutation mutation) { delegate.buffer(mutation); @@ -429,6 +642,15 @@ public Struct readRowUsingIndex( } } + @Override + public ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + try (AsyncResultSet rs = + readUsingIndexAsync(table, index, KeySet.singleKey(key), columns)) { + return AbstractReadContext.consumeSingleRowAsync(rs); + } + } + @Override public void buffer(Iterable mutations) { delegate.buffer(mutations); @@ -443,6 +665,15 @@ public long executeUpdate(Statement statement) { } } + @Override + public ApiFuture executeUpdateAsync(Statement statement) { + try { + return delegate.executeUpdateAsync(statement); + } catch (SessionNotFoundException e) { + throw handleSessionNotFound(e); + } + } + @Override public long[] batchUpdate(Iterable statements) { try { @@ -452,11 +683,29 @@ public long[] batchUpdate(Iterable statements) { } } + @Override + public ApiFuture batchUpdateAsync(Iterable statements) { + try { + return delegate.batchUpdateAsync(statements); + } catch (SessionNotFoundException e) { + throw handleSessionNotFound(e); + } + } + @Override public ResultSet executeQuery(Statement statement, QueryOption... options) { return new SessionPoolResultSet(delegate.executeQuery(statement, options)); } + @Override + public AsyncResultSet executeQueryAsync(Statement statement, QueryOption... options) { + try { + return delegate.executeQueryAsync(statement, options); + } catch (SessionNotFoundException e) { + throw handleSessionNotFound(e); + } + } + @Override public ResultSet analyzeQuery(Statement statement, QueryAnalyzeMode queryMode) { return new SessionPoolResultSet(delegate.analyzeQuery(statement, queryMode)); @@ -470,39 +719,40 @@ public void close() { private TransactionManager delegate; private final SessionPool sessionPool; - private PooledSession session; + private PooledSessionFuture session; private boolean closed; private boolean restartedAfterSessionNotFound; - AutoClosingTransactionManager(SessionPool sessionPool, PooledSession session) { + AutoClosingTransactionManager(SessionPool sessionPool, PooledSessionFuture session) { this.sessionPool = sessionPool; this.session = session; - this.delegate = session.delegate.transactionManager(); } @Override public TransactionContext begin() { + this.delegate = session.get().transactionManager(); while (true) { try { return internalBegin(); } catch (SessionNotFoundException e) { session = sessionPool.replaceReadWriteSession(e, session); - delegate = session.delegate.transactionManager(); + delegate = session.get().delegate.transactionManager(); } } } private TransactionContext internalBegin() { TransactionContext res = new SessionPoolTransactionContext(delegate.begin()); - session.markUsed(); + session.get().markUsed(); return res; } - private SpannerException handleSessionNotFound(SessionNotFoundException e) { - session = sessionPool.replaceReadWriteSession(e, session); - delegate = session.delegate.transactionManager(); + private SpannerException handleSessionNotFound(SessionNotFoundException notFound) { + session = sessionPool.replaceReadWriteSession(notFound, session); + delegate = session.get().delegate.transactionManager(); restartedAfterSessionNotFound = true; - return SpannerExceptionFactory.newSpannerException(ErrorCode.ABORTED, e.getMessage(), e); + return SpannerExceptionFactory.newSpannerException( + ErrorCode.ABORTED, notFound.getMessage(), notFound); } @Override @@ -540,7 +790,7 @@ public TransactionContext resetForRetry() { } } catch (SessionNotFoundException e) { session = sessionPool.replaceReadWriteSession(e, session); - delegate = session.delegate.transactionManager(); + delegate = session.get().delegate.transactionManager(); restartedAfterSessionNotFound = true; } } @@ -558,7 +808,9 @@ public void close() { } closed = true; try { - delegate.close(); + if (delegate != null) { + delegate.close(); + } } finally { session.close(); } @@ -569,7 +821,7 @@ public TransactionState getState() { if (restartedAfterSessionNotFound) { return TransactionState.ABORTED; } else { - return delegate.getState(); + return delegate == null ? null : delegate.getState(); } } } @@ -580,13 +832,19 @@ public TransactionState getState() { */ private static final class SessionPoolTransactionRunner implements TransactionRunner { private final SessionPool sessionPool; - private PooledSession session; + private PooledSessionFuture session; private TransactionRunner runner; - private SessionPoolTransactionRunner(SessionPool sessionPool, PooledSession session) { + private SessionPoolTransactionRunner(SessionPool sessionPool, PooledSessionFuture session) { this.sessionPool = sessionPool; this.session = session; - this.runner = session.delegate.readWriteTransaction(); + } + + private TransactionRunner getRunner() { + if (this.runner == null) { + this.runner = session.get().readWriteTransaction(); + } + return runner; } @Override @@ -596,17 +854,17 @@ public T run(TransactionCallable callable) { T result; while (true) { try { - result = runner.run(callable); + result = getRunner().run(callable); break; } catch (SessionNotFoundException e) { session = sessionPool.replaceReadWriteSession(e, session); - runner = session.delegate.readWriteTransaction(); + runner = session.get().delegate.readWriteTransaction(); } } - session.markUsed(); + session.get().markUsed(); return result; } catch (SpannerException e) { - throw session.lastException = e; + throw session.get().lastException = e; } finally { session.close(); } @@ -614,19 +872,86 @@ public T run(TransactionCallable callable) { @Override public Timestamp getCommitTimestamp() { - return runner.getCommitTimestamp(); + return getRunner().getCommitTimestamp(); } @Override public TransactionRunner allowNestedTransaction() { - runner.allowNestedTransaction(); + getRunner().allowNestedTransaction(); return this; } } + private static class SessionPoolAsyncRunner implements AsyncRunner { + private final SessionPool sessionPool; + private volatile PooledSessionFuture session; + private final SettableApiFuture commitTimestamp = SettableApiFuture.create(); + + private SessionPoolAsyncRunner(SessionPool sessionPool, PooledSessionFuture session) { + this.sessionPool = sessionPool; + this.session = session; + } + + @Override + public ApiFuture runAsync(final AsyncWork work, Executor executor) { + final SettableApiFuture res = SettableApiFuture.create(); + executor.execute( + new Runnable() { + @Override + public void run() { + SpannerException se = null; + R r = null; + AsyncRunner runner = null; + while (true) { + try { + runner = session.get().runAsync(); + r = runner.runAsync(work, MoreExecutors.directExecutor()).get(); + break; + } catch (ExecutionException e) { + se = SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (InterruptedException e) { + se = SpannerExceptionFactory.propagateInterrupt(e); + } catch (Throwable t) { + se = SpannerExceptionFactory.newSpannerException(t); + } finally { + if (se != null && se instanceof SessionNotFoundException) { + session = + sessionPool.replaceReadWriteSession((SessionNotFoundException) se, session); + } else { + break; + } + } + } + session.get().markUsed(); + session.close(); + setCommitTimestamp(runner); + if (se != null) { + res.setException(se); + } else { + res.set(r); + } + } + }); + return res; + } + + private void setCommitTimestamp(AsyncRunner delegate) { + try { + commitTimestamp.set(delegate.getCommitTimestamp().get()); + } catch (Throwable t) { + commitTimestamp.setException(t); + } + } + + @Override + public ApiFuture getCommitTimestamp() { + return commitTimestamp; + } + } + // Exception class used just to track the stack trace at the point when a session was handed out // from the pool. - private final class LeakedSessionException extends RuntimeException { + final class LeakedSessionException extends RuntimeException { private static final long serialVersionUID = 1451131180314064914L; private LeakedSessionException() { @@ -640,25 +965,124 @@ private enum SessionState { CLOSING, } - final class PooledSession implements Session { - @VisibleForTesting SessionImpl delegate; - private volatile Instant lastUseTime; - private volatile SpannerException lastException; - private volatile LeakedSessionException leakedException; - private volatile boolean allowReplacing = true; + /** + * Forwarding future that will return a {@link PooledSession}. If {@link #inProcessPrepare} has + * been set to true, the returned session will be prepared with a read/write session using the + * thread of the caller to {@link #get()}. This ensures that the executor that is responsible for + * background preparing of read/write transactions is not overwhelmed by requests in case of a + * large burst of write requests. Instead of filling up the queue of the background executor, the + * caller threads will be used for the BeginTransaction call. + */ + private final class ForwardingListenablePooledSessionFuture + extends SimpleForwardingListenableFuture { + private final boolean inProcessPrepare; + private final Span span; + private volatile boolean initialized = false; + private final Object prepareLock = new Object(); + private volatile PooledSession result; + private volatile SpannerException error; + + private ForwardingListenablePooledSessionFuture( + ListenableFuture delegate, boolean inProcessPrepare, Span span) { + super(delegate); + this.inProcessPrepare = inProcessPrepare; + this.span = span; + } - @GuardedBy("lock") - private SessionState state; + @Override + public PooledSession get() throws InterruptedException, ExecutionException { + try { + return initialize(super.get()); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } - private PooledSession(SessionImpl delegate) { - this.delegate = delegate; - this.state = SessionState.AVAILABLE; - this.lastUseTime = clock.instant(); + @Override + public PooledSession get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + try { + return initialize(super.get(timeout, unit)); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } catch (TimeoutException e) { + throw SpannerExceptionFactory.propagateTimeout(e); + } } - @VisibleForTesting - void setAllowReplacing(boolean allowReplacing) { - this.allowReplacing = allowReplacing; + private PooledSession initialize(PooledSession sess) { + if (!initialized) { + synchronized (prepareLock) { + if (!initialized) { + try { + result = prepare(sess); + } catch (Throwable t) { + error = SpannerExceptionFactory.newSpannerException(t); + } finally { + initialized = true; + } + } + } + } + if (error != null) { + throw error; + } + return result; + } + + private PooledSession prepare(PooledSession sess) { + if (inProcessPrepare && !sess.delegate.hasReadyTransaction()) { + while (true) { + try { + sess.prepareReadWriteTransaction(); + synchronized (lock) { + stopAutomaticPrepare = false; + } + break; + } catch (Throwable t) { + if (isClosed()) { + span.addAnnotation("Pool has been closed"); + throw new IllegalStateException("Pool has been closed"); + } + SpannerException e = newSpannerException(t); + WaiterFuture waiter = new WaiterFuture(); + synchronized (lock) { + handlePrepareSessionFailure(e, sess, false); + if (!isSessionNotFound(e)) { + throw e; + } + readWaiters.add(waiter); + } + sess = waiter.get(); + if (sess.delegate.hasReadyTransaction()) { + break; + } + } + } + } + return sess; + } + } + + private PooledSessionFuture createPooledSessionFuture( + ListenableFuture future, Span span) { + return new PooledSessionFuture(future, span); + } + + final class PooledSessionFuture extends SimpleForwardingListenableFuture + implements Session { + private volatile LeakedSessionException leakedException; + private volatile AtomicBoolean inUse = new AtomicBoolean(); + private volatile CountDownLatch initialized = new CountDownLatch(1); + private final Span span; + + private PooledSessionFuture(ListenableFuture delegate, Span span) { + super(delegate); + this.span = span; } @VisibleForTesting @@ -666,34 +1090,14 @@ void clearLeakedException() { this.leakedException = null; } - private void markBusy() { - this.state = SessionState.BUSY; + private void markCheckedOut() { this.leakedException = new LeakedSessionException(); } - private void markClosing() { - this.state = SessionState.CLOSING; - } - @Override public Timestamp write(Iterable mutations) throws SpannerException { try { - markUsed(); - return delegate.write(mutations); - } catch (SpannerException e) { - throw lastException = e; - } finally { - close(); - } - } - - @Override - public long executePartitionedUpdate(Statement stmt) throws SpannerException { - try { - markUsed(); - return delegate.executePartitionedUpdate(stmt); - } catch (SpannerException e) { - throw lastException = e; + return get().write(mutations); } finally { close(); } @@ -702,10 +1106,7 @@ public long executePartitionedUpdate(Statement stmt) throws SpannerException { @Override public Timestamp writeAtLeastOnce(Iterable mutations) throws SpannerException { try { - markUsed(); - return delegate.writeAtLeastOnce(mutations); - } catch (SpannerException e) { - throw lastException = e; + return get().writeAtLeastOnce(mutations); } finally { close(); } @@ -715,10 +1116,10 @@ public Timestamp writeAtLeastOnce(Iterable mutations) throws SpannerEx public ReadContext singleUse() { try { return new AutoClosingReadContext<>( - new Function() { + new Function() { @Override - public ReadContext apply(PooledSession session) { - return session.delegate.singleUse(); + public ReadContext apply(PooledSessionFuture session) { + return session.get().delegate.singleUse(); } }, SessionPool.this, @@ -734,10 +1135,10 @@ public ReadContext apply(PooledSession session) { public ReadContext singleUse(final TimestampBound bound) { try { return new AutoClosingReadContext<>( - new Function() { + new Function() { @Override - public ReadContext apply(PooledSession session) { - return session.delegate.singleUse(bound); + public ReadContext apply(PooledSessionFuture session) { + return session.get().delegate.singleUse(bound); } }, SessionPool.this, @@ -752,10 +1153,10 @@ public ReadContext apply(PooledSession session) { @Override public ReadOnlyTransaction singleUseReadOnlyTransaction() { return internalReadOnlyTransaction( - new Function() { + new Function() { @Override - public ReadOnlyTransaction apply(PooledSession session) { - return session.delegate.singleUseReadOnlyTransaction(); + public ReadOnlyTransaction apply(PooledSessionFuture session) { + return session.get().delegate.singleUseReadOnlyTransaction(); } }, true); @@ -764,10 +1165,10 @@ public ReadOnlyTransaction apply(PooledSession session) { @Override public ReadOnlyTransaction singleUseReadOnlyTransaction(final TimestampBound bound) { return internalReadOnlyTransaction( - new Function() { + new Function() { @Override - public ReadOnlyTransaction apply(PooledSession session) { - return session.delegate.singleUseReadOnlyTransaction(bound); + public ReadOnlyTransaction apply(PooledSessionFuture session) { + return session.get().delegate.singleUseReadOnlyTransaction(bound); } }, true); @@ -776,10 +1177,10 @@ public ReadOnlyTransaction apply(PooledSession session) { @Override public ReadOnlyTransaction readOnlyTransaction() { return internalReadOnlyTransaction( - new Function() { + new Function() { @Override - public ReadOnlyTransaction apply(PooledSession session) { - return session.delegate.readOnlyTransaction(); + public ReadOnlyTransaction apply(PooledSessionFuture session) { + return session.get().delegate.readOnlyTransaction(); } }, false); @@ -788,17 +1189,18 @@ public ReadOnlyTransaction apply(PooledSession session) { @Override public ReadOnlyTransaction readOnlyTransaction(final TimestampBound bound) { return internalReadOnlyTransaction( - new Function() { + new Function() { @Override - public ReadOnlyTransaction apply(PooledSession session) { - return session.delegate.readOnlyTransaction(bound); + public ReadOnlyTransaction apply(PooledSessionFuture session) { + return session.get().delegate.readOnlyTransaction(bound); } }, false); } private ReadOnlyTransaction internalReadOnlyTransaction( - Function transactionSupplier, boolean isSingleUse) { + Function transactionSupplier, + boolean isSingleUse) { try { return new AutoClosingReadTransaction( transactionSupplier, SessionPool.this, this, isSingleUse); @@ -813,6 +1215,188 @@ public TransactionRunner readWriteTransaction() { return new SessionPoolTransactionRunner(SessionPool.this, this); } + @Override + public TransactionManager transactionManager() { + return new AutoClosingTransactionManager(SessionPool.this, this); + } + + @Override + public AsyncRunner runAsync() { + return new SessionPoolAsyncRunner(SessionPool.this, this); + } + + @Override + public AsyncTransactionManager transactionManagerAsync() { + return new SessionPoolAsyncTransactionManager(this); + } + + @Override + public long executePartitionedUpdate(Statement stmt) { + try { + return get().executePartitionedUpdate(stmt); + } finally { + close(); + } + } + + @Override + public String getName() { + return get().getName(); + } + + @Override + public void prepareReadWriteTransaction() { + get().prepareReadWriteTransaction(); + } + + @Override + public void close() { + synchronized (lock) { + leakedException = null; + checkedOutSessions.remove(this); + } + get().close(); + } + + @Override + public ApiFuture asyncClose() { + synchronized (lock) { + leakedException = null; + checkedOutSessions.remove(this); + } + return get().asyncClose(); + } + + @Override + public PooledSession get() { + if (inUse.compareAndSet(false, true)) { + PooledSession res = null; + try { + res = super.get(); + } catch (Throwable e) { + // ignore the exception as it will be handled by the call to super.get() below. + } + if (res != null) { + res.markBusy(span); + span.addAnnotation(sessionAnnotation(res)); + synchronized (lock) { + incrementNumSessionsInUse(); + checkedOutSessions.add(this); + } + } + initialized.countDown(); + } + try { + initialized.await(); + return super.get(); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } + } + + final class PooledSession implements Session { + @VisibleForTesting SessionImpl delegate; + private volatile Instant lastUseTime; + private volatile SpannerException lastException; + private volatile boolean allowReplacing = true; + + @GuardedBy("lock") + private SessionState state; + + private PooledSession(SessionImpl delegate) { + this.delegate = delegate; + this.state = SessionState.AVAILABLE; + this.lastUseTime = clock.instant(); + } + + @Override + public String toString() { + return getName(); + } + + @VisibleForTesting + void setAllowReplacing(boolean allowReplacing) { + this.allowReplacing = allowReplacing; + } + + @Override + public Timestamp write(Iterable mutations) throws SpannerException { + try { + markUsed(); + return delegate.write(mutations); + } catch (SpannerException e) { + throw lastException = e; + } + } + + @Override + public Timestamp writeAtLeastOnce(Iterable mutations) throws SpannerException { + try { + markUsed(); + return delegate.writeAtLeastOnce(mutations); + } catch (SpannerException e) { + throw lastException = e; + } + } + + @Override + public long executePartitionedUpdate(Statement stmt) throws SpannerException { + try { + markUsed(); + return delegate.executePartitionedUpdate(stmt); + } catch (SpannerException e) { + throw lastException = e; + } + } + + @Override + public ReadContext singleUse() { + return delegate.singleUse(); + } + + @Override + public ReadContext singleUse(TimestampBound bound) { + return delegate.singleUse(bound); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction() { + return delegate.singleUseReadOnlyTransaction(); + } + + @Override + public ReadOnlyTransaction singleUseReadOnlyTransaction(TimestampBound bound) { + return delegate.singleUseReadOnlyTransaction(bound); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction() { + return delegate.readOnlyTransaction(); + } + + @Override + public ReadOnlyTransaction readOnlyTransaction(TimestampBound bound) { + return delegate.readOnlyTransaction(bound); + } + + @Override + public TransactionRunner readWriteTransaction() { + return delegate.readWriteTransaction(); + } + + @Override + public AsyncRunner runAsync() { + return delegate.runAsync(); + } + + @Override + public AsyncTransactionManagerImpl transactionManagerAsync() { + return delegate.transactionManagerAsync(); + } + @Override public ApiFuture asyncClose() { close(); @@ -825,7 +1409,6 @@ public void close() { numSessionsInUse--; numSessionsReleased++; } - leakedException = null; if (lastException != null && isSessionNotFound(lastException)) { invalidateSession(this); } else { @@ -868,59 +1451,56 @@ private void keepAlive() { } } + private void markBusy(Span span) { + this.delegate.setCurrentSpan(span); + this.state = SessionState.BUSY; + } + + private void markClosing() { + this.state = SessionState.CLOSING; + } + void markUsed() { lastUseTime = clock.instant(); } @Override public TransactionManager transactionManager() { - return new AutoClosingTransactionManager(SessionPool.this, this); + return delegate.transactionManager(); } } - private static final class SessionOrError { - private final PooledSession session; - private final SpannerException e; - - SessionOrError(PooledSession session) { - this.session = session; - this.e = null; - } + private final class WaiterFuture extends ForwardingListenableFuture { + private static final long MAX_SESSION_WAIT_TIMEOUT = 240_000L; + private final SettableFuture waiter = SettableFuture.create(); - SessionOrError(SpannerException e) { - this.session = null; - this.e = e; + @Override + protected ListenableFuture delegate() { + return waiter; } - } - - private final class Waiter { - private static final long MAX_SESSION_WAIT_TIMEOUT = 240_000L; - private final SynchronousQueue waiter = new SynchronousQueue<>(); private void put(PooledSession session) { - Uninterruptibles.putUninterruptibly(waiter, new SessionOrError(session)); + waiter.set(session); } private void put(SpannerException e) { - Uninterruptibles.putUninterruptibly(waiter, new SessionOrError(e)); + waiter.setException(e); } - private PooledSession take() throws SpannerException { + @Override + public PooledSession get() { long currentTimeout = options.getInitialWaitForSessionTimeoutMillis(); while (true) { Span span = tracer.spanBuilder(WAIT_FOR_SESSION).startSpan(); try (Scope waitScope = tracer.withSpan(span)) { - SessionOrError s = pollUninterruptiblyWithTimeout(currentTimeout); + PooledSession s = pollUninterruptiblyWithTimeout(currentTimeout); if (s == null) { // Set the status to DEADLINE_EXCEEDED and retry. numWaiterTimeouts.incrementAndGet(); tracer.getCurrentSpan().setStatus(Status.DEADLINE_EXCEEDED); currentTimeout = Math.min(currentTimeout * 2, MAX_SESSION_WAIT_TIMEOUT); } else { - if (s.e != null) { - throw newSpannerException(s.e); - } - return s.session; + return s; } } catch (Exception e) { TraceUtil.setWithFailure(span, e); @@ -931,14 +1511,18 @@ private PooledSession take() throws SpannerException { } } - private SessionOrError pollUninterruptiblyWithTimeout(long timeoutMillis) { + private PooledSession pollUninterruptiblyWithTimeout(long timeoutMillis) { boolean interrupted = false; try { while (true) { try { - return waiter.poll(timeoutMillis, TimeUnit.MILLISECONDS); + return waiter.get(timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { interrupted = true; + } catch (TimeoutException e) { + return null; + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause()); } } } finally { @@ -1118,6 +1702,7 @@ private static enum Position { private final ScheduledExecutorService executor; private final ExecutorFactory executorFactory; private final ScheduledExecutorService prepareExecutor; + private final int prepareThreadPoolSize; final PoolMaintainer poolMaintainer; private final Clock clock; @@ -1146,10 +1731,10 @@ private static enum Position { private final LinkedList writePreparedSessions = new LinkedList<>(); @GuardedBy("lock") - private final Queue readWaiters = new LinkedList<>(); + private final Queue readWaiters = new LinkedList<>(); @GuardedBy("lock") - private final Queue readWriteWaiters = new LinkedList<>(); + private final Queue readWriteWaiters = new LinkedList<>(); @GuardedBy("lock") private int numSessionsBeingPrepared = 0; @@ -1183,6 +1768,9 @@ private static enum Position { @GuardedBy("lock") private final Set allSessions = new HashSet<>(); + @GuardedBy("lock") + private final Set checkedOutSessions = new HashSet<>(); + private final SessionConsumer sessionConsumer = new SessionConsumerImpl(); @VisibleForTesting Function idleSessionRemovedListener; @@ -1275,6 +1863,12 @@ private SessionPool( } @VisibleForTesting + int getNumberOfSessionsInUse() { + synchronized (lock) { + return numSessionsInUse; + } + } + long getNumberOfSessionsInProcessPrepared() { synchronized (lock) { return numSessionsInProcessPrepared; @@ -1297,9 +1891,9 @@ void removeFromPool(PooledSession session) { session.markClosing(); allSessions.remove(session); numIdleSessionsRemoved++; - if (idleSessionRemovedListener != null) { - idleSessionRemovedListener.apply(session); - } + } + if (idleSessionRemovedListener != null) { + idleSessionRemovedListener.apply(session); } } @@ -1437,10 +2031,10 @@ boolean isValid() { * session being returned to the pool or a new session being created. * */ - PooledSession getReadSession() throws SpannerException { + PooledSessionFuture getReadSession() throws SpannerException { Span span = Tracing.getTracer().getCurrentSpan(); span.addAnnotation("Acquiring session"); - Waiter waiter = null; + WaiterFuture waiter = null; PooledSession sess = null; synchronized (lock) { if (closureFuture != null) { @@ -1462,7 +2056,7 @@ PooledSession getReadSession() throws SpannerException { if (sess == null) { span.addAnnotation("No session available"); maybeCreateSession(); - waiter = new Waiter(); + waiter = new WaiterFuture(); readWaiters.add(waiter); } else { span.addAnnotation("Acquired read write session"); @@ -1470,18 +2064,8 @@ PooledSession getReadSession() throws SpannerException { } else { span.addAnnotation("Acquired read only session"); } + return checkoutSession(span, sess, waiter, false, false); } - if (waiter != null) { - logger.log( - Level.FINE, - "No session available in the pool. Blocking for one to become available/created"); - span.addAnnotation("Waiting for read only session to be available"); - sess = waiter.take(); - } - sess.markBusy(); - incrementNumSessionsInUse(); - span.addAnnotation(sessionAnnotation(sess)); - return sess; } /** @@ -1502,129 +2086,123 @@ PooledSession getReadSession() throws SpannerException { * to the pool which is then write prepared. * */ - PooledSession getReadWriteSession() { + PooledSessionFuture getReadWriteSession() { Span span = Tracing.getTracer().getCurrentSpan(); span.addAnnotation("Acquiring read write session"); PooledSession sess = null; - // Loop to retry SessionNotFoundExceptions that might occur during in-process prepare of a - // session. - while (true) { - Waiter waiter = null; - boolean inProcessPrepare = stopAutomaticPrepare; - synchronized (lock) { - if (closureFuture != null) { - span.addAnnotation("Pool has been closed"); - throw new IllegalStateException("Pool has been closed", closedException); - } - if (resourceNotFoundException != null) { - span.addAnnotation("Database has been deleted"); - throw SpannerExceptionFactory.newSpannerException( - ErrorCode.NOT_FOUND, - String.format( - "The session pool has been invalidated because a previous RPC returned 'Database not found': %s", - resourceNotFoundException.getMessage()), - resourceNotFoundException); - } - sess = writePreparedSessions.poll(); - if (sess == null) { - if (!inProcessPrepare && numSessionsBeingPrepared <= prepareThreadPoolSize) { - if (numSessionsBeingPrepared <= readWriteWaiters.size()) { - PooledSession readSession = readSessions.poll(); - if (readSession != null) { - span.addAnnotation( - "Acquired read only session. Preparing for read write transaction"); - prepareSession(readSession); - } else { - span.addAnnotation("No session available"); - maybeCreateSession(); - } - } - } else { - inProcessPrepare = true; - numSessionsInProcessPrepared++; + WaiterFuture waiter = null; + boolean inProcessPrepare = stopAutomaticPrepare; + synchronized (lock) { + if (closureFuture != null) { + span.addAnnotation("Pool has been closed"); + throw new IllegalStateException("Pool has been closed", closedException); + } + if (resourceNotFoundException != null) { + span.addAnnotation("Database has been deleted"); + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.NOT_FOUND, + String.format( + "The session pool has been invalidated because a previous RPC returned 'Database not found': %s", + resourceNotFoundException.getMessage()), + resourceNotFoundException); + } + sess = writePreparedSessions.poll(); + if (sess == null) { + if (!inProcessPrepare && numSessionsBeingPrepared <= prepareThreadPoolSize) { + if (numSessionsBeingPrepared <= readWriteWaiters.size()) { PooledSession readSession = readSessions.poll(); if (readSession != null) { - // Create a read/write transaction in-process if there is already a queue for prepared - // sessions. This is more efficient than doing it asynchronously, as it scales with - // the number of user threads. The thread pool for asynchronously preparing sessions - // is fixed. span.addAnnotation( - "Acquired read only session. Preparing in-process for read write transaction"); - sess = readSession; + "Acquired read only session. Preparing for read write transaction"); + prepareSession(readSession); } else { span.addAnnotation("No session available"); maybeCreateSession(); } } - if (sess == null) { - waiter = new Waiter(); - if (inProcessPrepare) { - // inProcessPrepare=true means that we have already determined that the queue for - // preparing read/write sessions is larger than the number of threads in the prepare - // thread pool, and that it's more efficient to do the prepare in-process. We will - // therefore create a waiter for a read-only session, even though a read/write session - // has been requested. - readWaiters.add(waiter); - } else { - readWriteWaiters.add(waiter); - } - } } else { - span.addAnnotation("Acquired read write session"); - } - } - if (waiter != null) { - logger.log( - Level.FINE, - "No session available in the pool. Blocking for one to become available/created"); - span.addAnnotation("Waiting for read write session to be available"); - sess = waiter.take(); - } - if (inProcessPrepare) { - try { - sess.prepareReadWriteTransaction(); - // Session prepare succeeded, restart automatic prepare if it had been stopped. - synchronized (lock) { - stopAutomaticPrepare = false; - } - } catch (Throwable t) { - SpannerException e = newSpannerException(t); - if (!isClosed()) { - handlePrepareSessionFailure(e, sess, false); + inProcessPrepare = true; + numSessionsInProcessPrepared++; + PooledSession readSession = readSessions.poll(); + if (readSession != null) { + // Create a read/write transaction in-process if there is already a queue for prepared + // sessions. This is more efficient than doing it asynchronously, as it scales with + // the number of user threads. The thread pool for asynchronously preparing sessions + // is fixed. + span.addAnnotation( + "Acquired read only session. Preparing in-process for read write transaction"); + sess = readSession; + } else { + span.addAnnotation("No session available"); + maybeCreateSession(); } - sess = null; - if (!isSessionNotFound(e)) { - throw e; + } + if (sess == null) { + waiter = new WaiterFuture(); + if (inProcessPrepare) { + // inProcessPrepare=true means that we have already determined that the queue for + // preparing read/write sessions is larger than the number of threads in the prepare + // thread pool, and that it's more efficient to do the prepare in-process. We will + // therefore create a waiter for a read-only session, even though a read/write session + // has been requested. + readWaiters.add(waiter); + } else { + readWriteWaiters.add(waiter); } } + } else { + span.addAnnotation("Acquired read write session"); } - if (sess != null) { - break; - } + return checkoutSession(span, sess, waiter, true, inProcessPrepare); } - sess.markBusy(); - incrementNumSessionsInUse(); - span.addAnnotation(sessionAnnotation(sess)); - return sess; } - PooledSession replaceReadSession(SessionNotFoundException e, PooledSession session) { + private PooledSessionFuture checkoutSession( + final Span span, + final PooledSession readySession, + WaiterFuture waiter, + boolean write, + final boolean inProcessPrepare) { + ListenableFuture sessionFuture; + if (waiter != null) { + logger.log( + Level.FINE, + "No session available in the pool. Blocking for one to become available/created"); + span.addAnnotation( + String.format( + "Waiting for %s session to be available", write ? "read write" : "read only")); + sessionFuture = waiter; + } else { + SettableFuture fut = SettableFuture.create(); + fut.set(readySession); + sessionFuture = fut; + } + ForwardingListenablePooledSessionFuture forwardingFuture = + new ForwardingListenablePooledSessionFuture(sessionFuture, inProcessPrepare, span); + PooledSessionFuture res = createPooledSessionFuture(forwardingFuture, span); + res.markCheckedOut(); + return res; + } + + PooledSessionFuture replaceReadSession(SessionNotFoundException e, PooledSessionFuture session) { return replaceSession(e, session, false); } - PooledSession replaceReadWriteSession(SessionNotFoundException e, PooledSession session) { + PooledSessionFuture replaceReadWriteSession( + SessionNotFoundException e, PooledSessionFuture session) { return replaceSession(e, session, true); } - private PooledSession replaceSession( - SessionNotFoundException e, PooledSession session, boolean write) { - if (!options.isFailIfSessionNotFound() && session.allowReplacing) { + private PooledSessionFuture replaceSession( + SessionNotFoundException e, PooledSessionFuture session, boolean write) { + if (!options.isFailIfSessionNotFound() && session.get().allowReplacing) { synchronized (lock) { numSessionsInUse--; numSessionsReleased++; + checkedOutSessions.remove(session); } session.leakedException = null; - invalidateSession(session); + invalidateSession(session.get()); return write ? getReadWriteSession() : getReadSession(); } else { throw e; @@ -1787,7 +2365,7 @@ ListenableFuture closeAsync(ClosedException closedException) { } this.closedException = closedException; // Fail all pending waiters. - Waiter waiter = readWaiters.poll(); + WaiterFuture waiter = readWaiters.poll(); while (waiter != null) { waiter.put(newSpannerException(ErrorCode.INTERNAL, "Client has been closed")); waiter = readWaiters.poll(); @@ -1821,10 +2399,16 @@ public void run() { } } }); - for (final PooledSession session : ImmutableList.copyOf(allSessions)) { + for (PooledSessionFuture session : checkedOutSessions) { if (session.leakedException != null) { - logger.log(Level.WARNING, "Leaked session", session.leakedException); + if (options.isFailOnSessionLeak()) { + throw session.leakedException; + } else { + logger.log(Level.WARNING, "Leaked session", session.leakedException); + } } + } + for (final PooledSession session : ImmutableList.copyOf(allSessions)) { if (session.state != SessionState.CLOSING) { closeSessionAsync(session); } @@ -1894,7 +2478,7 @@ public void run() { } } }, - executor); + MoreExecutors.directExecutor()); return res; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolAsyncTransactionManager.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolAsyncTransactionManager.java new file mode 100644 index 0000000000..55b6102a27 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolAsyncTransactionManager.java @@ -0,0 +1,216 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiAsyncFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; +import com.google.cloud.spanner.TransactionContextFutureImpl.CommittableAsyncTransactionManager; +import com.google.cloud.spanner.TransactionManager.TransactionState; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.MoreExecutors; +import javax.annotation.concurrent.GuardedBy; + +class SessionPoolAsyncTransactionManager implements CommittableAsyncTransactionManager { + private final Object lock = new Object(); + + @GuardedBy("lock") + private TransactionState txnState; + + private volatile PooledSessionFuture session; + private final SettableApiFuture delegate = + SettableApiFuture.create(); + + SessionPoolAsyncTransactionManager(PooledSessionFuture session) { + this.session = session; + this.session.addListener( + new Runnable() { + @Override + public void run() { + try { + delegate.set( + SessionPoolAsyncTransactionManager.this.session.get().transactionManagerAsync()); + } catch (Throwable t) { + delegate.setException(t); + } + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public void close() { + delegate.addListener( + new Runnable() { + @Override + public void run() { + session.close(); + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public TransactionContextFuture beginAsync() { + synchronized (lock) { + Preconditions.checkState(txnState == null, "begin can only be called once"); + txnState = TransactionState.STARTED; + } + final SettableApiFuture delegateTxnFuture = SettableApiFuture.create(); + ApiFutures.addCallback( + delegate, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + delegateTxnFuture.setException(t); + } + + @Override + public void onSuccess(AsyncTransactionManagerImpl result) { + ApiFutures.addCallback( + result.beginAsync(), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + delegateTxnFuture.setException(t); + } + + @Override + public void onSuccess(TransactionContext result) { + delegateTxnFuture.set(result); + } + }, + MoreExecutors.directExecutor()); + } + }, + MoreExecutors.directExecutor()); + return new TransactionContextFutureImpl(this, delegateTxnFuture); + } + + @Override + public void onError(Throwable t) { + if (t instanceof AbortedException) { + synchronized (lock) { + txnState = TransactionState.ABORTED; + } + } + } + + @Override + public ApiFuture commitAsync() { + synchronized (lock) { + Preconditions.checkState( + txnState == TransactionState.STARTED, + "commit can only be invoked if the transaction is in progress. Current state: " + + txnState); + txnState = TransactionState.COMMITTED; + } + return ApiFutures.transformAsync( + delegate, + new ApiAsyncFunction() { + @Override + public ApiFuture apply(AsyncTransactionManagerImpl input) throws Exception { + final SettableApiFuture res = SettableApiFuture.create(); + ApiFutures.addCallback( + input.commitAsync(), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + synchronized (lock) { + if (t instanceof AbortedException) { + txnState = TransactionState.ABORTED; + } else { + txnState = TransactionState.COMMIT_FAILED; + } + } + res.setException(t); + } + + @Override + public void onSuccess(Timestamp result) { + res.set(result); + } + }, + MoreExecutors.directExecutor()); + return res; + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public ApiFuture rollbackAsync() { + synchronized (lock) { + Preconditions.checkState( + txnState == TransactionState.STARTED, + "rollback can only be called if the transaction is in progress"); + txnState = TransactionState.ROLLED_BACK; + } + return ApiFutures.transformAsync( + delegate, + new ApiAsyncFunction() { + @Override + public ApiFuture apply(AsyncTransactionManagerImpl input) throws Exception { + ApiFuture res = input.rollbackAsync(); + res.addListener( + new Runnable() { + @Override + public void run() { + session.close(); + } + }, + MoreExecutors.directExecutor()); + return res; + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public TransactionContextFuture resetForRetryAsync() { + synchronized (lock) { + Preconditions.checkState( + txnState == TransactionState.ABORTED, + "resetForRetry can only be called after the transaction aborted."); + txnState = TransactionState.STARTED; + } + return new TransactionContextFutureImpl( + this, + ApiFutures.transformAsync( + delegate, + new ApiAsyncFunction() { + @Override + public ApiFuture apply(AsyncTransactionManagerImpl input) + throws Exception { + return input.resetForRetryAsync(); + } + }, + MoreExecutors.directExecutor())); + } + + @Override + public TransactionState getState() { + synchronized (lock) { + return txnState; + } + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java index 17295a38ab..57dbd4debd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java @@ -37,6 +37,7 @@ public class SessionPoolOptions { private final int keepAliveIntervalMinutes; private final Duration removeInactiveSessionAfter; private final ActionOnSessionNotFound actionOnSessionNotFound; + private final ActionOnSessionLeak actionOnSessionLeak; private final long initialWaitForSessionTimeoutMillis; private SessionPoolOptions(Builder builder) { @@ -50,6 +51,7 @@ private SessionPoolOptions(Builder builder) { this.writeSessionsFraction = builder.writeSessionsFraction; this.actionOnExhaustion = builder.actionOnExhaustion; this.actionOnSessionNotFound = builder.actionOnSessionNotFound; + this.actionOnSessionLeak = builder.actionOnSessionLeak; this.initialWaitForSessionTimeoutMillis = builder.initialWaitForSessionTimeoutMillis; this.loopFrequency = builder.loopFrequency; this.keepAliveIntervalMinutes = builder.keepAliveIntervalMinutes; @@ -106,6 +108,11 @@ boolean isFailIfSessionNotFound() { return actionOnSessionNotFound == ActionOnSessionNotFound.FAIL; } + @VisibleForTesting + boolean isFailOnSessionLeak() { + return actionOnSessionLeak == ActionOnSessionLeak.FAIL; + } + public static Builder newBuilder() { return new Builder(); } @@ -120,6 +127,11 @@ private static enum ActionOnSessionNotFound { FAIL; } + private static enum ActionOnSessionLeak { + WARN, + FAIL; + } + /** Builder for creating SessionPoolOptions. */ public static class Builder { private boolean minSessionsSet = false; @@ -131,6 +143,7 @@ public static class Builder { private ActionOnExhaustion actionOnExhaustion = DEFAULT_ACTION; private long initialWaitForSessionTimeoutMillis = 30_000L; private ActionOnSessionNotFound actionOnSessionNotFound = ActionOnSessionNotFound.RETRY; + private ActionOnSessionLeak actionOnSessionLeak = ActionOnSessionLeak.WARN; private long loopFrequency = 10 * 1000L; private int keepAliveIntervalMinutes = 30; private Duration removeInactiveSessionAfter = Duration.ofMinutes(55L); @@ -240,6 +253,12 @@ Builder setFailIfSessionNotFound() { return this; } + @VisibleForTesting + Builder setFailOnSessionLeak() { + this.actionOnSessionLeak = ActionOnSessionLeak.FAIL; + return this; + } + /** * Fraction of sessions to be kept prepared for write transactions. This is an optimisation to * avoid the cost of sending a BeginTransaction() rpc. If all such sessions are in use and a diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Spanner.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Spanner.java index 0c6bec4ea8..52c35cb713 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Spanner.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Spanner.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner; +import com.google.api.gax.core.ExecutorProvider; import com.google.cloud.Service; /** @@ -108,4 +109,7 @@ public interface Spanner extends Service, AutoCloseable { /** @return true if this {@link Spanner} object is closed. */ boolean isClosed(); + + /** @return the {@link ExecutorProvider} that is used for asynchronous queries and operations. */ + ExecutorProvider getAsyncExecutorProvider(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java index 4e937459cf..2d034eda88 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java @@ -16,6 +16,7 @@ package com.google.cloud.spanner; +import com.google.api.gax.core.ExecutorProvider; import com.google.api.gax.core.GaxProperties; import com.google.api.gax.paging.Page; import com.google.cloud.BaseService; @@ -23,9 +24,11 @@ import com.google.cloud.PageImpl.NextPageFetcher; import com.google.cloud.grpc.GrpcTransportOptions; import com.google.cloud.spanner.SessionClient.SessionId; +import com.google.cloud.spanner.SpannerOptions.CloseableExecutorProvider; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; @@ -86,6 +89,8 @@ private static String nextDatabaseClientId(DatabaseId databaseId) { @GuardedBy("this") private final Map dbClients = new HashMap<>(); + private final CloseableExecutorProvider asyncExecutorProvider; + @GuardedBy("this") private final List invalidatedDbClients = new ArrayList<>(); @@ -116,6 +121,10 @@ static final class ClosedException extends RuntimeException { SpannerImpl(SpannerRpc gapicRpc, SpannerOptions options) { super(options); this.gapicRpc = gapicRpc; + this.asyncExecutorProvider = + MoreObjects.firstNonNull( + options.getAsyncExecutorProvider(), + SpannerOptions.createDefaultAsyncExecutorProvider()); this.dbAdminClient = new DatabaseAdminClientImpl(options.getProjectId(), gapicRpc); this.instanceClient = new InstanceAdminClientImpl(options.getProjectId(), gapicRpc, dbAdminClient); @@ -140,6 +149,13 @@ QueryOptions getDefaultQueryOptions(DatabaseId databaseId) { return getOptions().getDefaultQueryOptions(databaseId); } + /** + * Returns the {@link ExecutorProvider} to use for async methods that need a background executor. + */ + public ExecutorProvider getAsyncExecutorProvider() { + return asyncExecutorProvider; + } + SessionImpl sessionWithId(String name) { Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "name is null or empty"); SessionId id = SessionId.of(name); @@ -251,6 +267,7 @@ void close(long timeout, TimeUnit unit) { sessionClient.close(); } sessionClients.clear(); + asyncExecutorProvider.close(); try { gapicRpc.shutdown(); } catch (RuntimeException e) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index edeadb7b90..35a288530f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import com.google.api.core.ApiFunction; +import com.google.api.gax.core.ExecutorProvider; import com.google.api.gax.grpc.GrpcInterceptorProvider; import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; @@ -40,10 +41,12 @@ import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.cloud.spanner.v1.SpannerSettings; import com.google.cloud.spanner.v1.stub.SpannerStubSettings; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.spanner.admin.database.v1.CreateBackupRequest; import com.google.spanner.admin.database.v1.CreateDatabaseRequest; import com.google.spanner.admin.database.v1.RestoreDatabaseRequest; @@ -59,6 +62,11 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.threeten.bp.Duration; @@ -107,6 +115,7 @@ public class SpannerOptions extends ServiceOptions { private final Map mergedQueryOptions; private final CallCredentialsProvider callCredentialsProvider; + private final CloseableExecutorProvider asyncExecutorProvider; private final String compressorName; /** @@ -138,6 +147,67 @@ public ServiceRpc create(SpannerOptions options) { } } + private static final AtomicInteger DEFAULT_POOL_COUNT = new AtomicInteger(); + + /** {@link ExecutorProvider} that is used for {@link AsyncResultSet}. */ + interface CloseableExecutorProvider extends ExecutorProvider, AutoCloseable { + /** Overridden to suppress the throws declaration of the super interface. */ + @Override + public void close(); + } + + static class FixedCloseableExecutorProvider implements CloseableExecutorProvider { + private final ScheduledExecutorService executor; + + private FixedCloseableExecutorProvider(ScheduledExecutorService executor) { + this.executor = Preconditions.checkNotNull(executor); + } + + @Override + public void close() { + executor.shutdown(); + } + + @Override + public ScheduledExecutorService getExecutor() { + return executor; + } + + @Override + public boolean shouldAutoClose() { + return false; + } + + /** Creates a FixedCloseableExecutorProvider. */ + static FixedCloseableExecutorProvider create(ScheduledExecutorService executor) { + return new FixedCloseableExecutorProvider(executor); + } + } + + /** + * Default {@link ExecutorProvider} for high-level async calls that need an executor. The default + * uses a cached thread pool containing a max of 8 threads. The pool is lazily initialized and + * will not create any threads if the user application does not use any async methods. It will + * also scale down the thread usage if the async load allows for that. + */ + @VisibleForTesting + static CloseableExecutorProvider createDefaultAsyncExecutorProvider() { + return createAsyncExecutorProvider(8, 60L, TimeUnit.SECONDS); + } + + @VisibleForTesting + static CloseableExecutorProvider createAsyncExecutorProvider( + int poolSize, long keepAliveTime, TimeUnit unit) { + String format = + String.format("spanner-async-pool-%d-thread-%%d", DEFAULT_POOL_COUNT.incrementAndGet()); + ThreadFactory threadFactory = + new ThreadFactoryBuilder().setDaemon(true).setNameFormat(format).build(); + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(poolSize, threadFactory); + executor.setKeepAliveTime(keepAliveTime, unit); + executor.allowCoreThreadTimeOut(true); + return FixedCloseableExecutorProvider.create(executor); + } + private SpannerOptions(Builder builder) { super(SpannerFactory.class, SpannerRpcFactory.class, builder, new SpannerDefaults()); numChannels = builder.numChannels; @@ -178,6 +248,7 @@ private SpannerOptions(Builder builder) { this.mergedQueryOptions = ImmutableMap.copyOf(merged); } callCredentialsProvider = builder.callCredentialsProvider; + asyncExecutorProvider = builder.asyncExecutorProvider; compressorName = builder.compressorName; } @@ -243,6 +314,7 @@ public static class Builder private boolean autoThrottleAdministrativeRequests = false; private Map defaultQueryOptions = new HashMap<>(); private CallCredentialsProvider callCredentialsProvider; + private CloseableExecutorProvider asyncExecutorProvider; private String compressorName; private String emulatorHost = System.getenv("SPANNER_EMULATOR_HOST"); @@ -304,6 +376,11 @@ private Builder() { Builder(SpannerOptions options) { super(options); + if (options.getHost() != null + && this.emulatorHost != null + && !options.getHost().equals(this.emulatorHost)) { + this.emulatorHost = null; + } this.numChannels = options.numChannels; this.sessionPoolOptions = options.sessionPoolOptions; this.prefetchChunks = options.prefetchChunks; @@ -315,6 +392,7 @@ private Builder() { this.autoThrottleAdministrativeRequests = options.autoThrottleAdministrativeRequests; this.defaultQueryOptions = options.defaultQueryOptions; this.callCredentialsProvider = options.callCredentialsProvider; + this.asyncExecutorProvider = options.asyncExecutorProvider; this.compressorName = options.compressorName; this.channelProvider = options.channelProvider; this.channelConfigurator = options.channelConfigurator; @@ -736,6 +814,10 @@ public QueryOptions getDefaultQueryOptions(DatabaseId databaseId) { return options; } + CloseableExecutorProvider getAsyncExecutorProvider() { + return asyncExecutorProvider; + } + public int getPrefetchChunks() { return prefetchChunks; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceUtil.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceUtil.java index c5488ac55d..0d429661ad 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceUtil.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TraceUtil.java @@ -40,7 +40,7 @@ static Map getTransactionAnnotations(Transaction t) { AttributeValue.stringAttributeValue(Timestamp.fromProto(t.getReadTimestamp()).toString())); } - static ImmutableMap getExceptionAnnotations(RuntimeException e) { + static ImmutableMap getExceptionAnnotations(Throwable e) { if (e instanceof SpannerException) { return ImmutableMap.of( "Status", diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContext.java index a529c4c492..0b4a92f989 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContext.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContext.java @@ -16,6 +16,8 @@ package com.google.cloud.spanner; +import com.google.api.core.ApiFuture; + /** * Context for a single attempt of a locking read-write transaction. This type of transaction is the * only way to write data into Cloud Spanner; {@link Session#write(Iterable)} and {@link @@ -102,6 +104,17 @@ public interface TransactionContext extends ReadContext { */ long executeUpdate(Statement statement); + /** + * Same as {@link #executeUpdate(Statement)}, but is guaranteed to be non-blocking. If multiple + * asynchronous update statements are submitted to the same read/write transaction, the statements + * are guaranteed to be submitted to Cloud Spanner in the order that they were submitted in the + * client. This does however not guarantee that an asynchronous update statement will see the + * results of all previously submitted statements, as the execution of the statements can be + * parallel. If you rely on the results of a previous statement, you should block until the result + * of that statement is known and has been returned to the client. + */ + ApiFuture executeUpdateAsync(Statement statement); + /** * Executes a list of DML statements in a single request. The statements will be executed in order * and the semantics is the same as if each statement is executed by {@code executeUpdate} in a @@ -118,4 +131,15 @@ public interface TransactionContext extends ReadContext { * statement. The 3rd statement will not run. */ long[] batchUpdate(Iterable statements); + + /** + * Same as {@link #batchUpdate(Iterable)}, but is guaranteed to be non-blocking. If multiple + * asynchronous update statements are submitted to the same read/write transaction, the statements + * are guaranteed to be submitted to Cloud Spanner in the order that they were submitted in the + * client. This does however not guarantee that an asynchronous update statement will see the + * results of all previously submitted statements, as the execution of the statements can be + * parallel. If you rely on the results of a previous statement, you should block until the result + * of that statement is known and has been returned to the client. + */ + ApiFuture batchUpdateAsync(Iterable statements); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContextFutureImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContextFutureImpl.java new file mode 100644 index 0000000000..bc8262a535 --- /dev/null +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionContextFutureImpl.java @@ -0,0 +1,258 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.core.ForwardingApiFuture; +import com.google.api.core.InternalApi; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionFunction; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep; +import com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture; +import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +class TransactionContextFutureImpl extends ForwardingApiFuture + implements TransactionContextFuture { + + @InternalApi + interface CommittableAsyncTransactionManager extends AsyncTransactionManager { + void onError(Throwable t); + + ApiFuture commitAsync(); + } + /** + * {@link ApiFuture} that returns a commit timestamp. Any {@link AbortedException} that is thrown + * by either the commit call or any other rpc during the transaction will be thrown by the {@link + * #get()} method of this future as an {@link AbortedException} and not as an {@link + * ExecutionException} with an {@link AbortedException} as its cause. + */ + static class CommitTimestampFutureImpl extends ForwardingApiFuture + implements CommitTimestampFuture { + CommitTimestampFutureImpl(ApiFuture delegate) { + super(Preconditions.checkNotNull(delegate)); + } + + @Override + public Timestamp get() throws AbortedException, ExecutionException, InterruptedException { + try { + return super.get(); + } catch (ExecutionException e) { + if (e.getCause() != null && e.getCause() instanceof AbortedException) { + throw (AbortedException) e.getCause(); + } + throw e; + } + } + + @Override + public Timestamp get(long timeout, TimeUnit unit) + throws AbortedException, ExecutionException, InterruptedException, TimeoutException { + try { + return super.get(timeout, unit); + } catch (ExecutionException e) { + if (e.getCause() != null && e.getCause() instanceof AbortedException) { + throw (AbortedException) e.getCause(); + } + throw e; + } + } + } + + class AsyncTransactionStatementImpl extends ForwardingApiFuture + implements AsyncTransactionStep { + final ApiFuture txnFuture; + final SettableApiFuture statementResult; + + AsyncTransactionStatementImpl( + final ApiFuture txnFuture, + ApiFuture input, + final AsyncTransactionFunction function, + Executor executor) { + this(SettableApiFuture.create(), txnFuture, input, function, executor); + } + + AsyncTransactionStatementImpl( + SettableApiFuture delegate, + final ApiFuture txnFuture, + ApiFuture input, + final AsyncTransactionFunction function, + final Executor executor) { + super(delegate); + this.statementResult = delegate; + this.txnFuture = txnFuture; + ApiFutures.addCallback( + input, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + mgr.onError(t); + txnResult.setException(t); + } + + @Override + public void onSuccess(I result) { + try { + ApiFutures.addCallback( + runAsyncTransactionFunction(function, txnFuture.get(), result, executor), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + mgr.onError(t); + txnResult.setException(t); + } + + @Override + public void onSuccess(O result) { + statementResult.set(result); + } + }, + MoreExecutors.directExecutor()); + } catch (Throwable t) { + mgr.onError(t); + txnResult.setException(t); + } + } + }, + MoreExecutors.directExecutor()); + } + + @Override + public AsyncTransactionStatementImpl then( + AsyncTransactionFunction next, Executor executor) { + return new AsyncTransactionStatementImpl<>(txnFuture, statementResult, next, executor); + } + + @Override + public CommitTimestampFuture commitAsync() { + ApiFutures.addCallback( + statementResult, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + mgr.onError(t); + txnResult.setException(t); + } + + @Override + public void onSuccess(O result) { + ApiFutures.addCallback( + mgr.commitAsync(), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + mgr.onError(t); + txnResult.setException(t); + } + + @Override + public void onSuccess(Timestamp result) { + txnResult.set(result); + } + }, + MoreExecutors.directExecutor()); + } + }, + MoreExecutors.directExecutor()); + return new CommitTimestampFutureImpl(txnResult); + } + } + + static ApiFuture runAsyncTransactionFunction( + final AsyncTransactionFunction function, + final TransactionContext txn, + final I input, + Executor executor) + throws Exception { + // Shortcut for common path. + if (executor == MoreExecutors.directExecutor()) { + return Preconditions.checkNotNull( + function.apply(txn, input), + "AsyncTransactionFunction returned . Did you mean to return ApiFutures.immediateFuture(null)?"); + } else { + final SettableApiFuture res = SettableApiFuture.create(); + executor.execute( + new Runnable() { + @Override + public void run() { + try { + ApiFuture functionResult = + Preconditions.checkNotNull( + function.apply(txn, input), + "AsyncTransactionFunction returned . Did you mean to return ApiFutures.immediateFuture(null)?"); + ApiFutures.addCallback( + functionResult, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + res.setException(t); + } + + @Override + public void onSuccess(O result) { + res.set(result); + } + }, + MoreExecutors.directExecutor()); + } catch (Throwable t) { + res.setException(t); + } + } + }); + return res; + } + } + + final CommittableAsyncTransactionManager mgr; + final SettableApiFuture txnResult = SettableApiFuture.create(); + + TransactionContextFutureImpl( + CommittableAsyncTransactionManager mgr, ApiFuture txnFuture) { + super(txnFuture); + this.mgr = mgr; + } + + @Override + public AsyncTransactionStatementImpl then( + AsyncTransactionFunction function, Executor executor) { + final SettableApiFuture input = SettableApiFuture.create(); + ApiFutures.addCallback( + this, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + mgr.onError(t); + input.setException(t); + } + + @Override + public void onSuccess(TransactionContext result) { + input.set(null); + } + }, + MoreExecutors.directExecutor()); + return new AsyncTransactionStatementImpl<>(this, input, function, executor); + } +} diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionManagerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionManagerImpl.java index bdf7ec954f..8dbab88314 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionManagerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionManagerImpl.java @@ -29,14 +29,23 @@ final class TransactionManagerImpl implements TransactionManager, SessionTransac private static final Tracer tracer = Tracing.getTracer(); private final SessionImpl session; - private final Span span; + private Span span; private TransactionRunnerImpl.TransactionContextImpl txn; private TransactionState txnState; - TransactionManagerImpl(SessionImpl session) { + TransactionManagerImpl(SessionImpl session, Span span) { this.session = session; - this.span = Tracing.getTracer().getCurrentSpan(); + this.span = span; + } + + Span getSpan() { + return span; + } + + @Override + public void setSpan(Span span) { + this.span = span; } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java index cfa8b73c4a..c10b713285 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java @@ -21,18 +21,29 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import com.google.api.core.ApiAsyncFunction; +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; import com.google.cloud.Timestamp; +import com.google.cloud.spanner.Options.QueryOption; +import com.google.cloud.spanner.Options.ReadOption; import com.google.cloud.spanner.SessionImpl.SessionTransaction; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.ByteString; +import com.google.protobuf.Empty; import com.google.rpc.Code; import com.google.spanner.v1.CommitRequest; import com.google.spanner.v1.CommitResponse; import com.google.spanner.v1.ExecuteBatchDmlRequest; +import com.google.spanner.v1.ExecuteBatchDmlResponse; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryMode; +import com.google.spanner.v1.ResultSet; import com.google.spanner.v1.RollbackRequest; import com.google.spanner.v1.TransactionSelector; import io.opencensus.common.Scope; @@ -43,6 +54,8 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -76,6 +89,57 @@ static Builder newBuilder() { return new Builder(); } + /** + * {@link AsyncResultSet} implementation that keeps track of the async operations that are still + * running for this {@link TransactionContext} and that should finish before the {@link + * TransactionContext} can commit and release its session back into the pool. + */ + private class TransactionContextAsyncResultSetImpl extends ForwardingAsyncResultSet + implements ListenableAsyncResultSet { + private TransactionContextAsyncResultSetImpl(ListenableAsyncResultSet delegate) { + super(delegate); + } + + @Override + public ApiFuture setCallback(Executor exec, ReadyCallback cb) { + Runnable listener = + new Runnable() { + @Override + public void run() { + decreaseAsyncOperations(); + } + }; + try { + increaseAsynOperations(); + addListener(listener); + return super.setCallback(exec, cb); + } catch (Throwable t) { + removeListener(listener); + decreaseAsyncOperations(); + throw t; + } + } + + @Override + public void addListener(Runnable listener) { + ((ListenableAsyncResultSet) this.delegate).addListener(listener); + } + + @Override + public void removeListener(Runnable listener) { + ((ListenableAsyncResultSet) this.delegate).removeListener(listener); + } + } + + @GuardedBy("lock") + private volatile boolean committing; + + @GuardedBy("lock") + private volatile SettableApiFuture finishedAsyncOperations = SettableApiFuture.create(); + + @GuardedBy("lock") + private volatile int runningAsyncOperations; + @GuardedBy("lock") private List mutations = new ArrayList<>(); @@ -92,25 +156,70 @@ static Builder newBuilder() { private TransactionContextImpl(Builder builder) { super(builder); this.transactionId = builder.transactionId; + this.finishedAsyncOperations.set(null); + } + + private void increaseAsynOperations() { + synchronized (lock) { + if (runningAsyncOperations == 0) { + finishedAsyncOperations = SettableApiFuture.create(); + } + runningAsyncOperations++; + } + } + + private void decreaseAsyncOperations() { + synchronized (lock) { + runningAsyncOperations--; + if (runningAsyncOperations == 0) { + finishedAsyncOperations.set(null); + } + } } void ensureTxn() { + try { + ensureTxnAsync().get(); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause() == null ? e : e.getCause()); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } + + ApiFuture ensureTxnAsync() { + final SettableApiFuture res = SettableApiFuture.create(); if (transactionId == null || isAborted()) { span.addAnnotation("Creating Transaction"); - try { - transactionId = session.beginTransaction(); - span.addAnnotation( - "Transaction Creation Done", - ImmutableMap.of( - "Id", AttributeValue.stringAttributeValue(transactionId.toStringUtf8()))); - txnLogger.log( - Level.FINER, - "Started transaction {0}", - txnLogger.isLoggable(Level.FINER) ? transactionId.asReadOnlyByteBuffer() : null); - } catch (SpannerException e) { - span.addAnnotation("Transaction Creation Failed", TraceUtil.getExceptionAnnotations(e)); - throw e; - } + final ApiFuture fut = session.beginTransactionAsync(); + fut.addListener( + new Runnable() { + @Override + public void run() { + try { + transactionId = fut.get(); + span.addAnnotation( + "Transaction Creation Done", + ImmutableMap.of( + "Id", AttributeValue.stringAttributeValue(transactionId.toStringUtf8()))); + txnLogger.log( + Level.FINER, + "Started transaction {0}", + txnLogger.isLoggable(Level.FINER) + ? transactionId.asReadOnlyByteBuffer() + : null); + res.set(null); + } catch (ExecutionException e) { + span.addAnnotation( + "Transaction Creation Failed", + TraceUtil.getExceptionAnnotations(e.getCause() == null ? e : e.getCause())); + res.setException(e.getCause() == null ? e : e.getCause()); + } catch (InterruptedException e) { + res.setException(SpannerExceptionFactory.propagateInterrupt(e)); + } + } + }, + MoreExecutors.directExecutor()); } else { span.addAnnotation( "Transaction Initialized", @@ -120,41 +229,102 @@ void ensureTxn() { Level.FINER, "Using prepared transaction {0}", txnLogger.isLoggable(Level.FINER) ? transactionId.asReadOnlyByteBuffer() : null); + res.set(null); } + return res; } void commit() { - span.addAnnotation("Starting Commit"); - CommitRequest.Builder builder = - CommitRequest.newBuilder().setSession(session.getName()).setTransactionId(transactionId); - synchronized (lock) { - if (!mutations.isEmpty()) { - List mutationsProto = new ArrayList<>(); - Mutation.toProto(mutations, mutationsProto); - builder.addAllMutations(mutationsProto); - } - // Ensure that no call to buffer mutations that would be lost can succeed. - mutations = null; + try { + commitTimestamp = commitAsync().get(); + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } catch (ExecutionException e) { + throw SpannerExceptionFactory.newSpannerException(e.getCause() == null ? e : e.getCause()); } - final CommitRequest commitRequest = builder.build(); - Span opSpan = tracer.spanBuilderWithExplicitParent(SpannerImpl.COMMIT, span).startSpan(); - try (Scope s = tracer.withSpan(opSpan)) { - CommitResponse commitResponse = rpc.commit(commitRequest, session.getOptions()); - if (!commitResponse.hasCommitTimestamp()) { - throw newSpannerException( - ErrorCode.INTERNAL, "Missing commitTimestamp:\n" + session.getName()); - } - commitTimestamp = Timestamp.fromProto(commitResponse.getCommitTimestamp()); - opSpan.end(TraceUtil.END_SPAN_OPTIONS); - } catch (RuntimeException e) { - span.addAnnotation("Commit Failed", TraceUtil.getExceptionAnnotations(e)); - TraceUtil.endSpanWithFailure(opSpan, e); - if (e instanceof SpannerException) { - onError((SpannerException) e); - } - throw e; + } + + ApiFuture commitAsync() { + final SettableApiFuture res = SettableApiFuture.create(); + final SettableApiFuture latch; + synchronized (lock) { + latch = finishedAsyncOperations; } - span.addAnnotation("Commit Done"); + latch.addListener( + new Runnable() { + @Override + public void run() { + try { + latch.get(); + CommitRequest.Builder builder = + CommitRequest.newBuilder() + .setSession(session.getName()) + .setTransactionId(transactionId); + synchronized (lock) { + if (!mutations.isEmpty()) { + List mutationsProto = new ArrayList<>(); + Mutation.toProto(mutations, mutationsProto); + builder.addAllMutations(mutationsProto); + } + // Ensure that no call to buffer mutations that would be lost can succeed. + mutations = null; + } + final CommitRequest commitRequest = builder.build(); + span.addAnnotation("Starting Commit"); + final Span opSpan = + tracer.spanBuilderWithExplicitParent(SpannerImpl.COMMIT, span).startSpan(); + final ApiFuture commitFuture = + rpc.commitAsync(commitRequest, session.getOptions()); + commitFuture.addListener( + tracer.withSpan( + opSpan, + new Runnable() { + @Override + public void run() { + try { + CommitResponse commitResponse = commitFuture.get(); + if (!commitResponse.hasCommitTimestamp()) { + throw newSpannerException( + ErrorCode.INTERNAL, + "Missing commitTimestamp:\n" + session.getName()); + } + Timestamp ts = + Timestamp.fromProto(commitResponse.getCommitTimestamp()); + span.addAnnotation("Commit Done"); + opSpan.end(TraceUtil.END_SPAN_OPTIONS); + res.set(ts); + } catch (Throwable e) { + if (e instanceof ExecutionException) { + e = + SpannerExceptionFactory.newSpannerException( + e.getCause() == null ? e : e.getCause()); + } else if (e instanceof InterruptedException) { + e = + SpannerExceptionFactory.propagateInterrupt( + (InterruptedException) e); + } else { + e = SpannerExceptionFactory.newSpannerException(e); + } + span.addAnnotation( + "Commit Failed", TraceUtil.getExceptionAnnotations(e)); + TraceUtil.endSpanWithFailure(opSpan, e); + onError((SpannerException) e); + res.setException(e); + } + } + }), + MoreExecutors.directExecutor()); + } catch (InterruptedException e) { + res.setException(SpannerExceptionFactory.propagateInterrupt(e)); + } catch (ExecutionException e) { + res.setException( + SpannerExceptionFactory.newSpannerException( + e.getCause() == null ? e : e.getCause())); + } + } + }, + MoreExecutors.directExecutor()); + return res; } Timestamp commitTimestamp() { @@ -190,6 +360,25 @@ void rollback() { } } + ApiFuture rollbackAsync() { + span.addAnnotation("Starting Rollback"); + return ApiFutures.transformAsync( + rpc.rollbackAsync( + RollbackRequest.newBuilder() + .setSession(session.getName()) + .setTransactionId(transactionId) + .build(), + session.getOptions()), + new ApiAsyncFunction() { + @Override + public ApiFuture apply(Empty input) throws Exception { + span.addAnnotation("Rollback Done"); + return ApiFutures.immediateFuture(null); + } + }, + MoreExecutors.directExecutor()); + } + @Nullable @Override TransactionSelector getTransactionSelector() { @@ -252,6 +441,61 @@ public long executeUpdate(Statement statement) { } } + @Override + public ApiFuture executeUpdateAsync(Statement statement) { + beforeReadOrQuery(); + final ExecuteSqlRequest.Builder builder = + getExecuteSqlRequestBuilder(statement, QueryMode.NORMAL); + ApiFuture resultSet; + try { + // Register the update as an async operation that must finish before the transaction may + // commit. + increaseAsynOperations(); + resultSet = rpc.executeQueryAsync(builder.build(), session.getOptions()); + } catch (Throwable t) { + decreaseAsyncOperations(); + throw t; + } + ApiFuture updateCount = + ApiFutures.transform( + resultSet, + new ApiFunction() { + @Override + public Long apply(ResultSet input) { + if (!input.hasStats()) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, + "DML response missing stats possibly due to non-DML statement as input"); + } + // For standard DML, using the exact row count. + return input.getStats().getRowCountExact(); + } + }, + MoreExecutors.directExecutor()); + updateCount = + ApiFutures.catching( + updateCount, + Throwable.class, + new ApiFunction() { + @Override + public Long apply(Throwable input) { + SpannerException e = SpannerExceptionFactory.newSpannerException(input); + onError(e); + throw e; + } + }, + MoreExecutors.directExecutor()); + updateCount.addListener( + new Runnable() { + @Override + public void run() { + decreaseAsyncOperations(); + } + }, + MoreExecutors.directExecutor()); + return updateCount; + } + @Override public long[] batchUpdate(Iterable statements) { beforeReadOrQuery(); @@ -281,11 +525,91 @@ public long[] batchUpdate(Iterable statements) { throw e; } } + + @Override + public ApiFuture batchUpdateAsync(Iterable statements) { + beforeReadOrQuery(); + final ExecuteBatchDmlRequest.Builder builder = getExecuteBatchDmlRequestBuilder(statements); + ApiFuture response; + try { + // Register the update as an async operation that must finish before the transaction may + // commit. + increaseAsynOperations(); + response = rpc.executeBatchDmlAsync(builder.build(), session.getOptions()); + } catch (Throwable t) { + decreaseAsyncOperations(); + throw t; + } + final ApiFuture updateCounts = + ApiFutures.transform( + response, + new ApiFunction() { + @Override + public long[] apply(ExecuteBatchDmlResponse input) { + long[] results = new long[input.getResultSetsCount()]; + for (int i = 0; i < input.getResultSetsCount(); ++i) { + results[i] = input.getResultSets(i).getStats().getRowCountExact(); + } + // If one of the DML statements was aborted, we should throw an aborted exception. + // In all other cases, we should throw a BatchUpdateException. + if (input.getStatus().getCode() == Code.ABORTED_VALUE) { + throw newSpannerException( + ErrorCode.fromRpcStatus(input.getStatus()), input.getStatus().getMessage()); + } else if (input.getStatus().getCode() != 0) { + throw newSpannerBatchUpdateException( + ErrorCode.fromRpcStatus(input.getStatus()), + input.getStatus().getMessage(), + results); + } + return results; + } + }, + MoreExecutors.directExecutor()); + updateCounts.addListener( + new Runnable() { + @Override + public void run() { + try { + updateCounts.get(); + } catch (ExecutionException e) { + onError(SpannerExceptionFactory.newSpannerException(e.getCause())); + } catch (InterruptedException e) { + onError(SpannerExceptionFactory.propagateInterrupt(e)); + } finally { + decreaseAsyncOperations(); + } + } + }, + MoreExecutors.directExecutor()); + return updateCounts; + } + + private ListenableAsyncResultSet wrap(ListenableAsyncResultSet delegate) { + return new TransactionContextAsyncResultSetImpl(delegate); + } + + @Override + public ListenableAsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + return wrap(super.readAsync(table, keys, columns, options)); + } + + @Override + public ListenableAsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + return wrap(super.readUsingIndexAsync(table, index, keys, columns, options)); + } + + @Override + public ListenableAsyncResultSet executeQueryAsync( + final Statement statement, final QueryOption... options) { + return wrap(super.executeQueryAsync(statement, options)); + } } private boolean blockNestedTxn = true; private final SessionImpl session; - private final Span span; + private Span span; private TransactionContextImpl txn; private volatile boolean isValid = true; @@ -297,10 +621,14 @@ public TransactionRunner allowNestedTransaction() { TransactionRunnerImpl(SessionImpl session, SpannerRpc rpc, int defaultPrefetchChunks) { this.session = session; - this.span = Tracing.getTracer().getCurrentSpan(); this.txn = session.newTransaction(); } + @Override + public void setSpan(Span span) { + this.span = span; + } + @Nullable @Override public T run(TransactionCallable callable) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 6f383b1f79..9f7eaa8e8f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1078,8 +1078,14 @@ public void cancel(String message) { @Override public ResultSet executeQuery(ExecuteSqlRequest request, @Nullable Map options) { + return get(executeQueryAsync(request, options)); + } + + @Override + public ApiFuture executeQueryAsync( + ExecuteSqlRequest request, @Nullable Map options) { GrpcCallContext context = newCallContext(options, request.getSession()); - return get(spannerStub.executeSqlCallable().futureCall(request, context)); + return spannerStub.executeSqlCallable().futureCall(request, context); } @Override @@ -1127,30 +1133,52 @@ public void cancel(String message) { @Override public ExecuteBatchDmlResponse executeBatchDml( ExecuteBatchDmlRequest request, @Nullable Map options) { + return get(executeBatchDmlAsync(request, options)); + } + @Override + public ApiFuture executeBatchDmlAsync( + ExecuteBatchDmlRequest request, @Nullable Map options) { + GrpcCallContext context = newCallContext(options, request.getSession()); + return spannerStub.executeBatchDmlCallable().futureCall(request, context); + } + + @Override + public ApiFuture beginTransactionAsync( + BeginTransactionRequest request, @Nullable Map options) { GrpcCallContext context = newCallContext(options, request.getSession()); - return get(spannerStub.executeBatchDmlCallable().futureCall(request, context)); + return spannerStub.beginTransactionCallable().futureCall(request, context); } @Override public Transaction beginTransaction( BeginTransactionRequest request, @Nullable Map options) throws SpannerException { - GrpcCallContext context = newCallContext(options, request.getSession()); - return get(spannerStub.beginTransactionCallable().futureCall(request, context)); + return get(beginTransactionAsync(request, options)); + } + + @Override + public ApiFuture commitAsync( + CommitRequest commitRequest, @Nullable Map options) { + GrpcCallContext context = newCallContext(options, commitRequest.getSession()); + return spannerStub.commitCallable().futureCall(commitRequest, context); } @Override public CommitResponse commit(CommitRequest commitRequest, @Nullable Map options) throws SpannerException { - GrpcCallContext context = newCallContext(options, commitRequest.getSession()); - return get(spannerStub.commitCallable().futureCall(commitRequest, context)); + return get(commitAsync(commitRequest, options)); + } + + @Override + public ApiFuture rollbackAsync(RollbackRequest request, @Nullable Map options) { + GrpcCallContext context = newCallContext(options, request.getSession()); + return spannerStub.rollbackCallable().futureCall(request, context); } @Override public void rollback(RollbackRequest request, @Nullable Map options) throws SpannerException { - GrpcCallContext context = newCallContext(options, request.getSession()); - get(spannerStub.rollbackCallable().futureCall(request, context)); + get(rollbackAsync(request, options)); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 5b6c6756d9..6b42c0a754 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -284,6 +284,9 @@ StreamingCall read( ResultSet executeQuery(ExecuteSqlRequest request, @Nullable Map options); + ApiFuture executeQueryAsync( + ExecuteSqlRequest request, @Nullable Map options); + ResultSet executePartitionedDml(ExecuteSqlRequest request, @Nullable Map options); RetrySettings getPartitionedDmlRetrySettings(); @@ -296,14 +299,25 @@ StreamingCall executeQuery( ExecuteBatchDmlResponse executeBatchDml(ExecuteBatchDmlRequest build, Map options); + ApiFuture executeBatchDmlAsync( + ExecuteBatchDmlRequest build, Map options); + Transaction beginTransaction(BeginTransactionRequest request, @Nullable Map options) throws SpannerException; + ApiFuture beginTransactionAsync( + BeginTransactionRequest request, @Nullable Map options); + CommitResponse commit(CommitRequest commitRequest, @Nullable Map options) throws SpannerException; + ApiFuture commitAsync( + CommitRequest commitRequest, @Nullable Map options); + void rollback(RollbackRequest request, @Nullable Map options) throws SpannerException; + ApiFuture rollbackAsync(RollbackRequest request, @Nullable Map options); + PartitionResponse partitionQuery(PartitionQueryRequest request, @Nullable Map options) throws SpannerException; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractAsyncTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractAsyncTransactionTest.java new file mode 100644 index 0000000000..bf76ea4f39 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractAsyncTransactionTest.java @@ -0,0 +1,140 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.cloud.spanner.MockSpannerTestUtil.EMPTY_KEY_VALUE_RESULTSET; +import static com.google.cloud.spanner.MockSpannerTestUtil.INVALID_UPDATE_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_MULTIPLE_KEY_VALUE_RESULTSET; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_MULTIPLE_KEY_VALUE_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_ONE_EMPTY_KEY_VALUE_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_ONE_KEY_VALUE_RESULTSET; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_ONE_KEY_VALUE_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.TEST_DATABASE; +import static com.google.cloud.spanner.MockSpannerTestUtil.TEST_INSTANCE; +import static com.google.cloud.spanner.MockSpannerTestUtil.TEST_PROJECT; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_ABORTED_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_COUNT; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_STATEMENT; + +import com.google.api.core.ApiFunction; +import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Server; +import io.grpc.Status; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +/** Base class for {@link AsyncRunnerTest} and {@link AsyncTransactionManagerTest}. */ +public abstract class AbstractAsyncTransactionTest { + static MockSpannerServiceImpl mockSpanner; + private static Server server; + private static InetSocketAddress address; + static ExecutorService executor; + + Spanner spanner; + Spanner spannerWithEmptySessionPool; + + @BeforeClass + public static void setup() throws Exception { + mockSpanner = new MockSpannerServiceImpl(); + mockSpanner.setAbortProbability(0.0D); + mockSpanner.putStatementResult( + StatementResult.query(READ_ONE_EMPTY_KEY_VALUE_STATEMENT, EMPTY_KEY_VALUE_RESULTSET)); + mockSpanner.putStatementResult( + StatementResult.query(READ_ONE_KEY_VALUE_STATEMENT, READ_ONE_KEY_VALUE_RESULTSET)); + mockSpanner.putStatementResult( + StatementResult.query( + READ_MULTIPLE_KEY_VALUE_STATEMENT, READ_MULTIPLE_KEY_VALUE_RESULTSET)); + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + mockSpanner.putStatementResult( + StatementResult.exception( + INVALID_UPDATE_STATEMENT, + Status.INVALID_ARGUMENT.withDescription("invalid statement").asRuntimeException())); + mockSpanner.putStatementResult( + StatementResult.exception( + UPDATE_ABORTED_STATEMENT, + Status.ABORTED.withDescription("Transaction was aborted").asRuntimeException())); + + address = new InetSocketAddress("localhost", 0); + server = NettyServerBuilder.forAddress(address).addService(mockSpanner).build().start(); + executor = Executors.newSingleThreadExecutor(); + } + + @AfterClass + public static void teardown() throws Exception { + server.shutdown(); + server.awaitTermination(); + executor.shutdown(); + } + + @Before + public void before() throws Exception { + String endpoint = address.getHostString() + ":" + server.getPort(); + spanner = + SpannerOptions.newBuilder() + .setProjectId(TEST_PROJECT) + .setChannelConfigurator( + new ApiFunction() { + @Override + public ManagedChannelBuilder apply(ManagedChannelBuilder input) { + input.usePlaintext(); + return input; + } + }) + .setHost("http://" + endpoint) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption(SessionPoolOptions.newBuilder().setFailOnSessionLeak().build()) + .build() + .getService(); + spannerWithEmptySessionPool = + spanner + .getOptions() + .toBuilder() + .setSessionPoolOption( + SessionPoolOptions.newBuilder() + .setFailOnSessionLeak() + .setMinSessions(0) + .setIncStep(1) + .build()) + .build() + .getService(); + } + + @After + public void after() throws Exception { + spanner.close(); + spannerWithEmptySessionPool.close(); + mockSpanner.removeAllExecutionTimes(); + mockSpanner.reset(); + } + + DatabaseClient client() { + return spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + } + + DatabaseClient clientWithEmptySessionPool() { + return spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractReadContextTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractReadContextTest.java index bfd739d553..f9cee1c488 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractReadContextTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractReadContextTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.api.gax.core.ExecutorProvider; import com.google.cloud.spanner.spi.v1.SpannerRpc; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryMode; @@ -80,6 +81,7 @@ public void setup() { .setSession(session) .setRpc(mock(SpannerRpc.class)) .setDefaultQueryOptions(defaultQueryOptions) + .setExecutorProvider(mock(ExecutorProvider.class)) .build(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplStressTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplStressTest.java new file mode 100644 index 0000000000..c3383cadda --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplStressTest.java @@ -0,0 +1,464 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.api.gax.core.ExecutorProvider; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.CursorState; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.Type.StructField; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Timeout; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class AsyncResultSetImplStressTest { + private static final int TEST_RUNS = 1000; + + /** Timeout is applied to each test case individually. */ + @Rule public Timeout timeout = new Timeout(120, TimeUnit.SECONDS); + + @Parameter(0) + public int resultSetSize; + + @Parameters(name = "rows = {0}") + public static Collection data() { + List params = new ArrayList<>(); + for (int rows : new int[] {0, 1, 5, 10}) { + params.add(new Object[] {rows}); + } + return params; + } + + /** POJO representing a row in the test {@link ResultSet}. */ + private static final class Row { + private final Long id; + private final String name; + + static Row create(StructReader reader) { + return new Row(reader.getLong("ID"), reader.getString("NAME")); + } + + private Row(Long id, String name) { + this.id = id; + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Row)) { + return false; + } + Row other = (Row) o; + return Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name); + } + + @Override + public int hashCode() { + return Objects.hash(this.id, this.name); + } + + @Override + public String toString() { + return String.format("ID: %d, NAME: %s", id, name); + } + } + + private static final class ResultSetWithRandomErrors extends ForwardingResultSet { + private final Random random = new Random(); + private final double errorFraction; + + private ResultSetWithRandomErrors(ResultSet delegate, double errorFraction) { + super(delegate); + this.errorFraction = errorFraction; + } + + @Override + public boolean next() { + if (random.nextDouble() < errorFraction) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "random error"); + } + return super.next(); + } + } + + /** Creates a simple in-mem {@link ResultSet}. */ + private ResultSet createResultSet() { + List rows = new ArrayList<>(resultSetSize); + for (int i = 0; i < resultSetSize; i++) { + rows.add( + Struct.newBuilder() + .set("ID") + .to(i + 1) + .set("NAME") + .to(String.format("Row %d", (i + 1))) + .build()); + } + return ResultSets.forRows( + Type.struct(StructField.of("ID", Type.int64()), StructField.of("NAME", Type.string())), + rows); + } + + private ResultSet createResultSetWithErrors(double errorFraction) { + return new ResultSetWithRandomErrors(createResultSet(), errorFraction); + } + + /** + * Generates a list of {@link Row} instances that correspond with the rows in {@link + * #createResultSet()}. + */ + private List createExpectedRows() { + List rows = new ArrayList<>(resultSetSize); + for (int i = 0; i < resultSetSize; i++) { + rows.add(new Row(Long.valueOf(i + 1), String.format("Row %d", (i + 1)))); + } + return rows; + } + + /** Creates a single-threaded {@link ExecutorService}. */ + private static ScheduledExecutorService createExecService() { + return createExecService(1); + } + + /** Creates an {@link ExecutorService} using a bounded pool of threadCount threads. */ + private static ScheduledExecutorService createExecService(int threadCount) { + return Executors.newScheduledThreadPool( + threadCount, new ThreadFactoryBuilder().setDaemon(true).build()); + } + + @Test + public void toList() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + for (int i = 0; i < TEST_RUNS; i++) { + try (AsyncResultSetImpl impl = + new AsyncResultSetImpl(executorProvider, createResultSet(), bufferSize)) { + ImmutableList list = + impl.toList( + new Function() { + @Override + public Row apply(StructReader input) { + return Row.create(input); + } + }); + assertThat(list).containsExactlyElementsIn(createExpectedRows()); + } + } + } + } + + @Test + public void toListWithErrors() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + for (int i = 0; i < TEST_RUNS; i++) { + try (AsyncResultSetImpl impl = + new AsyncResultSetImpl( + executorProvider, createResultSetWithErrors(1.0 / resultSetSize), bufferSize)) { + ImmutableList list = + impl.toList( + new Function() { + @Override + public Row apply(StructReader input) { + return Row.create(input); + } + }); + assertThat(list).containsExactlyElementsIn(createExpectedRows()); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()).contains("random error"); + } + } + } + } + + @Test + public void asyncToList() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + List>> futures = new ArrayList<>(TEST_RUNS); + ExecutorService executor = createExecService(32); + for (int i = 0; i < TEST_RUNS; i++) { + try (AsyncResultSet impl = + new AsyncResultSetImpl(executorProvider, createResultSet(), bufferSize)) { + futures.add( + impl.toListAsync( + new Function() { + @Override + public Row apply(StructReader input) { + return Row.create(input); + } + }, + executor)); + } + } + List> lists = ApiFutures.allAsList(futures).get(); + for (ImmutableList list : lists) { + assertThat(list).containsExactlyElementsIn(createExpectedRows()); + } + executor.shutdown(); + } + } + + @Test + public void consume() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + final Random random = new Random(); + for (Executor executor : + new Executor[] { + MoreExecutors.directExecutor(), createExecService(), createExecService(32) + }) { + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + for (int i = 0; i < TEST_RUNS; i++) { + final SettableApiFuture> future = SettableApiFuture.create(); + try (AsyncResultSetImpl impl = + new AsyncResultSetImpl(executorProvider, createResultSet(), bufferSize)) { + final ImmutableList.Builder builder = ImmutableList.builder(); + impl.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + // Randomly do something with the received data or not. Not calling tryNext() in + // the onDataReady is not 'normal', but users may do it, and the result set + // should be able to handle that. + if (random.nextBoolean()) { + CursorState state; + while ((state = resultSet.tryNext()) == CursorState.OK) { + builder.add(Row.create(resultSet)); + } + if (state == CursorState.DONE) { + future.set(builder.build()); + } + } + return CallbackResponse.CONTINUE; + } + }); + assertThat(future.get()).containsExactlyElementsIn(createExpectedRows()); + } + } + } + } + } + + @Test + public void pauseResume() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + final Random random = new Random(); + List>> futures = new ArrayList<>(); + for (Executor executor : + new Executor[] { + MoreExecutors.directExecutor(), createExecService(), createExecService(32) + }) { + final List resultSets = + Collections.synchronizedList(new ArrayList()); + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + for (int i = 0; i < TEST_RUNS; i++) { + final SettableApiFuture> future = SettableApiFuture.create(); + futures.add(future); + try (AsyncResultSetImpl impl = + new AsyncResultSetImpl(executorProvider, createResultSet(), bufferSize)) { + resultSets.add(impl); + final ImmutableList.Builder builder = ImmutableList.builder(); + impl.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + CursorState state; + while ((state = resultSet.tryNext()) == CursorState.OK) { + builder.add(Row.create(resultSet)); + // Randomly request the iterator to pause. + if (random.nextBoolean()) { + return CallbackResponse.PAUSE; + } + } + if (state == CursorState.DONE) { + future.set(builder.build()); + } + return CallbackResponse.CONTINUE; + } + }); + } + } + } + final AtomicBoolean finished = new AtomicBoolean(false); + ExecutorService resumeService = createExecService(); + resumeService.execute( + new Runnable() { + @Override + public void run() { + while (!finished.get()) { + // Randomly resume result sets. + resultSets.get(random.nextInt(resultSets.size())).resume(); + } + } + }); + List> lists = ApiFutures.allAsList(futures).get(); + for (ImmutableList list : lists) { + assertThat(list).containsExactlyElementsIn(createExpectedRows()); + } + if (executor instanceof ExecutorService) { + ((ExecutorService) executor).shutdown(); + } + finished.set(true); + resumeService.shutdown(); + } + } + + @Test + public void cancel() throws Exception { + ExecutorProvider executorProvider = SpannerOptions.createDefaultAsyncExecutorProvider(); + final Random random = new Random(); + for (Executor executor : + new Executor[] { + MoreExecutors.directExecutor(), createExecService(), createExecService(32) + }) { + List>> futures = new ArrayList<>(); + final List resultSets = + Collections.synchronizedList(new ArrayList()); + final Set cancelledIndexes = new HashSet<>(); + for (int bufferSize = 1; bufferSize < resultSetSize * 2; bufferSize *= 2) { + for (int i = 0; i < TEST_RUNS; i++) { + final SettableApiFuture> future = SettableApiFuture.create(); + futures.add(future); + try (AsyncResultSetImpl impl = + new AsyncResultSetImpl(executorProvider, createResultSet(), bufferSize)) { + resultSets.add(impl); + final ImmutableList.Builder builder = ImmutableList.builder(); + impl.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + CursorState state; + while ((state = resultSet.tryNext()) == CursorState.OK) { + builder.add(Row.create(resultSet)); + // Randomly request the iterator to pause. + if (random.nextBoolean()) { + return CallbackResponse.PAUSE; + } + } + if (state == CursorState.DONE) { + future.set(builder.build()); + } + return CallbackResponse.CONTINUE; + } catch (SpannerException e) { + future.setException(e); + throw e; + } + } + }); + } + } + } + final AtomicBoolean finished = new AtomicBoolean(false); + // Both resume and cancel resultsets randomly. + ExecutorService resumeService = createExecService(); + resumeService.execute( + new Runnable() { + @Override + public void run() { + while (!finished.get()) { + // Randomly resume result sets. + resultSets.get(random.nextInt(resultSets.size())).resume(); + } + // Make sure all result sets finish. + for (AsyncResultSet rs : resultSets) { + rs.resume(); + } + } + }); + ExecutorService cancelService = createExecService(); + cancelService.execute( + new Runnable() { + @Override + public void run() { + while (!finished.get()) { + // Randomly cancel result sets. + int index = random.nextInt(resultSets.size()); + resultSets.get(index).cancel(); + cancelledIndexes.add(index); + } + } + }); + + // First wait until all result sets have finished. + for (ApiFuture> future : futures) { + try { + future.get(); + } catch (Throwable e) { + // ignore for now. + } + } + finished.set(true); + cancelService.shutdown(); + cancelService.awaitTermination(10L, TimeUnit.SECONDS); + + int index = 0; + for (ApiFuture> future : futures) { + try { + ImmutableList list = future.get(30L, TimeUnit.SECONDS); + // Note that the fact that the call succeeded for for this result set, does not + // necessarily mean that the result set was not cancelled. Cancelling a result set is a + // best-effort operation, and the entire result set may still be produced and returned to + // the user. + assertThat(list).containsExactlyElementsIn(createExpectedRows()); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.CANCELLED); + assertThat(cancelledIndexes).contains(index); + } + index++; + } + if (executor instanceof ExecutorService) { + ((ExecutorService) executor).shutdown(); + } + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java new file mode 100644 index 0000000000..9359dc6694 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java @@ -0,0 +1,443 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.api.core.ApiFuture; +import com.google.api.gax.core.ExecutorProvider; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.CursorState; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Range; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AsyncResultSetImplTest { + private ExecutorProvider mockedProvider; + private ExecutorProvider simpleProvider; + + @Before + public void setup() { + mockedProvider = mock(ExecutorProvider.class); + when(mockedProvider.getExecutor()).thenReturn(mock(ScheduledExecutorService.class)); + simpleProvider = SpannerOptions.createAsyncExecutorProvider(1, 1L, TimeUnit.SECONDS); + } + + @SuppressWarnings("unchecked") + @Test + public void close() { + AsyncResultSetImpl rs = + new AsyncResultSetImpl( + mockedProvider, mock(ResultSet.class), AsyncResultSetImpl.DEFAULT_BUFFER_SIZE); + rs.close(); + // Closing a second time should be a no-op. + rs.close(); + + // The following methods are not allowed to call after closing the result set. + try { + rs.setCallback(mock(Executor.class), mock(ReadyCallback.class)); + fail("missing expected exception"); + } catch (IllegalStateException e) { + } + try { + rs.toList(mock(Function.class)); + fail("missing expected exception"); + } catch (IllegalStateException e) { + } + try { + rs.toListAsync(mock(Function.class), mock(Executor.class)); + fail("missing expected exception"); + } catch (IllegalStateException e) { + } + + // The following methods are allowed on a closed result set. + AsyncResultSetImpl rs2 = + new AsyncResultSetImpl( + mockedProvider, mock(ResultSet.class), AsyncResultSetImpl.DEFAULT_BUFFER_SIZE); + rs2.setCallback(mock(Executor.class), mock(ReadyCallback.class)); + rs2.close(); + rs2.cancel(); + rs2.resume(); + } + + @Test + public void tryNextNotAllowed() { + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl( + mockedProvider, mock(ResultSet.class), AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback(mock(Executor.class), mock(ReadyCallback.class)); + try { + rs.tryNext(); + fail("missing expected exception"); + } catch (IllegalStateException e) { + assertThat(e.getMessage()) + .contains("tryNext may only be called from a DataReady callback."); + } + } + } + + @Test + public void toList() { + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + ImmutableList list = + rs.toList( + new Function() { + @Override + public Object apply(StructReader input) { + return new Object(); + } + }); + assertThat(list).hasSize(3); + } + } + + @Test + public void toListPropagatesError() { + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()) + .thenThrow( + SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "invalid query")); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.toList( + new Function() { + @Override + public Object apply(StructReader input) { + return new Object(); + } + }); + fail("missing expected exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()).contains("invalid query"); + } + } + + @Test + public void toListAsync() throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newFixedThreadPool(1); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + ApiFuture> future = + rs.toListAsync( + new Function() { + @Override + public Object apply(StructReader input) { + return new Object(); + } + }, + executor); + assertThat(future.get()).hasSize(3); + } + executor.shutdown(); + } + + @Test + public void toListAsyncPropagatesError() throws InterruptedException { + ExecutorService executor = Executors.newFixedThreadPool(1); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()) + .thenThrow( + SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "invalid query")); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.toListAsync( + new Function() { + @Override + public Object apply(StructReader input) { + return new Object(); + } + }, + executor) + .get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid query"); + } + executor.shutdown(); + } + + @Test + public void withCallback() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + final AtomicInteger callbackCounter = new AtomicInteger(); + final AtomicInteger rowCounter = new AtomicInteger(); + final CountDownLatch finishedLatch = new CountDownLatch(1); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + callbackCounter.incrementAndGet(); + CursorState state; + while ((state = resultSet.tryNext()) == CursorState.OK) { + rowCounter.incrementAndGet(); + } + if (state == CursorState.DONE) { + finishedLatch.countDown(); + } + return CallbackResponse.CONTINUE; + } + }); + } + finishedLatch.await(); + // There should be between 1 and 4 callbacks, depending on the timing of the threads. + // Normally, there should be just 1 callback. + assertThat(callbackCounter.get()).isIn(Range.closed(1, 4)); + assertThat(rowCounter.get()).isEqualTo(3); + } + + @Test + public void callbackReceivesError() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()) + .thenThrow( + SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "invalid query")); + final BlockingDeque receivedErr = new LinkedBlockingDeque<>(1); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + resultSet.tryNext(); + receivedErr.push(new Exception("missing expected exception")); + } catch (SpannerException e) { + receivedErr.push(e); + } + return CallbackResponse.DONE; + } + }); + } + Exception e = receivedErr.take(); + assertThat(e).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e; + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid query"); + } + + @Test + public void callbackReceivesErrorHalfwayThrough() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()) + .thenReturn(true) + .thenThrow( + SpannerExceptionFactory.newSpannerException( + ErrorCode.INVALID_ARGUMENT, "invalid query")); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + final AtomicInteger rowCount = new AtomicInteger(); + final BlockingDeque receivedErr = new LinkedBlockingDeque<>(1); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + if (resultSet.tryNext() != CursorState.DONE) { + rowCount.incrementAndGet(); + return CallbackResponse.CONTINUE; + } + } catch (SpannerException e) { + receivedErr.push(e); + } + return CallbackResponse.DONE; + } + }); + } + Exception e = receivedErr.take(); + assertThat(e).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e; + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid query"); + assertThat(rowCount.get()).isEqualTo(1); + } + + @Test + public void pauseResume() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + final AtomicInteger callbackCounter = new AtomicInteger(); + final BlockingDeque queue = new LinkedBlockingDeque<>(1); + final AtomicBoolean finished = new AtomicBoolean(false); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + callbackCounter.incrementAndGet(); + CursorState state = resultSet.tryNext(); + if (state == CursorState.OK) { + try { + queue.put(new Object()); + } catch (InterruptedException e) { + // Finish early if an error occurs. + return CallbackResponse.DONE; + } + return CallbackResponse.PAUSE; + } + finished.set(true); + return CallbackResponse.DONE; + } + }); + int rowCounter = 0; + while (!finished.get()) { + Object o = queue.poll(1L, TimeUnit.MILLISECONDS); + if (o != null) { + rowCounter++; + } + rs.resume(); + } + // There should be exactly 4 callbacks as we only consume one row per callback. + assertThat(callbackCounter.get()).isEqualTo(4); + assertThat(rowCounter).isEqualTo(3); + } + } + + @Test + public void cancel() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + final AtomicInteger callbackCounter = new AtomicInteger(); + final BlockingDeque queue = new LinkedBlockingDeque<>(1); + final AtomicBoolean finished = new AtomicBoolean(false); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + callbackCounter.incrementAndGet(); + try { + CursorState state = resultSet.tryNext(); + if (state == CursorState.OK) { + try { + queue.put(new Object()); + } catch (InterruptedException e) { + // Finish early if an error occurs. + return CallbackResponse.DONE; + } + } + // Pause after 2 rows to make sure that no more data is consumed until the cancel + // call has been received. + return callbackCounter.get() == 2 + ? CallbackResponse.PAUSE + : CallbackResponse.CONTINUE; + } catch (SpannerException e) { + if (e.getErrorCode() == ErrorCode.CANCELLED) { + finished.set(true); + } + } + return CallbackResponse.DONE; + } + }); + int rowCounter = 0; + while (!finished.get()) { + Object o = queue.poll(1L, TimeUnit.MILLISECONDS); + if (o != null) { + rowCounter++; + } + if (rowCounter == 2) { + // Cancel the result set and then resume it to get the cancelled error. + rs.cancel(); + rs.resume(); + } + } + assertThat(callbackCounter.get()).isIn(Range.closed(2, 4)); + assertThat(rowCounter).isIn(Range.closed(2, 3)); + } + } + + @Test + public void callbackReturnsError() throws InterruptedException { + Executor executor = Executors.newSingleThreadExecutor(); + ResultSet delegate = mock(ResultSet.class); + when(delegate.next()).thenReturn(true, true, true, false); + when(delegate.getCurrentRowAsStruct()).thenReturn(mock(Struct.class)); + final AtomicInteger callbackCounter = new AtomicInteger(); + try (AsyncResultSetImpl rs = + new AsyncResultSetImpl(simpleProvider, delegate, AsyncResultSetImpl.DEFAULT_BUFFER_SIZE)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + callbackCounter.incrementAndGet(); + throw new RuntimeException("async test"); + } + }); + rs.getResult().get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.UNKNOWN); + assertThat(se.getMessage()).contains("async test"); + assertThat(callbackCounter.get()).isEqualTo(1); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java new file mode 100644 index 0000000000..eb00047ca4 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncRunnerTest.java @@ -0,0 +1,618 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.cloud.spanner.MockSpannerTestUtil.*; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.AsyncRunner.AsyncWork; +import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; +import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.spanner.v1.BatchCreateSessionsRequest; +import com.google.spanner.v1.BeginTransactionRequest; +import com.google.spanner.v1.CommitRequest; +import com.google.spanner.v1.ExecuteBatchDmlRequest; +import com.google.spanner.v1.ExecuteSqlRequest; +import io.grpc.Status; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AsyncRunnerTest extends AbstractAsyncTransactionTest { + @Test + public void asyncRunnerUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.executeUpdateAsync(UPDATE_STATEMENT); + } + }, + executor); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + } + + @Test + public void asyncRunnerIsNonBlocking() throws Exception { + mockSpanner.freeze(); + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.executeUpdateAsync(UPDATE_STATEMENT); + return ApiFutures.immediateFuture(null); + } + }, + executor); + ApiFuture ts = runner.getCommitTimestamp(); + mockSpanner.unfreeze(); + assertThat(res.get()).isNull(); + assertThat(ts.get()).isNotNull(); + } + + @Test + public void asyncRunnerInvalidUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.executeUpdateAsync(INVALID_UPDATE_STATEMENT); + } + }, + executor); + try { + updateCount.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid statement"); + } + } + + @Test + public void asyncRunnerFireAndForgetInvalidUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.executeUpdateAsync(INVALID_UPDATE_STATEMENT); + return txn.executeUpdateAsync(UPDATE_STATEMENT); + } + }, + executor); + assertThat(res.get()).isEqualTo(UPDATE_COUNT); + } + + @Test + public void asyncRunnerUpdateAborted() throws Exception { + try { + // Temporarily set the result of the update to 2 rows. + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT + 1L)); + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } else { + // Set the result of the update statement back to 1 row. + mockSpanner.putStatementResult( + StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + return txn.executeUpdateAsync(UPDATE_STATEMENT); + } + }, + executor); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + assertThat(attempt.get()).isEqualTo(2); + } finally { + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + } + + @Test + public void asyncRunnerCommitAborted() throws Exception { + try { + // Temporarily set the result of the update to 2 rows. + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT + 1L)); + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(final TransactionContext txn) { + if (attempt.get() > 0) { + // Set the result of the update statement back to 1 row. + mockSpanner.putStatementResult( + StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + ApiFuture updateCount = txn.executeUpdateAsync(UPDATE_STATEMENT); + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + return updateCount; + } + }, + executor); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + assertThat(attempt.get()).isEqualTo(2); + } finally { + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + } + + @Test + public void asyncRunnerUpdateAbortedWithoutGettingResult() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture result = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + // 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. + txn.executeUpdateAsync(UPDATE_STATEMENT); + // Resolving this future will not resolve the result of the entire transaction. The + // transaction result will be resolved when the commit has actually finished + // successfully. + return ApiFutures.immediateFuture(null); + } + }, + executor); + assertThat(result.get()).isNull(); + assertThat(attempt.get()).isEqualTo(2); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + CommitRequest.class, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncRunnerCommitFails() throws Exception { + mockSpanner.setCommitExecutionTime( + SimulatedExecutionTime.ofException( + Status.RESOURCE_EXHAUSTED + .withDescription("mutation limit exceeded") + .asRuntimeException())); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + // This statement will succeed, but the commit will fail. The error from the commit + // will bubble up to the future that is returned by the transaction, and the update + // count returned here will never reach the user application. + return txn.executeUpdateAsync(UPDATE_STATEMENT); + } + }, + executor); + try { + updateCount.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + assertThat(se.getMessage()).contains("mutation limit exceeded"); + } + } + + @Test + public void asyncRunnerWaitsUntilAsyncUpdateHasFinished() throws Exception { + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.executeUpdateAsync(UPDATE_STATEMENT); + return ApiFutures.immediateFuture(null); + } + }, + executor); + res.get(); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncRunnerBatchUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + } + }, + executor); + assertThat(updateCount.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + } + + @Test + public void asyncRunnerIsNonBlockingWithBatchUpdate() throws Exception { + mockSpanner.freeze(); + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT)); + return ApiFutures.immediateFuture(null); + } + }, + executor); + ApiFuture ts = runner.getCommitTimestamp(); + mockSpanner.unfreeze(); + assertThat(res.get()).isNull(); + assertThat(ts.get()).isNotNull(); + } + + @Test + public void asyncRunnerInvalidBatchUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.batchUpdateAsync( + ImmutableList.of(UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT)); + } + }, + executor); + try { + updateCount.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid statement"); + } + } + + @Test + public void asyncRunnerFireAndForgetInvalidBatchUpdate() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT)); + return txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + } + }, + executor); + assertThat(res.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + } + + @Test + public void asyncRunnerBatchUpdateAborted() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + if (attempt.incrementAndGet() == 1) { + return txn.batchUpdateAsync( + ImmutableList.of(UPDATE_STATEMENT, UPDATE_ABORTED_STATEMENT)); + } else { + return txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + } + } + }, + executor); + assertThat(updateCount.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + assertThat(attempt.get()).isEqualTo(2); + } + + @Test + public void asyncRunnerWithBatchUpdateCommitAborted() throws Exception { + try { + // Temporarily set the result of the update to 2 rows. + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT + 1L)); + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(final TransactionContext txn) { + if (attempt.get() > 0) { + // Set the result of the update statement back to 1 row. + mockSpanner.putStatementResult( + StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + ApiFuture updateCount = + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + return updateCount; + } + }, + executor); + assertThat(updateCount.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + assertThat(attempt.get()).isEqualTo(2); + } finally { + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + } + + @Test + public void asyncRunnerBatchUpdateAbortedWithoutGettingResult() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture result = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + // 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. + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + // Resolving this future will not resolve the result of the entire transaction. The + // transaction result will be resolved when the commit has actually finished + // successfully. + return ApiFutures.immediateFuture(null); + } + }, + executor); + assertThat(result.get()).isNull(); + assertThat(attempt.get()).isEqualTo(2); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncRunnerWithBatchUpdateCommitFails() throws Exception { + mockSpanner.setCommitExecutionTime( + SimulatedExecutionTime.ofException( + Status.RESOURCE_EXHAUSTED + .withDescription("mutation limit exceeded") + .asRuntimeException())); + AsyncRunner runner = client().runAsync(); + ApiFuture updateCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + // This statement will succeed, but the commit will fail. The error from the commit + // will bubble up to the future that is returned by the transaction, and the update + // count returned here will never reach the user application. + return txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + } + }, + executor); + try { + updateCount.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + assertThat(se.getMessage()).contains("mutation limit exceeded"); + } + } + + @Test + public void asyncRunnerWaitsUntilAsyncBatchUpdateHasFinished() throws Exception { + AsyncRunner runner = clientWithEmptySessionPool().runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT)); + return ApiFutures.immediateFuture(null); + } + }, + executor); + res.get(); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void closeTransactionBeforeEndOfAsyncQuery() throws Exception { + final BlockingQueue results = new SynchronousQueue<>(); + final SettableApiFuture finished = SettableApiFuture.create(); + DatabaseClientImpl clientImpl = (DatabaseClientImpl) client(); + + // There should currently not be any sessions checked out of the pool. + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(0); + + AsyncRunner runner = clientImpl.runAsync(); + final CountDownLatch dataReceived = new CountDownLatch(1); + final CountDownLatch dataChecked = new CountDownLatch(1); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + try (AsyncResultSet rs = + txn.readAsync( + READ_TABLE_NAME, KeySet.all(), READ_COLUMN_NAMES, Options.bufferRows(1))) { + rs.setCallback( + Executors.newSingleThreadExecutor(), + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + dataReceived.countDown(); + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + finished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + dataChecked.await(); + results.put(resultSet.getString(0)); + } + } + } catch (Throwable t) { + finished.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + try { + dataReceived.await(); + return ApiFutures.immediateFuture(null); + } catch (InterruptedException e) { + return ApiFutures.immediateFailedFuture( + SpannerExceptionFactory.propagateInterrupt(e)); + } + } + }, + executor); + // Wait until at least one row has been fetched. At that moment there should be one session + // checked out. + dataReceived.await(); + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(1); + assertThat(res.isDone()).isFalse(); + dataChecked.countDown(); + // Get the data from the transaction. + List resultList = new ArrayList<>(); + do { + results.drainTo(resultList); + } while (!finished.isDone() || results.size() > 0); + assertThat(finished.get()).isTrue(); + assertThat(resultList).containsExactly("k1", "k2", "k3"); + assertThat(res.get()).isNull(); + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(0); + } + + @Test + public void asyncRunnerReadRow() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture val = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return ApiFutures.transform( + txn.readRowAsync(READ_TABLE_NAME, Key.of(1L), READ_COLUMN_NAMES), + new ApiFunction() { + @Override + public String apply(Struct input) { + return input.getString("Value"); + } + }, + MoreExecutors.directExecutor()); + } + }, + executor); + assertThat(val.get()).isEqualTo("v1"); + } + + @Test + public void asyncRunnerRead() throws Exception { + AsyncRunner runner = client().runAsync(); + ApiFuture> val = + runner.runAsync( + new AsyncWork>() { + @Override + public ApiFuture> doWorkAsync(TransactionContext txn) { + return txn.readAsync(READ_TABLE_NAME, KeySet.all(), READ_COLUMN_NAMES) + .toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("Value"); + } + }, + MoreExecutors.directExecutor()); + } + }, + executor); + assertThat(val.get()).containsExactly("v1", "v2", "v3"); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java new file mode 100644 index 0000000000..e2299f3615 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java @@ -0,0 +1,1045 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.cloud.spanner.MockSpannerTestUtil.INVALID_UPDATE_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_COLUMN_NAMES; +import static com.google.cloud.spanner.MockSpannerTestUtil.READ_TABLE_NAME; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_ABORTED_STATEMENT; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_COUNT; +import static com.google.cloud.spanner.MockSpannerTestUtil.UPDATE_STATEMENT; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionFunction; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep; +import com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture; +import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture; +import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; +import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import com.google.cloud.spanner.Options.ReadOption; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Range; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.AbstractMessage; +import com.google.spanner.v1.BatchCreateSessionsRequest; +import com.google.spanner.v1.BeginTransactionRequest; +import com.google.spanner.v1.CommitRequest; +import com.google.spanner.v1.ExecuteBatchDmlRequest; +import com.google.spanner.v1.ExecuteSqlRequest; +import io.grpc.Status; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class AsyncTransactionManagerTest extends AbstractAsyncTransactionTest { + + @Parameter public Executor executor; + + @Parameters(name = "executor = {0}") + public static Collection data() { + return Arrays.asList( + new Object[][] { + {MoreExecutors.directExecutor()}, + {Executors.newSingleThreadExecutor()}, + {Executors.newFixedThreadPool(4)} + }); + } + + /** + * Static helper methods that simplifies creating {@link AsyncTransactionFunction}s for Java7. + * Java8 and higher can use lambda expressions. + */ + public static class AsyncTransactionManagerHelper { + + public static AsyncTransactionFunction readAsync( + final String table, + final KeySet keys, + final Iterable columns, + final ReadOption... options) { + return new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, I input) throws Exception { + return ApiFutures.immediateFuture(txn.readAsync(table, keys, columns, options)); + } + }; + } + + public static AsyncTransactionFunction readRowAsync( + final String table, final Key key, final Iterable columns) { + return new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, I input) throws Exception { + return txn.readRowAsync(table, key, columns); + } + }; + } + + public static AsyncTransactionFunction buffer(Mutation mutation) { + return buffer(ImmutableList.of(mutation)); + } + + public static AsyncTransactionFunction buffer(final Iterable mutations) { + return new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, I input) throws Exception { + txn.buffer(mutations); + return ApiFutures.immediateFuture(null); + } + }; + } + + public static AsyncTransactionFunction executeUpdateAsync(Statement statement) { + return executeUpdateAsync(SettableApiFuture.create(), statement); + } + + public static AsyncTransactionFunction executeUpdateAsync( + final SettableApiFuture result, final Statement statement) { + return new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, I input) throws Exception { + ApiFuture updateCount = txn.executeUpdateAsync(statement); + ApiFutures.addCallback( + updateCount, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + result.setException(t); + } + + @Override + public void onSuccess(Long input) { + result.set(input); + } + }, + MoreExecutors.directExecutor()); + return updateCount; + } + }; + } + + public static AsyncTransactionFunction batchUpdateAsync( + final Statement... statements) { + return batchUpdateAsync(SettableApiFuture.create(), statements); + } + + public static AsyncTransactionFunction batchUpdateAsync( + final SettableApiFuture result, final Statement... statements) { + return new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, I input) throws Exception { + ApiFuture updateCounts = txn.batchUpdateAsync(Arrays.asList(statements)); + ApiFutures.addCallback( + updateCounts, + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + result.setException(t); + } + + @Override + public void onSuccess(long[] input) { + result.set(input); + } + }, + MoreExecutors.directExecutor()); + return updateCounts; + } + }; + } + } + + @Test + public void asyncTransactionManagerUpdate() throws Exception { + final SettableApiFuture updateCount = SettableApiFuture.create(); + + try (AsyncTransactionManager manager = client().transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + try { + CommitTimestampFuture commitTimestamp = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync( + updateCount, UPDATE_STATEMENT), + executor) + .commitAsync(); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + assertThat(commitTimestamp.get()).isNotNull(); + break; + } catch (AbortedException e) { + txn = manager.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerIsNonBlocking() throws Exception { + SettableApiFuture updateCount = SettableApiFuture.create(); + + mockSpanner.freeze(); + try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + try { + CommitTimestampFuture commitTimestamp = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync( + updateCount, UPDATE_STATEMENT), + executor) + .commitAsync(); + mockSpanner.unfreeze(); + assertThat(updateCount.get(10L, TimeUnit.SECONDS)).isEqualTo(UPDATE_COUNT); + assertThat(commitTimestamp.get(10L, TimeUnit.SECONDS)).isNotNull(); + break; + } catch (AbortedException e) { + txn = manager.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerInvalidUpdate() throws Exception { + try (AsyncTransactionManager manager = client().transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + try { + CommitTimestampFuture commitTimestamp = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync( + INVALID_UPDATE_STATEMENT), + executor) + .commitAsync(); + commitTimestamp.get(); + fail("missing expected exception"); + } catch (AbortedException e) { + txn = manager.resetForRetryAsync(); + } catch (ExecutionException e) { + manager.rollbackAsync(); + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid statement"); + break; + } + } + } + } + + @Test + public void asyncTransactionManagerCommitAborted() throws Exception { + SettableApiFuture updateCount = SettableApiFuture.create(); + final AtomicInteger attempt = new AtomicInteger(); + try (AsyncTransactionManager manager = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + try { + attempt.incrementAndGet(); + CommitTimestampFuture commitTimestamp = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync( + updateCount, UPDATE_STATEMENT), + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Long input) + throws Exception { + if (attempt.get() == 1) { + mockSpanner.abortTransaction(txn); + } + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync(); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + assertThat(commitTimestamp.get()).isNotNull(); + assertThat(attempt.get()).isEqualTo(2); + break; + } catch (AbortedException e) { + txn = manager.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerFireAndForgetInvalidUpdate() throws Exception { + final SettableApiFuture updateCount = SettableApiFuture.create(); + + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + // This fire-and-forget update statement should not fail the transaction. + txn.executeUpdateAsync(INVALID_UPDATE_STATEMENT); + ApiFutures.addCallback( + txn.executeUpdateAsync(UPDATE_STATEMENT), + new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + updateCount.setException(t); + } + + @Override + public void onSuccess(Long result) { + updateCount.set(result); + } + }, + MoreExecutors.directExecutor()); + return updateCount; + } + }, + executor) + .commitAsync(); + assertThat(updateCount.get()).isEqualTo(UPDATE_COUNT); + assertThat(ts.get()).isNotNull(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerChain() throws Exception { + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync(UPDATE_STATEMENT), + executor) + .then( + AsyncTransactionManagerHelper.readRowAsync( + READ_TABLE_NAME, Key.of(1L), READ_COLUMN_NAMES), + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Struct input) + throws Exception { + return ApiFutures.immediateFuture(input.getString("Value")); + } + }, + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, String input) + throws Exception { + assertThat(input).isEqualTo("v1"); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync(); + assertThat(ts.get()).isNotNull(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerChainWithErrorInTheMiddle() throws Exception { + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync( + INVALID_UPDATE_STATEMENT), + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Long input) + throws Exception { + throw new IllegalStateException("this should not be executed"); + } + }, + executor) + .commitAsync(); + ts.get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } catch (ExecutionException e) { + mgr.rollbackAsync(); + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + break; + } + } + } + } + + @Test + public void asyncTransactionManagerUpdateAborted() throws Exception { + try (AsyncTransactionManager mgr = client().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 = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + if (attempt.incrementAndGet() == 1) { + // Abort the first attempt. + mockSpanner.abortTransaction(txn); + } else { + // Set the result of the update statement back to 1 row. + mockSpanner.putStatementResult( + StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + return ApiFutures.immediateFuture(null); + } + }, + executor) + .then( + AsyncTransactionManagerHelper.executeUpdateAsync(UPDATE_STATEMENT), + executor) + .commitAsync(); + assertThat(ts.get()).isNotNull(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + assertThat(attempt.get()).isEqualTo(2); + } finally { + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + } + + @Test + public void asyncTransactionManagerUpdateAbortedWithoutGettingResult() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + // 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. + txn.executeUpdateAsync(UPDATE_STATEMENT); + // Resolving this future will not resolve the result of the entire + // transaction. The transaction result will be resolved when the commit + // has actually finished successfully. + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync(); + assertThat(ts.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, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + CommitRequest.class); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerCommitFails() throws Exception { + mockSpanner.setCommitExecutionTime( + SimulatedExecutionTime.ofException( + Status.RESOURCE_EXHAUSTED + .withDescription("mutation limit exceeded") + .asRuntimeException())); + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + AsyncTransactionManagerHelper.executeUpdateAsync(UPDATE_STATEMENT), + executor) + .commitAsync() + .get(); + fail("missing expected exception"); + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + assertThat(se.getMessage()).contains("mutation limit exceeded"); + break; + } + } + } + } + + @Test + public void asyncTransactionManagerWaitsUntilAsyncUpdateHasFinished() throws Exception { + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + // Shoot-and-forget update. The commit will still wait for this request to + // finish. + txn.executeUpdateAsync(UPDATE_STATEMENT); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync() + .get(); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteSqlRequest.class, + CommitRequest.class); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerBatchUpdate() throws Exception { + final SettableApiFuture result = SettableApiFuture.create(); + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + AsyncTransactionManagerHelper.batchUpdateAsync( + result, UPDATE_STATEMENT, UPDATE_STATEMENT), + executor) + .commitAsync() + .get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(result.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + } + + @Test + public void asyncTransactionManagerIsNonBlockingWithBatchUpdate() throws Exception { + SettableApiFuture res = SettableApiFuture.create(); + mockSpanner.freeze(); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + CommitTimestampFuture ts = + txn.then( + AsyncTransactionManagerHelper.batchUpdateAsync(res, UPDATE_STATEMENT), + executor) + .commitAsync(); + mockSpanner.unfreeze(); + assertThat(ts.get()).isNotNull(); + assertThat(res.get()).asList().containsExactly(UPDATE_COUNT); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + } + + @Test + public void asyncTransactionManagerInvalidBatchUpdate() throws Exception { + SettableApiFuture result = SettableApiFuture.create(); + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + AsyncTransactionManagerHelper.batchUpdateAsync( + result, UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT), + executor) + .commitAsync() + .get(); + fail("missing expected exception"); + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(se.getMessage()).contains("invalid statement"); + break; + } + } + } + } + + @Test + public void asyncTransactionManagerFireAndForgetInvalidBatchUpdate() throws Exception { + SettableApiFuture result = SettableApiFuture.create(); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + txn.batchUpdateAsync( + ImmutableList.of(UPDATE_STATEMENT, INVALID_UPDATE_STATEMENT)); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .then( + AsyncTransactionManagerHelper.batchUpdateAsync( + result, UPDATE_STATEMENT, UPDATE_STATEMENT), + executor) + .commitAsync() + .get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(result.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncTransactionManagerBatchUpdateAborted() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + if (attempt.incrementAndGet() == 1) { + return txn.batchUpdateAsync( + ImmutableList.of(UPDATE_STATEMENT, UPDATE_ABORTED_STATEMENT)); + } else { + return txn.batchUpdateAsync( + ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + } + } + }, + executor) + .commitAsync() + .get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(attempt.get()).isEqualTo(2); + // There should only be 1 CommitRequest, as the first attempt should abort already after the + // ExecuteBatchDmlRequest. + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncTransactionManagerWithBatchUpdateCommitAborted() throws Exception { + try (AsyncTransactionManager mgr = 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 = mgr.beginAsync(); + while (true) { + final SettableApiFuture result = SettableApiFuture.create(); + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + 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.immediateFuture(null); + } + }, + executor) + .then( + AsyncTransactionManagerHelper.batchUpdateAsync( + result, UPDATE_STATEMENT, UPDATE_STATEMENT), + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, long[] input) + throws Exception { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync() + .get(); + assertThat(result.get()).asList().containsExactly(UPDATE_COUNT, UPDATE_COUNT); + assertThat(attempt.get()).isEqualTo(2); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } finally { + mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); + } + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncTransactionManagerBatchUpdateAbortedWithoutGettingResult() throws Exception { + final AtomicInteger attempt = new AtomicInteger(); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + if (attempt.incrementAndGet() == 1) { + mockSpanner.abortTransaction(txn); + } + // 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. + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT, UPDATE_STATEMENT)); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync() + .get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(attempt.get()).isEqualTo(2); + Iterable> requests = mockSpanner.getRequestTypes(); + int size = Iterables.size(requests); + assertThat(size).isIn(Range.closed(6, 7)); + if (size == 6) { + assertThat(requests) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } else { + assertThat(requests) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + } + + @Test + public void asyncTransactionManagerWithBatchUpdateCommitFails() throws Exception { + mockSpanner.setCommitExecutionTime( + SimulatedExecutionTime.ofException( + Status.RESOURCE_EXHAUSTED + .withDescription("mutation limit exceeded") + .asRuntimeException())); + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + AsyncTransactionManagerHelper.batchUpdateAsync( + UPDATE_STATEMENT, UPDATE_STATEMENT), + executor) + .commitAsync() + .get(); + fail("missing expected exception"); + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.RESOURCE_EXHAUSTED); + assertThat(se.getMessage()).contains("mutation limit exceeded"); + break; + } + } + } + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncTransactionManagerWaitsUntilAsyncBatchUpdateHasFinished() throws Exception { + try (AsyncTransactionManager mgr = clientWithEmptySessionPool().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + txn.batchUpdateAsync(ImmutableList.of(UPDATE_STATEMENT)); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync() + .get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(mockSpanner.getRequestTypes()) + .containsExactly( + BatchCreateSessionsRequest.class, + BeginTransactionRequest.class, + ExecuteBatchDmlRequest.class, + CommitRequest.class); + } + + @Test + public void asyncTransactionManagerReadRow() throws Exception { + ApiFuture val; + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + AsyncTransactionStep step; + val = + step = + txn.then( + AsyncTransactionManagerHelper.readRowAsync( + READ_TABLE_NAME, Key.of(1L), READ_COLUMN_NAMES), + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Struct input) + throws Exception { + return ApiFutures.immediateFuture(input.getString("Value")); + } + }, + executor); + step.commitAsync().get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(val.get()).isEqualTo("v1"); + } + + @Test + public void asyncTransactionManagerRead() throws Exception { + AsyncTransactionStep> res; + try (AsyncTransactionManager mgr = client().transactionManagerAsync()) { + TransactionContextFuture txn = mgr.beginAsync(); + while (true) { + try { + res = + txn.then( + new AsyncTransactionFunction>() { + @Override + public ApiFuture> apply( + TransactionContext txn, Void input) throws Exception { + return txn.readAsync(READ_TABLE_NAME, KeySet.all(), READ_COLUMN_NAMES) + .toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("Value"); + } + }, + MoreExecutors.directExecutor()); + } + }, + executor); + // Commit the transaction. + res.commitAsync().get(); + break; + } catch (AbortedException e) { + txn = mgr.resetForRetryAsync(); + } + } + } + assertThat(res.get()).containsExactly("v1", "v2", "v3"); + } + + @Test + public void asyncTransactionManagerQuery() throws Exception { + mockSpanner.putStatementResult( + StatementResult.query( + Statement.of("SELECT FirstName FROM Singers WHERE ID=1"), + MockSpannerTestUtil.READ_FIRST_NAME_SINGERS_RESULTSET)); + final long singerId = 1L; + try (AsyncTransactionManager manager = client().transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + final String column = "FirstName"; + CommitTimestampFuture commitTimestamp = + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + return txn.readRowAsync( + "Singers", Key.of(singerId), Collections.singleton(column)); + } + }, + executor) + .then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Struct input) + throws Exception { + String name = input.getString(column); + txn.buffer( + Mutation.newUpdateBuilder("Singers") + .set(column) + .to(name.toUpperCase()) + .build()); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync(); + try { + commitTimestamp.get(); + break; + } catch (AbortedException e) { + Thread.sleep(e.getRetryDelayInMillis() / 1000); + txn = manager.resetForRetryAsync(); + } + } + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BaseSessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BaseSessionPoolTest.java index 26bbef4535..1bcb303f72 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BaseSessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BaseSessionPoolTest.java @@ -59,7 +59,7 @@ public void release(ScheduledExecutorService executor) { } SessionImpl mockSession() { - SessionImpl session = mock(SessionImpl.class); + final SessionImpl session = mock(SessionImpl.class); when(session.getName()) .thenReturn( "projects/dummy/instances/dummy/database/dummy/sessions/session" + sessionIndex); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index 4f98f59104..3a41a46961 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -16,35 +16,42 @@ package com.google.cloud.spanner; +import static com.google.cloud.spanner.MockSpannerTestUtil.SELECT1; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; import com.google.api.gax.grpc.testing.LocalChannelProvider; import com.google.api.gax.retrying.RetrySettings; import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.AsyncRunner.AsyncWork; import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode; import com.google.cloud.spanner.TransactionRunner.TransactionCallable; import com.google.common.base.Stopwatch; +import com.google.common.util.concurrent.SettableFuture; import com.google.protobuf.AbstractMessage; -import com.google.protobuf.ListValue; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryMode; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; -import com.google.spanner.v1.ResultSetMetadata; -import com.google.spanner.v1.StructType; -import com.google.spanner.v1.StructType.Field; -import com.google.spanner.v1.TypeCode; import io.grpc.Server; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.inprocess.InProcessServerBuilder; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -72,37 +79,17 @@ public class DatabaseClientImplTest { private static final Statement INVALID_UPDATE_STATEMENT = Statement.of("UPDATE NON_EXISTENT_TABLE SET BAR=1 WHERE BAZ=2"); private static final long UPDATE_COUNT = 1L; - private static final Statement SELECT1 = Statement.of("SELECT 1 AS COL1"); - private static final ResultSetMetadata SELECT1_METADATA = - ResultSetMetadata.newBuilder() - .setRowType( - StructType.newBuilder() - .addFields( - Field.newBuilder() - .setName("COL1") - .setType( - com.google.spanner.v1.Type.newBuilder() - .setCode(TypeCode.INT64) - .build()) - .build()) - .build()) - .build(); - private static final com.google.spanner.v1.ResultSet SELECT1_RESULTSET = - com.google.spanner.v1.ResultSet.newBuilder() - .addRows( - ListValue.newBuilder() - .addValues(com.google.protobuf.Value.newBuilder().setStringValue("1").build()) - .build()) - .setMetadata(SELECT1_METADATA) - .build(); private Spanner spanner; + private Spanner spannerWithEmptySessionPool; + private static final ExecutorService executor = Executors.newSingleThreadExecutor(); @BeforeClass public static void startStaticServer() throws IOException { mockSpanner = new MockSpannerServiceImpl(); mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions. mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT)); - mockSpanner.putStatementResult(StatementResult.query(SELECT1, SELECT1_RESULTSET)); + mockSpanner.putStatementResult( + StatementResult.query(SELECT1, MockSpannerTestUtil.SELECT1_RESULTSET)); mockSpanner.putStatementResult( StatementResult.exception( INVALID_UPDATE_STATEMENT, @@ -123,6 +110,7 @@ public static void startStaticServer() throws IOException { public static void stopServer() throws InterruptedException { server.shutdown(); server.awaitTermination(); + executor.shutdown(); } @Before @@ -132,17 +120,473 @@ public void setUp() { .setProjectId(TEST_PROJECT) .setChannelProvider(channelProvider) .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption(SessionPoolOptions.newBuilder().setFailOnSessionLeak().build()) + .build() + .getService(); + spannerWithEmptySessionPool = + spanner + .getOptions() + .toBuilder() + .setSessionPoolOption( + SessionPoolOptions.newBuilder().setMinSessions(0).setFailOnSessionLeak().build()) .build() .getService(); } @After public void tearDown() { + mockSpanner.unfreeze(); spanner.close(); + spannerWithEmptySessionPool.close(); mockSpanner.reset(); mockSpanner.removeAllExecutionTimes(); } + @Test + public void write() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + client.write( + Arrays.asList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build())); + } + + @Test + public void writeAtLeastOnce() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + client.writeAtLeastOnce( + Arrays.asList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build())); + } + + @Test + public void singleUse() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = client.singleUse().executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseIsNonBlocking() { + mockSpanner.freeze(); + // Use a Spanner instance with no initial sessions in the pool to show that getting a session + // from the pool and then preparing a query is non-blocking (i.e. does not wait on a reply from + // the server). + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = client.singleUse().executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseAsync() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + final AtomicInteger rowCount = new AtomicInteger(); + ApiFuture res; + try (AsyncResultSet rs = client.singleUse().executeQueryAsync(SELECT1)) { + res = + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + while (true) { + switch (resultSet.tryNext()) { + case OK: + rowCount.incrementAndGet(); + break; + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + } + } + } + }); + } + res.get(); + assertThat(rowCount.get()).isEqualTo(1); + } + + @Test + public void singleUseBound() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = + client + .singleUse(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS)) + .executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseBoundIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = + client + .singleUse(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS)) + .executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseBoundAsync() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + final AtomicInteger rowCount = new AtomicInteger(); + ApiFuture res; + try (AsyncResultSet rs = + client + .singleUse(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS)) + .executeQueryAsync(SELECT1)) { + res = + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + while (true) { + switch (resultSet.tryNext()) { + case OK: + rowCount.incrementAndGet(); + break; + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + } + } + } + }); + } + res.get(); + assertThat(rowCount.get()).isEqualTo(1); + } + + @Test + public void singleUseTransaction() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = client.singleUseReadOnlyTransaction().executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseTransactionIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = client.singleUseReadOnlyTransaction().executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseTransactionBound() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = + client + .singleUseReadOnlyTransaction(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS)) + .executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void singleUseTransactionBoundIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ResultSet rs = + client + .singleUseReadOnlyTransaction(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS)) + .executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + + @Test + public void readOnlyTransaction() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (ResultSet rs = tx.executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + } + + @Test + public void readOnlyTransactionIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (ResultSet rs = tx.executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + } + + @Test + public void readOnlyTransactionBound() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ReadOnlyTransaction tx = + client.readOnlyTransaction(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS))) { + try (ResultSet rs = tx.executeQuery(SELECT1)) { + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + } + + @Test + public void readOnlyTransactionBoundIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (ReadOnlyTransaction tx = + client.readOnlyTransaction(TimestampBound.ofExactStaleness(15L, TimeUnit.SECONDS))) { + try (ResultSet rs = tx.executeQuery(SELECT1)) { + mockSpanner.unfreeze(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getLong(0)).isEqualTo(1L); + assertThat(rs.next()).isFalse(); + } + } + } + + @Test + public void readWriteTransaction() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + runner.run( + new TransactionCallable() { + @Override + public Void run(TransactionContext transaction) throws Exception { + transaction.executeUpdate(UPDATE_STATEMENT); + return null; + } + }); + } + + @Test + public void readWriteTransactionIsNonBlocking() { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + // The runner.run(...) method cannot be made non-blocking, as it returns the result of the + // transaction. + mockSpanner.unfreeze(); + runner.run( + new TransactionCallable() { + @Override + public Void run(TransactionContext transaction) throws Exception { + transaction.executeUpdate(UPDATE_STATEMENT); + return null; + } + }); + } + + @Test + public void runAsync() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + AsyncRunner runner = client.runAsync(); + ApiFuture fut = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return ApiFutures.immediateFuture(txn.executeUpdate(UPDATE_STATEMENT)); + } + }, + executor); + assertThat(fut.get()).isEqualTo(UPDATE_COUNT); + executor.shutdown(); + } + + @Test + public void runAsyncIsNonBlocking() throws Exception { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + AsyncRunner runner = client.runAsync(); + ApiFuture fut = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return ApiFutures.immediateFuture(txn.executeUpdate(UPDATE_STATEMENT)); + } + }, + executor); + mockSpanner.unfreeze(); + assertThat(fut.get()).isEqualTo(UPDATE_COUNT); + executor.shutdown(); + } + + @Test + public void runAsyncWithException() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + AsyncRunner runner = client.runAsync(); + ApiFuture fut = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return ApiFutures.immediateFuture(txn.executeUpdate(INVALID_UPDATE_STATEMENT)); + } + }, + executor); + try { + fut.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + } + executor.shutdown(); + } + + @Test + public void transactionManager() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (TransactionManager txManager = client.transactionManager()) { + while (true) { + TransactionContext tx = txManager.begin(); + try { + tx.executeUpdate(UPDATE_STATEMENT); + txManager.commit(); + break; + } catch (AbortedException e) { + Thread.sleep(e.getRetryDelayInMillis() / 1000); + tx = txManager.resetForRetry(); + } + } + } + } + + @Test + public void transactionManagerIsNonBlocking() throws Exception { + mockSpanner.freeze(); + DatabaseClient client = + spannerWithEmptySessionPool.getDatabaseClient( + DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (TransactionManager txManager = client.transactionManager()) { + while (true) { + mockSpanner.unfreeze(); + TransactionContext tx = txManager.begin(); + try { + tx.executeUpdate(UPDATE_STATEMENT); + txManager.commit(); + break; + } catch (AbortedException e) { + Thread.sleep(e.getRetryDelayInMillis() / 1000); + tx = txManager.resetForRetry(); + } + } + } + } + + @Test + public void transactionManagerExecuteQueryAsync() throws Exception { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + final AtomicInteger rowCount = new AtomicInteger(); + try (TransactionManager txManager = client.transactionManager()) { + while (true) { + TransactionContext tx = txManager.begin(); + try { + try (AsyncResultSet rs = tx.executeQueryAsync(SELECT1)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case OK: + rowCount.incrementAndGet(); + break; + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + } + } + } catch (Throwable t) { + return CallbackResponse.DONE; + } + } + }); + } + txManager.commit(); + break; + } catch (AbortedException e) { + Thread.sleep(e.getRetryDelayInMillis() / 1000); + tx = txManager.resetForRetry(); + } + } + } + assertThat(rowCount.get()).isEqualTo(1); + } + /** * Test that the update statement can be executed as a partitioned transaction that returns a * lower bound update count. @@ -470,6 +914,7 @@ public void testDatabaseOrInstanceDoesNotExistOnCreate() { DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); // The create session failure should propagate to the client and not retry. try (ResultSet rs = dbClient.singleUse().executeQuery(SELECT1)) { + rs.next(); fail("missing expected exception"); } catch (DatabaseNotFoundException | InstanceNotFoundException e) { // The server should only receive one BatchCreateSessions request. @@ -933,6 +1378,54 @@ public void testBackendPartitionQueryOptions() { } } + @Test + public void testAsyncQuery() throws Exception { + final int EXPECTED_ROW_COUNT = 10; + RandomResultSetGenerator generator = new RandomResultSetGenerator(EXPECTED_ROW_COUNT); + com.google.spanner.v1.ResultSet resultSet = generator.generate(); + mockSpanner.putStatementResult( + StatementResult.query(Statement.of("SELECT * FROM RANDOM"), resultSet)); + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + ApiFuture resultSetClosed; + final SettableFuture finished = SettableFuture.create(); + final List receivedResults = new ArrayList<>(); + try (AsyncResultSet rs = + client.singleUse().executeQueryAsync(Statement.of("SELECT * FROM RANDOM"))) { + resultSetClosed = + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (rs.tryNext()) { + case DONE: + finished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + receivedResults.add(resultSet.getCurrentRowAsStruct()); + break; + default: + throw new IllegalStateException("Unknown cursor state"); + } + } + } catch (Throwable t) { + finished.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + assertThat(finished.get()).isTrue(); + assertThat(receivedResults.size()).isEqualTo(EXPECTED_ROW_COUNT); + resultSetClosed.get(); + } + @Test public void testClientIdReusedOnDatabaseNotFound() { mockSpanner.setBatchCreateSessionsExecutionTime( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java index 6b22ba77c3..edbc7976c0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestWithClosedSessionsEnv.java @@ -17,6 +17,7 @@ package com.google.cloud.spanner; import com.google.cloud.spanner.SessionPool.PooledSession; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; import com.google.cloud.spanner.testing.RemoteSpannerHelper; /** @@ -73,30 +74,30 @@ public void setAllowSessionReplacing(boolean allow) { } @Override - PooledSession getReadSession() { - PooledSession session = super.getReadSession(); + PooledSessionFuture getReadSession() { + PooledSessionFuture session = super.getReadSession(); if (invalidateNextSession) { - session.delegate.close(); - session.setAllowReplacing(false); - awaitDeleted(session.delegate); - session.setAllowReplacing(allowReplacing); + session.get().delegate.close(); + session.get().setAllowReplacing(false); + awaitDeleted(session.get().delegate); + session.get().setAllowReplacing(allowReplacing); invalidateNextSession = false; } - session.setAllowReplacing(allowReplacing); + session.get().setAllowReplacing(allowReplacing); return session; } @Override - PooledSession getReadWriteSession() { - PooledSession session = super.getReadWriteSession(); + PooledSessionFuture getReadWriteSession() { + PooledSessionFuture session = super.getReadWriteSession(); if (invalidateNextSession) { - session.delegate.close(); - session.setAllowReplacing(false); - awaitDeleted(session.delegate); - session.setAllowReplacing(allowReplacing); + session.get().delegate.close(); + session.get().setAllowReplacing(false); + awaitDeleted(session.get().delegate); + session.get().setAllowReplacing(allowReplacing); invalidateNextSession = false; } - session.setAllowReplacing(allowReplacing); + session.get().setAllowReplacing(allowReplacing); return session; } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java index 832dccb14c..25e162039b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockDatabaseAdminServiceImpl.java @@ -79,8 +79,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.CountDownLatch; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -434,7 +433,7 @@ private com.google.rpc.Status fromException(Exception e) { private static final String EXPIRE_TIME_MASK = "expire_time"; private static final Random RND = new Random(); private final Queue exceptions = new ConcurrentLinkedQueue<>(); - private final ReadWriteLock freezeLock = new ReentrantReadWriteLock(); + private volatile CountDownLatch freezeLock = new CountDownLatch(0); private final ConcurrentMap databases = new ConcurrentHashMap<>(); private final ConcurrentMap backups = new ConcurrentHashMap<>(); private final ConcurrentMap> filterMatches = new ConcurrentHashMap<>(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java index 164a8842c7..cae41510fc 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java @@ -19,9 +19,11 @@ import com.google.api.gax.grpc.testing.MockGrpcService; import com.google.cloud.ByteArray; import com.google.cloud.Date; +import com.google.cloud.spanner.AbstractResultSet.GrpcStruct; import com.google.cloud.spanner.TransactionRunnerImpl.TransactionContextImpl; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; import com.google.common.base.Throwables; import com.google.common.util.concurrent.Uninterruptibles; import com.google.protobuf.AbstractMessage; @@ -79,6 +81,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -88,14 +91,15 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import org.threeten.bp.Instant; /** @@ -232,7 +236,7 @@ private enum StatementResultType { private final StatementResultType type; private final Statement statement; private final Long updateCount; - private final ResultSet resultSet; + private final Deque resultSets; private final StatusRuntimeException exception; /** Creates a {@link StatementResult} for a query that returns a {@link ResultSet}. */ @@ -240,6 +244,15 @@ public static StatementResult query(Statement statement, ResultSet resultSet) { return new StatementResult(statement, resultSet); } + /** + * Creates a {@link StatementResult} for a query that returns a {@link ResultSet} the first + * time, and a different {@link ResultSet} for all subsequent calls. + */ + public static StatementResult queryAndThen( + Statement statement, ResultSet resultSet, ResultSet next) { + return new StatementResult(statement, resultSet); + } + /** Creates a {@link StatementResult} for a read request. */ public static StatementResult read( String table, KeySet keySet, Iterable columns, ResultSet resultSet) { @@ -256,6 +269,25 @@ public static StatementResult exception(Statement statement, StatusRuntimeExcept return new StatementResult(statement, exception); } + private static class KeepLastElementDeque extends LinkedList { + private static KeepLastElementDeque singleton(E item) { + return new KeepLastElementDeque(Collections.singleton(item)); + } + + private static KeepLastElementDeque of(E first, E second) { + return new KeepLastElementDeque(Arrays.asList(first, second)); + } + + private KeepLastElementDeque(Collection coll) { + super(coll); + } + + @Override + public E pop() { + return this.size() == 1 ? super.peek() : super.pop(); + } + } + /** * Creates a {@link Statement} for a read statement. This {@link Statement} can be used to mock * a result for a read request. @@ -275,6 +307,7 @@ public static Statement createReadStatement( builder.append(", "); } builder.append(col); + first = false; } builder.append(" FROM ").append(table); if (keySet.isAll()) { @@ -302,14 +335,24 @@ private static boolean isValidKeySet(KeySet keySet) { private StatementResult(Statement statement, Long updateCount) { this.statement = Preconditions.checkNotNull(statement); this.updateCount = Preconditions.checkNotNull(updateCount); - this.resultSet = null; + this.resultSets = null; this.exception = null; this.type = StatementResultType.UPDATE_COUNT; } private StatementResult(Statement statement, ResultSet resultSet) { this.statement = Preconditions.checkNotNull(statement); - this.resultSet = Preconditions.checkNotNull(resultSet); + this.resultSets = KeepLastElementDeque.singleton(Preconditions.checkNotNull(resultSet)); + this.updateCount = null; + this.exception = null; + this.type = StatementResultType.RESULT_SET; + } + + private StatementResult(Statement statement, ResultSet resultSet, ResultSet andThen) { + this.statement = Preconditions.checkNotNull(statement); + this.resultSets = + KeepLastElementDeque.of( + Preconditions.checkNotNull(resultSet), Preconditions.checkNotNull(andThen)); this.updateCount = null; this.exception = null; this.type = StatementResultType.RESULT_SET; @@ -318,7 +361,7 @@ private StatementResult(Statement statement, ResultSet resultSet) { private StatementResult( String table, KeySet keySet, Iterable columns, ResultSet resultSet) { this.statement = createReadStatement(table, keySet, columns); - this.resultSet = Preconditions.checkNotNull(resultSet); + this.resultSets = KeepLastElementDeque.singleton(Preconditions.checkNotNull(resultSet)); this.updateCount = null; this.exception = null; this.type = StatementResultType.RESULT_SET; @@ -327,7 +370,7 @@ private StatementResult( private StatementResult(Statement statement, StatusRuntimeException exception) { this.statement = Preconditions.checkNotNull(statement); this.exception = Preconditions.checkNotNull(exception); - this.resultSet = null; + this.resultSets = null; this.updateCount = null; this.type = StatementResultType.EXCEPTION; } @@ -340,7 +383,7 @@ private ResultSet getResultSet() { Preconditions.checkState( type == StatementResultType.RESULT_SET, "This statement result does not contain a result set"); - return resultSet; + return resultSets.pop(); } private Long getUpdateCount() { @@ -394,6 +437,11 @@ public static SimulatedExecutionTime ofStickyException(Exception exception) { return new SimulatedExecutionTime(0, 0, Arrays.asList(exception), true); } + public static SimulatedExecutionTime stickyDatabaseNotFoundException(String name) { + return ofStickyException( + SpannerExceptionFactoryTest.newStatusDatabaseNotFoundException(name)); + } + public static SimulatedExecutionTime ofExceptions(Collection exceptions) { return new SimulatedExecutionTime(0, 0, exceptions, false); } @@ -421,19 +469,15 @@ private SimulatedExecutionTime( void simulateExecutionTime( Queue globalExceptions, boolean stickyGlobalExceptions, - ReadWriteLock freezeLock) { - try { - freezeLock.readLock().lock(); - checkException(globalExceptions, stickyGlobalExceptions); - checkException(this.exceptions, stickyException); - if (minimumExecutionTime > 0 || randomExecutionTime > 0) { - Uninterruptibles.sleepUninterruptibly( - (randomExecutionTime == 0 ? 0 : RANDOM.nextInt(randomExecutionTime)) - + minimumExecutionTime, - TimeUnit.MILLISECONDS); - } - } finally { - freezeLock.readLock().unlock(); + CountDownLatch freezeLock) { + Uninterruptibles.awaitUninterruptibly(freezeLock); + checkException(globalExceptions, stickyGlobalExceptions); + checkException(this.exceptions, stickyException); + if (minimumExecutionTime > 0 || randomExecutionTime > 0) { + Uninterruptibles.sleepUninterruptibly( + (randomExecutionTime == 0 ? 0 : RANDOM.nextInt(randomExecutionTime)) + + minimumExecutionTime, + TimeUnit.MILLISECONDS); } } @@ -451,22 +495,23 @@ private static void checkException(Queue exceptions, boolean keepExce private final Random random = new Random(); private double abortProbability = 0.0010D; - private final Queue requests = new ConcurrentLinkedQueue<>(); - private final ReadWriteLock freezeLock = new ReentrantReadWriteLock(); - private final Queue exceptions = new ConcurrentLinkedQueue<>(); + private final Object lock = new Object(); + private Deque requests = new ConcurrentLinkedDeque<>(); + private volatile CountDownLatch freezeLock = new CountDownLatch(0); + private Queue exceptions = new ConcurrentLinkedQueue<>(); private boolean stickyGlobalExceptions = false; - private final ConcurrentMap statementResults = - new ConcurrentHashMap<>(); - private final ConcurrentMap sessions = new ConcurrentHashMap<>(); + private ConcurrentMap statementResults = new ConcurrentHashMap<>(); + private ConcurrentMap statementGetCounts = new ConcurrentHashMap<>(); + private ConcurrentMap sessions = new ConcurrentHashMap<>(); private ConcurrentMap sessionLastUsed = new ConcurrentHashMap<>(); - private final ConcurrentMap transactions = new ConcurrentHashMap<>(); - private final ConcurrentMap isPartitionedDmlTransaction = + private ConcurrentMap transactions = new ConcurrentHashMap<>(); + private ConcurrentMap isPartitionedDmlTransaction = new ConcurrentHashMap<>(); - private final ConcurrentMap abortedTransactions = new ConcurrentHashMap<>(); + private ConcurrentMap abortedTransactions = new ConcurrentHashMap<>(); private final AtomicBoolean abortNextTransaction = new AtomicBoolean(); private final AtomicBoolean abortNextStatement = new AtomicBoolean(); - private final ConcurrentMap transactionCounters = new ConcurrentHashMap<>(); - private final ConcurrentMap> partitionTokens = new ConcurrentHashMap<>(); + private ConcurrentMap transactionCounters = new ConcurrentHashMap<>(); + private ConcurrentMap> partitionTokens = new ConcurrentHashMap<>(); private ConcurrentMap transactionLastUsed = new ConcurrentHashMap<>(); private int maxNumSessionsInOneBatch = 100; private int maxTotalSessions = Integer.MAX_VALUE; @@ -532,11 +577,29 @@ private Timestamp getCurrentGoogleTimestamp() { */ public void putStatementResult(StatementResult result) { Preconditions.checkNotNull(result); - statementResults.put(result.statement, result); + synchronized (lock) { + statementResults.put(result.statement, result); + } + } + + public void putStatementResults(StatementResult... results) { + synchronized (lock) { + for (StatementResult result : results) { + statementResults.put(result.statement, result); + } + } } private StatementResult getResult(Statement statement) { - StatementResult res = statementResults.get(statement); + StatementResult res; + synchronized (lock) { + res = statementResults.get(statement); + if (statementGetCounts.containsKey(statement)) { + statementGetCounts.put(statement, statementGetCounts.get(statement) + 1L); + } else { + statementGetCounts.put(statement, 1L); + } + } if (res == null) { throw Status.INTERNAL .withDescription( @@ -593,11 +656,11 @@ public void abortAllTransactions() { } public void freeze() { - freezeLock.writeLock().lock(); + freezeLock = new CountDownLatch(1); } public void unfreeze() { - freezeLock.writeLock().unlock(); + freezeLock.countDown(); } public void setMaxSessionsInOneBatch(int max) { @@ -935,6 +998,7 @@ public void executeBatchDml( status = com.google.rpc.Status.newBuilder() .setCode(res.getException().getStatus().getCode().value()) + .setMessage(res.getException().getMessage()) .build(); break resultLoop; case RESULT_SET: @@ -1055,6 +1119,7 @@ public void executeStreamingSql( } } + @SuppressWarnings("unchecked") private Statement buildStatement( String sql, Map paramTypes, com.google.protobuf.Struct params) { Statement.Builder builder = Statement.newBuilder(sql); @@ -1063,7 +1128,37 @@ private Statement buildStatement( if (value.getKindCase() == KindCase.NULL_VALUE) { switch (entry.getValue().getCode()) { case ARRAY: - throw new IllegalArgumentException("Array parameters not (yet) supported"); + switch (entry.getValue().getArrayElementType().getCode()) { + case BOOL: + builder.bind(entry.getKey()).toBoolArray((Iterable) null); + break; + case BYTES: + builder.bind(entry.getKey()).toBytesArray(null); + break; + case DATE: + builder.bind(entry.getKey()).toDateArray(null); + break; + case FLOAT64: + builder.bind(entry.getKey()).toFloat64Array((Iterable) null); + break; + case INT64: + builder.bind(entry.getKey()).toInt64Array((Iterable) null); + break; + case STRING: + builder.bind(entry.getKey()).toStringArray(null); + break; + case TIMESTAMP: + builder.bind(entry.getKey()).toTimestampArray(null); + break; + case STRUCT: + case TYPE_CODE_UNSPECIFIED: + case UNRECOGNIZED: + default: + throw new IllegalArgumentException( + "Unknown or invalid array parameter type: " + + entry.getValue().getArrayElementType().getCode()); + } + break; case BOOL: builder.bind(entry.getKey()).to((Boolean) null); break; @@ -1097,7 +1192,72 @@ private Statement buildStatement( } else { switch (entry.getValue().getCode()) { case ARRAY: - throw new IllegalArgumentException("Array parameters not (yet) supported"); + switch (entry.getValue().getArrayElementType().getCode()) { + case BOOL: + builder + .bind(entry.getKey()) + .toBoolArray( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.bool(), value.getListValue())); + break; + case BYTES: + builder + .bind(entry.getKey()) + .toBytesArray( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.bytes(), value.getListValue())); + break; + case DATE: + builder + .bind(entry.getKey()) + .toDateArray( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.date(), value.getListValue())); + break; + case FLOAT64: + builder + .bind(entry.getKey()) + .toFloat64Array( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.float64(), value.getListValue())); + break; + case INT64: + builder + .bind(entry.getKey()) + .toInt64Array( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.int64(), value.getListValue())); + break; + case STRING: + builder + .bind(entry.getKey()) + .toStringArray( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.string(), value.getListValue())); + break; + case TIMESTAMP: + builder + .bind(entry.getKey()) + .toTimestampArray( + (Iterable) + GrpcStruct.decodeArrayValue( + com.google.cloud.spanner.Type.timestamp(), value.getListValue())); + break; + case STRUCT: + case TYPE_CODE_UNSPECIFIED: + case UNRECOGNIZED: + default: + throw new IllegalArgumentException( + "Unknown or invalid array parameter type: " + + entry.getValue().getArrayElementType().getCode()); + } + break; case BOOL: builder.bind(entry.getKey()).to(value.getBoolValue()); break; @@ -1119,6 +1279,9 @@ private Statement buildStatement( case STRUCT: throw new IllegalArgumentException("Struct parameters not (yet) supported"); case TIMESTAMP: + builder + .bind(entry.getKey()) + .to(com.google.cloud.Timestamp.parseTimestamp(value.getStringValue())); break; case TYPE_CODE_UNSPECIFIED: case UNRECOGNIZED: @@ -1200,12 +1363,12 @@ public Iterator iterator() { return request.getColumnsList().iterator(); } }; - StatementResult res = - statementResults.get( - StatementResult.createReadStatement( - request.getTable(), - request.getKeySet().getAll() ? KeySet.all() : KeySet.singleKey(Key.of()), - cols)); + Statement statement = + StatementResult.createReadStatement( + request.getTable(), + request.getKeySet().getAll() ? KeySet.all() : KeySet.singleKey(Key.of()), + cols); + StatementResult res = getResult(statement); returnResultSet( res.getResultSet(), transactionId, request.getTransaction(), responseObserver); responseObserver.onCompleted(); @@ -1250,12 +1413,17 @@ public Iterator iterator() { return request.getColumnsList().iterator(); } }; - StatementResult res = - statementResults.get( - StatementResult.createReadStatement( - request.getTable(), - request.getKeySet().getAll() ? KeySet.all() : KeySet.singleKey(Key.of()), - cols)); + Statement statement = + StatementResult.createReadStatement( + request.getTable(), + request.getKeySet().getAll() ? KeySet.all() : KeySet.singleKey(Key.of()), + cols); + StatementResult res = getResult(statement); + if (res == null) { + throw Status.NOT_FOUND + .withDescription("No result found for " + statement.toString()) + .asRuntimeException(); + } returnPartialResultSet( res.getResultSet(), transactionId, request.getTransaction(), responseObserver); } catch (StatusRuntimeException e) { @@ -1496,7 +1664,10 @@ private void ensureMostRecentTransaction(Session session, ByteString transaction throw Status.FAILED_PRECONDITION .withDescription( String.format( - "This transaction has been invalidated by a later transaction in the same session.", + "This transaction has been invalidated by a later transaction in the same session.\nTransaction id: " + + id + + "\nExpected: " + + counter.get(), session.getName())) .asRuntimeException(); } @@ -1662,6 +1833,37 @@ public List getRequests() { return new ArrayList<>(this.requests); } + public Iterable> getRequestTypes() { + List> res = new LinkedList<>(); + for (AbstractMessage m : this.requests) { + res.add(m.getClass()); + } + return res; + } + + public int countRequestsOfType(Class type) { + int c = 0; + for (AbstractMessage m : this.requests) { + if (m.getClass().equals(type)) { + c++; + } + } + return c; + } + + public void waitForLastRequestToBe(Class type, long timeoutMillis) + throws InterruptedException, TimeoutException { + Stopwatch watch = Stopwatch.createStarted(); + while (!(this.requests.peekLast() != null + && this.requests.peekLast().getClass().equals(type))) { + Thread.sleep(10L); + if (watch.elapsed(TimeUnit.MILLISECONDS) > timeoutMillis) { + throw new TimeoutException( + "Timeout while waiting for last request to become " + type.getName()); + } + } + } + @Override public void addResponse(AbstractMessage response) { throw new UnsupportedOperationException(); @@ -1672,6 +1874,10 @@ public void addException(Exception exception) { exceptions.add(exception); } + public void clearExceptions() { + exceptions.clear(); + } + public void setStickyGlobalExceptions(boolean sticky) { this.stickyGlobalExceptions = sticky; } @@ -1684,18 +1890,21 @@ public ServerServiceDefinition getServiceDefinition() { /** Removes all sessions and transactions. Mocked results are not removed. */ @Override public void reset() { - requests.clear(); - sessions.clear(); + requests = new ConcurrentLinkedDeque<>(); + exceptions = new ConcurrentLinkedQueue<>(); + statementGetCounts = new ConcurrentHashMap<>(); + sessions = new ConcurrentHashMap<>(); + sessionLastUsed = new ConcurrentHashMap<>(); + transactions = new ConcurrentHashMap<>(); + isPartitionedDmlTransaction = new ConcurrentHashMap<>(); + abortedTransactions = new ConcurrentHashMap<>(); + transactionCounters = new ConcurrentHashMap<>(); + partitionTokens = new ConcurrentHashMap<>(); + transactionLastUsed = new ConcurrentHashMap<>(); + numSessionsCreated.set(0); - sessionLastUsed.clear(); - transactions.clear(); - isPartitionedDmlTransaction.clear(); - abortedTransactions.clear(); - transactionCounters.clear(); - partitionTokens.clear(); - transactionLastUsed.clear(); - exceptions.clear(); stickyGlobalExceptions = false; + freezeLock.countDown(); } public void removeAllExecutionTimes() { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerTestUtil.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerTestUtil.java new file mode 100644 index 0000000000..cc6784b679 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerTestUtil.java @@ -0,0 +1,151 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.cloud.spanner.Type.StructField; +import com.google.common.collect.ContiguousSet; +import com.google.protobuf.ListValue; +import com.google.spanner.v1.ResultSetMetadata; +import com.google.spanner.v1.StructType; +import com.google.spanner.v1.StructType.Field; +import com.google.spanner.v1.TypeCode; +import java.util.Arrays; + +public class MockSpannerTestUtil { + static final Statement SELECT1 = Statement.of("SELECT 1 AS COL1"); + private static final ResultSetMetadata SELECT1_METADATA = + ResultSetMetadata.newBuilder() + .setRowType( + StructType.newBuilder() + .addFields( + Field.newBuilder() + .setName("COL1") + .setType( + com.google.spanner.v1.Type.newBuilder() + .setCode(TypeCode.INT64) + .build()) + .build()) + .build()) + .build(); + static final com.google.spanner.v1.ResultSet SELECT1_RESULTSET = + com.google.spanner.v1.ResultSet.newBuilder() + .addRows( + ListValue.newBuilder() + .addValues(com.google.protobuf.Value.newBuilder().setStringValue("1").build()) + .build()) + .setMetadata(SELECT1_METADATA) + .build(); + + static final String TEST_PROJECT = "my-project"; + static final String TEST_INSTANCE = "my-instance"; + static final String TEST_DATABASE = "my-database"; + + static final Statement UPDATE_STATEMENT = Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=2"); + static final Statement INVALID_UPDATE_STATEMENT = + Statement.of("UPDATE NON_EXISTENT_TABLE SET BAR=1 WHERE BAZ=2"); + static final Statement UPDATE_ABORTED_STATEMENT = + Statement.of("UPDATE FOO SET BAR=1 WHERE BAZ=2 AND THIS_WILL_ABORT=TRUE"); + static final long UPDATE_COUNT = 1L; + + static final String READ_TABLE_NAME = "TestTable"; + static final String EMPTY_READ_TABLE_NAME = "EmptyTestTable"; + static final Iterable READ_COLUMN_NAMES = Arrays.asList("Key", "Value"); + static final Statement READ_ONE_KEY_VALUE_STATEMENT = + Statement.of("SELECT Key, Value FROM TestTable WHERE ID=1"); + static final Statement READ_MULTIPLE_KEY_VALUE_STATEMENT = + Statement.of("SELECT Key, Value FROM TestTable WHERE 1=1"); + static final Statement READ_ONE_EMPTY_KEY_VALUE_STATEMENT = + Statement.of("SELECT Key, Value FROM EmptyTestTable WHERE ID=1"); + static final Statement READ_ALL_EMPTY_KEY_VALUE_STATEMENT = + Statement.of("SELECT Key, Value FROM EmptyTestTable WHERE 1=1"); + static final ResultSetMetadata READ_KEY_VALUE_METADATA = + ResultSetMetadata.newBuilder() + .setRowType( + StructType.newBuilder() + .addFields( + Field.newBuilder() + .setName("Key") + .setType( + com.google.spanner.v1.Type.newBuilder() + .setCode(TypeCode.STRING) + .build()) + .build()) + .addFields( + Field.newBuilder() + .setName("Value") + .setType( + com.google.spanner.v1.Type.newBuilder() + .setCode(TypeCode.STRING) + .build()) + .build()) + .build()) + .build(); + static final Type READ_TABLE_TYPE = + Type.struct(StructField.of("Key", Type.string()), StructField.of("Value", Type.string())); + static final com.google.spanner.v1.ResultSet EMPTY_KEY_VALUE_RESULTSET = + com.google.spanner.v1.ResultSet.newBuilder() + .addRows(ListValue.newBuilder().build()) + .setMetadata(READ_KEY_VALUE_METADATA) + .build(); + static final com.google.spanner.v1.ResultSet READ_ONE_KEY_VALUE_RESULTSET = + com.google.spanner.v1.ResultSet.newBuilder() + .addRows( + ListValue.newBuilder() + .addValues(com.google.protobuf.Value.newBuilder().setStringValue("k1").build()) + .addValues(com.google.protobuf.Value.newBuilder().setStringValue("v1").build()) + .build()) + .setMetadata(READ_KEY_VALUE_METADATA) + .build(); + static final com.google.spanner.v1.ResultSet READ_MULTIPLE_KEY_VALUE_RESULTSET = + generateKeyValueResultSet(ContiguousSet.closed(1, 3)); + + static com.google.spanner.v1.ResultSet generateKeyValueResultSet(Iterable rows) { + com.google.spanner.v1.ResultSet.Builder builder = com.google.spanner.v1.ResultSet.newBuilder(); + for (Integer row : rows) { + builder.addRows( + ListValue.newBuilder() + .addValues(com.google.protobuf.Value.newBuilder().setStringValue("k" + row).build()) + .addValues(com.google.protobuf.Value.newBuilder().setStringValue("v" + row).build()) + .build()); + } + return builder.setMetadata(READ_KEY_VALUE_METADATA).build(); + } + + static final ResultSetMetadata READ_FIRST_NAME_SINGERS_METADATA = + ResultSetMetadata.newBuilder() + .setRowType( + StructType.newBuilder() + .addFields( + Field.newBuilder() + .setName("FirstName") + .setType( + com.google.spanner.v1.Type.newBuilder() + .setCode(TypeCode.STRING) + .build()) + .build()) + .build()) + .build(); + static final com.google.spanner.v1.ResultSet READ_FIRST_NAME_SINGERS_RESULTSET = + com.google.spanner.v1.ResultSet.newBuilder() + .addRows( + ListValue.newBuilder() + .addValues( + com.google.protobuf.Value.newBuilder().setStringValue("FirstName").build()) + .build()) + .setMetadata(READ_FIRST_NAME_SINGERS_METADATA) + .build(); +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java new file mode 100644 index 0000000000..63bc234a41 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java @@ -0,0 +1,166 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.client.util.Base64; +import com.google.cloud.Date; +import com.google.cloud.Timestamp; +import com.google.protobuf.ListValue; +import com.google.protobuf.NullValue; +import com.google.protobuf.Value; +import com.google.protobuf.util.Timestamps; +import com.google.spanner.v1.ResultSet; +import com.google.spanner.v1.ResultSetMetadata; +import com.google.spanner.v1.StructType; +import com.google.spanner.v1.StructType.Field; +import com.google.spanner.v1.Type; +import com.google.spanner.v1.TypeCode; +import java.util.Random; + +public class RandomResultSetGenerator { + private static final Type TYPES[] = + new Type[] { + Type.newBuilder().setCode(TypeCode.BOOL).build(), + Type.newBuilder().setCode(TypeCode.INT64).build(), + Type.newBuilder().setCode(TypeCode.FLOAT64).build(), + Type.newBuilder().setCode(TypeCode.STRING).build(), + Type.newBuilder().setCode(TypeCode.BYTES).build(), + Type.newBuilder().setCode(TypeCode.DATE).build(), + Type.newBuilder().setCode(TypeCode.TIMESTAMP).build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.BOOL)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.INT64)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.FLOAT64)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.STRING)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.BYTES)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.DATE)) + .build(), + Type.newBuilder() + .setCode(TypeCode.ARRAY) + .setArrayElementType(Type.newBuilder().setCode(TypeCode.TIMESTAMP)) + .build(), + }; + + private static final ResultSetMetadata generateMetadata() { + StructType.Builder rowTypeBuilder = StructType.newBuilder(); + for (int col = 0; col < TYPES.length; col++) { + rowTypeBuilder.addFields(Field.newBuilder().setName("COL" + col).setType(TYPES[col])).build(); + } + ResultSetMetadata.Builder builder = ResultSetMetadata.newBuilder(); + builder.setRowType(rowTypeBuilder.build()); + return builder.build(); + } + + private static final ResultSetMetadata METADATA = generateMetadata(); + + private final int rowCount; + private final Random random = new Random(); + + public RandomResultSetGenerator(int rowCount) { + this.rowCount = rowCount; + } + + public ResultSet generate() { + ResultSet.Builder builder = ResultSet.newBuilder(); + for (int row = 0; row < rowCount; row++) { + ListValue.Builder rowBuilder = ListValue.newBuilder(); + for (int col = 0; col < TYPES.length; col++) { + Value.Builder valueBuilder = Value.newBuilder(); + setRandomValue(valueBuilder, TYPES[col]); + rowBuilder.addValues(valueBuilder.build()); + } + builder.addRows(rowBuilder.build()); + } + builder.setMetadata(METADATA); + return builder.build(); + } + + private void setRandomValue(Value.Builder builder, Type type) { + if (randomNull()) { + builder.setNullValue(NullValue.NULL_VALUE); + } else { + switch (type.getCode()) { + case ARRAY: + int length = random.nextInt(20) + 1; + ListValue.Builder arrayBuilder = ListValue.newBuilder(); + for (int i = 0; i < length; i++) { + Value.Builder valueBuilder = Value.newBuilder(); + setRandomValue(valueBuilder, type.getArrayElementType()); + arrayBuilder.addValues(valueBuilder.build()); + } + builder.setListValue(arrayBuilder.build()); + break; + case BOOL: + builder.setBoolValue(random.nextBoolean()); + break; + case STRING: + case BYTES: + byte[] bytes = new byte[random.nextInt(200)]; + random.nextBytes(bytes); + builder.setStringValue(Base64.encodeBase64String(bytes)); + break; + case DATE: + Date date = + Date.fromYearMonthDay( + random.nextInt(2019) + 1, random.nextInt(11) + 1, random.nextInt(28) + 1); + builder.setStringValue(date.toString()); + break; + case FLOAT64: + builder.setNumberValue(random.nextDouble()); + break; + case INT64: + builder.setStringValue(String.valueOf(random.nextLong())); + break; + case TIMESTAMP: + com.google.protobuf.Timestamp ts = + Timestamps.add( + Timestamps.EPOCH, + com.google.protobuf.Duration.newBuilder() + .setSeconds(random.nextInt(100_000_000)) + .setNanos(random.nextInt(1000_000_000)) + .build()); + builder.setStringValue(Timestamp.fromProto(ts).toString()); + break; + case STRUCT: + case TYPE_CODE_UNSPECIFIED: + case UNRECOGNIZED: + default: + throw new IllegalArgumentException("Unknown or unsupported type: " + type.getCode()); + } + } + } + + private boolean randomNull() { + return random.nextInt(10) == 0; + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java new file mode 100644 index 0000000000..13e4c47d08 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java @@ -0,0 +1,510 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import static com.google.cloud.spanner.MockSpannerTestUtil.*; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.api.gax.grpc.testing.LocalChannelProvider; +import com.google.cloud.NoCredentials; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; +import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; +import com.google.common.base.Function; +import com.google.common.collect.ContiguousSet; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import io.grpc.Server; +import io.grpc.Status; +import io.grpc.inprocess.InProcessServerBuilder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ReadAsyncTest { + private static MockSpannerServiceImpl mockSpanner; + private static Server server; + private static LocalChannelProvider channelProvider; + + private static ExecutorService executor; + private Spanner spanner; + private DatabaseClient client; + + @BeforeClass + public static void setup() throws Exception { + mockSpanner = new MockSpannerServiceImpl(); + mockSpanner.putStatementResult( + StatementResult.query(READ_ONE_KEY_VALUE_STATEMENT, READ_ONE_KEY_VALUE_RESULTSET)); + mockSpanner.putStatementResult( + StatementResult.query(READ_ONE_EMPTY_KEY_VALUE_STATEMENT, EMPTY_KEY_VALUE_RESULTSET)); + mockSpanner.putStatementResult( + StatementResult.query( + READ_MULTIPLE_KEY_VALUE_STATEMENT, READ_MULTIPLE_KEY_VALUE_RESULTSET)); + + String uniqueName = InProcessServerBuilder.generateName(); + server = + InProcessServerBuilder.forName(uniqueName) + .scheduledExecutorService(new ScheduledThreadPoolExecutor(1)) + .addService(mockSpanner) + .build() + .start(); + channelProvider = LocalChannelProvider.create(uniqueName); + executor = Executors.newScheduledThreadPool(8); + } + + @AfterClass + public static void teardown() throws Exception { + executor.shutdown(); + server.shutdown(); + server.awaitTermination(); + } + + @Before + public void before() { + spanner = + SpannerOptions.newBuilder() + .setProjectId(TEST_PROJECT) + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .setSessionPoolOption( + SessionPoolOptions.newBuilder().setFailOnSessionLeak().setMinSessions(0).build()) + .build() + .getService(); + client = spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + } + + @After + public void after() { + spanner.close(); + mockSpanner.removeAllExecutionTimes(); + } + + @Test + public void readAsyncPropagatesError() throws Exception { + ApiFuture result; + try (AsyncResultSet resultSet = + client + .singleUse(TimestampBound.strong()) + .readAsync(EMPTY_READ_TABLE_NAME, KeySet.singleKey(Key.of("k99")), READ_COLUMN_NAMES)) { + result = + resultSet.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.CANCELLED, "Don't want the data"); + } + }); + } + try { + result.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.CANCELLED); + assertThat(se.getMessage()).contains("Don't want the data"); + } + } + + @Test + public void emptyReadAsync() throws Exception { + ApiFuture result; + try (AsyncResultSet resultSet = + client + .singleUse(TimestampBound.strong()) + .readAsync(EMPTY_READ_TABLE_NAME, KeySet.singleKey(Key.of("k99")), READ_COLUMN_NAMES)) { + result = + resultSet.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + while (true) { + switch (resultSet.tryNext()) { + case OK: + fail("received unexpected data"); + case NOT_READY: + return CallbackResponse.CONTINUE; + case DONE: + assertThat(resultSet.getType()).isEqualTo(READ_TABLE_TYPE); + return CallbackResponse.DONE; + } + } + } + }); + } + assertThat(result.get()).isNull(); + } + + @Test + public void pointReadAsync() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync(READ_TABLE_NAME, Key.of("k1"), READ_COLUMN_NAMES); + assertThat(row.get()).isNotNull(); + assertThat(row.get().getString(0)).isEqualTo("k1"); + assertThat(row.get().getString(1)).isEqualTo("v1"); + } + + @Test + public void pointReadNotFound() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync(EMPTY_READ_TABLE_NAME, Key.of("k999"), READ_COLUMN_NAMES); + assertThat(row.get()).isNull(); + } + + @Test + public void invalidDatabase() throws Exception { + mockSpanner.setBatchCreateSessionsExecutionTime( + SimulatedExecutionTime.stickyDatabaseNotFoundException("invalid-database")); + DatabaseClient invalidClient = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, "invalid-database")); + ApiFuture row = + invalidClient + .singleUse(TimestampBound.strong()) + .readRowAsync(READ_TABLE_NAME, Key.of("k99"), READ_COLUMN_NAMES); + try { + row.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(DatabaseNotFoundException.class); + } + } + + @Test + public void tableNotFound() throws Exception { + mockSpanner.setStreamingReadExecutionTime( + SimulatedExecutionTime.ofException( + Status.NOT_FOUND + .withDescription("Table not found: BadTableName") + .asRuntimeException())); + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync("BadTableName", Key.of("k1"), READ_COLUMN_NAMES); + try { + row.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(se.getMessage()).contains("BadTableName"); + } + } + + /** + * Ending a read-only transaction before an asynchronous query that was executed on that + * transaction has finished fetching all rows should keep the session checked out of the pool + * until all the rows have been returned. The session is then automatically returned to the + * session. + */ + @Test + public void closeTransactionBeforeEndOfAsyncQuery() throws Exception { + final BlockingQueue results = new SynchronousQueue<>(); + final SettableApiFuture finished = SettableApiFuture.create(); + ApiFuture closed; + DatabaseClientImpl clientImpl = (DatabaseClientImpl) client; + + // There should currently not be any sessions checked out of the pool. + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(0); + + final CountDownLatch dataReceived = new CountDownLatch(1); + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (AsyncResultSet rs = + tx.readAsync(READ_TABLE_NAME, KeySet.all(), READ_COLUMN_NAMES, Options.bufferRows(1))) { + closed = + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + finished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + dataReceived.countDown(); + results.put(resultSet.getString(0)); + } + } + } catch (Throwable t) { + finished.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + // Wait until at least one row has been fetched. At that moment there should be one session + // checked out. + dataReceived.await(); + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(1); + } + // The read-only transaction is now closed, but the ready callback will continue to receive + // data. As it tries to put the data into a synchronous queue and the underlying buffer can also + // only hold 1 row, the async result set has not yet finished. The read-only transaction will + // release the session back into the pool when all async statements have finished. The number of + // sessions in use is therefore still 1. + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(1); + List resultList = new ArrayList<>(); + do { + results.drainTo(resultList); + } while (!finished.isDone() || results.size() > 0); + assertThat(finished.get()).isTrue(); + assertThat(resultList).containsExactly("k1", "k2", "k3"); + // The session will be released back into the pool by the asynchronous result set when it has + // returned all rows. As this is done in the background, it could take a couple of milliseconds. + closed.get(); + assertThat(clientImpl.pool.getNumberOfSessionsInUse()).isEqualTo(0); + } + + @Test + public void readOnlyTransaction() throws Exception { + Statement statement1 = + Statement.of("SELECT * FROM TestTable WHERE Key IN ('k10', 'k11', 'k12')"); + Statement statement2 = Statement.of("SELECT * FROM TestTable WHERE Key IN ('k1', 'k2', 'k3"); + mockSpanner.putStatementResult( + StatementResult.query(statement1, generateKeyValueResultSet(ContiguousSet.closed(10, 12)))); + mockSpanner.putStatementResult( + StatementResult.query(statement2, generateKeyValueResultSet(ContiguousSet.closed(1, 3)))); + + ApiFuture> values1; + ApiFuture> values2; + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (AsyncResultSet rs = tx.executeQueryAsync(statement1)) { + values1 = + rs.toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("Value"); + } + }, + executor); + } + try (AsyncResultSet rs = tx.executeQueryAsync(statement2)) { + values2 = + rs.toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("Value"); + } + }, + executor); + } + } + ApiFuture> allValues = + ApiFutures.transform( + ApiFutures.allAsList(Arrays.asList(values1, values2)), + new ApiFunction>, Iterable>() { + @Override + public Iterable apply(List> input) { + return Iterables.mergeSorted( + input, + new Comparator() { + @Override + public int compare(String o1, String o2) { + // Return in numerical order (i.e. without the preceding 'v'). + return Integer.valueOf(o1.substring(1)) + .compareTo(Integer.valueOf(o2.substring(1))); + } + }); + } + }, + executor); + assertThat(allValues.get()).containsExactly("v1", "v2", "v3", "v10", "v11", "v12"); + } + + @Test + public void pauseResume() throws Exception { + Statement unevenStatement = + Statement.of("SELECT * FROM TestTable WHERE MOD(CAST(SUBSTR(Key, 2) AS INT64), 2) = 1"); + Statement evenStatement = + Statement.of("SELECT * FROM TestTable WHERE MOD(CAST(SUBSTR(Key, 2) AS INT64), 2) = 0"); + mockSpanner.putStatementResult( + StatementResult.query( + unevenStatement, generateKeyValueResultSet(ImmutableSet.of(1, 3, 5, 7, 9)))); + mockSpanner.putStatementResult( + StatementResult.query( + evenStatement, generateKeyValueResultSet(ImmutableSet.of(2, 4, 6, 8, 10)))); + + final Object lock = new Object(); + ApiFuture evenFinished; + ApiFuture unevenFinished; + final CountDownLatch unevenReturnedFirstRow = new CountDownLatch(1); + final Deque allValues = new ConcurrentLinkedDeque<>(); + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (AsyncResultSet evenRs = tx.executeQueryAsync(evenStatement); + AsyncResultSet unevenRs = tx.executeQueryAsync(unevenStatement)) { + unevenFinished = + unevenRs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + synchronized (lock) { + allValues.add(resultSet.getString("Value")); + } + unevenReturnedFirstRow.countDown(); + return CallbackResponse.PAUSE; + } + } + } + }); + evenFinished = + evenRs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + // Make sure the uneven result set has returned the first before we start the + // even + // results. + unevenReturnedFirstRow.await(); + while (true) { + switch (resultSet.tryNext()) { + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + synchronized (lock) { + allValues.add(resultSet.getString("Value")); + } + return CallbackResponse.PAUSE; + } + } + } catch (InterruptedException e) { + throw SpannerExceptionFactory.propagateInterrupt(e); + } + } + }); + while (!(evenFinished.isDone() && unevenFinished.isDone())) { + synchronized (lock) { + if (allValues.peekLast() != null) { + if (Integer.valueOf(allValues.peekLast().substring(1)) % 2 == 1) { + evenRs.resume(); + } else { + unevenRs.resume(); + } + } + if (allValues.size() == 10) { + unevenRs.resume(); + evenRs.resume(); + } + } + } + } + } + assertThat(ApiFutures.allAsList(Arrays.asList(evenFinished, unevenFinished)).get()) + .containsExactly(null, null); + assertThat(allValues) + .containsExactly("v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10"); + } + + @Test + public void cancel() throws Exception { + final List values = new LinkedList<>(); + final CountDownLatch receivedFirstRow = new CountDownLatch(1); + final CountDownLatch cancelled = new CountDownLatch(1); + final ApiFuture res; + try (AsyncResultSet rs = + client.singleUse().readAsync(READ_TABLE_NAME, KeySet.all(), READ_COLUMN_NAMES)) { + res = + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + values.add(resultSet.getString("Value")); + receivedFirstRow.countDown(); + cancelled.await(); + break; + } + } + } catch (Throwable t) { + return CallbackResponse.DONE; + } + } + }); + receivedFirstRow.await(); + rs.cancel(); + } + cancelled.countDown(); + try { + res.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.CANCELLED); + assertThat(values).containsExactly("v1"); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java index 29f442a761..7380791eed 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RetryOnInvalidatedSessionTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import com.google.api.core.ApiFuture; import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.testing.LocalChannelProvider; import com.google.cloud.NoCredentials; @@ -28,7 +29,9 @@ import com.google.cloud.spanner.v1.SpannerClient; import com.google.cloud.spanner.v1.SpannerClient.ListSessionsPagedResponse; import com.google.cloud.spanner.v1.SpannerSettings; +import com.google.common.base.Function; import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; import com.google.protobuf.ListValue; import com.google.spanner.v1.ResultSetMetadata; import com.google.spanner.v1.StructType; @@ -41,6 +44,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.AfterClass; @@ -54,6 +60,14 @@ @RunWith(Parameterized.class) public class RetryOnInvalidatedSessionTest { + private static final class ToLongTransformer implements Function { + @Override + public Long apply(StructReader input) { + return input.getLong(0); + } + } + + private static final ToLongTransformer TO_LONG = new ToLongTransformer(); @Parameter(0) public boolean failOnInvalidatedSession; @@ -138,6 +152,7 @@ public static Collection data() { private static SpannerClient spannerClient; private static Spanner spanner; private static DatabaseClient client; + private static ExecutorService executor; @BeforeClass public static void startStaticServer() throws IOException { @@ -166,6 +181,7 @@ public static void startStaticServer() throws IOException { .setCredentialsProvider(NoCredentialsProvider.create()) .build(); spannerClient = SpannerClient.create(settings); + executor = Executors.newSingleThreadExecutor(); } @AfterClass @@ -173,13 +189,16 @@ public static void stopServer() throws InterruptedException { spannerClient.close(); server.shutdown(); server.awaitTermination(); + executor.shutdown(); } @Before public void setUp() { mockSpanner.reset(); SessionPoolOptions.Builder builder = - SessionPoolOptions.newBuilder().setWriteSessionsFraction(WRITE_SESSIONS_FRACTION); + SessionPoolOptions.newBuilder() + .setWriteSessionsFraction(WRITE_SESSIONS_FRACTION) + .setFailOnSessionLeak(); if (failOnInvalidatedSession) { builder.setFailIfSessionNotFound(); } @@ -253,6 +272,20 @@ public void singleUseSelect() throws InterruptedException { } } + @Test + public void singleUseSelectAsync() throws Exception { + invalidateSessionPool(); + ApiFuture> list; + try (AsyncResultSet rs = client.singleUse().executeQueryAsync(SELECT1AND2)) { + list = rs.toListAsync(TO_LONG, executor); + assertThat(list.get()).containsExactly(1L, 2L); + assertThat(failOnInvalidatedSession).isFalse(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SessionNotFoundException.class); + assertThat(failOnInvalidatedSession).isTrue(); + } + } + @Test public void singleUseRead() throws InterruptedException { invalidateSessionPool(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java index be4179f21b..c756a7898a 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionImplTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.api.core.ApiFutures; import com.google.api.core.NanoClock; import com.google.api.gax.retrying.RetrySettings; import com.google.cloud.Timestamp; @@ -41,6 +42,7 @@ import com.google.spanner.v1.ResultSetMetadata; import com.google.spanner.v1.Session; import com.google.spanner.v1.Transaction; +import io.opencensus.trace.Span; import java.text.ParseException; import java.util.Arrays; import java.util.Calendar; @@ -98,16 +100,17 @@ public void setUp() { .thenReturn(sessionProto); Transaction txn = Transaction.newBuilder().setId(ByteString.copyFromUtf8("TEST")).build(); Mockito.when( - rpc.beginTransaction( + rpc.beginTransactionAsync( Mockito.any(BeginTransactionRequest.class), Mockito.any(Map.class))) - .thenReturn(txn); + .thenReturn(ApiFutures.immediateFuture(txn)); CommitResponse commitResponse = CommitResponse.newBuilder() .setCommitTimestamp(com.google.protobuf.Timestamp.getDefaultInstance()) .build(); - Mockito.when(rpc.commit(Mockito.any(CommitRequest.class), Mockito.any(Map.class))) - .thenReturn(commitResponse); + Mockito.when(rpc.commitAsync(Mockito.any(CommitRequest.class), Mockito.any(Map.class))) + .thenReturn(ApiFutures.immediateFuture(commitResponse)); session = spanner.getSessionClient(db).createSession(); + ((SessionImpl) session).setCurrentSpan(mock(Span.class)); // We expect the same options, "options", on all calls on "session". options = optionsCaptor.getValue(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java index 8007ce8385..0e72b2b9bc 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolMaintainerTest.java @@ -25,6 +25,7 @@ import com.google.cloud.spanner.SessionClient.SessionConsumer; import com.google.cloud.spanner.SessionPool.PooledSession; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; import com.google.cloud.spanner.SessionPool.SessionConsumerImpl; import com.google.common.base.Function; import java.util.ArrayList; @@ -200,7 +201,7 @@ public void testKeepAlive() throws Exception { assertThat(pingedSessions).containsExactly(session1.getName(), 2, session2.getName(), 3); // Update the last use date and release the session to the pool and do another maintenance // cycle. - ((PooledSession) session6).markUsed(); + ((PooledSessionFuture) session6).get().markUsed(); session6.close(); runMaintainanceLoop(clock, pool, 3); assertThat(pingedSessions).containsExactly(session1.getName(), 2, session2.getName(), 3); @@ -261,9 +262,9 @@ public void testIdleSessions() throws Exception { // Now check out three sessions so the pool will create an additional session. The pool will // only keep 2 sessions alive, as that is the setting for MinSessions. - Session session3 = pool.getReadSession(); - Session session4 = pool.getReadSession(); - Session session5 = pool.getReadSession(); + Session session3 = pool.getReadSession().get(); + Session session4 = pool.getReadSession().get(); + Session session5 = pool.getReadSession().get(); // Note that session2 was now the first session in the pool as it was the last to receive a // ping. assertThat(session3.getName()).isEqualTo(session2.getName()); @@ -278,9 +279,9 @@ public void testIdleSessions() throws Exception { assertThat(pool.totalSessions()).isEqualTo(2); // Check out three sessions again and keep one session checked out. - Session session6 = pool.getReadSession(); - Session session7 = pool.getReadSession(); - Session session8 = pool.getReadSession(); + Session session6 = pool.getReadSession().get(); + Session session7 = pool.getReadSession().get(); + Session session8 = pool.getReadSession().get(); session8.close(); session7.close(); // Now advance the clock to idle sessions. This should remove session8 from the pool. @@ -292,9 +293,9 @@ public void testIdleSessions() throws Exception { // Check out three sessions and keep them all checked out. No sessions should be removed from // the pool. - Session session9 = pool.getReadSession(); - Session session10 = pool.getReadSession(); - Session session11 = pool.getReadSession(); + Session session9 = pool.getReadSession().get(); + Session session10 = pool.getReadSession().get(); + Session session11 = pool.getReadSession().get(); runMaintainanceLoop(clock, pool, loopsToIdleSessions); assertThat(idledSessions).containsExactly(session5, session8); assertThat(pool.totalSessions()).isEqualTo(3); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java index e5f5dff463..b806f5fad6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolStressTest.java @@ -17,7 +17,7 @@ package com.google.cloud.spanner; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.any; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -26,9 +26,11 @@ import com.google.api.core.ApiFutures; import com.google.cloud.spanner.SessionClient.SessionConsumer; import com.google.cloud.spanner.SessionPool.PooledSession; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; import com.google.cloud.spanner.SessionPool.SessionConsumerImpl; import com.google.common.base.Function; import com.google.common.util.concurrent.Uninterruptibles; +import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +41,8 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; @@ -66,6 +70,7 @@ public class SessionPoolStressTest extends BaseSessionPoolTest { DatabaseId db = DatabaseId.of("projects/p/instances/i/databases/unused"); SessionPool pool; SessionPoolOptions options; + ExecutorService createExecutor = Executors.newSingleThreadExecutor(); Object lock = new Object(); Random random = new Random(); FakeClock clock = new FakeClock(); @@ -97,43 +102,31 @@ private void setupSpanner(DatabaseId db) { SessionClient sessionClient = mock(SessionClient.class); when(mockSpanner.getSessionClient(db)).thenReturn(sessionClient); when(mockSpanner.getOptions()).thenReturn(spannerOptions); - when(sessionClient.createSession()) - .thenAnswer( - new Answer() { - - @Override - public Session answer(InvocationOnMock invocation) { - synchronized (lock) { - SessionImpl session = mockSession(); - setupSession(session); - - sessions.put(session.getName(), false); - if (sessions.size() > maxAliveSessions) { - maxAliveSessions = sessions.size(); - } - return session; - } - } - }); doAnswer( new Answer() { @Override - public Void answer(InvocationOnMock invocation) { - int sessionCount = invocation.getArgumentAt(0, Integer.class); - for (int s = 0; s < sessionCount; s++) { - synchronized (lock) { - SessionImpl session = mockSession(); - setupSession(session); - - sessions.put(session.getName(), false); - if (sessions.size() > maxAliveSessions) { - maxAliveSessions = sessions.size(); - } - SessionConsumerImpl consumer = - invocation.getArgumentAt(2, SessionConsumerImpl.class); - consumer.onSessionReady(session); - } - } + public Void answer(final InvocationOnMock invocation) { + createExecutor.submit( + new Runnable() { + @Override + public void run() { + int sessionCount = invocation.getArgumentAt(0, Integer.class); + for (int s = 0; s < sessionCount; s++) { + SessionImpl session; + synchronized (lock) { + session = mockSession(); + setupSession(session); + sessions.put(session.getName(), false); + if (sessions.size() > maxAliveSessions) { + maxAliveSessions = sessions.size(); + } + } + SessionConsumerImpl consumer = + invocation.getArgumentAt(2, SessionConsumerImpl.class); + consumer.onSessionReady(session); + } + } + }); return null; } }) @@ -189,36 +182,43 @@ public Void answer(InvocationOnMock invocation) { expireSession(session); throw SpannerExceptionFactoryTest.newSessionNotFoundException(session.getName()); } + String name = session.getName(); synchronized (lock) { - if (sessions.put(session.getName(), true)) { + if (sessions.put(name, true)) { setFailed(); } + session.readyTransactionId = ByteString.copyFromUtf8("foo"); } return null; } }) .when(session) .prepareReadWriteTransaction(); + when(session.hasReadyTransaction()).thenCallRealMethod(); } private void expireSession(Session session) { + String name = session.getName(); synchronized (lock) { - sessions.remove(session.getName()); - expiredSessions.add(session.getName()); + sessions.remove(name); + expiredSessions.add(name); } } private void assertWritePrepared(Session session) { + String name = session.getName(); synchronized (lock) { - if (!sessions.get(session.getName())) { + if (!sessions.containsKey(name) || !sessions.get(name)) { setFailed(); } } } - private void resetTransaction(Session session) { + private void resetTransaction(SessionImpl session) { + String name = session.getName(); synchronized (lock) { - sessions.put(session.getName(), false); + session.readyTransactionId = null; + sessions.put(name, false); } } @@ -264,8 +264,9 @@ public void stressTest() throws Exception { new Function() { @Override public Void apply(PooledSession pooled) { + String name = pooled.getName(); synchronized (lock) { - sessions.remove(pooled.getName()); + sessions.remove(name); return null; } } @@ -279,16 +280,18 @@ public void run() { Uninterruptibles.awaitUninterruptibly(releaseThreads); for (int j = 0; j < numOperationsPerThread; j++) { try { - Session session = null; + PooledSessionFuture session = null; if (random.nextInt(10) < writeOperationFraction) { session = pool.getReadWriteSession(); - assertWritePrepared(session); + PooledSession sess = session.get(); + assertWritePrepared(sess); } else { session = pool.getReadSession(); + session.get(); } Uninterruptibles.sleepUninterruptibly( random.nextInt(5), TimeUnit.MILLISECONDS); - resetTransaction(session); + resetTransaction(session.get().delegate); session.close(); } catch (SpannerException e) { if (e.getErrorCode() != ErrorCode.RESOURCE_EXHAUSTED || shouldBlock) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java index db56c8ff82..d5ea648bbd 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SessionPoolTest.java @@ -47,6 +47,7 @@ import com.google.cloud.spanner.SessionClient.SessionConsumer; import com.google.cloud.spanner.SessionPool.Clock; import com.google.cloud.spanner.SessionPool.PooledSession; +import com.google.cloud.spanner.SessionPool.PooledSessionFuture; import com.google.cloud.spanner.SessionPool.SessionConsumerImpl; import com.google.cloud.spanner.SpannerImpl.ClosedException; import com.google.cloud.spanner.TransactionRunner.TransactionCallable; @@ -59,12 +60,14 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.spanner.v1.CommitRequest; +import com.google.spanner.v1.CommitResponse; import com.google.spanner.v1.ExecuteBatchDmlRequest; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ResultSetStats; import com.google.spanner.v1.RollbackRequest; import io.opencensus.metrics.LabelValue; import io.opencensus.metrics.MetricRegistry; +import io.opencensus.trace.Span; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; @@ -204,21 +207,21 @@ public void sessionCreation() { public void poolLifo() { setupMockSessionCreation(); pool = createPool(); - Session session1 = pool.getReadSession(); - Session session2 = pool.getReadSession(); + Session session1 = pool.getReadSession().get(); + Session session2 = pool.getReadSession().get(); assertThat(session1).isNotEqualTo(session2); session2.close(); session1.close(); - Session session3 = pool.getReadSession(); - Session session4 = pool.getReadSession(); + Session session3 = pool.getReadSession().get(); + Session session4 = pool.getReadSession().get(); assertThat(session3).isEqualTo(session1); assertThat(session4).isEqualTo(session2); session3.close(); session4.close(); - Session session5 = pool.getReadWriteSession(); - Session session6 = pool.getReadWriteSession(); + Session session5 = pool.getReadWriteSession().get(); + Session session6 = pool.getReadWriteSession().get(); assertThat(session5).isEqualTo(session4); assertThat(session6).isEqualTo(session3); session6.close(); @@ -259,7 +262,7 @@ public void run() { pool = createPool(); Session session1 = pool.getReadSession(); // Leaked sessions - PooledSession leakedSession = pool.getReadSession(); + PooledSessionFuture leakedSession = pool.getReadSession(); // Clear the leaked exception to suppress logging of expected exceptions. leakedSession.clearLeakedException(); session1.close(); @@ -335,7 +338,7 @@ public Void call() throws Exception { .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - PooledSession leakedSession = pool.getReadSession(); + PooledSessionFuture leakedSession = pool.getReadSession(); // Suppress expected leakedSession warning. leakedSession.clearLeakedException(); AtomicBoolean failed = new AtomicBoolean(false); @@ -344,7 +347,7 @@ public Void call() throws Exception { insideCreation.await(); pool.closeAsync(new SpannerImpl.ClosedException()); releaseCreation.countDown(); - latch.await(); + latch.await(5L, TimeUnit.SECONDS); assertThat(failed.get()).isTrue(); } @@ -393,7 +396,7 @@ public Void call() throws Exception { .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - PooledSession leakedSession = pool.getReadSession(); + PooledSessionFuture leakedSession = pool.getReadSession(); // Suppress expected leakedSession warning. leakedSession.clearLeakedException(); AtomicBoolean failed = new AtomicBoolean(false); @@ -510,7 +513,8 @@ public void run() { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - PooledSession leakedSession = pool.getReadSession(); + PooledSessionFuture leakedSession = pool.getReadSession(); + leakedSession.get(); // Suppress expected leakedSession warning. leakedSession.clearLeakedException(); pool.closeAsync(new SpannerImpl.ClosedException()); @@ -562,7 +566,7 @@ public Void call() { .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); try { - pool.getReadSession(); + pool.getReadSession().get(); fail("Expected exception"); } catch (SpannerException ex) { assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); @@ -593,7 +597,7 @@ public Void call() { .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); try { - pool.getReadWriteSession(); + pool.getReadWriteSession().get(); fail("Expected exception"); } catch (SpannerException ex) { assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); @@ -626,7 +630,7 @@ public void run() { .prepareReadWriteTransaction(); pool = createPool(); try { - pool.getReadWriteSession(); + pool.getReadWriteSession().get(); fail("Expected exception"); } catch (SpannerException ex) { assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.INTERNAL); @@ -655,14 +659,15 @@ public void run() { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - try (Session session = pool.getReadWriteSession()) { + try (PooledSessionFuture session = pool.getReadWriteSession()) { assertThat(session).isNotNull(); + session.get(); verify(mockSession).prepareReadWriteTransaction(); } } @Test - public void getMultipleReadWriteSessions() { + public void getMultipleReadWriteSessions() throws Exception { SessionImpl mockSession1 = mockSession(); SessionImpl mockSession2 = mockSession(); final LinkedList sessions = @@ -686,8 +691,10 @@ public void run() { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - Session session1 = pool.getReadWriteSession(); - Session session2 = pool.getReadWriteSession(); + PooledSessionFuture session1 = pool.getReadWriteSession(); + PooledSessionFuture session2 = pool.getReadWriteSession(); + session1.get(); + session2.get(); verify(mockSession1).prepareReadWriteTransaction(); verify(mockSession2).prepareReadWriteTransaction(); session1.close(); @@ -782,8 +789,8 @@ public void run() { pool = createPool(); // One of the sessions would be pre prepared. Uninterruptibles.awaitUninterruptibly(prepareLatch); - PooledSession readSession = pool.getReadSession(); - PooledSession writeSession = pool.getReadWriteSession(); + PooledSession readSession = pool.getReadSession().get(); + PooledSession writeSession = pool.getReadWriteSession().get(); verify(writeSession.delegate, times(1)).prepareReadWriteTransaction(); verify(readSession.delegate, never()).prepareReadWriteTransaction(); readSession.close(); @@ -832,7 +839,7 @@ public void run() { pool.getReadWriteSession().close(); prepareLatch.await(); // This session should also be write prepared. - PooledSession readSession = pool.getReadSession(); + PooledSession readSession = pool.getReadSession().get(); verify(readSession.delegate, times(2)).prepareReadWriteTransaction(); } @@ -904,7 +911,7 @@ public void run() { .when(sessionClient) .asyncBatchCreateSessions(Mockito.eq(1), Mockito.anyBoolean(), any(SessionConsumer.class)); pool = createPool(); - assertThat(pool.getReadWriteSession().delegate).isEqualTo(mockSession2); + assertThat(pool.getReadWriteSession().get().delegate).isEqualTo(mockSession2); } @Test @@ -949,9 +956,14 @@ public void run() { pool.getReadSession().close(); runMaintainanceLoop(clock, pool, pool.poolMaintainer.numClosureCycles); assertThat(pool.numIdleSessionsRemoved()).isEqualTo(0L); - Session readSession1 = pool.getReadSession(); - Session readSession2 = pool.getReadSession(); - Session readSession3 = pool.getReadSession(); + PooledSessionFuture readSession1 = pool.getReadSession(); + PooledSessionFuture readSession2 = pool.getReadSession(); + PooledSessionFuture readSession3 = pool.getReadSession(); + // Wait until the sessions have actually been gotten in order to make sure they are in use in + // parallel. + readSession1.get(); + readSession2.get(); + readSession3.get(); readSession1.close(); readSession2.close(); readSession3.close(); @@ -1005,8 +1017,10 @@ public void run() { FakeClock clock = new FakeClock(); clock.currentTimeMillis = System.currentTimeMillis(); pool = createPool(clock); - Session session1 = pool.getReadSession(); - Session session2 = pool.getReadSession(); + PooledSessionFuture session1 = pool.getReadSession(); + PooledSessionFuture session2 = pool.getReadSession(); + session1.get(); + session2.get(); session1.close(); session2.close(); runMaintainanceLoop(clock, pool, pool.poolMaintainer.numKeepAliveCycles); @@ -1133,7 +1147,8 @@ public void blockAndTimeoutOnPoolExhaustion() throws Exception { setupMockSessionCreation(); pool = createPool(); // Take the only session that can be in the pool. - Session checkedOutSession = pool.getReadSession(); + PooledSessionFuture checkedOutSession = pool.getReadSession(); + checkedOutSession.get(); final Boolean finWrite = write; ExecutorService executor = Executors.newFixedThreadPool(1); final CountDownLatch latch = new CountDownLatch(1); @@ -1143,7 +1158,7 @@ public void blockAndTimeoutOnPoolExhaustion() throws Exception { new Callable() { @Override public Void call() { - Session session; + PooledSessionFuture session; latch.countDown(); if (finWrite) { session = pool.getReadWriteSession(); @@ -1326,7 +1341,8 @@ public void testSessionNotFoundReadWriteTransaction() { .thenThrow(sessionNotFound); when(rpc.executeBatchDml(any(ExecuteBatchDmlRequest.class), any(Map.class))) .thenThrow(sessionNotFound); - when(rpc.commit(any(CommitRequest.class), any(Map.class))).thenThrow(sessionNotFound); + when(rpc.commitAsync(any(CommitRequest.class), any(Map.class))) + .thenReturn(ApiFutures.immediateFailedFuture(sessionNotFound)); doThrow(sessionNotFound).when(rpc).rollback(any(RollbackRequest.class), any(Map.class)); final SessionImpl closedSession = mock(SessionImpl.class); when(closedSession.getName()) @@ -1342,9 +1358,10 @@ public void testSessionNotFoundReadWriteTransaction() { when(closedSession.asyncClose()) .thenReturn(ApiFutures.immediateFuture(Empty.getDefaultInstance())); when(closedSession.newTransaction()).thenReturn(closedTransactionContext); - when(closedSession.beginTransaction()).thenThrow(sessionNotFound); + when(closedSession.beginTransactionAsync()).thenThrow(sessionNotFound); TransactionRunnerImpl closedTransactionRunner = new TransactionRunnerImpl(closedSession, rpc, 10); + closedTransactionRunner.setSpan(mock(Span.class)); when(closedSession.readWriteTransaction()).thenReturn(closedTransactionRunner); final SessionImpl openSession = mock(SessionImpl.class); @@ -1354,9 +1371,11 @@ public void testSessionNotFoundReadWriteTransaction() { .thenReturn("projects/dummy/instances/dummy/database/dummy/sessions/session-open"); final TransactionContextImpl openTransactionContext = mock(TransactionContextImpl.class); when(openSession.newTransaction()).thenReturn(openTransactionContext); - when(openSession.beginTransaction()).thenReturn(ByteString.copyFromUtf8("open-txn")); + when(openSession.beginTransactionAsync()) + .thenReturn(ApiFutures.immediateFuture(ByteString.copyFromUtf8("open-txn"))); TransactionRunnerImpl openTransactionRunner = new TransactionRunnerImpl(openSession, mock(SpannerRpc.class), 10); + openTransactionRunner.setSpan(mock(Span.class)); when(openSession.readWriteTransaction()).thenReturn(openTransactionRunner); ResultSet openResultSet = mock(ResultSet.class); @@ -1422,7 +1441,7 @@ public void run() { SessionPool pool = SessionPool.createPool( options, new TestExecutorFactory(), spanner.getSessionClient(db)); - try (PooledSession readWriteSession = pool.getReadWriteSession()) { + try (PooledSessionFuture readWriteSession = pool.getReadWriteSession()) { TransactionRunner runner = readWriteSession.readWriteTransaction(); try { runner.run( @@ -1546,7 +1565,7 @@ public void run() { FakeClock clock = new FakeClock(); clock.currentTimeMillis = System.currentTimeMillis(); pool = createPool(clock); - PooledSession session = pool.getReadWriteSession(); + PooledSession session = pool.getReadWriteSession().get(); assertThat(session.delegate).isEqualTo(openSession); } @@ -1726,8 +1745,10 @@ public void testSessionMetrics() throws Exception { setupMockSessionCreation(); pool = createPool(clock, metricRegistry, labelValues); - Session session1 = pool.getReadSession(); - Session session2 = pool.getReadSession(); + PooledSessionFuture session1 = pool.getReadSession(); + PooledSessionFuture session2 = pool.getReadSession(); + session1.get(); + session2.get(); MetricsRecord record = metricRegistry.pollRecord(); assertThat(record.getMetrics().size()).isEqualTo(6); @@ -1861,7 +1882,8 @@ private void getSessionAsync(final CountDownLatch latch, final AtomicBoolean fai new Runnable() { @Override public void run() { - try (Session session = pool.getReadSession()) { + try (PooledSessionFuture future = pool.getReadSession()) { + PooledSession session = future.get(); failed.compareAndSet(false, session == null); Uninterruptibles.sleepUninterruptibly(10, TimeUnit.MILLISECONDS); } catch (Throwable e) { @@ -1879,7 +1901,8 @@ private void getReadWriteSessionAsync(final CountDownLatch latch, final AtomicBo new Runnable() { @Override public void run() { - try (Session session = pool.getReadWriteSession()) { + try (PooledSessionFuture future = pool.getReadWriteSession()) { + PooledSession session = future.get(); failed.compareAndSet(false, session == null); Uninterruptibles.sleepUninterruptibly(2, TimeUnit.MILLISECONDS); } catch (SpannerException e) { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java index 9bbbdcea82..7dcc9b65e1 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpanTest.java @@ -324,6 +324,7 @@ public Void run(TransactionContext transaction) { } Map spans = failOnOverkillTraceComponent.getSpans(); + assertThat(spans.size()).isEqualTo(5); assertThat(spans).containsEntry("CloudSpanner.ReadWriteTransaction", true); assertThat(spans).containsEntry("CloudSpannerOperation.BatchCreateSessions", true); assertThat(spans).containsEntry("SessionPool.WaitForSession", true); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerExceptionFactoryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerExceptionFactoryTest.java index bc7dd5498d..49cbfb905d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerExceptionFactoryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerExceptionFactoryTest.java @@ -52,6 +52,11 @@ static DatabaseNotFoundException newDatabaseNotFoundException(String name) { "Database", SpannerExceptionFactory.DATABASE_RESOURCE_TYPE, name); } + static StatusRuntimeException newStatusDatabaseNotFoundException(String name) { + return newStatusResourceNotFoundException( + "Database", SpannerExceptionFactory.DATABASE_RESOURCE_TYPE, name); + } + static InstanceNotFoundException newInstanceNotFoundException(String name) { return (InstanceNotFoundException) newResourceNotFoundException( diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java index 05729d6f53..b98702f87c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerGaxRetryTest.java @@ -321,6 +321,13 @@ public void readWriteTransactionTimeout() { mockSpanner.setBeginTransactionExecutionTime(ONE_SECOND); try { TransactionRunner runner = clientWithTimeout.readWriteTransaction(); + runner.run( + new TransactionCallable() { + @Override + public Void run(TransactionContext transaction) throws Exception { + return null; + } + }); fail("Expected exception"); } catch (SpannerException ex) { assertEquals(ErrorCode.DEADLINE_EXCEEDED, ex.getErrorCode()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerMatchers.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerMatchers.java index 9662047867..4723497a47 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerMatchers.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/SpannerMatchers.java @@ -21,6 +21,7 @@ import com.google.protobuf.Message; import com.google.protobuf.TextFormat; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ExecutionException; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -47,6 +48,15 @@ public static Matcher isSpannerException(ErrorCode code return new SpannerExceptionMatcher<>(code); } + /** + * Returns a method that checks that a {@link Throwable} is an {@link ExecutionException} where + * the cause is a {@link SpannerException} with an error code to {@code code}. + */ + public static Matcher isExecutionExceptionWithSpannerCause( + ErrorCode code) { + return new ExecutionExceptionWithSpannerCauseMatcher<>(code); + } + private static class ProtoTextMatcher extends BaseMatcher { private final T expected; @@ -110,4 +120,31 @@ public void describeTo(Description description) { description.appendText("SpannerException[" + expectedCode + "]"); } } + + private static class ExecutionExceptionWithSpannerCauseMatcher + extends BaseMatcher { + private final ErrorCode expectedCode; + + ExecutionExceptionWithSpannerCauseMatcher(ErrorCode expectedCode) { + this.expectedCode = checkNotNull(expectedCode); + } + + @Override + public boolean matches(Object item) { + if (!(item instanceof ExecutionException)) { + return false; + } + ExecutionException ee = (ExecutionException) item; + if (!(ee.getCause() instanceof SpannerException)) { + return false; + } + SpannerException e = (SpannerException) ee.getCause(); + return e.getErrorCode() == expectedCode; + } + + @Override + public void describeTo(Description description) { + description.appendText("ExecutionException[SpannerException[" + expectedCode + "]]"); + } + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java index ba569653c3..38aa66516e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionManagerImplTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; +import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; import com.google.cloud.Timestamp; import com.google.cloud.grpc.GrpcTransportOptions; @@ -38,6 +39,7 @@ import com.google.spanner.v1.CommitRequest; import com.google.spanner.v1.CommitResponse; import com.google.spanner.v1.Transaction; +import io.opencensus.trace.Span; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -75,7 +77,7 @@ public void release(ScheduledExecutorService exec) { @Before public void setUp() { initMocks(this); - manager = new TransactionManagerImpl(session); + manager = new TransactionManagerImpl(session, mock(Span.class)); } @Test @@ -246,26 +248,29 @@ public List answer(InvocationOnMock invocation) { .build()); } }); - when(rpc.beginTransaction(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap())) + when(rpc.beginTransactionAsync(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap())) .thenAnswer( - new Answer() { + new Answer>() { @Override - public Transaction answer(InvocationOnMock invocation) { - return Transaction.newBuilder() - .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) - .build(); + public ApiFuture answer(InvocationOnMock invocation) { + return ApiFutures.immediateFuture( + Transaction.newBuilder() + .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) + .build()); } }); - when(rpc.commit(Mockito.any(CommitRequest.class), Mockito.anyMap())) + when(rpc.commitAsync(Mockito.any(CommitRequest.class), Mockito.anyMap())) .thenAnswer( - new Answer() { + new Answer>() { @Override - public CommitResponse answer(InvocationOnMock invocation) { - return CommitResponse.newBuilder() - .setCommitTimestamp( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(System.currentTimeMillis() * 1000)) - .build(); + public ApiFuture answer(InvocationOnMock invocation) + throws Throwable { + return ApiFutures.immediateFuture( + CommitResponse.newBuilder() + .setCommitTimestamp( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(System.currentTimeMillis() * 1000)) + .build()); } }); DatabaseId db = DatabaseId.of("test", "test", "test"); @@ -276,7 +281,7 @@ public CommitResponse answer(InvocationOnMock invocation) { mgr.commit(); } verify(rpc, times(1)) - .beginTransaction(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap()); + .beginTransactionAsync(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap()); } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java index 074f0a905c..d61c89300f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TransactionRunnerImplTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; import com.google.cloud.grpc.GrpcTransportOptions; import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory; @@ -50,6 +51,7 @@ import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.protobuf.ProtoUtils; +import io.opencensus.trace.Span; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -95,6 +97,13 @@ public void setUp() { firstRun = true; when(session.newTransaction()).thenReturn(txn); transactionRunner = new TransactionRunnerImpl(session, rpc, 1); + when(rpc.commitAsync(Mockito.any(CommitRequest.class), Mockito.anyMap())) + .thenReturn( + ApiFutures.immediateFuture( + CommitResponse.newBuilder() + .setCommitTimestamp(Timestamp.getDefaultInstance()) + .build())); + transactionRunner.setSpan(mock(Span.class)); } @SuppressWarnings("unchecked") @@ -126,25 +135,28 @@ public List answer(InvocationOnMock invocation) { .build()); } }); - when(rpc.beginTransaction(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap())) + when(rpc.beginTransactionAsync(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap())) .thenAnswer( - new Answer() { + new Answer>() { @Override - public Transaction answer(InvocationOnMock invocation) { - return Transaction.newBuilder() - .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) - .build(); + public ApiFuture answer(InvocationOnMock invocation) { + return ApiFutures.immediateFuture( + Transaction.newBuilder() + .setId(ByteString.copyFromUtf8(UUID.randomUUID().toString())) + .build()); } }); - when(rpc.commit(Mockito.any(CommitRequest.class), Mockito.anyMap())) + when(rpc.commitAsync(Mockito.any(CommitRequest.class), Mockito.anyMap())) .thenAnswer( - new Answer() { + new Answer>() { @Override - public CommitResponse answer(InvocationOnMock invocation) { - return CommitResponse.newBuilder() - .setCommitTimestamp( - Timestamp.newBuilder().setSeconds(System.currentTimeMillis() * 1000)) - .build(); + public ApiFuture answer(InvocationOnMock invocation) + throws Throwable { + return ApiFutures.immediateFuture( + CommitResponse.newBuilder() + .setCommitTimestamp( + Timestamp.newBuilder().setSeconds(System.currentTimeMillis() * 1000)) + .build()); } }); DatabaseId db = DatabaseId.of("test", "test", "test"); @@ -160,7 +172,7 @@ public Void run(TransactionContext transaction) { } }); verify(rpc, times(1)) - .beginTransaction(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap()); + .beginTransactionAsync(Mockito.any(BeginTransactionRequest.class), Mockito.anyMap()); } } @@ -272,10 +284,12 @@ private long[] batchDmlException(int status) { .setRpc(rpc) .build(); when(session.newTransaction()).thenReturn(transaction); - when(session.beginTransaction()) - .thenReturn(ByteString.copyFromUtf8(UUID.randomUUID().toString())); + when(session.beginTransactionAsync()) + .thenReturn( + ApiFutures.immediateFuture(ByteString.copyFromUtf8(UUID.randomUUID().toString()))); when(session.getName()).thenReturn(SessionId.of("p", "i", "d", "test").getName()); TransactionRunnerImpl runner = new TransactionRunnerImpl(session, rpc, 10); + runner.setSpan(mock(Span.class)); ExecuteBatchDmlResponse response1 = ExecuteBatchDmlResponse.newBuilder() .addResultSets( @@ -300,7 +314,8 @@ private long[] batchDmlException(int status) { .thenReturn(response1, response2); CommitResponse commitResponse = CommitResponse.newBuilder().setCommitTimestamp(Timestamp.getDefaultInstance()).build(); - when(rpc.commit(Mockito.any(CommitRequest.class), Mockito.anyMap())).thenReturn(commitResponse); + when(rpc.commitAsync(Mockito.any(CommitRequest.class), Mockito.anyMap())) + .thenReturn(ApiFutures.immediateFuture(commitResponse)); final Statement statement = Statement.of("UPDATE FOO SET BAR=1"); final AtomicInteger numCalls = new AtomicInteger(0); long updateCount[] = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java index aac55bd9f8..118f596c86 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadOnlyTransactionTest.java @@ -26,7 +26,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.api.core.ApiFuture; import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncResultSet; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Key; @@ -131,6 +133,34 @@ public void close() {} public Timestamp getReadTimestamp() { return readTimestamp; } + + @Override + public AsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + return null; + } + + @Override + public AsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + return null; + } + + @Override + public ApiFuture readRowAsync(String table, Key key, Iterable columns) { + return null; + } + + @Override + public ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + return null; + } + + @Override + public AsyncResultSet executeQueryAsync(Statement statement, QueryOption... options) { + return null; + } } private ReadOnlyTransaction createSubject() { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java index 27ee1903fa..e73eb8e0b2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SingleUseTransactionTest.java @@ -24,8 +24,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.google.api.core.ApiFuture; import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.Timestamp; +import com.google.cloud.spanner.AsyncResultSet; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Key; @@ -230,6 +232,34 @@ public void close() {} public Timestamp getReadTimestamp() { return readTimestamp; } + + @Override + public AsyncResultSet readAsync( + String table, KeySet keys, Iterable columns, ReadOption... options) { + return null; + } + + @Override + public AsyncResultSet readUsingIndexAsync( + String table, String index, KeySet keys, Iterable columns, ReadOption... options) { + return null; + } + + @Override + public ApiFuture readRowAsync(String table, Key key, Iterable columns) { + return null; + } + + @Override + public ApiFuture readRowUsingIndexAsync( + String table, String index, Key key, Iterable columns) { + return null; + } + + @Override + public AsyncResultSet executeQueryAsync(Statement statement, QueryOption... options) { + return null; + } } private DdlClient createDefaultMockDdlClient() { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncAPITest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncAPITest.java new file mode 100644 index 0000000000..a2239aa3b9 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncAPITest.java @@ -0,0 +1,309 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.it; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; + +import com.google.api.core.ApiFuture; +import com.google.cloud.spanner.AsyncResultSet; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.AsyncRunner; +import com.google.cloud.spanner.AsyncRunner.AsyncWork; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.ErrorCode; +import com.google.cloud.spanner.IntegrationTest; +import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeyRange; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.Mutation; +import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.Struct; +import com.google.cloud.spanner.TimestampBound; +import com.google.cloud.spanner.TransactionContext; +import com.google.cloud.spanner.Type; +import com.google.cloud.spanner.Type.StructField; +import com.google.cloud.spanner.testing.RemoteSpannerHelper; +import com.google.common.util.concurrent.SettableFuture; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Integration tests for asynchronous APIs. */ +@Category(IntegrationTest.class) +@RunWith(JUnit4.class) +public class ITAsyncAPITest { + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static final String TABLE_NAME = "TestTable"; + private static final String INDEX_NAME = "TestTableByValue"; + private static final List ALL_COLUMNS = Arrays.asList("Key", "StringValue"); + private static final Type TABLE_TYPE = + Type.struct( + StructField.of("Key", Type.string()), StructField.of("StringValue", Type.string())); + + private static Database db; + private static DatabaseClient client; + private static ExecutorService executor; + + @BeforeClass + public static void setUpDatabase() { + db = + env.getTestHelper() + .createTestDatabase( + "CREATE TABLE TestTable (" + + " Key STRING(MAX) NOT NULL," + + " StringValue STRING(MAX)," + + ") PRIMARY KEY (Key)", + "CREATE INDEX TestTableByValue ON TestTable(StringValue)", + "CREATE INDEX TestTableByValueDesc ON TestTable(StringValue DESC)"); + client = env.getTestHelper().getDatabaseClient(db); + + // Includes k0..k14. Note that strings k{10,14} sort between k1 and k2. + List mutations = new ArrayList<>(); + for (int i = 0; i < 15; ++i) { + mutations.add( + Mutation.newInsertOrUpdateBuilder(TABLE_NAME) + .set("Key") + .to("k" + i) + .set("StringValue") + .to("v" + i) + .build()); + } + client.write(mutations); + executor = Executors.newSingleThreadExecutor(); + } + + @AfterClass + public static void cleanup() { + executor.shutdown(); + } + + @Test + public void emptyReadAsync() throws Exception { + final SettableFuture result = SettableFuture.create(); + AsyncResultSet resultSet = + client + .singleUse(TimestampBound.strong()) + .readAsync( + TABLE_NAME, + KeySet.range(KeyRange.closedOpen(Key.of("k99"), Key.of("z"))), + ALL_COLUMNS); + resultSet.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case OK: + fail("received unexpected data"); + case NOT_READY: + return CallbackResponse.CONTINUE; + case DONE: + assertThat(resultSet.getType()).isEqualTo(TABLE_TYPE); + result.set(true); + return CallbackResponse.DONE; + } + } + } catch (Throwable t) { + result.setException(t); + return CallbackResponse.DONE; + } + } + }); + assertThat(result.get()).isTrue(); + } + + @Test + public void indexEmptyReadAsync() throws Exception { + final SettableFuture result = SettableFuture.create(); + AsyncResultSet resultSet = + client + .singleUse(TimestampBound.strong()) + .readUsingIndexAsync( + TABLE_NAME, + INDEX_NAME, + KeySet.range(KeyRange.closedOpen(Key.of("v99"), Key.of("z"))), + ALL_COLUMNS); + resultSet.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case OK: + fail("received unexpected data"); + case NOT_READY: + return CallbackResponse.CONTINUE; + case DONE: + assertThat(resultSet.getType()).isEqualTo(TABLE_TYPE); + result.set(true); + return CallbackResponse.DONE; + } + } + } catch (Throwable t) { + result.setException(t); + return CallbackResponse.DONE; + } + } + }); + assertThat(result.get()).isTrue(); + } + + @Test + public void pointReadAsync() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync(TABLE_NAME, Key.of("k1"), ALL_COLUMNS); + assertThat(row.get()).isNotNull(); + assertThat(row.get().getString(0)).isEqualTo("k1"); + assertThat(row.get().getString(1)).isEqualTo("v1"); + // Ensure that the Struct implementation supports equality properly. + assertThat(row.get()) + .isEqualTo(Struct.newBuilder().set("Key").to("k1").set("StringValue").to("v1").build()); + } + + @Test + public void indexPointReadAsync() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowUsingIndexAsync(TABLE_NAME, INDEX_NAME, Key.of("v1"), ALL_COLUMNS); + assertThat(row.get()).isNotNull(); + assertThat(row.get().getString(0)).isEqualTo("k1"); + assertThat(row.get().getString(1)).isEqualTo("v1"); + } + + @Test + public void pointReadNotFound() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync(TABLE_NAME, Key.of("k999"), ALL_COLUMNS); + assertThat(row.get()).isNull(); + } + + @Test + public void indexPointReadNotFound() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowUsingIndexAsync(TABLE_NAME, INDEX_NAME, Key.of("v999"), ALL_COLUMNS); + assertThat(row.get()).isNull(); + } + + @Test + public void invalidDatabase() throws Exception { + RemoteSpannerHelper helper = env.getTestHelper(); + DatabaseClient invalidClient = + helper.getClient().getDatabaseClient(DatabaseId.of(helper.getInstanceId(), "invalid")); + ApiFuture row = + invalidClient + .singleUse(TimestampBound.strong()) + .readRowAsync(TABLE_NAME, Key.of("k99"), ALL_COLUMNS); + try { + row.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + } + } + + @Test + public void tableNotFound() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync("BadTableName", Key.of("k1"), ALL_COLUMNS); + try { + row.get(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(se.getMessage()).contains("BadTableName"); + } + } + + @Test + public void columnNotFound() throws Exception { + ApiFuture row = + client + .singleUse(TimestampBound.strong()) + .readRowAsync(TABLE_NAME, Key.of("k1"), Arrays.asList("Key", "BadColumnName")); + try { + row.get(); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.NOT_FOUND); + assertThat(se.getMessage()).contains("BadColumnName"); + } + } + + @Test + public void asyncRunnerFireAndForgetInvalidUpdate() throws Exception { + assumeFalse( + "errors in read/write transactions on emulator are sticky", + env.getTestHelper().isEmulator()); + try { + assertThat(client.singleUse().readRow("TestTable", Key.of("k999"), ALL_COLUMNS)).isNull(); + AsyncRunner runner = client.runAsync(); + ApiFuture res = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + // The error returned by this update statement will not bubble up and fail the + // transaction. + txn.executeUpdateAsync(Statement.of("UPDATE BadTableName SET FOO=1 WHERE ID=2")); + return txn.executeUpdateAsync( + Statement.of( + "INSERT INTO TestTable (Key, StringValue) VALUES ('k999', 'v999')")); + } + }, + executor); + assertThat(res.get()).isEqualTo(1L); + assertThat(client.singleUse().readRow("TestTable", Key.of("k999"), ALL_COLUMNS)).isNotNull(); + } finally { + client.writeAtLeastOnce(Arrays.asList(Mutation.delete("TestTable", Key.of("k999")))); + assertThat(client.singleUse().readRow("TestTable", Key.of("k999"), ALL_COLUMNS)).isNull(); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java new file mode 100644 index 0000000000..c5e2419ba6 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java @@ -0,0 +1,550 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.it; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.SettableApiFuture; +import com.google.cloud.spanner.AsyncResultSet; +import com.google.cloud.spanner.AsyncResultSet.CallbackResponse; +import com.google.cloud.spanner.AsyncResultSet.ReadyCallback; +import com.google.cloud.spanner.AsyncRunner; +import com.google.cloud.spanner.AsyncRunner.AsyncWork; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.ErrorCode; +import com.google.cloud.spanner.IntegrationTest; +import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.Mutation; +import com.google.cloud.spanner.ReadOnlyTransaction; +import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.Struct; +import com.google.cloud.spanner.StructReader; +import com.google.cloud.spanner.TransactionContext; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Integration tests for asynchronous APIs. */ +@Category(IntegrationTest.class) +@RunWith(JUnit4.class) +public class ITAsyncExamplesTest { + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static final String TABLE_NAME = "TestTable"; + private static final String INDEX_NAME = "TestTableByValue"; + private static final List ALL_COLUMNS = Arrays.asList("Key", "StringValue"); + private static final ImmutableList ALL_VALUES_IN_PK_ORDER = + ImmutableList.of( + "v0", "v1", "v10", "v11", "v12", "v13", "v14", "v2", "v3", "v4", "v5", "v6", "v7", "v8", + "v9"); + + private static Database db; + private static DatabaseClient client; + private static ExecutorService executor; + + @BeforeClass + public static void setUpDatabase() { + db = + env.getTestHelper() + .createTestDatabase( + "CREATE TABLE TestTable (" + + " Key STRING(MAX) NOT NULL," + + " StringValue STRING(MAX)," + + ") PRIMARY KEY (Key)", + "CREATE INDEX TestTableByValue ON TestTable(StringValue)", + "CREATE INDEX TestTableByValueDesc ON TestTable(StringValue DESC)"); + client = env.getTestHelper().getDatabaseClient(db); + + // Includes k0..k14. Note that strings k{10,14} sort between k1 and k2. + List mutations = new ArrayList<>(); + for (int i = 0; i < 15; ++i) { + mutations.add( + Mutation.newInsertOrUpdateBuilder(TABLE_NAME) + .set("Key") + .to("k" + i) + .set("StringValue") + .to("v" + i) + .build()); + } + client.write(mutations); + executor = Executors.newScheduledThreadPool(8); + } + + @AfterClass + public static void cleanup() { + executor.shutdown(); + } + + @Test + public void readAsync() throws Exception { + final SettableApiFuture> future = SettableApiFuture.create(); + try (AsyncResultSet rs = client.singleUse().readAsync(TABLE_NAME, KeySet.all(), ALL_COLUMNS)) { + rs.setCallback( + executor, + new ReadyCallback() { + final List values = new LinkedList<>(); + + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + future.set(values); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + values.add(resultSet.getString("StringValue")); + break; + } + } + } catch (Throwable t) { + future.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + assertThat(future.get()).containsExactlyElementsIn(ALL_VALUES_IN_PK_ORDER); + } + + @Test + public void readUsingIndexAsync() throws Exception { + final SettableApiFuture> future = SettableApiFuture.create(); + try (AsyncResultSet rs = + client.singleUse().readUsingIndexAsync(TABLE_NAME, INDEX_NAME, KeySet.all(), ALL_COLUMNS)) { + rs.setCallback( + executor, + new ReadyCallback() { + final List values = new LinkedList<>(); + + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + future.set(values); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + values.add(resultSet.getString("StringValue")); + break; + } + } + } catch (Throwable t) { + future.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + assertThat(future.get()).containsExactlyElementsIn(ALL_VALUES_IN_PK_ORDER); + } + + @Test + public void readRowAsync() throws Exception { + ApiFuture row = client.singleUse().readRowAsync(TABLE_NAME, Key.of("k1"), ALL_COLUMNS); + assertThat(row.get().getString("StringValue")).isEqualTo("v1"); + } + + @Test + public void readRowUsingIndexAsync() throws Exception { + ApiFuture row = + client + .singleUse() + .readRowUsingIndexAsync(TABLE_NAME, INDEX_NAME, Key.of("v2"), ALL_COLUMNS); + assertThat(row.get().getString("Key")).isEqualTo("k2"); + } + + @Test + public void executeQueryAsync() throws Exception { + final ImmutableList keys = ImmutableList.of("k3", "k4"); + final SettableApiFuture> future = SettableApiFuture.create(); + try (AsyncResultSet rs = + client + .singleUse() + .executeQueryAsync( + Statement.newBuilder("SELECT StringValue FROM TestTable WHERE Key IN UNNEST(@keys)") + .bind("keys") + .toStringArray(keys) + .build())) { + rs.setCallback( + executor, + new ReadyCallback() { + final List values = new LinkedList<>(); + + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + future.set(values); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + values.add(resultSet.getString("StringValue")); + break; + } + } + } catch (Throwable t) { + future.setException(t); + return CallbackResponse.DONE; + } + } + }); + } + assertThat(future.get()).containsExactly("v3", "v4"); + } + + @Test + public void runAsync() throws Exception { + AsyncRunner runner = client.runAsync(); + ApiFuture insertCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + // Even though this is a shoot-and-forget asynchronous DML statement, it is + // guaranteed to be executed within the transaction before the commit is executed. + return txn.executeUpdateAsync( + Statement.newBuilder( + "INSERT INTO TestTable (Key, StringValue) VALUES (@key, @value)") + .bind("key") + .to("k999") + .bind("value") + .to("v999") + .build()); + } + }, + executor); + assertThat(insertCount.get()).isEqualTo(1L); + ApiFuture deleteCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.executeUpdateAsync( + Statement.newBuilder("DELETE FROM TestTable WHERE Key=@key") + .bind("key") + .to("k999") + .build()); + } + }, + executor); + assertThat(deleteCount.get()).isEqualTo(1L); + } + + @Test + public void runAsyncBatchUpdate() throws Exception { + AsyncRunner runner = client.runAsync(); + ApiFuture insertCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + // Even though this is a shoot-and-forget asynchronous DML statement, it is + // guaranteed to be executed within the transaction before the commit is executed. + return txn.batchUpdateAsync( + ImmutableList.of( + Statement.newBuilder( + "INSERT INTO TestTable (Key, StringValue) VALUES (@key, @value)") + .bind("key") + .to("k997") + .bind("value") + .to("v997") + .build(), + Statement.newBuilder( + "INSERT INTO TestTable (Key, StringValue) VALUES (@key, @value)") + .bind("key") + .to("k998") + .bind("value") + .to("v998") + .build(), + Statement.newBuilder( + "INSERT INTO TestTable (Key, StringValue) VALUES (@key, @value)") + .bind("key") + .to("k999") + .bind("value") + .to("v999") + .build())); + } + }, + executor); + assertThat(insertCount.get()).asList().containsExactly(1L, 1L, 1L); + ApiFuture deleteCount = + runner.runAsync( + new AsyncWork() { + @Override + public ApiFuture doWorkAsync(TransactionContext txn) { + return txn.batchUpdateAsync( + ImmutableList.of( + Statement.newBuilder("DELETE FROM TestTable WHERE Key=@key") + .bind("key") + .to("k997") + .build(), + Statement.newBuilder("DELETE FROM TestTable WHERE Key=@key") + .bind("key") + .to("k998") + .build(), + Statement.newBuilder("DELETE FROM TestTable WHERE Key=@key") + .bind("key") + .to("k999") + .build())); + } + }, + executor); + assertThat(deleteCount.get()).asList().containsExactly(1L, 1L, 1L); + } + + @Test + public void readOnlyTransaction() throws Exception { + ImmutableList keys1 = ImmutableList.of("k10", "k11", "k12"); + ImmutableList keys2 = ImmutableList.of("k1", "k2", "k3"); + ApiFuture> values1; + ApiFuture> values2; + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (AsyncResultSet rs = + tx.executeQueryAsync( + Statement.newBuilder("SELECT * FROM TestTable WHERE Key IN UNNEST(@keys)") + .bind("keys") + .toStringArray(keys1) + .build())) { + values1 = + rs.toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("StringValue"); + } + }, + executor); + } + try (AsyncResultSet rs = + tx.executeQueryAsync( + Statement.newBuilder("SELECT * FROM TestTable WHERE Key IN UNNEST(@keys)") + .bind("keys") + .toStringArray(keys2) + .build())) { + values2 = + rs.toListAsync( + new Function() { + @Override + public String apply(StructReader input) { + return input.getString("StringValue"); + } + }, + executor); + } + } + ApiFuture> allValues = + ApiFutures.transform( + ApiFutures.allAsList(Arrays.asList(values1, values2)), + new ApiFunction>, Iterable>() { + @Override + public Iterable apply(List> input) { + return Iterables.mergeSorted( + input, + new Comparator() { + @Override + public int compare(String o1, String o2) { + // Compare based on numerical order (i.e. without the preceding 'v'). + return Integer.valueOf(o1.substring(1)) + .compareTo(Integer.valueOf(o2.substring(1))); + } + }); + } + }, + executor); + assertThat(allValues.get()).containsExactly("v1", "v2", "v3", "v10", "v11", "v12"); + } + + @Test + public void pauseResume() throws Exception { + Statement unevenStatement = + Statement.of( + "SELECT * FROM TestTable WHERE MOD(CAST(SUBSTR(Key, 2) AS INT64), 2) = 1 ORDER BY CAST(SUBSTR(Key, 2) AS INT64)"); + Statement evenStatement = + Statement.of( + "SELECT * FROM TestTable WHERE MOD(CAST(SUBSTR(Key, 2) AS INT64), 2) = 0 ORDER BY CAST(SUBSTR(Key, 2) AS INT64)"); + + final Object lock = new Object(); + final SettableApiFuture evenFinished = SettableApiFuture.create(); + final SettableApiFuture unevenFinished = SettableApiFuture.create(); + final CountDownLatch evenReturnedFirstRow = new CountDownLatch(1); + final Deque allValues = new LinkedList<>(); + try (ReadOnlyTransaction tx = client.readOnlyTransaction()) { + try (AsyncResultSet evenRs = tx.executeQueryAsync(evenStatement); + AsyncResultSet unevenRs = tx.executeQueryAsync(unevenStatement)) { + evenRs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + evenFinished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + synchronized (lock) { + allValues.add(resultSet.getString("StringValue")); + } + evenReturnedFirstRow.countDown(); + return CallbackResponse.PAUSE; + } + } + } catch (Throwable t) { + evenFinished.setException(t); + return CallbackResponse.DONE; + } + } + }); + + unevenRs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + // Make sure the even result set has returned the first before we start the uneven + // results. + evenReturnedFirstRow.await(); + while (true) { + switch (resultSet.tryNext()) { + case DONE: + unevenFinished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + synchronized (lock) { + allValues.add(resultSet.getString("StringValue")); + } + return CallbackResponse.PAUSE; + } + } + } catch (Throwable t) { + unevenFinished.setException(t); + return CallbackResponse.DONE; + } + } + }); + while (!(evenFinished.isDone() && unevenFinished.isDone())) { + synchronized (lock) { + if (allValues.peekLast() != null) { + if (Integer.valueOf(allValues.peekLast().substring(1)) % 2 == 1) { + evenRs.resume(); + } else { + unevenRs.resume(); + } + } + if (allValues.size() == 15) { + unevenRs.resume(); + evenRs.resume(); + } + } + } + } + } + assertThat(ApiFutures.allAsList(Arrays.asList(evenFinished, unevenFinished)).get()) + .containsExactly(Boolean.TRUE, Boolean.TRUE); + assertThat(allValues) + .containsExactly( + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", + "v14"); + } + + @Test + public void cancel() throws Exception { + final List values = new LinkedList<>(); + final SettableApiFuture finished = SettableApiFuture.create(); + final CountDownLatch receivedFirstRow = new CountDownLatch(1); + final CountDownLatch cancelled = new CountDownLatch(1); + try (AsyncResultSet rs = client.singleUse().readAsync(TABLE_NAME, KeySet.all(), ALL_COLUMNS)) { + rs.setCallback( + executor, + new ReadyCallback() { + @Override + public CallbackResponse cursorReady(AsyncResultSet resultSet) { + try { + while (true) { + switch (resultSet.tryNext()) { + case DONE: + finished.set(true); + return CallbackResponse.DONE; + case NOT_READY: + return CallbackResponse.CONTINUE; + case OK: + values.add(resultSet.getString("StringValue")); + receivedFirstRow.countDown(); + cancelled.await(); + break; + } + } + } catch (Throwable t) { + finished.setException(t); + return CallbackResponse.DONE; + } + } + }); + receivedFirstRow.await(); + rs.cancel(); + } + cancelled.countDown(); + try { + finished.get(); + fail("missing expected exception"); + } catch (ExecutionException e) { + assertThat(e.getCause()).isInstanceOf(SpannerException.class); + SpannerException se = (SpannerException) e.getCause(); + assertThat(se.getErrorCode()).isEqualTo(ErrorCode.CANCELLED); + assertThat(values).containsExactly("v0"); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java index fda120bff6..450c7463c5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITDatabaseTest.java @@ -146,6 +146,7 @@ public void instanceNotFound() { .getClient() .getDatabaseClient(DatabaseId.of(nonExistingInstanceId, "some-db")); try (ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1"))) { + rs.next(); fail("missing expected exception"); } catch (InstanceNotFoundException e) { assertThat(e.getResourceName()).isEqualTo(nonExistingInstanceId.getName()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java index a52a108151..db68b5ec88 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadOnlyTxnTest.java @@ -310,9 +310,12 @@ public void multiReadTimestamp() { @Test public void multiMinReadTimestamp() { // Cannot use bounded modes with multi-read transactions. - try { - client.readOnlyTransaction(TimestampBound.ofMinReadTimestamp(history.get(2).timestamp)); - fail("Expected exception"); + try (ReadOnlyTransaction tx = + client.readOnlyTransaction(TimestampBound.ofMinReadTimestamp(history.get(2).timestamp))) { + try (ResultSet rs = tx.executeQuery(Statement.of("SELECT 1"))) { + rs.next(); + fail("Expected exception"); + } } catch (IllegalArgumentException ex) { assertNotNull(ex.getMessage()); } @@ -341,9 +344,12 @@ public void multiExactStaleness() { @Test public void multiMaxStaleness() { // Cannot use bounded modes with multi-read transactions. - try { - client.readOnlyTransaction(TimestampBound.ofMaxStaleness(1, TimeUnit.SECONDS)); - fail("Expected exception"); + try (ReadOnlyTransaction tx = + client.readOnlyTransaction(TimestampBound.ofMaxStaleness(1, TimeUnit.SECONDS))) { + try (ResultSet rs = tx.executeQuery(Statement.of("SELECT 1"))) { + rs.next(); + fail("Expected exception"); + } } catch (IllegalArgumentException ex) { assertNotNull(ex.getMessage()); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java index 4682ddd1ec..87c9e0ae3f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITReadTest.java @@ -358,6 +358,7 @@ public void run() { try { work.run(); + fail("missing expected exception"); } catch (SpannerException e) { MatcherAssert.assertThat(e, isSpannerException(ErrorCode.CANCELLED)); } @@ -381,6 +382,7 @@ public void run() { try { work.run(); + fail("missing expected exception"); } catch (SpannerException e) { MatcherAssert.assertThat(e, isSpannerException(ErrorCode.DEADLINE_EXCEEDED)); } finally { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerAsyncTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerAsyncTest.java new file mode 100644 index 0000000000..c802493dec --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionManagerAsyncTest.java @@ -0,0 +1,318 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.it; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.cloud.spanner.AbortedException; +import com.google.cloud.spanner.AsyncTransactionManager; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionFunction; +import com.google.cloud.spanner.AsyncTransactionManager.AsyncTransactionStep; +import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.ErrorCode; +import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.Mutation; +import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.Struct; +import com.google.cloud.spanner.TransactionContext; +import com.google.cloud.spanner.TransactionManager.TransactionState; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.MoreExecutors; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ITTransactionManagerAsyncTest { + + @Parameter public Executor executor; + + @Parameters(name = "executor = {0}") + public static Collection data() { + return Arrays.asList( + new Object[][] { + {MoreExecutors.directExecutor()}, + {Executors.newSingleThreadExecutor()}, + {Executors.newFixedThreadPool(4)} + }); + } + + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static Database db; + private static DatabaseClient client; + + @BeforeClass + public static void setUpDatabase() { + // Empty database. + db = + env.getTestHelper() + .createTestDatabase( + "CREATE TABLE T (" + + " K STRING(MAX) NOT NULL," + + " BoolValue BOOL," + + ") PRIMARY KEY (K)"); + client = env.getTestHelper().getDatabaseClient(db); + } + + @Before + public void clearTable() { + client.write(ImmutableList.of(Mutation.delete("T", KeySet.all()))); + } + + @Test + public void testSimpleInsert() throws ExecutionException, InterruptedException { + try (AsyncTransactionManager manager = client.transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + assertThat(manager.getState()).isEqualTo(TransactionState.STARTED); + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + txn.buffer( + Mutation.newInsertBuilder("T") + .set("K") + .to("Key1") + .set("BoolValue") + .to(true) + .build()); + return ApiFutures.immediateFuture(null); + } + }, + executor) + .commitAsync() + .get(); + assertThat(manager.getState()).isEqualTo(TransactionState.COMMITTED); + Struct row = + client.singleUse().readRow("T", Key.of("Key1"), Arrays.asList("K", "BoolValue")); + assertThat(row.getString(0)).isEqualTo("Key1"); + assertThat(row.getBoolean(1)).isTrue(); + break; + } catch (AbortedException e) { + Thread.sleep(e.getRetryDelayInMillis() / 1000); + txn = manager.resetForRetryAsync(); + } + } + } + } + + @Test + public void testInvalidInsert() throws InterruptedException { + try (AsyncTransactionManager manager = client.transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + try { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + txn.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() / 1000); + 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()); + } + } + } + + @Test + public void testRollback() throws InterruptedException { + try (AsyncTransactionManager manager = client.transactionManagerAsync()) { + TransactionContextFuture txn = manager.beginAsync(); + while (true) { + txn.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) throws Exception { + txn.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() / 1000); + 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(); + } + } + + @Test + public void testAbortAndRetry() throws InterruptedException, ExecutionException { + assumeFalse( + "Emulator does not support more than 1 simultanous transaction. " + + "This test would therefore loop indefinetly on the emulator.", + env.getTestHelper().isEmulator()); + + client.write( + Arrays.asList( + 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 txn2Step1; + while (true) { + try { + AsyncTransactionStep txn1Step1 = + txn1.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + return txn.readRowAsync("T", Key.of("Key3"), Arrays.asList("K", "BoolValue")); + } + }, + executor); + manager2 = client.transactionManagerAsync(); + txn2 = manager2.beginAsync(); + txn2Step1 = + txn2.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) + throws Exception { + return txn.readRowAsync("T", Key.of("Key3"), Arrays.asList("K", "BoolValue")); + } + }, + executor); + + AsyncTransactionStep txn1Step2 = + txn1Step1.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Struct input) + throws Exception { + txn.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() / 1000); + // It is possible that it was txn2 that aborted. + // 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 txn2Step2 = + txn2.then( + new AsyncTransactionFunction() { + @Override + public ApiFuture apply(TransactionContext txn, Void input) throws Exception { + txn.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(); + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java index a05029ad99..5e3c1483e7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java @@ -477,7 +477,12 @@ public void nestedSingleUseReadTxnThrows() { new TransactionCallable() { @Override public Void run(TransactionContext transaction) throws SpannerException { - client.singleUseReadOnlyTransaction(); + try (ResultSet rs = + client + .singleUseReadOnlyTransaction() + .executeQuery(Statement.of("SELECT 1"))) { + rs.next(); + } return null; } diff --git a/versions.txt b/versions.txt index ba2b2e5e35..0d5258a9ce 100644 --- a/versions.txt +++ b/versions.txt @@ -7,4 +7,4 @@ proto-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 grpc-google-cloud-spanner-v1:1.57.0:1.57.0 grpc-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.0 grpc-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 -google-cloud-spanner:1.57.0:1.57.0 \ No newline at end of file +google-cloud-spanner:1.57.0:1.57.0 From 3d6fb9fd7dc6b2b5b2ff9935228701ac795c9167 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 1 Jul 2020 21:03:49 +0200 Subject: [PATCH 32/55] deps: update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.2 (#315) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:google-cloud-shared-dependencies](https://togithub.com/googleapis/java-shared-dependencies) | patch | `0.8.1` -> `0.8.2` | --- ### Release Notes
googleapis/java-shared-dependencies ### [`v0.8.2`](https://togithub.com/googleapis/java-shared-dependencies/blob/master/CHANGELOG.md#​082-httpswwwgithubcomgoogleapisjava-shared-dependenciescomparev081v082-2020-07-01) [Compare Source](https://togithub.com/googleapis/java-shared-dependencies/compare/v0.8.1...v0.8.2)
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 45003534c0..d7f896357f 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ com.google.cloud google-cloud-shared-dependencies - 0.8.1 + 0.8.2 pom import From 122a997681ef10b95dbb036d35d724fe7c5ecf6e Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 2 Jul 2020 01:39:11 +0200 Subject: [PATCH 33/55] chore(deps): update dependency com.google.cloud:google-cloud-spanner to v1.57.0 (#312) --- samples/install-without-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 9267fb1f98..afc346dbbf 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-spanner - 1.56.0 + 1.57.0 From 543373b22336be72b10026fda9f0b55939ab94b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 6 Jul 2020 20:31:04 +0200 Subject: [PATCH 34/55] fix: set default values for streaming retry (#316) --- .../java/com/google/cloud/spanner/AbstractResultSet.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java index 6b0681b588..1dfea318e0 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java @@ -855,8 +855,9 @@ private static ExponentialBackOff newBackOff() { return new ExponentialBackOff.Builder() .setMultiplier(STREAMING_RETRY_SETTINGS.getRetryDelayMultiplier()) .setInitialIntervalMillis( - (int) STREAMING_RETRY_SETTINGS.getInitialRetryDelay().toMillis()) - .setMaxIntervalMillis((int) STREAMING_RETRY_SETTINGS.getMaxRetryDelay().toMillis()) + Math.max(10, (int) STREAMING_RETRY_SETTINGS.getInitialRetryDelay().toMillis())) + .setMaxIntervalMillis( + Math.max(1000, (int) STREAMING_RETRY_SETTINGS.getMaxRetryDelay().toMillis())) .setMaxElapsedTimeMillis(Integer.MAX_VALUE) // Prevent Backoff.STOP from getting returned. .build(); } From 9665f3a1cb6a52578cff90621f41aa7c2d205dee Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2020 20:12:03 +1000 Subject: [PATCH 35/55] chore: release 1.57.1-SNAPSHOT (#313) * updated versions.txt [ci skip] * updated samples/pom.xml [ci skip] * updated samples/snippets/pom.xml [ci skip] * updated samples/install-without-bom/pom.xml [ci skip] * updated google-cloud-spanner-bom/pom.xml [ci skip] * updated google-cloud-spanner/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-v1/pom.xml [ci skip] * updated pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-v1/pom.xml [ci skip] * updated samples/snapshot/pom.xml Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: skuruppu --- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 9e94ad8c5d..b4a0e51096 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.57.0 + 1.57.1-SNAPSHOT pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.57.0 + 1.57.1-SNAPSHOT com.google.cloud google-cloud-spanner test-jar - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 060cb88ced..7387b7f988 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.57.0 + 1.57.1-SNAPSHOT jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index fa9c667359..0466e58f9f 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 07c1cb53eb..43d6cde632 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 7baf5c3120..aa02b3a794 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index d7f896357f..0427a52f3b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.57.0 + 1.57.1-SNAPSHOT Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 49d8cf6b52..fe9066e97e 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.0 + 1.57.1-SNAPSHOT proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 998b7594ec..4905ad643d 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.0 + 1.57.1-SNAPSHOT proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 2ef621ce2c..ae36730387 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.0 + 1.57.1-SNAPSHOT proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 833c082962..380aac49ba 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.57.0 + 1.57.1-SNAPSHOT diff --git a/versions.txt b/versions.txt index 0d5258a9ce..18ea96ec31 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.0 -proto-google-cloud-spanner-v1:1.57.0:1.57.0 -proto-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 -grpc-google-cloud-spanner-v1:1.57.0:1.57.0 -grpc-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.0 -grpc-google-cloud-spanner-admin-database-v1:1.57.0:1.57.0 -google-cloud-spanner:1.57.0:1.57.0 +proto-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.1-SNAPSHOT +proto-google-cloud-spanner-v1:1.57.0:1.57.1-SNAPSHOT +proto-google-cloud-spanner-admin-database-v1:1.57.0:1.57.1-SNAPSHOT +grpc-google-cloud-spanner-v1:1.57.0:1.57.1-SNAPSHOT +grpc-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.1-SNAPSHOT +grpc-google-cloud-spanner-admin-database-v1:1.57.0:1.57.1-SNAPSHOT +google-cloud-spanner:1.57.0:1.57.1-SNAPSHOT \ No newline at end of file From a7378f8a4c5680b8f22fa62a34e11023fbb83061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 7 Jul 2020 12:13:40 +0200 Subject: [PATCH 36/55] tests: skip autocommit timeout test on emulator (#320) --- .../connection/it/ITReadWriteAutocommitSpannerTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java index 928fc8869f..6b85d8b44b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadWriteAutocommitSpannerTest.java @@ -21,6 +21,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.Mutation; @@ -73,6 +74,9 @@ public void test02_WriteMutation() { @Test public void test03_MultipleStatements_WithTimeouts() { + assumeFalse( + "Rolling back a transaction while an update statement is still in flight can cause the transaction to remain active on the emulator", + env.getTestHelper().isEmulator()); try (ITConnection connection = createConnection()) { // do an insert that should succeed assertThat( @@ -91,10 +95,9 @@ public void test03_MultipleStatements_WithTimeouts() { connection.setStatementTimeout(1L, TimeUnit.MILLISECONDS); try { connection.executeUpdate(Statement.of("UPDATE TEST SET NAME='test18' WHERE ID=1000")); + fail("missing expected exception"); } catch (SpannerException e) { - if (e.getErrorCode() != ErrorCode.DEADLINE_EXCEEDED) { - throw e; - } + assertThat(e.getErrorCode(), is(equalTo(ErrorCode.DEADLINE_EXCEEDED))); } // remove the timeout setting connection.clearStatementTimeout(); From 341f1af5f8bd1b579dad3120f34f2c6f817a08b8 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2020 12:58:03 +0000 Subject: [PATCH 37/55] chore: release 1.58.0 (#321) :robot: I have created a release \*beep\* \*boop\* --- ## [1.58.0](https://www.github.com/googleapis/java-spanner/compare/v1.57.0...v1.58.0) (2020-07-07) ### Features * add async api ([#81](https://www.github.com/googleapis/java-spanner/issues/81)) ([462839b](https://www.github.com/googleapis/java-spanner/commit/462839b625e58e235581b8ba10b398e1d222eaaf)) * support setting compression option ([#192](https://www.github.com/googleapis/java-spanner/issues/192)) ([965e95e](https://www.github.com/googleapis/java-spanner/commit/965e95e70ccd9c62abd6513b0011aab136e48e26)) ### Bug Fixes * set default values for streaming retry ([#316](https://www.github.com/googleapis/java-spanner/issues/316)) ([543373b](https://www.github.com/googleapis/java-spanner/commit/543373b22336be72b10026fda9f0b55939ab94b4)) ### Performance Improvements * use streaming RPC for PDML ([#287](https://www.github.com/googleapis/java-spanner/issues/287)) ([df47c13](https://www.github.com/googleapis/java-spanner/commit/df47c13a4c00bdf5e6eafa01bbb64c12a96d7fb8)) ### Dependencies * update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.2 ([#315](https://www.github.com/googleapis/java-spanner/issues/315)) ([3d6fb9f](https://www.github.com/googleapis/java-spanner/commit/3d6fb9fd7dc6b2b5b2ff9935228701ac795c9167)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). --- CHANGELOG.md | 23 +++++++++++++++++++ README.md | 4 ++-- google-cloud-spanner-bom/pom.xml | 18 +++++++-------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++------ 13 files changed, 64 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c172a8492..c5d23b9efa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [1.58.0](https://www.github.com/googleapis/java-spanner/compare/v1.57.0...v1.58.0) (2020-07-07) + + +### Features + +* add async api ([#81](https://www.github.com/googleapis/java-spanner/issues/81)) ([462839b](https://www.github.com/googleapis/java-spanner/commit/462839b625e58e235581b8ba10b398e1d222eaaf)) +* support setting compression option ([#192](https://www.github.com/googleapis/java-spanner/issues/192)) ([965e95e](https://www.github.com/googleapis/java-spanner/commit/965e95e70ccd9c62abd6513b0011aab136e48e26)) + + +### Bug Fixes + +* set default values for streaming retry ([#316](https://www.github.com/googleapis/java-spanner/issues/316)) ([543373b](https://www.github.com/googleapis/java-spanner/commit/543373b22336be72b10026fda9f0b55939ab94b4)) + + +### Performance Improvements + +* use streaming RPC for PDML ([#287](https://www.github.com/googleapis/java-spanner/issues/287)) ([df47c13](https://www.github.com/googleapis/java-spanner/commit/df47c13a4c00bdf5e6eafa01bbb64c12a96d7fb8)) + + +### Dependencies + +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.2 ([#315](https://www.github.com/googleapis/java-spanner/issues/315)) ([3d6fb9f](https://www.github.com/googleapis/java-spanner/commit/3d6fb9fd7dc6b2b5b2ff9935228701ac795c9167)) + ## [1.57.0](https://www.github.com/googleapis/java-spanner/compare/v1.56.0...v1.57.0) (2020-06-29) diff --git a/README.md b/README.md index bb5b4b043b..ec6eed6cb6 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-spanner:1.57.0' +compile 'com.google.cloud:google-cloud-spanner:1.58.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.57.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "1.58.0" ``` [//]: # ({x-version-update-end}) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index b4a0e51096..3cedbfe62b 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.57.1-SNAPSHOT + 1.58.0 pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.cloud google-cloud-spanner - 1.57.1-SNAPSHOT + 1.58.0 com.google.cloud google-cloud-spanner test-jar - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 7387b7f988..13361abf7a 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.57.1-SNAPSHOT + 1.58.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 0466e58f9f..5bf5bc228b 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 43d6cde632..1d3ad4767e 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index aa02b3a794..e7ec2c07b8 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/pom.xml b/pom.xml index 0427a52f3b..0467ead42e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.57.1-SNAPSHOT + 1.58.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 com.google.cloud google-cloud-spanner - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index fe9066e97e..fcbda36e11 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.57.1-SNAPSHOT + 1.58.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 4905ad643d..3327e40234 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.57.1-SNAPSHOT + 1.58.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index ae36730387..264c7126b2 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.57.1-SNAPSHOT + 1.58.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 380aac49ba..c32dd0f8fa 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.57.1-SNAPSHOT + 1.58.0 diff --git a/versions.txt b/versions.txt index 18ea96ec31..06ec98aee5 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.1-SNAPSHOT -proto-google-cloud-spanner-v1:1.57.0:1.57.1-SNAPSHOT -proto-google-cloud-spanner-admin-database-v1:1.57.0:1.57.1-SNAPSHOT -grpc-google-cloud-spanner-v1:1.57.0:1.57.1-SNAPSHOT -grpc-google-cloud-spanner-admin-instance-v1:1.57.0:1.57.1-SNAPSHOT -grpc-google-cloud-spanner-admin-database-v1:1.57.0:1.57.1-SNAPSHOT -google-cloud-spanner:1.57.0:1.57.1-SNAPSHOT \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.0 +proto-google-cloud-spanner-v1:1.58.0:1.58.0 +proto-google-cloud-spanner-admin-database-v1:1.58.0:1.58.0 +grpc-google-cloud-spanner-v1:1.58.0:1.58.0 +grpc-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.0 +grpc-google-cloud-spanner-admin-database-v1:1.58.0:1.58.0 +google-cloud-spanner:1.58.0:1.58.0 \ No newline at end of file From eead88d13c7e70119400b0c60c6583865d71c3ef Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 8 Jul 2020 04:36:03 +0200 Subject: [PATCH 38/55] chore(deps): update dependency com.google.cloud:google-cloud-spanner to v1.58.0 (#322) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:google-cloud-spanner](https://togithub.com/googleapis/java-spanner) | minor | `1.57.0` -> `1.58.0` | --- ### Release Notes
googleapis/java-spanner ### [`v1.58.0`](https://togithub.com/googleapis/java-spanner/blob/master/CHANGELOG.md#​1580-httpswwwgithubcomgoogleapisjava-spannercomparev1570v1580-2020-07-07) [Compare Source](https://togithub.com/googleapis/java-spanner/compare/v1.57.0...v1.58.0) ##### Features - add async api ([#​81](https://www.github.com/googleapis/java-spanner/issues/81)) ([462839b](https://www.github.com/googleapis/java-spanner/commit/462839b625e58e235581b8ba10b398e1d222eaaf)) - support setting compression option ([#​192](https://www.github.com/googleapis/java-spanner/issues/192)) ([965e95e](https://www.github.com/googleapis/java-spanner/commit/965e95e70ccd9c62abd6513b0011aab136e48e26)) ##### Bug Fixes - set default values for streaming retry ([#​316](https://www.github.com/googleapis/java-spanner/issues/316)) ([543373b](https://www.github.com/googleapis/java-spanner/commit/543373b22336be72b10026fda9f0b55939ab94b4)) ##### Performance Improvements - use streaming RPC for PDML ([#​287](https://www.github.com/googleapis/java-spanner/issues/287)) ([df47c13](https://www.github.com/googleapis/java-spanner/commit/df47c13a4c00bdf5e6eafa01bbb64c12a96d7fb8)) ##### Dependencies - update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.2 ([#​315](https://www.github.com/googleapis/java-spanner/issues/315)) ([3d6fb9f](https://www.github.com/googleapis/java-spanner/commit/3d6fb9fd7dc6b2b5b2ff9935228701ac795c9167))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- samples/install-without-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index afc346dbbf..ea47e935d2 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-spanner - 1.57.0 + 1.58.0 From 8cd79e798e95a4c4da0f698aecb9659baa2cb63a Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 9 Jul 2020 15:21:26 +1000 Subject: [PATCH 39/55] test: clean up system-test setup against emulator (#319) * test: change system-test setup against emulator Use Docker image instead of manually downloading the emulator binary and running it. * chore: cleanup unusued script file * fix: use latest version of docker image --- .../integration-tests-against-emulator.sh | 47 ------------------- .../integration-tests-against-emulator.yaml | 12 ++++- 2 files changed, 11 insertions(+), 48 deletions(-) delete mode 100644 .github/workflows/integration-tests-against-emulator.sh diff --git a/.github/workflows/integration-tests-against-emulator.sh b/.github/workflows/integration-tests-against-emulator.sh deleted file mode 100644 index 2125d5f308..0000000000 --- a/.github/workflows/integration-tests-against-emulator.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License.. - -# Fail on any error -set -e - -# Display commands being run -set -x - -export SPANNER_EMULATOR_HOST=localhost:9010 -export GOOGLE_CLOUD_PROJECT=emulator-test-project -echo "Running the Cloud Spanner emulator: $SPANNER_EMULATOR_HOST"; - -# Download the emulator -EMULATOR_VERSION=0.8.0 -wget https://storage.googleapis.com/cloud-spanner-emulator/releases/${EMULATOR_VERSION}/cloud-spanner-emulator_linux_amd64-${EMULATOR_VERSION}.tar.gz -tar zxvf cloud-spanner-emulator_linux_amd64-${EMULATOR_VERSION}.tar.gz -chmod u+x emulator_main - -# Start the emulator -./emulator_main --host_port $SPANNER_EMULATOR_HOST & - -EMULATOR_PID=$! - -# Stop the emulator & clean the environment variable -trap "kill -15 $EMULATOR_PID; unset SPANNER_EMULATOR_HOST; unset GOOGLE_CLOUD_PROJECT; echo \"Cleanup the emulator\";" EXIT - -mvn -B -Dspanner.testenv.instance="" \ - -Penable-integration-tests \ - -DtrimStackTrace=false \ - -Dclirr.skip=true \ - -Denforcer.skip=true \ - -fae \ - verify diff --git a/.github/workflows/integration-tests-against-emulator.yaml b/.github/workflows/integration-tests-against-emulator.yaml index ac27f8e17e..adb38152d1 100644 --- a/.github/workflows/integration-tests-against-emulator.yaml +++ b/.github/workflows/integration-tests-against-emulator.yaml @@ -7,6 +7,14 @@ name: integration-tests-against-emulator jobs: units: runs-on: ubuntu-latest + + services: + emulator: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + - 9020:9020 + steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 @@ -14,6 +22,8 @@ jobs: java-version: 8 - run: java -version - run: .kokoro/build.sh - - run: sh .github/workflows/integration-tests-against-emulator.sh + - run: mvn -B -Dspanner.testenv.instance="" -Penable-integration-tests -DtrimStackTrace=false -Dclirr.skip=true -Denforcer.skip=true -fae verify env: JOB_TYPE: test + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: emulator-test-project From 2b91806f54dce1336125319e2c588d5d1200d83c Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 8 Jul 2020 22:28:02 -0700 Subject: [PATCH 40/55] chore: re-generated to pick up changes from self (#317) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/8f9b2ee6-9eab-4b87-867c-98d5f8fc5313/targets - [ ] To automatically regenerate this PR, check this box. --- README.md | 2 +- synth.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec6eed6cb6..9e47c69bbd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 1.56.0 + 1.57.0 ``` diff --git a/synth.metadata b/synth.metadata index 37d62fcdba..c4d130d795 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "3d479e4ac478b8a46bbb77c74ca0d08876d74db6" + "sha": "122a997681ef10b95dbb036d35d724fe7c5ecf6e" } }, { From 341e6594a7eec7dccdf62a1f1caf2f81e1a05bdb Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 8 Jul 2020 23:06:03 -0700 Subject: [PATCH 41/55] bazel: update protobuf, rules_go, gazelle, and gapic-generator-go versions - protobuf v3.12.1 - rules_go v0.23.0 - gazelle v0.21.0 - gapic-generator-go v0.14.1 (#263) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/e66d5b32-5d3a-4216-853d-260a1b0f526f/targets - [ ] To automatically regenerate this PR, check this box. PiperOrigin-RevId: 313460921 Source-Link: https://github.com/googleapis/googleapis/commit/c4e37010d74071851ff24121f522e802231ac86e --- .../spanner/admin/database/v1/Backup.java | 21 +++++++++ .../spanner/admin/database/v1/BackupInfo.java | 7 +++ .../database/v1/CreateBackupMetadata.java | 10 +++++ .../database/v1/CreateBackupRequest.java | 7 +++ .../database/v1/CreateDatabaseMetadata.java | 2 + .../database/v1/CreateDatabaseRequest.java | 4 ++ .../spanner/admin/database/v1/Database.java | 17 +++++++ .../database/v1/DeleteBackupRequest.java | 2 + .../database/v1/DropDatabaseRequest.java | 2 + .../admin/database/v1/GetBackupRequest.java | 2 + .../database/v1/GetDatabaseDdlRequest.java | 2 + .../admin/database/v1/GetDatabaseRequest.java | 2 + .../v1/ListBackupOperationsRequest.java | 8 ++++ .../v1/ListBackupOperationsResponse.java | 7 +++ .../admin/database/v1/ListBackupsRequest.java | 8 ++++ .../database/v1/ListBackupsResponse.java | 7 +++ .../v1/ListDatabaseOperationsRequest.java | 8 ++++ .../v1/ListDatabaseOperationsResponse.java | 7 +++ .../database/v1/ListDatabasesRequest.java | 6 +++ .../database/v1/ListDatabasesResponse.java | 7 +++ .../admin/database/v1/OperationProgress.java | 8 ++++ .../v1/OptimizeRestoredDatabaseMetadata.java | 5 +++ .../database/v1/RestoreDatabaseMetadata.java | 21 +++++++++ .../database/v1/RestoreDatabaseRequest.java | 6 +++ .../admin/database/v1/RestoreInfo.java | 11 +++++ .../admin/database/v1/RestoreSourceType.java | 4 ++ .../database/v1/UpdateBackupRequest.java | 6 +++ .../v1/UpdateDatabaseDdlMetadata.java | 7 +++ .../database/v1/UpdateDatabaseDdlRequest.java | 4 ++ .../instance/v1/CreateInstanceMetadata.java | 12 +++++ .../instance/v1/CreateInstanceRequest.java | 7 +++ .../instance/v1/DeleteInstanceRequest.java | 2 + .../instance/v1/GetInstanceConfigRequest.java | 2 + .../admin/instance/v1/GetInstanceRequest.java | 5 +++ .../spanner/admin/instance/v1/Instance.java | 27 +++++++++++ .../admin/instance/v1/InstanceConfig.java | 9 ++++ .../v1/ListInstanceConfigsRequest.java | 6 +++ .../v1/ListInstanceConfigsResponse.java | 7 +++ .../instance/v1/ListInstancesRequest.java | 8 ++++ .../instance/v1/ListInstancesResponse.java | 7 +++ .../admin/instance/v1/ReplicaInfo.java | 13 ++++++ .../instance/v1/UpdateInstanceMetadata.java | 12 +++++ .../instance/v1/UpdateInstanceRequest.java | 6 +++ .../v1/BatchCreateSessionsRequest.java | 7 +++ .../v1/BatchCreateSessionsResponse.java | 5 +++ .../spanner/v1/BeginTransactionRequest.java | 5 +++ .../com/google/spanner/v1/CommitRequest.java | 14 ++++++ .../com/google/spanner/v1/CommitResponse.java | 3 ++ .../spanner/v1/CreateSessionRequest.java | 5 +++ .../spanner/v1/DeleteSessionRequest.java | 2 + .../spanner/v1/ExecuteBatchDmlRequest.java | 27 +++++++++++ .../spanner/v1/ExecuteBatchDmlResponse.java | 8 ++++ .../google/spanner/v1/ExecuteSqlRequest.java | 40 +++++++++++++++++ .../google/spanner/v1/GetSessionRequest.java | 2 + .../java/com/google/spanner/v1/KeyRange.java | 24 ++++++++++ .../java/com/google/spanner/v1/KeySet.java | 12 +++++ .../spanner/v1/ListSessionsRequest.java | 8 ++++ .../spanner/v1/ListSessionsResponse.java | 7 +++ .../java/com/google/spanner/v1/Mutation.java | 42 +++++++++++++++++ .../google/spanner/v1/PartialResultSet.java | 15 +++++++ .../java/com/google/spanner/v1/Partition.java | 2 + .../google/spanner/v1/PartitionOptions.java | 4 ++ .../spanner/v1/PartitionQueryRequest.java | 23 ++++++++++ .../spanner/v1/PartitionReadRequest.java | 15 +++++++ .../google/spanner/v1/PartitionResponse.java | 8 ++++ .../java/com/google/spanner/v1/PlanNode.java | 45 +++++++++++++++++++ .../java/com/google/spanner/v1/QueryPlan.java | 5 +++ .../com/google/spanner/v1/ReadRequest.java | 18 ++++++++ .../java/com/google/spanner/v1/ResultSet.java | 11 +++++ .../google/spanner/v1/ResultSetMetadata.java | 6 +++ .../com/google/spanner/v1/ResultSetStats.java | 8 ++++ .../google/spanner/v1/RollbackRequest.java | 4 ++ .../java/com/google/spanner/v1/Session.java | 18 ++++++++ .../com/google/spanner/v1/StructType.java | 10 +++++ .../com/google/spanner/v1/Transaction.java | 5 +++ .../google/spanner/v1/TransactionOptions.java | 45 +++++++++++++++++++ .../spanner/v1/TransactionSelector.java | 13 ++++++ .../main/java/com/google/spanner/v1/Type.java | 11 +++++ .../java/com/google/spanner/v1/TypeCode.java | 4 ++ synth.metadata | 4 +- 80 files changed, 814 insertions(+), 2 deletions(-) diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Backup.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Backup.java index 75d8efc8fc..0d9230003e 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Backup.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Backup.java @@ -300,6 +300,10 @@ public State findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -349,6 +353,7 @@ private State(int value) { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -375,6 +380,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -405,6 +411,7 @@ public com.google.protobuf.ByteString getDatabaseBytes() { * * @return Whether the expireTime field is set. */ + @java.lang.Override public boolean hasExpireTime() { return expireTime_ != null; } @@ -424,6 +431,7 @@ public boolean hasExpireTime() { * * @return The expireTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getExpireTime() { return expireTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : expireTime_; } @@ -441,6 +449,7 @@ public com.google.protobuf.Timestamp getExpireTime() { * * .google.protobuf.Timestamp expire_time = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getExpireTimeOrBuilder() { return getExpireTime(); } @@ -468,6 +477,7 @@ public com.google.protobuf.TimestampOrBuilder getExpireTimeOrBuilder() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -500,6 +510,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -529,6 +540,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return Whether the createTime field is set. */ + @java.lang.Override public boolean hasCreateTime() { return createTime_ != null; } @@ -547,6 +559,7 @@ public boolean hasCreateTime() { * * @return The createTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCreateTime() { return createTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : createTime_; } @@ -563,6 +576,7 @@ public com.google.protobuf.Timestamp getCreateTime() { * .google.protobuf.Timestamp create_time = 4 [(.google.api.field_behavior) = OUTPUT_ONLY]; * */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { return getCreateTime(); } @@ -580,6 +594,7 @@ public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { * * @return The sizeBytes. */ + @java.lang.Override public long getSizeBytes() { return sizeBytes_; } @@ -599,6 +614,7 @@ public long getSizeBytes() { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -615,6 +631,7 @@ public int getStateValue() { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Backup.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.Backup.State result = @@ -1916,6 +1933,7 @@ public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { * * @return The sizeBytes. */ + @java.lang.Override public long getSizeBytes() { return sizeBytes_; } @@ -1969,6 +1987,7 @@ public Builder clearSizeBytes() { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -1987,6 +2006,7 @@ public int getStateValue() { * @return This builder for chaining. */ public Builder setStateValue(int value) { + state_ = value; onChanged(); return this; @@ -2004,6 +2024,7 @@ public Builder setStateValue(int value) { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Backup.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.Backup.State result = diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupInfo.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupInfo.java index 8e9bcfc842..99bc0f1019 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupInfo.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupInfo.java @@ -147,6 +147,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The backup. */ + @java.lang.Override public java.lang.String getBackup() { java.lang.Object ref = backup_; if (ref instanceof java.lang.String) { @@ -169,6 +170,7 @@ public java.lang.String getBackup() { * * @return The bytes for backup. */ + @java.lang.Override public com.google.protobuf.ByteString getBackupBytes() { java.lang.Object ref = backup_; if (ref instanceof java.lang.String) { @@ -195,6 +197,7 @@ public com.google.protobuf.ByteString getBackupBytes() { * * @return Whether the createTime field is set. */ + @java.lang.Override public boolean hasCreateTime() { return createTime_ != null; } @@ -210,6 +213,7 @@ public boolean hasCreateTime() { * * @return The createTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCreateTime() { return createTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : createTime_; } @@ -223,6 +227,7 @@ public com.google.protobuf.Timestamp getCreateTime() { * * .google.protobuf.Timestamp create_time = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { return getCreateTime(); } @@ -240,6 +245,7 @@ public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { * * @return The sourceDatabase. */ + @java.lang.Override public java.lang.String getSourceDatabase() { java.lang.Object ref = sourceDatabase_; if (ref instanceof java.lang.String) { @@ -262,6 +268,7 @@ public java.lang.String getSourceDatabase() { * * @return The bytes for sourceDatabase. */ + @java.lang.Override public com.google.protobuf.ByteString getSourceDatabaseBytes() { java.lang.Object ref = sourceDatabase_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupMetadata.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupMetadata.java index 18894be36e..a1b0cc3512 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupMetadata.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupMetadata.java @@ -165,6 +165,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -187,6 +188,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -212,6 +214,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -234,6 +237,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -260,6 +264,7 @@ public com.google.protobuf.ByteString getDatabaseBytes() { * * @return Whether the progress field is set. */ + @java.lang.Override public boolean hasProgress() { return progress_ != null; } @@ -275,6 +280,7 @@ public boolean hasProgress() { * * @return The progress. */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgress getProgress() { return progress_ == null ? com.google.spanner.admin.database.v1.OperationProgress.getDefaultInstance() @@ -290,6 +296,7 @@ public com.google.spanner.admin.database.v1.OperationProgress getProgress() { * * .google.spanner.admin.database.v1.OperationProgress progress = 3; */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgressOrBuilder getProgressOrBuilder() { return getProgress(); } @@ -317,6 +324,7 @@ public com.google.spanner.admin.database.v1.OperationProgressOrBuilder getProgre * * @return Whether the cancelTime field is set. */ + @java.lang.Override public boolean hasCancelTime() { return cancelTime_ != null; } @@ -341,6 +349,7 @@ public boolean hasCancelTime() { * * @return The cancelTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCancelTime() { return cancelTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : cancelTime_; } @@ -363,6 +372,7 @@ public com.google.protobuf.Timestamp getCancelTime() { * * .google.protobuf.Timestamp cancel_time = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { return getCancelTime(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupRequest.java index 988fb812fe..42e0cac7a8 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateBackupRequest.java @@ -155,6 +155,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -184,6 +185,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -211,6 +213,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The backupId. */ + @java.lang.Override public java.lang.String getBackupId() { java.lang.Object ref = backupId_; if (ref instanceof java.lang.String) { @@ -235,6 +238,7 @@ public java.lang.String getBackupId() { * * @return The bytes for backupId. */ + @java.lang.Override public com.google.protobuf.ByteString getBackupIdBytes() { java.lang.Object ref = backupId_; if (ref instanceof java.lang.String) { @@ -262,6 +266,7 @@ public com.google.protobuf.ByteString getBackupIdBytes() { * * @return Whether the backup field is set. */ + @java.lang.Override public boolean hasBackup() { return backup_ != null; } @@ -278,6 +283,7 @@ public boolean hasBackup() { * * @return The backup. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Backup getBackup() { return backup_ == null ? com.google.spanner.admin.database.v1.Backup.getDefaultInstance() @@ -294,6 +300,7 @@ public com.google.spanner.admin.database.v1.Backup getBackup() { * .google.spanner.admin.database.v1.Backup backup = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupOrBuilder getBackupOrBuilder() { return getBackup(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseMetadata.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseMetadata.java index 83c8bd01d3..8ee27de47d 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseMetadata.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseMetadata.java @@ -125,6 +125,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -147,6 +148,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java index ca9fdbd1ce..f05c47f738 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java @@ -150,6 +150,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -175,6 +176,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -204,6 +206,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The createStatement. */ + @java.lang.Override public java.lang.String getCreateStatement() { java.lang.Object ref = createStatement_; if (ref instanceof java.lang.String) { @@ -230,6 +233,7 @@ public java.lang.String getCreateStatement() { * * @return The bytes for createStatement. */ + @java.lang.Override public com.google.protobuf.ByteString getCreateStatementBytes() { java.lang.Object ref = createStatement_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Database.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Database.java index f9d10c3ae9..768f470254 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Database.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/Database.java @@ -307,6 +307,10 @@ public State findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -356,6 +360,7 @@ private State(int value) { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -382,6 +387,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -409,6 +415,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -425,6 +432,7 @@ public int getStateValue() { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Database.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.Database.State result = @@ -448,6 +456,7 @@ public com.google.spanner.admin.database.v1.Database.State getState() { * * @return Whether the createTime field is set. */ + @java.lang.Override public boolean hasCreateTime() { return createTime_ != null; } @@ -463,6 +472,7 @@ public boolean hasCreateTime() { * * @return The createTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCreateTime() { return createTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : createTime_; } @@ -476,6 +486,7 @@ public com.google.protobuf.Timestamp getCreateTime() { * .google.protobuf.Timestamp create_time = 3 [(.google.api.field_behavior) = OUTPUT_ONLY]; * */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { return getCreateTime(); } @@ -496,6 +507,7 @@ public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { * * @return Whether the restoreInfo field is set. */ + @java.lang.Override public boolean hasRestoreInfo() { return restoreInfo_ != null; } @@ -513,6 +525,7 @@ public boolean hasRestoreInfo() { * * @return The restoreInfo. */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreInfo getRestoreInfo() { return restoreInfo_ == null ? com.google.spanner.admin.database.v1.RestoreInfo.getDefaultInstance() @@ -530,6 +543,7 @@ public com.google.spanner.admin.database.v1.RestoreInfo getRestoreInfo() { * .google.spanner.admin.database.v1.RestoreInfo restore_info = 4 [(.google.api.field_behavior) = OUTPUT_ONLY]; * */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreInfoOrBuilder getRestoreInfoOrBuilder() { return getRestoreInfo(); } @@ -1063,6 +1077,7 @@ public Builder setNameBytes(com.google.protobuf.ByteString value) { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -1081,6 +1096,7 @@ public int getStateValue() { * @return This builder for chaining. */ public Builder setStateValue(int value) { + state_ = value; onChanged(); return this; @@ -1098,6 +1114,7 @@ public Builder setStateValue(int value) { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Database.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.Database.State result = diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DeleteBackupRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DeleteBackupRequest.java index c4be22ef45..44e63a951a 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DeleteBackupRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DeleteBackupRequest.java @@ -128,6 +128,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -154,6 +155,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DropDatabaseRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DropDatabaseRequest.java index 25b2fd4ab2..e834f43e72 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DropDatabaseRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/DropDatabaseRequest.java @@ -126,6 +126,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -150,6 +151,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetBackupRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetBackupRequest.java index 97f34ed23d..c503740fca 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetBackupRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetBackupRequest.java @@ -128,6 +128,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -154,6 +155,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlRequest.java index f0a18af7ce..d730718fb3 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlRequest.java @@ -126,6 +126,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -150,6 +151,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseRequest.java index 212ee524bf..37a5e3ef97 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseRequest.java @@ -127,6 +127,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -152,6 +153,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsRequest.java index fac83d2127..baea7c8f1f 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsRequest.java @@ -149,6 +149,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -174,6 +175,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -230,6 +232,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The filter. */ + @java.lang.Override public java.lang.String getFilter() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -283,6 +286,7 @@ public java.lang.String getFilter() { * * @return The bytes for filter. */ + @java.lang.Override public com.google.protobuf.ByteString getFilterBytes() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -309,6 +313,7 @@ public com.google.protobuf.ByteString getFilterBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -329,6 +334,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -354,6 +360,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -1132,6 +1139,7 @@ public Builder setFilterBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsResponse.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsResponse.java index 55d243d80d..a615824bb2 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsResponse.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupOperationsResponse.java @@ -146,6 +146,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public java.util.List getOperationsList() { return operations_; } @@ -166,6 +167,7 @@ public java.util.List getOperationsList() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public java.util.List getOperationsOrBuilderList() { return operations_; @@ -187,6 +189,7 @@ public java.util.List getOperationsList() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public int getOperationsCount() { return operations_.size(); } @@ -207,6 +210,7 @@ public int getOperationsCount() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public com.google.longrunning.Operation getOperations(int index) { return operations_.get(index); } @@ -227,6 +231,7 @@ public com.google.longrunning.Operation getOperations(int index) { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public com.google.longrunning.OperationOrBuilder getOperationsOrBuilder(int index) { return operations_.get(index); } @@ -246,6 +251,7 @@ public com.google.longrunning.OperationOrBuilder getOperationsOrBuilder(int inde * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -270,6 +276,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsRequest.java index 33b32bd56f..9ec5b03ed7 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsRequest.java @@ -148,6 +148,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -173,6 +174,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -225,6 +227,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The filter. */ + @java.lang.Override public java.lang.String getFilter() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -274,6 +277,7 @@ public java.lang.String getFilter() { * * @return The bytes for filter. */ + @java.lang.Override public com.google.protobuf.ByteString getFilterBytes() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -300,6 +304,7 @@ public com.google.protobuf.ByteString getFilterBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -320,6 +325,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -345,6 +351,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -1098,6 +1105,7 @@ public Builder setFilterBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsResponse.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsResponse.java index 035426ab5f..8e0b6a12ac 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsResponse.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListBackupsResponse.java @@ -139,6 +139,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.database.v1.Backup backups = 1; */ + @java.lang.Override public java.util.List getBackupsList() { return backups_; } @@ -152,6 +153,7 @@ public java.util.List getBackupsLis * * repeated .google.spanner.admin.database.v1.Backup backups = 1; */ + @java.lang.Override public java.util.List getBackupsOrBuilderList() { return backups_; @@ -166,6 +168,7 @@ public java.util.List getBackupsLis * * repeated .google.spanner.admin.database.v1.Backup backups = 1; */ + @java.lang.Override public int getBackupsCount() { return backups_.size(); } @@ -179,6 +182,7 @@ public int getBackupsCount() { * * repeated .google.spanner.admin.database.v1.Backup backups = 1; */ + @java.lang.Override public com.google.spanner.admin.database.v1.Backup getBackups(int index) { return backups_.get(index); } @@ -192,6 +196,7 @@ public com.google.spanner.admin.database.v1.Backup getBackups(int index) { * * repeated .google.spanner.admin.database.v1.Backup backups = 1; */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupOrBuilder getBackupsOrBuilder(int index) { return backups_.get(index); } @@ -211,6 +216,7 @@ public com.google.spanner.admin.database.v1.BackupOrBuilder getBackupsOrBuilder( * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -235,6 +241,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsRequest.java index 9233c50f20..06cff39b68 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsRequest.java @@ -149,6 +149,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -174,6 +175,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -232,6 +234,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The filter. */ + @java.lang.Override public java.lang.String getFilter() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -287,6 +290,7 @@ public java.lang.String getFilter() { * * @return The bytes for filter. */ + @java.lang.Override public com.google.protobuf.ByteString getFilterBytes() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -313,6 +317,7 @@ public com.google.protobuf.ByteString getFilterBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -333,6 +338,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -358,6 +364,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -1150,6 +1157,7 @@ public Builder setFilterBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsResponse.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsResponse.java index 1eee660e6a..46169b5a16 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsResponse.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabaseOperationsResponse.java @@ -143,6 +143,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public java.util.List getOperationsList() { return operations_; } @@ -159,6 +160,7 @@ public java.util.List getOperationsList() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public java.util.List getOperationsOrBuilderList() { return operations_; @@ -176,6 +178,7 @@ public java.util.List getOperationsList() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public int getOperationsCount() { return operations_.size(); } @@ -192,6 +195,7 @@ public int getOperationsCount() { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public com.google.longrunning.Operation getOperations(int index) { return operations_.get(index); } @@ -208,6 +212,7 @@ public com.google.longrunning.Operation getOperations(int index) { * * repeated .google.longrunning.Operation operations = 1; */ + @java.lang.Override public com.google.longrunning.OperationOrBuilder getOperationsOrBuilder(int index) { return operations_.get(index); } @@ -227,6 +232,7 @@ public com.google.longrunning.OperationOrBuilder getOperationsOrBuilder(int inde * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -251,6 +257,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesRequest.java index 9b27f3b7cb..8c7bf427c4 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesRequest.java @@ -140,6 +140,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -165,6 +166,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -191,6 +193,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -210,6 +213,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -234,6 +238,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -730,6 +735,7 @@ public Builder setParentBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesResponse.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesResponse.java index 8de9251912..b96d13481b 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesResponse.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/ListDatabasesResponse.java @@ -139,6 +139,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.database.v1.Database databases = 1; */ + @java.lang.Override public java.util.List getDatabasesList() { return databases_; } @@ -151,6 +152,7 @@ public java.util.List getDatabase * * repeated .google.spanner.admin.database.v1.Database databases = 1; */ + @java.lang.Override public java.util.List getDatabasesOrBuilderList() { return databases_; @@ -164,6 +166,7 @@ public java.util.List getDatabase * * repeated .google.spanner.admin.database.v1.Database databases = 1; */ + @java.lang.Override public int getDatabasesCount() { return databases_.size(); } @@ -176,6 +179,7 @@ public int getDatabasesCount() { * * repeated .google.spanner.admin.database.v1.Database databases = 1; */ + @java.lang.Override public com.google.spanner.admin.database.v1.Database getDatabases(int index) { return databases_.get(index); } @@ -188,6 +192,7 @@ public com.google.spanner.admin.database.v1.Database getDatabases(int index) { * * repeated .google.spanner.admin.database.v1.Database databases = 1; */ + @java.lang.Override public com.google.spanner.admin.database.v1.DatabaseOrBuilder getDatabasesOrBuilder(int index) { return databases_.get(index); } @@ -207,6 +212,7 @@ public com.google.spanner.admin.database.v1.DatabaseOrBuilder getDatabasesOrBuil * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -231,6 +237,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OperationProgress.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OperationProgress.java index d31d4ee7d6..b4dc5c581e 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OperationProgress.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OperationProgress.java @@ -152,6 +152,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The progressPercent. */ + @java.lang.Override public int getProgressPercent() { return progressPercent_; } @@ -169,6 +170,7 @@ public int getProgressPercent() { * * @return Whether the startTime field is set. */ + @java.lang.Override public boolean hasStartTime() { return startTime_ != null; } @@ -183,6 +185,7 @@ public boolean hasStartTime() { * * @return The startTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getStartTime() { return startTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : startTime_; } @@ -195,6 +198,7 @@ public com.google.protobuf.Timestamp getStartTime() { * * .google.protobuf.Timestamp start_time = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { return getStartTime(); } @@ -213,6 +217,7 @@ public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { * * @return Whether the endTime field is set. */ + @java.lang.Override public boolean hasEndTime() { return endTime_ != null; } @@ -228,6 +233,7 @@ public boolean hasEndTime() { * * @return The endTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getEndTime() { return endTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : endTime_; } @@ -241,6 +247,7 @@ public com.google.protobuf.Timestamp getEndTime() { * * .google.protobuf.Timestamp end_time = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getEndTimeOrBuilder() { return getEndTime(); } @@ -633,6 +640,7 @@ public Builder mergeFrom( * * @return The progressPercent. */ + @java.lang.Override public int getProgressPercent() { return progressPercent_; } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OptimizeRestoredDatabaseMetadata.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OptimizeRestoredDatabaseMetadata.java index 6db17d6496..88c49cdc15 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OptimizeRestoredDatabaseMetadata.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/OptimizeRestoredDatabaseMetadata.java @@ -145,6 +145,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -167,6 +168,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -192,6 +194,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return Whether the progress field is set. */ + @java.lang.Override public boolean hasProgress() { return progress_ != null; } @@ -206,6 +209,7 @@ public boolean hasProgress() { * * @return The progress. */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgress getProgress() { return progress_ == null ? com.google.spanner.admin.database.v1.OperationProgress.getDefaultInstance() @@ -220,6 +224,7 @@ public com.google.spanner.admin.database.v1.OperationProgress getProgress() { * * .google.spanner.admin.database.v1.OperationProgress progress = 2; */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgressOrBuilder getProgressOrBuilder() { return getProgress(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseMetadata.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseMetadata.java index d7689dd31c..4cb9915103 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseMetadata.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseMetadata.java @@ -234,6 +234,7 @@ public SourceInfoCase getSourceInfoCase() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -256,6 +257,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -281,6 +283,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return The enum numeric value on the wire for sourceType. */ + @java.lang.Override public int getSourceTypeValue() { return sourceType_; } @@ -295,6 +298,7 @@ public int getSourceTypeValue() { * * @return The sourceType. */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.RestoreSourceType result = @@ -316,6 +320,7 @@ public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { * * @return Whether the backupInfo field is set. */ + @java.lang.Override public boolean hasBackupInfo() { return sourceInfoCase_ == 3; } @@ -330,6 +335,7 @@ public boolean hasBackupInfo() { * * @return The backupInfo. */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { if (sourceInfoCase_ == 3) { return (com.google.spanner.admin.database.v1.BackupInfo) sourceInfo_; @@ -345,6 +351,7 @@ public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { * * .google.spanner.admin.database.v1.BackupInfo backup_info = 3; */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfoOrBuilder getBackupInfoOrBuilder() { if (sourceInfoCase_ == 3) { return (com.google.spanner.admin.database.v1.BackupInfo) sourceInfo_; @@ -367,6 +374,7 @@ public com.google.spanner.admin.database.v1.BackupInfoOrBuilder getBackupInfoOrB * * @return Whether the progress field is set. */ + @java.lang.Override public boolean hasProgress() { return progress_ != null; } @@ -383,6 +391,7 @@ public boolean hasProgress() { * * @return The progress. */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgress getProgress() { return progress_ == null ? com.google.spanner.admin.database.v1.OperationProgress.getDefaultInstance() @@ -399,6 +408,7 @@ public com.google.spanner.admin.database.v1.OperationProgress getProgress() { * * .google.spanner.admin.database.v1.OperationProgress progress = 4; */ + @java.lang.Override public com.google.spanner.admin.database.v1.OperationProgressOrBuilder getProgressOrBuilder() { return getProgress(); } @@ -426,6 +436,7 @@ public com.google.spanner.admin.database.v1.OperationProgressOrBuilder getProgre * * @return Whether the cancelTime field is set. */ + @java.lang.Override public boolean hasCancelTime() { return cancelTime_ != null; } @@ -450,6 +461,7 @@ public boolean hasCancelTime() { * * @return The cancelTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCancelTime() { return cancelTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : cancelTime_; } @@ -472,6 +484,7 @@ public com.google.protobuf.Timestamp getCancelTime() { * * .google.protobuf.Timestamp cancel_time = 5; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { return getCancelTime(); } @@ -499,6 +512,7 @@ public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { * * @return The optimizeDatabaseOperationName. */ + @java.lang.Override public java.lang.String getOptimizeDatabaseOperationName() { java.lang.Object ref = optimizeDatabaseOperationName_; if (ref instanceof java.lang.String) { @@ -531,6 +545,7 @@ public java.lang.String getOptimizeDatabaseOperationName() { * * @return The bytes for optimizeDatabaseOperationName. */ + @java.lang.Override public com.google.protobuf.ByteString getOptimizeDatabaseOperationNameBytes() { java.lang.Object ref = optimizeDatabaseOperationName_; if (ref instanceof java.lang.String) { @@ -1134,6 +1149,7 @@ public Builder setNameBytes(com.google.protobuf.ByteString value) { * * @return The enum numeric value on the wire for sourceType. */ + @java.lang.Override public int getSourceTypeValue() { return sourceType_; } @@ -1150,6 +1166,7 @@ public int getSourceTypeValue() { * @return This builder for chaining. */ public Builder setSourceTypeValue(int value) { + sourceType_ = value; onChanged(); return this; @@ -1165,6 +1182,7 @@ public Builder setSourceTypeValue(int value) { * * @return The sourceType. */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.RestoreSourceType result = @@ -1228,6 +1246,7 @@ public Builder clearSourceType() { * * @return Whether the backupInfo field is set. */ + @java.lang.Override public boolean hasBackupInfo() { return sourceInfoCase_ == 3; } @@ -1242,6 +1261,7 @@ public boolean hasBackupInfo() { * * @return The backupInfo. */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { if (backupInfoBuilder_ == null) { if (sourceInfoCase_ == 3) { @@ -1375,6 +1395,7 @@ public com.google.spanner.admin.database.v1.BackupInfo.Builder getBackupInfoBuil * * .google.spanner.admin.database.v1.BackupInfo backup_info = 3; */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfoOrBuilder getBackupInfoOrBuilder() { if ((sourceInfoCase_ == 3) && (backupInfoBuilder_ != null)) { return backupInfoBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseRequest.java index 16894b794d..ac2faaff1d 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreDatabaseRequest.java @@ -190,6 +190,7 @@ public SourceCase getSourceCase() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -218,6 +219,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -246,6 +248,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The databaseId. */ + @java.lang.Override public java.lang.String getDatabaseId() { java.lang.Object ref = databaseId_; if (ref instanceof java.lang.String) { @@ -271,6 +274,7 @@ public java.lang.String getDatabaseId() { * * @return The bytes for databaseId. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseIdBytes() { java.lang.Object ref = databaseId_; if (ref instanceof java.lang.String) { @@ -1001,6 +1005,7 @@ public Builder setDatabaseIdBytes(com.google.protobuf.ByteString value) { * * @return The backup. */ + @java.lang.Override public java.lang.String getBackup() { java.lang.Object ref = ""; if (sourceCase_ == 3) { @@ -1029,6 +1034,7 @@ public java.lang.String getBackup() { * * @return The bytes for backup. */ + @java.lang.Override public com.google.protobuf.ByteString getBackupBytes() { java.lang.Object ref = ""; if (sourceCase_ == 3) { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreInfo.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreInfo.java index e6698baf64..9e18faf6d3 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreInfo.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreInfo.java @@ -185,6 +185,7 @@ public SourceInfoCase getSourceInfoCase() { * * @return The enum numeric value on the wire for sourceType. */ + @java.lang.Override public int getSourceTypeValue() { return sourceType_; } @@ -199,6 +200,7 @@ public int getSourceTypeValue() { * * @return The sourceType. */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.RestoreSourceType result = @@ -221,6 +223,7 @@ public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { * * @return Whether the backupInfo field is set. */ + @java.lang.Override public boolean hasBackupInfo() { return sourceInfoCase_ == 2; } @@ -236,6 +239,7 @@ public boolean hasBackupInfo() { * * @return The backupInfo. */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { if (sourceInfoCase_ == 2) { return (com.google.spanner.admin.database.v1.BackupInfo) sourceInfo_; @@ -252,6 +256,7 @@ public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { * * .google.spanner.admin.database.v1.BackupInfo backup_info = 2; */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfoOrBuilder getBackupInfoOrBuilder() { if (sourceInfoCase_ == 2) { return (com.google.spanner.admin.database.v1.BackupInfo) sourceInfo_; @@ -648,6 +653,7 @@ public Builder clearSourceInfo() { * * @return The enum numeric value on the wire for sourceType. */ + @java.lang.Override public int getSourceTypeValue() { return sourceType_; } @@ -664,6 +670,7 @@ public int getSourceTypeValue() { * @return This builder for chaining. */ public Builder setSourceTypeValue(int value) { + sourceType_ = value; onChanged(); return this; @@ -679,6 +686,7 @@ public Builder setSourceTypeValue(int value) { * * @return The sourceType. */ + @java.lang.Override public com.google.spanner.admin.database.v1.RestoreSourceType getSourceType() { @SuppressWarnings("deprecation") com.google.spanner.admin.database.v1.RestoreSourceType result = @@ -743,6 +751,7 @@ public Builder clearSourceType() { * * @return Whether the backupInfo field is set. */ + @java.lang.Override public boolean hasBackupInfo() { return sourceInfoCase_ == 2; } @@ -758,6 +767,7 @@ public boolean hasBackupInfo() { * * @return The backupInfo. */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfo getBackupInfo() { if (backupInfoBuilder_ == null) { if (sourceInfoCase_ == 2) { @@ -897,6 +907,7 @@ public com.google.spanner.admin.database.v1.BackupInfo.Builder getBackupInfoBuil * * .google.spanner.admin.database.v1.BackupInfo backup_info = 2; */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupInfoOrBuilder getBackupInfoOrBuilder() { if ((sourceInfoCase_ == 2) && (backupInfoBuilder_ != null)) { return backupInfoBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreSourceType.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreSourceType.java index 49a8acb2f6..e881b2a591 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreSourceType.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/RestoreSourceType.java @@ -118,6 +118,10 @@ public RestoreSourceType findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateBackupRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateBackupRequest.java index 1ea632c0c7..6eb84dbaf8 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateBackupRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateBackupRequest.java @@ -151,6 +151,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the backup field is set. */ + @java.lang.Override public boolean hasBackup() { return backup_ != null; } @@ -170,6 +171,7 @@ public boolean hasBackup() { * * @return The backup. */ + @java.lang.Override public com.google.spanner.admin.database.v1.Backup getBackup() { return backup_ == null ? com.google.spanner.admin.database.v1.Backup.getDefaultInstance() @@ -189,6 +191,7 @@ public com.google.spanner.admin.database.v1.Backup getBackup() { * .google.spanner.admin.database.v1.Backup backup = 1 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.admin.database.v1.BackupOrBuilder getBackupOrBuilder() { return getBackup(); } @@ -211,6 +214,7 @@ public com.google.spanner.admin.database.v1.BackupOrBuilder getBackupOrBuilder() * * @return Whether the updateMask field is set. */ + @java.lang.Override public boolean hasUpdateMask() { return updateMask_ != null; } @@ -230,6 +234,7 @@ public boolean hasUpdateMask() { * * @return The updateMask. */ + @java.lang.Override public com.google.protobuf.FieldMask getUpdateMask() { return updateMask_ == null ? com.google.protobuf.FieldMask.getDefaultInstance() : updateMask_; } @@ -247,6 +252,7 @@ public com.google.protobuf.FieldMask getUpdateMask() { * .google.protobuf.FieldMask update_mask = 2 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.protobuf.FieldMaskOrBuilder getUpdateMaskOrBuilder() { return getUpdateMask(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlMetadata.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlMetadata.java index 26fd5d8337..698e69f57b 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlMetadata.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlMetadata.java @@ -154,6 +154,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -176,6 +177,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -266,6 +268,7 @@ public com.google.protobuf.ByteString getStatementsBytes(int index) { * * repeated .google.protobuf.Timestamp commit_timestamps = 3; */ + @java.lang.Override public java.util.List getCommitTimestampsList() { return commitTimestamps_; } @@ -280,6 +283,7 @@ public java.util.List getCommitTimestampsList() { * * repeated .google.protobuf.Timestamp commit_timestamps = 3; */ + @java.lang.Override public java.util.List getCommitTimestampsOrBuilderList() { return commitTimestamps_; @@ -295,6 +299,7 @@ public java.util.List getCommitTimestampsList() { * * repeated .google.protobuf.Timestamp commit_timestamps = 3; */ + @java.lang.Override public int getCommitTimestampsCount() { return commitTimestamps_.size(); } @@ -309,6 +314,7 @@ public int getCommitTimestampsCount() { * * repeated .google.protobuf.Timestamp commit_timestamps = 3; */ + @java.lang.Override public com.google.protobuf.Timestamp getCommitTimestamps(int index) { return commitTimestamps_.get(index); } @@ -323,6 +329,7 @@ public com.google.protobuf.Timestamp getCommitTimestamps(int index) { * * repeated .google.protobuf.Timestamp commit_timestamps = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCommitTimestampsOrBuilder(int index) { return commitTimestamps_.get(index); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java index 0bd5b682b3..d4b1adc70f 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java @@ -163,6 +163,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -187,6 +188,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -289,6 +291,7 @@ public com.google.protobuf.ByteString getStatementsBytes(int index) { * * @return The operationId. */ + @java.lang.Override public java.lang.String getOperationId() { java.lang.Object ref = operationId_; if (ref instanceof java.lang.String) { @@ -327,6 +330,7 @@ public java.lang.String getOperationId() { * * @return The bytes for operationId. */ + @java.lang.Override public com.google.protobuf.ByteString getOperationIdBytes() { java.lang.Object ref = operationId_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceMetadata.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceMetadata.java index a8163ffba2..a5923b520b 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceMetadata.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceMetadata.java @@ -177,6 +177,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the instance field is set. */ + @java.lang.Override public boolean hasInstance() { return instance_ != null; } @@ -191,6 +192,7 @@ public boolean hasInstance() { * * @return The instance. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance getInstance() { return instance_ == null ? com.google.spanner.admin.instance.v1.Instance.getDefaultInstance() @@ -205,6 +207,7 @@ public com.google.spanner.admin.instance.v1.Instance getInstance() { * * .google.spanner.admin.instance.v1.Instance instance = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuilder() { return getInstance(); } @@ -224,6 +227,7 @@ public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuild * * @return Whether the startTime field is set. */ + @java.lang.Override public boolean hasStartTime() { return startTime_ != null; } @@ -240,6 +244,7 @@ public boolean hasStartTime() { * * @return The startTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getStartTime() { return startTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : startTime_; } @@ -254,6 +259,7 @@ public com.google.protobuf.Timestamp getStartTime() { * * .google.protobuf.Timestamp start_time = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { return getStartTime(); } @@ -273,6 +279,7 @@ public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { * * @return Whether the cancelTime field is set. */ + @java.lang.Override public boolean hasCancelTime() { return cancelTime_ != null; } @@ -289,6 +296,7 @@ public boolean hasCancelTime() { * * @return The cancelTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCancelTime() { return cancelTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : cancelTime_; } @@ -303,6 +311,7 @@ public com.google.protobuf.Timestamp getCancelTime() { * * .google.protobuf.Timestamp cancel_time = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { return getCancelTime(); } @@ -320,6 +329,7 @@ public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { * * @return Whether the endTime field is set. */ + @java.lang.Override public boolean hasEndTime() { return endTime_ != null; } @@ -334,6 +344,7 @@ public boolean hasEndTime() { * * @return The endTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getEndTime() { return endTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : endTime_; } @@ -346,6 +357,7 @@ public com.google.protobuf.Timestamp getEndTime() { * * .google.protobuf.Timestamp end_time = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getEndTimeOrBuilder() { return getEndTime(); } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceRequest.java index 3b41baa914..012caa5572 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/CreateInstanceRequest.java @@ -151,6 +151,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -176,6 +177,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -203,6 +205,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The instanceId. */ + @java.lang.Override public java.lang.String getInstanceId() { java.lang.Object ref = instanceId_; if (ref instanceof java.lang.String) { @@ -227,6 +230,7 @@ public java.lang.String getInstanceId() { * * @return The bytes for instanceId. */ + @java.lang.Override public com.google.protobuf.ByteString getInstanceIdBytes() { java.lang.Object ref = instanceId_; if (ref instanceof java.lang.String) { @@ -255,6 +259,7 @@ public com.google.protobuf.ByteString getInstanceIdBytes() { * * @return Whether the instance field is set. */ + @java.lang.Override public boolean hasInstance() { return instance_ != null; } @@ -272,6 +277,7 @@ public boolean hasInstance() { * * @return The instance. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance getInstance() { return instance_ == null ? com.google.spanner.admin.instance.v1.Instance.getDefaultInstance() @@ -289,6 +295,7 @@ public com.google.spanner.admin.instance.v1.Instance getInstance() { * .google.spanner.admin.instance.v1.Instance instance = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuilder() { return getInstance(); } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/DeleteInstanceRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/DeleteInstanceRequest.java index 8693544bef..b3b2e52a68 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/DeleteInstanceRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/DeleteInstanceRequest.java @@ -127,6 +127,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -152,6 +153,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceConfigRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceConfigRequest.java index de1e98f8b2..5b2d5a7eda 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceConfigRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceConfigRequest.java @@ -128,6 +128,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -153,6 +154,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceRequest.java index e73700280c..28caf28eae 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/GetInstanceRequest.java @@ -142,6 +142,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -167,6 +168,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -194,6 +196,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return Whether the fieldMask field is set. */ + @java.lang.Override public boolean hasFieldMask() { return fieldMask_ != null; } @@ -210,6 +213,7 @@ public boolean hasFieldMask() { * * @return The fieldMask. */ + @java.lang.Override public com.google.protobuf.FieldMask getFieldMask() { return fieldMask_ == null ? com.google.protobuf.FieldMask.getDefaultInstance() : fieldMask_; } @@ -224,6 +228,7 @@ public com.google.protobuf.FieldMask getFieldMask() { * * .google.protobuf.FieldMask field_mask = 2; */ + @java.lang.Override public com.google.protobuf.FieldMaskOrBuilder getFieldMaskOrBuilder() { return getFieldMask(); } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/Instance.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/Instance.java index b6ab001a22..e80fe9c269 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/Instance.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/Instance.java @@ -306,6 +306,10 @@ public State findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -354,6 +358,7 @@ private State(int value) { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -379,6 +384,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -407,6 +413,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return The config. */ + @java.lang.Override public java.lang.String getConfig() { java.lang.Object ref = config_; if (ref instanceof java.lang.String) { @@ -432,6 +439,7 @@ public java.lang.String getConfig() { * * @return The bytes for config. */ + @java.lang.Override public com.google.protobuf.ByteString getConfigBytes() { java.lang.Object ref = config_; if (ref instanceof java.lang.String) { @@ -458,6 +466,7 @@ public com.google.protobuf.ByteString getConfigBytes() { * * @return The displayName. */ + @java.lang.Override public java.lang.String getDisplayName() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -481,6 +490,7 @@ public java.lang.String getDisplayName() { * * @return The bytes for displayName. */ + @java.lang.Override public com.google.protobuf.ByteString getDisplayNameBytes() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -510,6 +520,7 @@ public com.google.protobuf.ByteString getDisplayNameBytes() { * * @return The nodeCount. */ + @java.lang.Override public int getNodeCount() { return nodeCount_; } @@ -531,6 +542,7 @@ public int getNodeCount() { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -549,6 +561,7 @@ public int getStateValue() { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.instance.v1.Instance.State result = @@ -609,6 +622,7 @@ public int getLabelsCount() { * * map<string, string> labels = 7; */ + @java.lang.Override public boolean containsLabels(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -616,6 +630,7 @@ public boolean containsLabels(java.lang.String key) { return internalGetLabels().getMap().containsKey(key); } /** Use {@link #getLabelsMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getLabels() { return getLabelsMap(); @@ -646,6 +661,7 @@ public java.util.Map getLabels() { * * map<string, string> labels = 7; */ + @java.lang.Override public java.util.Map getLabelsMap() { return internalGetLabels().getMap(); } @@ -675,6 +691,7 @@ public java.util.Map getLabelsMap() { * * map<string, string> labels = 7; */ + @java.lang.Override public java.lang.String getLabelsOrDefault(java.lang.String key, java.lang.String defaultValue) { if (key == null) { throw new java.lang.NullPointerException(); @@ -708,6 +725,7 @@ public java.lang.String getLabelsOrDefault(java.lang.String key, java.lang.Strin * * map<string, string> labels = 7; */ + @java.lang.Override public java.lang.String getLabelsOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1606,6 +1624,7 @@ public Builder setDisplayNameBytes(com.google.protobuf.ByteString value) { * * @return The nodeCount. */ + @java.lang.Override public int getNodeCount() { return nodeCount_; } @@ -1669,6 +1688,7 @@ public Builder clearNodeCount() { * * @return The enum numeric value on the wire for state. */ + @java.lang.Override public int getStateValue() { return state_; } @@ -1689,6 +1709,7 @@ public int getStateValue() { * @return This builder for chaining. */ public Builder setStateValue(int value) { + state_ = value; onChanged(); return this; @@ -1708,6 +1729,7 @@ public Builder setStateValue(int value) { * * @return The state. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance.State getState() { @SuppressWarnings("deprecation") com.google.spanner.admin.instance.v1.Instance.State result = @@ -1814,6 +1836,7 @@ public int getLabelsCount() { * * map<string, string> labels = 7; */ + @java.lang.Override public boolean containsLabels(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1821,6 +1844,7 @@ public boolean containsLabels(java.lang.String key) { return internalGetLabels().getMap().containsKey(key); } /** Use {@link #getLabelsMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getLabels() { return getLabelsMap(); @@ -1851,6 +1875,7 @@ public java.util.Map getLabels() { * * map<string, string> labels = 7; */ + @java.lang.Override public java.util.Map getLabelsMap() { return internalGetLabels().getMap(); } @@ -1880,6 +1905,7 @@ public java.util.Map getLabelsMap() { * * map<string, string> labels = 7; */ + @java.lang.Override public java.lang.String getLabelsOrDefault( java.lang.String key, java.lang.String defaultValue) { if (key == null) { @@ -1914,6 +1940,7 @@ public java.lang.String getLabelsOrDefault( * * map<string, string> labels = 7; */ + @java.lang.Override public java.lang.String getLabelsOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/InstanceConfig.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/InstanceConfig.java index 2fec1f92be..169fd017cb 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/InstanceConfig.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/InstanceConfig.java @@ -153,6 +153,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -177,6 +178,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -202,6 +204,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return The displayName. */ + @java.lang.Override public java.lang.String getDisplayName() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -224,6 +227,7 @@ public java.lang.String getDisplayName() { * * @return The bytes for displayName. */ + @java.lang.Override public com.google.protobuf.ByteString getDisplayNameBytes() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -248,6 +252,7 @@ public com.google.protobuf.ByteString getDisplayNameBytes() { * * repeated .google.spanner.admin.instance.v1.ReplicaInfo replicas = 3; */ + @java.lang.Override public java.util.List getReplicasList() { return replicas_; } @@ -261,6 +266,7 @@ public java.util.List getRepli * * repeated .google.spanner.admin.instance.v1.ReplicaInfo replicas = 3; */ + @java.lang.Override public java.util.List getReplicasOrBuilderList() { return replicas_; @@ -275,6 +281,7 @@ public java.util.List getRepli * * repeated .google.spanner.admin.instance.v1.ReplicaInfo replicas = 3; */ + @java.lang.Override public int getReplicasCount() { return replicas_.size(); } @@ -288,6 +295,7 @@ public int getReplicasCount() { * * repeated .google.spanner.admin.instance.v1.ReplicaInfo replicas = 3; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.ReplicaInfo getReplicas(int index) { return replicas_.get(index); } @@ -301,6 +309,7 @@ public com.google.spanner.admin.instance.v1.ReplicaInfo getReplicas(int index) { * * repeated .google.spanner.admin.instance.v1.ReplicaInfo replicas = 3; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.ReplicaInfoOrBuilder getReplicasOrBuilder(int index) { return replicas_.get(index); } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsRequest.java index 6df61c2a81..a4cb810d6c 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsRequest.java @@ -141,6 +141,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -167,6 +168,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -193,6 +195,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -212,6 +215,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -236,6 +240,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -741,6 +746,7 @@ public Builder setParentBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsResponse.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsResponse.java index dcc3b6943a..824e327d69 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsResponse.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstanceConfigsResponse.java @@ -140,6 +140,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.instance.v1.InstanceConfig instance_configs = 1; */ + @java.lang.Override public java.util.List getInstanceConfigsList() { return instanceConfigs_; @@ -153,6 +154,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.instance.v1.InstanceConfig instance_configs = 1; */ + @java.lang.Override public java.util.List getInstanceConfigsOrBuilderList() { return instanceConfigs_; @@ -166,6 +168,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.instance.v1.InstanceConfig instance_configs = 1; */ + @java.lang.Override public int getInstanceConfigsCount() { return instanceConfigs_.size(); } @@ -178,6 +181,7 @@ public int getInstanceConfigsCount() { * * repeated .google.spanner.admin.instance.v1.InstanceConfig instance_configs = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceConfig getInstanceConfigs(int index) { return instanceConfigs_.get(index); } @@ -190,6 +194,7 @@ public com.google.spanner.admin.instance.v1.InstanceConfig getInstanceConfigs(in * * repeated .google.spanner.admin.instance.v1.InstanceConfig instance_configs = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceConfigOrBuilder getInstanceConfigsOrBuilder( int index) { return instanceConfigs_.get(index); @@ -210,6 +215,7 @@ public com.google.spanner.admin.instance.v1.InstanceConfigOrBuilder getInstanceC * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -234,6 +240,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesRequest.java index 58b336a15c..b12cc10d0b 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesRequest.java @@ -148,6 +148,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The parent. */ + @java.lang.Override public java.lang.String getParent() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -173,6 +174,7 @@ public java.lang.String getParent() { * * @return The bytes for parent. */ + @java.lang.Override public com.google.protobuf.ByteString getParentBytes() { java.lang.Object ref = parent_; if (ref instanceof java.lang.String) { @@ -199,6 +201,7 @@ public com.google.protobuf.ByteString getParentBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -218,6 +221,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -242,6 +246,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -282,6 +287,7 @@ public com.google.protobuf.ByteString getPageTokenBytes() { * * @return The filter. */ + @java.lang.Override public java.lang.String getFilter() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -319,6 +325,7 @@ public java.lang.String getFilter() { * * @return The bytes for filter. */ + @java.lang.Override public com.google.protobuf.ByteString getFilterBytes() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -831,6 +838,7 @@ public Builder setParentBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesResponse.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesResponse.java index 873904d3d2..bf38519d98 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesResponse.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ListInstancesResponse.java @@ -139,6 +139,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.admin.instance.v1.Instance instances = 1; */ + @java.lang.Override public java.util.List getInstancesList() { return instances_; } @@ -151,6 +152,7 @@ public java.util.List getInstance * * repeated .google.spanner.admin.instance.v1.Instance instances = 1; */ + @java.lang.Override public java.util.List getInstancesOrBuilderList() { return instances_; @@ -164,6 +166,7 @@ public java.util.List getInstance * * repeated .google.spanner.admin.instance.v1.Instance instances = 1; */ + @java.lang.Override public int getInstancesCount() { return instances_.size(); } @@ -176,6 +179,7 @@ public int getInstancesCount() { * * repeated .google.spanner.admin.instance.v1.Instance instances = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance getInstances(int index) { return instances_.get(index); } @@ -188,6 +192,7 @@ public com.google.spanner.admin.instance.v1.Instance getInstances(int index) { * * repeated .google.spanner.admin.instance.v1.Instance instances = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstancesOrBuilder(int index) { return instances_.get(index); } @@ -207,6 +212,7 @@ public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstancesOrBuil * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -231,6 +237,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ReplicaInfo.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ReplicaInfo.java index 9ff4e397ac..d016c20831 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ReplicaInfo.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/ReplicaInfo.java @@ -289,6 +289,10 @@ public ReplicaType findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -334,6 +338,7 @@ private ReplicaType(int value) { * * @return The location. */ + @java.lang.Override public java.lang.String getLocation() { java.lang.Object ref = location_; if (ref instanceof java.lang.String) { @@ -356,6 +361,7 @@ public java.lang.String getLocation() { * * @return The bytes for location. */ + @java.lang.Override public com.google.protobuf.ByteString getLocationBytes() { java.lang.Object ref = location_; if (ref instanceof java.lang.String) { @@ -381,6 +387,7 @@ public com.google.protobuf.ByteString getLocationBytes() { * * @return The enum numeric value on the wire for type. */ + @java.lang.Override public int getTypeValue() { return type_; } @@ -395,6 +402,7 @@ public int getTypeValue() { * * @return The type. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType getType() { @SuppressWarnings("deprecation") com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType result = @@ -420,6 +428,7 @@ public com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType getType() { * * @return The defaultLeaderLocation. */ + @java.lang.Override public boolean getDefaultLeaderLocation() { return defaultLeaderLocation_; } @@ -885,6 +894,7 @@ public Builder setLocationBytes(com.google.protobuf.ByteString value) { * * @return The enum numeric value on the wire for type. */ + @java.lang.Override public int getTypeValue() { return type_; } @@ -901,6 +911,7 @@ public int getTypeValue() { * @return This builder for chaining. */ public Builder setTypeValue(int value) { + type_ = value; onChanged(); return this; @@ -916,6 +927,7 @@ public Builder setTypeValue(int value) { * * @return The type. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType getType() { @SuppressWarnings("deprecation") com.google.spanner.admin.instance.v1.ReplicaInfo.ReplicaType result = @@ -978,6 +990,7 @@ public Builder clearType() { * * @return The defaultLeaderLocation. */ + @java.lang.Override public boolean getDefaultLeaderLocation() { return defaultLeaderLocation_; } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceMetadata.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceMetadata.java index cfee6cdcdf..fdb914299e 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceMetadata.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceMetadata.java @@ -177,6 +177,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the instance field is set. */ + @java.lang.Override public boolean hasInstance() { return instance_ != null; } @@ -191,6 +192,7 @@ public boolean hasInstance() { * * @return The instance. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance getInstance() { return instance_ == null ? com.google.spanner.admin.instance.v1.Instance.getDefaultInstance() @@ -205,6 +207,7 @@ public com.google.spanner.admin.instance.v1.Instance getInstance() { * * .google.spanner.admin.instance.v1.Instance instance = 1; */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuilder() { return getInstance(); } @@ -223,6 +226,7 @@ public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuild * * @return Whether the startTime field is set. */ + @java.lang.Override public boolean hasStartTime() { return startTime_ != null; } @@ -238,6 +242,7 @@ public boolean hasStartTime() { * * @return The startTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getStartTime() { return startTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : startTime_; } @@ -251,6 +256,7 @@ public com.google.protobuf.Timestamp getStartTime() { * * .google.protobuf.Timestamp start_time = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { return getStartTime(); } @@ -270,6 +276,7 @@ public com.google.protobuf.TimestampOrBuilder getStartTimeOrBuilder() { * * @return Whether the cancelTime field is set. */ + @java.lang.Override public boolean hasCancelTime() { return cancelTime_ != null; } @@ -286,6 +293,7 @@ public boolean hasCancelTime() { * * @return The cancelTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCancelTime() { return cancelTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : cancelTime_; } @@ -300,6 +308,7 @@ public com.google.protobuf.Timestamp getCancelTime() { * * .google.protobuf.Timestamp cancel_time = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { return getCancelTime(); } @@ -317,6 +326,7 @@ public com.google.protobuf.TimestampOrBuilder getCancelTimeOrBuilder() { * * @return Whether the endTime field is set. */ + @java.lang.Override public boolean hasEndTime() { return endTime_ != null; } @@ -331,6 +341,7 @@ public boolean hasEndTime() { * * @return The endTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getEndTime() { return endTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : endTime_; } @@ -343,6 +354,7 @@ public com.google.protobuf.Timestamp getEndTime() { * * .google.protobuf.Timestamp end_time = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getEndTimeOrBuilder() { return getEndTime(); } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceRequest.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceRequest.java index 417a5596ca..44034ce459 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceRequest.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/UpdateInstanceRequest.java @@ -149,6 +149,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the instance field is set. */ + @java.lang.Override public boolean hasInstance() { return instance_ != null; } @@ -166,6 +167,7 @@ public boolean hasInstance() { * * @return The instance. */ + @java.lang.Override public com.google.spanner.admin.instance.v1.Instance getInstance() { return instance_ == null ? com.google.spanner.admin.instance.v1.Instance.getDefaultInstance() @@ -183,6 +185,7 @@ public com.google.spanner.admin.instance.v1.Instance getInstance() { * .google.spanner.admin.instance.v1.Instance instance = 1 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuilder() { return getInstance(); } @@ -204,6 +207,7 @@ public com.google.spanner.admin.instance.v1.InstanceOrBuilder getInstanceOrBuild * * @return Whether the fieldMask field is set. */ + @java.lang.Override public boolean hasFieldMask() { return fieldMask_ != null; } @@ -222,6 +226,7 @@ public boolean hasFieldMask() { * * @return The fieldMask. */ + @java.lang.Override public com.google.protobuf.FieldMask getFieldMask() { return fieldMask_ == null ? com.google.protobuf.FieldMask.getDefaultInstance() : fieldMask_; } @@ -238,6 +243,7 @@ public com.google.protobuf.FieldMask getFieldMask() { * .google.protobuf.FieldMask field_mask = 2 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.protobuf.FieldMaskOrBuilder getFieldMaskOrBuilder() { return getFieldMask(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsRequest.java index e81418ea91..cdca44bf67 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsRequest.java @@ -146,6 +146,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -170,6 +171,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -195,6 +197,7 @@ public com.google.protobuf.ByteString getDatabaseBytes() { * * @return Whether the sessionTemplate field is set. */ + @java.lang.Override public boolean hasSessionTemplate() { return sessionTemplate_ != null; } @@ -209,6 +212,7 @@ public boolean hasSessionTemplate() { * * @return The sessionTemplate. */ + @java.lang.Override public com.google.spanner.v1.Session getSessionTemplate() { return sessionTemplate_ == null ? com.google.spanner.v1.Session.getDefaultInstance() @@ -223,6 +227,7 @@ public com.google.spanner.v1.Session getSessionTemplate() { * * .google.spanner.v1.Session session_template = 2; */ + @java.lang.Override public com.google.spanner.v1.SessionOrBuilder getSessionTemplateOrBuilder() { return getSessionTemplate(); } @@ -244,6 +249,7 @@ public com.google.spanner.v1.SessionOrBuilder getSessionTemplateOrBuilder() { * * @return The sessionCount. */ + @java.lang.Override public int getSessionCount() { return sessionCount_; } @@ -925,6 +931,7 @@ public com.google.spanner.v1.SessionOrBuilder getSessionTemplateOrBuilder() { * * @return The sessionCount. */ + @java.lang.Override public int getSessionCount() { return sessionCount_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsResponse.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsResponse.java index 271c39a3b5..76704fd06e 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsResponse.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BatchCreateSessionsResponse.java @@ -129,6 +129,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.v1.Session session = 1; */ + @java.lang.Override public java.util.List getSessionList() { return session_; } @@ -141,6 +142,7 @@ public java.util.List getSessionList() { * * repeated .google.spanner.v1.Session session = 1; */ + @java.lang.Override public java.util.List getSessionOrBuilderList() { return session_; @@ -154,6 +156,7 @@ public java.util.List getSessionList() { * * repeated .google.spanner.v1.Session session = 1; */ + @java.lang.Override public int getSessionCount() { return session_.size(); } @@ -166,6 +169,7 @@ public int getSessionCount() { * * repeated .google.spanner.v1.Session session = 1; */ + @java.lang.Override public com.google.spanner.v1.Session getSession(int index) { return session_.get(index); } @@ -178,6 +182,7 @@ public com.google.spanner.v1.Session getSession(int index) { * * repeated .google.spanner.v1.Session session = 1; */ + @java.lang.Override public com.google.spanner.v1.SessionOrBuilder getSessionOrBuilder(int index) { return session_.get(index); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BeginTransactionRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BeginTransactionRequest.java index ecc0bd3610..9a89fe0b89 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BeginTransactionRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/BeginTransactionRequest.java @@ -142,6 +142,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -166,6 +167,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -193,6 +195,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the options field is set. */ + @java.lang.Override public boolean hasOptions() { return options_ != null; } @@ -209,6 +212,7 @@ public boolean hasOptions() { * * @return The options. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getOptions() { return options_ == null ? com.google.spanner.v1.TransactionOptions.getDefaultInstance() @@ -225,6 +229,7 @@ public com.google.spanner.v1.TransactionOptions getOptions() { * .google.spanner.v1.TransactionOptions options = 2 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getOptionsOrBuilder() { return getOptions(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitRequest.java index 8c967a9446..f322ec04c0 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitRequest.java @@ -210,6 +210,7 @@ public TransactionCase getTransactionCase() { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -234,6 +235,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -258,6 +260,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return The transactionId. */ + @java.lang.Override public com.google.protobuf.ByteString getTransactionId() { if (transactionCase_ == 2) { return (com.google.protobuf.ByteString) transaction_; @@ -285,6 +288,7 @@ public com.google.protobuf.ByteString getTransactionId() { * * @return Whether the singleUseTransaction field is set. */ + @java.lang.Override public boolean hasSingleUseTransaction() { return transactionCase_ == 3; } @@ -307,6 +311,7 @@ public boolean hasSingleUseTransaction() { * * @return The singleUseTransaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getSingleUseTransaction() { if (transactionCase_ == 3) { return (com.google.spanner.v1.TransactionOptions) transaction_; @@ -330,6 +335,7 @@ public com.google.spanner.v1.TransactionOptions getSingleUseTransaction() { * * .google.spanner.v1.TransactionOptions single_use_transaction = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseTransactionOrBuilder() { if (transactionCase_ == 3) { return (com.google.spanner.v1.TransactionOptions) transaction_; @@ -350,6 +356,7 @@ public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseTransaction * * repeated .google.spanner.v1.Mutation mutations = 4; */ + @java.lang.Override public java.util.List getMutationsList() { return mutations_; } @@ -364,6 +371,7 @@ public java.util.List getMutationsList() { * * repeated .google.spanner.v1.Mutation mutations = 4; */ + @java.lang.Override public java.util.List getMutationsOrBuilderList() { return mutations_; @@ -379,6 +387,7 @@ public java.util.List getMutationsList() { * * repeated .google.spanner.v1.Mutation mutations = 4; */ + @java.lang.Override public int getMutationsCount() { return mutations_.size(); } @@ -393,6 +402,7 @@ public int getMutationsCount() { * * repeated .google.spanner.v1.Mutation mutations = 4; */ + @java.lang.Override public com.google.spanner.v1.Mutation getMutations(int index) { return mutations_.get(index); } @@ -407,6 +417,7 @@ public com.google.spanner.v1.Mutation getMutations(int index) { * * repeated .google.spanner.v1.Mutation mutations = 4; */ + @java.lang.Override public com.google.spanner.v1.MutationOrBuilder getMutationsOrBuilder(int index) { return mutations_.get(index); } @@ -1062,6 +1073,7 @@ public Builder clearTransactionId() { * * @return Whether the singleUseTransaction field is set. */ + @java.lang.Override public boolean hasSingleUseTransaction() { return transactionCase_ == 3; } @@ -1084,6 +1096,7 @@ public boolean hasSingleUseTransaction() { * * @return The singleUseTransaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getSingleUseTransaction() { if (singleUseTransactionBuilder_ == null) { if (transactionCase_ == 3) { @@ -1264,6 +1277,7 @@ public com.google.spanner.v1.TransactionOptions.Builder getSingleUseTransactionB * * .google.spanner.v1.TransactionOptions single_use_transaction = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseTransactionOrBuilder() { if ((transactionCase_ == 3) && (singleUseTransactionBuilder_ != null)) { return singleUseTransactionBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitResponse.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitResponse.java index 0b0507af4b..2877285845 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitResponse.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CommitResponse.java @@ -130,6 +130,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the commitTimestamp field is set. */ + @java.lang.Override public boolean hasCommitTimestamp() { return commitTimestamp_ != null; } @@ -144,6 +145,7 @@ public boolean hasCommitTimestamp() { * * @return The commitTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getCommitTimestamp() { return commitTimestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() @@ -158,6 +160,7 @@ public com.google.protobuf.Timestamp getCommitTimestamp() { * * .google.protobuf.Timestamp commit_timestamp = 1; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCommitTimestampOrBuilder() { return getCommitTimestamp(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CreateSessionRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CreateSessionRequest.java index c3706ec702..ea35c5266a 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CreateSessionRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/CreateSessionRequest.java @@ -141,6 +141,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -165,6 +166,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -190,6 +192,7 @@ public com.google.protobuf.ByteString getDatabaseBytes() { * * @return Whether the session field is set. */ + @java.lang.Override public boolean hasSession() { return session_ != null; } @@ -204,6 +207,7 @@ public boolean hasSession() { * * @return The session. */ + @java.lang.Override public com.google.spanner.v1.Session getSession() { return session_ == null ? com.google.spanner.v1.Session.getDefaultInstance() : session_; } @@ -216,6 +220,7 @@ public com.google.spanner.v1.Session getSession() { * * .google.spanner.v1.Session session = 2; */ + @java.lang.Override public com.google.spanner.v1.SessionOrBuilder getSessionOrBuilder() { return getSession(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/DeleteSessionRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/DeleteSessionRequest.java index 93b92ad259..ca462176e7 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/DeleteSessionRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/DeleteSessionRequest.java @@ -126,6 +126,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -150,6 +151,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlRequest.java index 521d2d616e..80dbef5507 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlRequest.java @@ -470,6 +470,7 @@ protected com.google.protobuf.MapField internalGetMapField(int number) { * * @return The sql. */ + @java.lang.Override public java.lang.String getSql() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -492,6 +493,7 @@ public java.lang.String getSql() { * * @return The bytes for sql. */ + @java.lang.Override public com.google.protobuf.ByteString getSqlBytes() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -524,6 +526,7 @@ public com.google.protobuf.ByteString getSqlBytes() { * * @return Whether the params field is set. */ + @java.lang.Override public boolean hasParams() { return params_ != null; } @@ -545,6 +548,7 @@ public boolean hasParams() { * * @return The params. */ + @java.lang.Override public com.google.protobuf.Struct getParams() { return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; } @@ -564,6 +568,7 @@ public com.google.protobuf.Struct getParams() { * * .google.protobuf.Struct params = 2; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { return getParams(); } @@ -612,6 +617,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -619,6 +625,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -638,6 +645,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -656,6 +664,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -680,6 +689,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1479,6 +1489,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1486,6 +1497,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -1505,6 +1517,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -1523,6 +1536,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -1547,6 +1561,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 3; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1703,6 +1718,7 @@ public com.google.spanner.v1.ExecuteBatchDmlRequest.Statement getDefaultInstance * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -1727,6 +1743,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -1757,6 +1774,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -1776,6 +1794,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionSelector getTransaction() { return transaction_ == null ? com.google.spanner.v1.TransactionSelector.getDefaultInstance() @@ -1795,6 +1814,7 @@ public com.google.spanner.v1.TransactionSelector getTransaction() { * .google.spanner.v1.TransactionSelector transaction = 2 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilder() { return getTransaction(); } @@ -1816,6 +1836,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * repeated .google.spanner.v1.ExecuteBatchDmlRequest.Statement statements = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public java.util.List getStatementsList() { return statements_; @@ -1835,6 +1856,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * repeated .google.spanner.v1.ExecuteBatchDmlRequest.Statement statements = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public java.util.List getStatementsOrBuilderList() { return statements_; @@ -1854,6 +1876,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * repeated .google.spanner.v1.ExecuteBatchDmlRequest.Statement statements = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public int getStatementsCount() { return statements_.size(); } @@ -1872,6 +1895,7 @@ public int getStatementsCount() { * repeated .google.spanner.v1.ExecuteBatchDmlRequest.Statement statements = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.v1.ExecuteBatchDmlRequest.Statement getStatements(int index) { return statements_.get(index); } @@ -1890,6 +1914,7 @@ public com.google.spanner.v1.ExecuteBatchDmlRequest.Statement getStatements(int * repeated .google.spanner.v1.ExecuteBatchDmlRequest.Statement statements = 3 [(.google.api.field_behavior) = REQUIRED]; * */ + @java.lang.Override public com.google.spanner.v1.ExecuteBatchDmlRequest.StatementOrBuilder getStatementsOrBuilder( int index) { return statements_.get(index); @@ -1914,6 +1939,7 @@ public com.google.spanner.v1.ExecuteBatchDmlRequest.StatementOrBuilder getStatem * * @return The seqno. */ + @java.lang.Override public long getSeqno() { return seqno_; } @@ -3168,6 +3194,7 @@ public com.google.spanner.v1.ExecuteBatchDmlRequest.Statement.Builder addStateme * * @return The seqno. */ + @java.lang.Override public long getSeqno() { return seqno_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlResponse.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlResponse.java index 34430d3961..814553409d 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlResponse.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteBatchDmlResponse.java @@ -165,6 +165,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.v1.ResultSet result_sets = 1; */ + @java.lang.Override public java.util.List getResultSetsList() { return resultSets_; } @@ -182,6 +183,7 @@ public java.util.List getResultSetsList() { * * repeated .google.spanner.v1.ResultSet result_sets = 1; */ + @java.lang.Override public java.util.List getResultSetsOrBuilderList() { return resultSets_; @@ -200,6 +202,7 @@ public java.util.List getResultSetsList() { * * repeated .google.spanner.v1.ResultSet result_sets = 1; */ + @java.lang.Override public int getResultSetsCount() { return resultSets_.size(); } @@ -217,6 +220,7 @@ public int getResultSetsCount() { * * repeated .google.spanner.v1.ResultSet result_sets = 1; */ + @java.lang.Override public com.google.spanner.v1.ResultSet getResultSets(int index) { return resultSets_.get(index); } @@ -234,6 +238,7 @@ public com.google.spanner.v1.ResultSet getResultSets(int index) { * * repeated .google.spanner.v1.ResultSet result_sets = 1; */ + @java.lang.Override public com.google.spanner.v1.ResultSetOrBuilder getResultSetsOrBuilder(int index) { return resultSets_.get(index); } @@ -252,6 +257,7 @@ public com.google.spanner.v1.ResultSetOrBuilder getResultSetsOrBuilder(int index * * @return Whether the status field is set. */ + @java.lang.Override public boolean hasStatus() { return status_ != null; } @@ -267,6 +273,7 @@ public boolean hasStatus() { * * @return The status. */ + @java.lang.Override public com.google.rpc.Status getStatus() { return status_ == null ? com.google.rpc.Status.getDefaultInstance() : status_; } @@ -280,6 +287,7 @@ public com.google.rpc.Status getStatus() { * * .google.rpc.Status status = 2; */ + @java.lang.Override public com.google.rpc.StatusOrBuilder getStatusOrBuilder() { return getStatus(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteSqlRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteSqlRequest.java index d2c7bbb456..1e757805fd 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteSqlRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ExecuteSqlRequest.java @@ -345,6 +345,10 @@ public QueryMode findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -549,6 +553,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The optimizerVersion. */ + @java.lang.Override public java.lang.String getOptimizerVersion() { java.lang.Object ref = optimizerVersion_; if (ref instanceof java.lang.String) { @@ -583,6 +588,7 @@ public java.lang.String getOptimizerVersion() { * * @return The bytes for optimizerVersion. */ + @java.lang.Override public com.google.protobuf.ByteString getOptimizerVersionBytes() { java.lang.Object ref = optimizerVersion_; if (ref instanceof java.lang.String) { @@ -1151,6 +1157,7 @@ public com.google.spanner.v1.ExecuteSqlRequest.QueryOptions getDefaultInstanceFo * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -1175,6 +1182,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -1206,6 +1214,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -1226,6 +1235,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionSelector getTransaction() { return transaction_ == null ? com.google.spanner.v1.TransactionSelector.getDefaultInstance() @@ -1246,6 +1256,7 @@ public com.google.spanner.v1.TransactionSelector getTransaction() { * * .google.spanner.v1.TransactionSelector transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilder() { return getTransaction(); } @@ -1263,6 +1274,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * * @return The sql. */ + @java.lang.Override public java.lang.String getSql() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -1285,6 +1297,7 @@ public java.lang.String getSql() { * * @return The bytes for sql. */ + @java.lang.Override public com.google.protobuf.ByteString getSqlBytes() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -1317,6 +1330,7 @@ public com.google.protobuf.ByteString getSqlBytes() { * * @return Whether the params field is set. */ + @java.lang.Override public boolean hasParams() { return params_ != null; } @@ -1338,6 +1352,7 @@ public boolean hasParams() { * * @return The params. */ + @java.lang.Override public com.google.protobuf.Struct getParams() { return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; } @@ -1357,6 +1372,7 @@ public com.google.protobuf.Struct getParams() { * * .google.protobuf.Struct params = 4; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { return getParams(); } @@ -1404,6 +1420,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1411,6 +1428,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -1430,6 +1448,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -1448,6 +1467,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -1472,6 +1492,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1502,6 +1523,7 @@ public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } @@ -1521,6 +1543,7 @@ public com.google.protobuf.ByteString getResumeToken() { * * @return The enum numeric value on the wire for queryMode. */ + @java.lang.Override public int getQueryModeValue() { return queryMode_; } @@ -1537,6 +1560,7 @@ public int getQueryModeValue() { * * @return The queryMode. */ + @java.lang.Override public com.google.spanner.v1.ExecuteSqlRequest.QueryMode getQueryMode() { @SuppressWarnings("deprecation") com.google.spanner.v1.ExecuteSqlRequest.QueryMode result = @@ -1560,6 +1584,7 @@ public com.google.spanner.v1.ExecuteSqlRequest.QueryMode getQueryMode() { * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } @@ -1584,6 +1609,7 @@ public com.google.protobuf.ByteString getPartitionToken() { * * @return The seqno. */ + @java.lang.Override public long getSeqno() { return seqno_; } @@ -1601,6 +1627,7 @@ public long getSeqno() { * * @return Whether the queryOptions field is set. */ + @java.lang.Override public boolean hasQueryOptions() { return queryOptions_ != null; } @@ -1615,6 +1642,7 @@ public boolean hasQueryOptions() { * * @return The queryOptions. */ + @java.lang.Override public com.google.spanner.v1.ExecuteSqlRequest.QueryOptions getQueryOptions() { return queryOptions_ == null ? com.google.spanner.v1.ExecuteSqlRequest.QueryOptions.getDefaultInstance() @@ -1629,6 +1657,7 @@ public com.google.spanner.v1.ExecuteSqlRequest.QueryOptions getQueryOptions() { * * .google.spanner.v1.ExecuteSqlRequest.QueryOptions query_options = 10; */ + @java.lang.Override public com.google.spanner.v1.ExecuteSqlRequest.QueryOptionsOrBuilder getQueryOptionsOrBuilder() { return getQueryOptions(); } @@ -2899,6 +2928,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -2906,6 +2936,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -2925,6 +2956,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -2943,6 +2975,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -2967,6 +3000,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -3073,6 +3107,7 @@ public Builder putAllParamTypes( * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } @@ -3139,6 +3174,7 @@ public Builder clearResumeToken() { * * @return The enum numeric value on the wire for queryMode. */ + @java.lang.Override public int getQueryModeValue() { return queryMode_; } @@ -3157,6 +3193,7 @@ public int getQueryModeValue() { * @return This builder for chaining. */ public Builder setQueryModeValue(int value) { + queryMode_ = value; onChanged(); return this; @@ -3174,6 +3211,7 @@ public Builder setQueryModeValue(int value) { * * @return The queryMode. */ + @java.lang.Override public com.google.spanner.v1.ExecuteSqlRequest.QueryMode getQueryMode() { @SuppressWarnings("deprecation") com.google.spanner.v1.ExecuteSqlRequest.QueryMode result = @@ -3240,6 +3278,7 @@ public Builder clearQueryMode() { * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } @@ -3307,6 +3346,7 @@ public Builder clearPartitionToken() { * * @return The seqno. */ + @java.lang.Override public long getSeqno() { return seqno_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/GetSessionRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/GetSessionRequest.java index 4e0d9a719e..e8c23cb150 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/GetSessionRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/GetSessionRequest.java @@ -126,6 +126,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -150,6 +151,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeyRange.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeyRange.java index 0556df3bac..31eeafed84 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeyRange.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeyRange.java @@ -327,6 +327,7 @@ public EndKeyTypeCase getEndKeyTypeCase() { * * @return Whether the startClosed field is set. */ + @java.lang.Override public boolean hasStartClosed() { return startKeyTypeCase_ == 1; } @@ -342,6 +343,7 @@ public boolean hasStartClosed() { * * @return The startClosed. */ + @java.lang.Override public com.google.protobuf.ListValue getStartClosed() { if (startKeyTypeCase_ == 1) { return (com.google.protobuf.ListValue) startKeyType_; @@ -358,6 +360,7 @@ public com.google.protobuf.ListValue getStartClosed() { * * .google.protobuf.ListValue start_closed = 1; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getStartClosedOrBuilder() { if (startKeyTypeCase_ == 1) { return (com.google.protobuf.ListValue) startKeyType_; @@ -378,6 +381,7 @@ public com.google.protobuf.ListValueOrBuilder getStartClosedOrBuilder() { * * @return Whether the startOpen field is set. */ + @java.lang.Override public boolean hasStartOpen() { return startKeyTypeCase_ == 2; } @@ -393,6 +397,7 @@ public boolean hasStartOpen() { * * @return The startOpen. */ + @java.lang.Override public com.google.protobuf.ListValue getStartOpen() { if (startKeyTypeCase_ == 2) { return (com.google.protobuf.ListValue) startKeyType_; @@ -409,6 +414,7 @@ public com.google.protobuf.ListValue getStartOpen() { * * .google.protobuf.ListValue start_open = 2; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getStartOpenOrBuilder() { if (startKeyTypeCase_ == 2) { return (com.google.protobuf.ListValue) startKeyType_; @@ -429,6 +435,7 @@ public com.google.protobuf.ListValueOrBuilder getStartOpenOrBuilder() { * * @return Whether the endClosed field is set. */ + @java.lang.Override public boolean hasEndClosed() { return endKeyTypeCase_ == 3; } @@ -444,6 +451,7 @@ public boolean hasEndClosed() { * * @return The endClosed. */ + @java.lang.Override public com.google.protobuf.ListValue getEndClosed() { if (endKeyTypeCase_ == 3) { return (com.google.protobuf.ListValue) endKeyType_; @@ -460,6 +468,7 @@ public com.google.protobuf.ListValue getEndClosed() { * * .google.protobuf.ListValue end_closed = 3; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getEndClosedOrBuilder() { if (endKeyTypeCase_ == 3) { return (com.google.protobuf.ListValue) endKeyType_; @@ -480,6 +489,7 @@ public com.google.protobuf.ListValueOrBuilder getEndClosedOrBuilder() { * * @return Whether the endOpen field is set. */ + @java.lang.Override public boolean hasEndOpen() { return endKeyTypeCase_ == 4; } @@ -495,6 +505,7 @@ public boolean hasEndOpen() { * * @return The endOpen. */ + @java.lang.Override public com.google.protobuf.ListValue getEndOpen() { if (endKeyTypeCase_ == 4) { return (com.google.protobuf.ListValue) endKeyType_; @@ -511,6 +522,7 @@ public com.google.protobuf.ListValue getEndOpen() { * * .google.protobuf.ListValue end_open = 4; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getEndOpenOrBuilder() { if (endKeyTypeCase_ == 4) { return (com.google.protobuf.ListValue) endKeyType_; @@ -1061,6 +1073,7 @@ public Builder clearEndKeyType() { * * @return Whether the startClosed field is set. */ + @java.lang.Override public boolean hasStartClosed() { return startKeyTypeCase_ == 1; } @@ -1076,6 +1089,7 @@ public boolean hasStartClosed() { * * @return The startClosed. */ + @java.lang.Override public com.google.protobuf.ListValue getStartClosed() { if (startClosedBuilder_ == null) { if (startKeyTypeCase_ == 1) { @@ -1213,6 +1227,7 @@ public com.google.protobuf.ListValue.Builder getStartClosedBuilder() { * * .google.protobuf.ListValue start_closed = 1; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getStartClosedOrBuilder() { if ((startKeyTypeCase_ == 1) && (startClosedBuilder_ != null)) { return startClosedBuilder_.getMessageOrBuilder(); @@ -1273,6 +1288,7 @@ public com.google.protobuf.ListValueOrBuilder getStartClosedOrBuilder() { * * @return Whether the startOpen field is set. */ + @java.lang.Override public boolean hasStartOpen() { return startKeyTypeCase_ == 2; } @@ -1288,6 +1304,7 @@ public boolean hasStartOpen() { * * @return The startOpen. */ + @java.lang.Override public com.google.protobuf.ListValue getStartOpen() { if (startOpenBuilder_ == null) { if (startKeyTypeCase_ == 2) { @@ -1425,6 +1442,7 @@ public com.google.protobuf.ListValue.Builder getStartOpenBuilder() { * * .google.protobuf.ListValue start_open = 2; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getStartOpenOrBuilder() { if ((startKeyTypeCase_ == 2) && (startOpenBuilder_ != null)) { return startOpenBuilder_.getMessageOrBuilder(); @@ -1485,6 +1503,7 @@ public com.google.protobuf.ListValueOrBuilder getStartOpenOrBuilder() { * * @return Whether the endClosed field is set. */ + @java.lang.Override public boolean hasEndClosed() { return endKeyTypeCase_ == 3; } @@ -1500,6 +1519,7 @@ public boolean hasEndClosed() { * * @return The endClosed. */ + @java.lang.Override public com.google.protobuf.ListValue getEndClosed() { if (endClosedBuilder_ == null) { if (endKeyTypeCase_ == 3) { @@ -1636,6 +1656,7 @@ public com.google.protobuf.ListValue.Builder getEndClosedBuilder() { * * .google.protobuf.ListValue end_closed = 3; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getEndClosedOrBuilder() { if ((endKeyTypeCase_ == 3) && (endClosedBuilder_ != null)) { return endClosedBuilder_.getMessageOrBuilder(); @@ -1696,6 +1717,7 @@ public com.google.protobuf.ListValueOrBuilder getEndClosedOrBuilder() { * * @return Whether the endOpen field is set. */ + @java.lang.Override public boolean hasEndOpen() { return endKeyTypeCase_ == 4; } @@ -1711,6 +1733,7 @@ public boolean hasEndOpen() { * * @return The endOpen. */ + @java.lang.Override public com.google.protobuf.ListValue getEndOpen() { if (endOpenBuilder_ == null) { if (endKeyTypeCase_ == 4) { @@ -1847,6 +1870,7 @@ public com.google.protobuf.ListValue.Builder getEndOpenBuilder() { * * .google.protobuf.ListValue end_open = 4; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getEndOpenOrBuilder() { if ((endKeyTypeCase_ == 4) && (endOpenBuilder_ != null)) { return endOpenBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeySet.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeySet.java index 36bff5a49f..c9cc35fa86 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeySet.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeySet.java @@ -154,6 +154,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.protobuf.ListValue keys = 1; */ + @java.lang.Override public java.util.List getKeysList() { return keys_; } @@ -169,6 +170,7 @@ public java.util.List getKeysList() { * * repeated .google.protobuf.ListValue keys = 1; */ + @java.lang.Override public java.util.List getKeysOrBuilderList() { return keys_; } @@ -184,6 +186,7 @@ public java.util.List getKeysO * * repeated .google.protobuf.ListValue keys = 1; */ + @java.lang.Override public int getKeysCount() { return keys_.size(); } @@ -199,6 +202,7 @@ public int getKeysCount() { * * repeated .google.protobuf.ListValue keys = 1; */ + @java.lang.Override public com.google.protobuf.ListValue getKeys(int index) { return keys_.get(index); } @@ -214,6 +218,7 @@ public com.google.protobuf.ListValue getKeys(int index) { * * repeated .google.protobuf.ListValue keys = 1; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getKeysOrBuilder(int index) { return keys_.get(index); } @@ -230,6 +235,7 @@ public com.google.protobuf.ListValueOrBuilder getKeysOrBuilder(int index) { * * repeated .google.spanner.v1.KeyRange ranges = 2; */ + @java.lang.Override public java.util.List getRangesList() { return ranges_; } @@ -243,6 +249,7 @@ public java.util.List getRangesList() { * * repeated .google.spanner.v1.KeyRange ranges = 2; */ + @java.lang.Override public java.util.List getRangesOrBuilderList() { return ranges_; @@ -257,6 +264,7 @@ public java.util.List getRangesList() { * * repeated .google.spanner.v1.KeyRange ranges = 2; */ + @java.lang.Override public int getRangesCount() { return ranges_.size(); } @@ -270,6 +278,7 @@ public int getRangesCount() { * * repeated .google.spanner.v1.KeyRange ranges = 2; */ + @java.lang.Override public com.google.spanner.v1.KeyRange getRanges(int index) { return ranges_.get(index); } @@ -283,6 +292,7 @@ public com.google.spanner.v1.KeyRange getRanges(int index) { * * repeated .google.spanner.v1.KeyRange ranges = 2; */ + @java.lang.Override public com.google.spanner.v1.KeyRangeOrBuilder getRangesOrBuilder(int index) { return ranges_.get(index); } @@ -302,6 +312,7 @@ public com.google.spanner.v1.KeyRangeOrBuilder getRangesOrBuilder(int index) { * * @return The all. */ + @java.lang.Override public boolean getAll() { return all_; } @@ -1506,6 +1517,7 @@ public java.util.List getRangesBuilderLi * * @return The all. */ + @java.lang.Override public boolean getAll() { return all_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsRequest.java index d7095c122a..6d39079533 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsRequest.java @@ -147,6 +147,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The database. */ + @java.lang.Override public java.lang.String getDatabase() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -171,6 +172,7 @@ public java.lang.String getDatabase() { * * @return The bytes for database. */ + @java.lang.Override public com.google.protobuf.ByteString getDatabaseBytes() { java.lang.Object ref = database_; if (ref instanceof java.lang.String) { @@ -197,6 +199,7 @@ public com.google.protobuf.ByteString getDatabaseBytes() { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } @@ -216,6 +219,7 @@ public int getPageSize() { * * @return The pageToken. */ + @java.lang.Override public java.lang.String getPageToken() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -240,6 +244,7 @@ public java.lang.String getPageToken() { * * @return The bytes for pageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPageTokenBytes() { java.lang.Object ref = pageToken_; if (ref instanceof java.lang.String) { @@ -271,6 +276,7 @@ public com.google.protobuf.ByteString getPageTokenBytes() { * * @return The filter. */ + @java.lang.Override public java.lang.String getFilter() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -299,6 +305,7 @@ public java.lang.String getFilter() { * * @return The bytes for filter. */ + @java.lang.Override public com.google.protobuf.ByteString getFilterBytes() { java.lang.Object ref = filter_; if (ref instanceof java.lang.String) { @@ -803,6 +810,7 @@ public Builder setDatabaseBytes(com.google.protobuf.ByteString value) { * * @return The pageSize. */ + @java.lang.Override public int getPageSize() { return pageSize_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsResponse.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsResponse.java index c04b870c22..6e7f0627e5 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsResponse.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ListSessionsResponse.java @@ -137,6 +137,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.v1.Session sessions = 1; */ + @java.lang.Override public java.util.List getSessionsList() { return sessions_; } @@ -149,6 +150,7 @@ public java.util.List getSessionsList() { * * repeated .google.spanner.v1.Session sessions = 1; */ + @java.lang.Override public java.util.List getSessionsOrBuilderList() { return sessions_; @@ -162,6 +164,7 @@ public java.util.List getSessionsList() { * * repeated .google.spanner.v1.Session sessions = 1; */ + @java.lang.Override public int getSessionsCount() { return sessions_.size(); } @@ -174,6 +177,7 @@ public int getSessionsCount() { * * repeated .google.spanner.v1.Session sessions = 1; */ + @java.lang.Override public com.google.spanner.v1.Session getSessions(int index) { return sessions_.get(index); } @@ -186,6 +190,7 @@ public com.google.spanner.v1.Session getSessions(int index) { * * repeated .google.spanner.v1.Session sessions = 1; */ + @java.lang.Override public com.google.spanner.v1.SessionOrBuilder getSessionsOrBuilder(int index) { return sessions_.get(index); } @@ -205,6 +210,7 @@ public com.google.spanner.v1.SessionOrBuilder getSessionsOrBuilder(int index) { * * @return The nextPageToken. */ + @java.lang.Override public java.lang.String getNextPageToken() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { @@ -229,6 +235,7 @@ public java.lang.String getNextPageToken() { * * @return The bytes for nextPageToken. */ + @java.lang.Override public com.google.protobuf.ByteString getNextPageTokenBytes() { java.lang.Object ref = nextPageToken_; if (ref instanceof java.lang.String) { diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Mutation.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Mutation.java index 644ad56058..8d3222c5ee 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Mutation.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Mutation.java @@ -498,6 +498,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The table. */ + @java.lang.Override public java.lang.String getTable() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -520,6 +521,7 @@ public java.lang.String getTable() { * * @return The bytes for table. */ + @java.lang.Override public com.google.protobuf.ByteString getTableBytes() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -623,6 +625,7 @@ public com.google.protobuf.ByteString getColumnsBytes(int index) { * * repeated .google.protobuf.ListValue values = 3; */ + @java.lang.Override public java.util.List getValuesList() { return values_; } @@ -642,6 +645,7 @@ public java.util.List getValuesList() { * * repeated .google.protobuf.ListValue values = 3; */ + @java.lang.Override public java.util.List getValuesOrBuilderList() { return values_; @@ -662,6 +666,7 @@ public java.util.List getValuesList() { * * repeated .google.protobuf.ListValue values = 3; */ + @java.lang.Override public int getValuesCount() { return values_.size(); } @@ -681,6 +686,7 @@ public int getValuesCount() { * * repeated .google.protobuf.ListValue values = 3; */ + @java.lang.Override public com.google.protobuf.ListValue getValues(int index) { return values_.get(index); } @@ -700,6 +706,7 @@ public com.google.protobuf.ListValue getValues(int index) { * * repeated .google.protobuf.ListValue values = 3; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getValuesOrBuilder(int index) { return values_.get(index); } @@ -2141,6 +2148,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The table. */ + @java.lang.Override public java.lang.String getTable() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -2163,6 +2171,7 @@ public java.lang.String getTable() { * * @return The bytes for table. */ + @java.lang.Override public com.google.protobuf.ByteString getTableBytes() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -2193,6 +2202,7 @@ public com.google.protobuf.ByteString getTableBytes() { * * @return Whether the keySet field is set. */ + @java.lang.Override public boolean hasKeySet() { return keySet_ != null; } @@ -2212,6 +2222,7 @@ public boolean hasKeySet() { * * @return The keySet. */ + @java.lang.Override public com.google.spanner.v1.KeySet getKeySet() { return keySet_ == null ? com.google.spanner.v1.KeySet.getDefaultInstance() : keySet_; } @@ -2229,6 +2240,7 @@ public com.google.spanner.v1.KeySet getKeySet() { * * .google.spanner.v1.KeySet key_set = 2; */ + @java.lang.Override public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { return getKeySet(); } @@ -3031,6 +3043,7 @@ public OperationCase getOperationCase() { * * @return Whether the insert field is set. */ + @java.lang.Override public boolean hasInsert() { return operationCase_ == 1; } @@ -3046,6 +3059,7 @@ public boolean hasInsert() { * * @return The insert. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getInsert() { if (operationCase_ == 1) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3062,6 +3076,7 @@ public com.google.spanner.v1.Mutation.Write getInsert() { * * .google.spanner.v1.Mutation.Write insert = 1; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrBuilder() { if (operationCase_ == 1) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3082,6 +3097,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrBuilder() { * * @return Whether the update field is set. */ + @java.lang.Override public boolean hasUpdate() { return operationCase_ == 2; } @@ -3097,6 +3113,7 @@ public boolean hasUpdate() { * * @return The update. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getUpdate() { if (operationCase_ == 2) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3113,6 +3130,7 @@ public com.google.spanner.v1.Mutation.Write getUpdate() { * * .google.spanner.v1.Mutation.Write update = 2; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getUpdateOrBuilder() { if (operationCase_ == 2) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3137,6 +3155,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getUpdateOrBuilder() { * * @return Whether the insertOrUpdate field is set. */ + @java.lang.Override public boolean hasInsertOrUpdate() { return operationCase_ == 3; } @@ -3156,6 +3175,7 @@ public boolean hasInsertOrUpdate() { * * @return The insertOrUpdate. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getInsertOrUpdate() { if (operationCase_ == 3) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3176,6 +3196,7 @@ public com.google.spanner.v1.Mutation.Write getInsertOrUpdate() { * * .google.spanner.v1.Mutation.Write insert_or_update = 3; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrUpdateOrBuilder() { if (operationCase_ == 3) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3202,6 +3223,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrUpdateOrBuilder( * * @return Whether the replace field is set. */ + @java.lang.Override public boolean hasReplace() { return operationCase_ == 4; } @@ -3223,6 +3245,7 @@ public boolean hasReplace() { * * @return The replace. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getReplace() { if (operationCase_ == 4) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3245,6 +3268,7 @@ public com.google.spanner.v1.Mutation.Write getReplace() { * * .google.spanner.v1.Mutation.Write replace = 4; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getReplaceOrBuilder() { if (operationCase_ == 4) { return (com.google.spanner.v1.Mutation.Write) operation_; @@ -3265,6 +3289,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getReplaceOrBuilder() { * * @return Whether the delete field is set. */ + @java.lang.Override public boolean hasDelete() { return operationCase_ == 5; } @@ -3280,6 +3305,7 @@ public boolean hasDelete() { * * @return The delete. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Delete getDelete() { if (operationCase_ == 5) { return (com.google.spanner.v1.Mutation.Delete) operation_; @@ -3296,6 +3322,7 @@ public com.google.spanner.v1.Mutation.Delete getDelete() { * * .google.spanner.v1.Mutation.Delete delete = 5; */ + @java.lang.Override public com.google.spanner.v1.Mutation.DeleteOrBuilder getDeleteOrBuilder() { if (operationCase_ == 5) { return (com.google.spanner.v1.Mutation.Delete) operation_; @@ -3785,6 +3812,7 @@ public Builder clearOperation() { * * @return Whether the insert field is set. */ + @java.lang.Override public boolean hasInsert() { return operationCase_ == 1; } @@ -3800,6 +3828,7 @@ public boolean hasInsert() { * * @return The insert. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getInsert() { if (insertBuilder_ == null) { if (operationCase_ == 1) { @@ -3937,6 +3966,7 @@ public com.google.spanner.v1.Mutation.Write.Builder getInsertBuilder() { * * .google.spanner.v1.Mutation.Write insert = 1; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrBuilder() { if ((operationCase_ == 1) && (insertBuilder_ != null)) { return insertBuilder_.getMessageOrBuilder(); @@ -3999,6 +4029,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrBuilder() { * * @return Whether the update field is set. */ + @java.lang.Override public boolean hasUpdate() { return operationCase_ == 2; } @@ -4014,6 +4045,7 @@ public boolean hasUpdate() { * * @return The update. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getUpdate() { if (updateBuilder_ == null) { if (operationCase_ == 2) { @@ -4151,6 +4183,7 @@ public com.google.spanner.v1.Mutation.Write.Builder getUpdateBuilder() { * * .google.spanner.v1.Mutation.Write update = 2; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getUpdateOrBuilder() { if ((operationCase_ == 2) && (updateBuilder_ != null)) { return updateBuilder_.getMessageOrBuilder(); @@ -4217,6 +4250,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getUpdateOrBuilder() { * * @return Whether the insertOrUpdate field is set. */ + @java.lang.Override public boolean hasInsertOrUpdate() { return operationCase_ == 3; } @@ -4236,6 +4270,7 @@ public boolean hasInsertOrUpdate() { * * @return The insertOrUpdate. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getInsertOrUpdate() { if (insertOrUpdateBuilder_ == null) { if (operationCase_ == 3) { @@ -4397,6 +4432,7 @@ public com.google.spanner.v1.Mutation.Write.Builder getInsertOrUpdateBuilder() { * * .google.spanner.v1.Mutation.Write insert_or_update = 3; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrUpdateOrBuilder() { if ((operationCase_ == 3) && (insertOrUpdateBuilder_ != null)) { return insertOrUpdateBuilder_.getMessageOrBuilder(); @@ -4469,6 +4505,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getInsertOrUpdateOrBuilder( * * @return Whether the replace field is set. */ + @java.lang.Override public boolean hasReplace() { return operationCase_ == 4; } @@ -4490,6 +4527,7 @@ public boolean hasReplace() { * * @return The replace. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Write getReplace() { if (replaceBuilder_ == null) { if (operationCase_ == 4) { @@ -4663,6 +4701,7 @@ public com.google.spanner.v1.Mutation.Write.Builder getReplaceBuilder() { * * .google.spanner.v1.Mutation.Write replace = 4; */ + @java.lang.Override public com.google.spanner.v1.Mutation.WriteOrBuilder getReplaceOrBuilder() { if ((operationCase_ == 4) && (replaceBuilder_ != null)) { return replaceBuilder_.getMessageOrBuilder(); @@ -4731,6 +4770,7 @@ public com.google.spanner.v1.Mutation.WriteOrBuilder getReplaceOrBuilder() { * * @return Whether the delete field is set. */ + @java.lang.Override public boolean hasDelete() { return operationCase_ == 5; } @@ -4746,6 +4786,7 @@ public boolean hasDelete() { * * @return The delete. */ + @java.lang.Override public com.google.spanner.v1.Mutation.Delete getDelete() { if (deleteBuilder_ == null) { if (operationCase_ == 5) { @@ -4883,6 +4924,7 @@ public com.google.spanner.v1.Mutation.Delete.Builder getDeleteBuilder() { * * .google.spanner.v1.Mutation.Delete delete = 5; */ + @java.lang.Override public com.google.spanner.v1.Mutation.DeleteOrBuilder getDeleteOrBuilder() { if ((operationCase_ == 5) && (deleteBuilder_ != null)) { return deleteBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartialResultSet.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartialResultSet.java index ae19e230bf..4caabb2902 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartialResultSet.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartialResultSet.java @@ -176,6 +176,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the metadata field is set. */ + @java.lang.Override public boolean hasMetadata() { return metadata_ != null; } @@ -191,6 +192,7 @@ public boolean hasMetadata() { * * @return The metadata. */ + @java.lang.Override public com.google.spanner.v1.ResultSetMetadata getMetadata() { return metadata_ == null ? com.google.spanner.v1.ResultSetMetadata.getDefaultInstance() @@ -206,6 +208,7 @@ public com.google.spanner.v1.ResultSetMetadata getMetadata() { * * .google.spanner.v1.ResultSetMetadata metadata = 1; */ + @java.lang.Override public com.google.spanner.v1.ResultSetMetadataOrBuilder getMetadataOrBuilder() { return getMetadata(); } @@ -279,6 +282,7 @@ public com.google.spanner.v1.ResultSetMetadataOrBuilder getMetadataOrBuilder() { * * repeated .google.protobuf.Value values = 2; */ + @java.lang.Override public java.util.List getValuesList() { return values_; } @@ -349,6 +353,7 @@ public java.util.List getValuesList() { * * repeated .google.protobuf.Value values = 2; */ + @java.lang.Override public java.util.List getValuesOrBuilderList() { return values_; } @@ -419,6 +424,7 @@ public java.util.List getValuesOrB * * repeated .google.protobuf.Value values = 2; */ + @java.lang.Override public int getValuesCount() { return values_.size(); } @@ -489,6 +495,7 @@ public int getValuesCount() { * * repeated .google.protobuf.Value values = 2; */ + @java.lang.Override public com.google.protobuf.Value getValues(int index) { return values_.get(index); } @@ -559,6 +566,7 @@ public com.google.protobuf.Value getValues(int index) { * * repeated .google.protobuf.Value values = 2; */ + @java.lang.Override public com.google.protobuf.ValueOrBuilder getValuesOrBuilder(int index) { return values_.get(index); } @@ -578,6 +586,7 @@ public com.google.protobuf.ValueOrBuilder getValuesOrBuilder(int index) { * * @return The chunkedValue. */ + @java.lang.Override public boolean getChunkedValue() { return chunkedValue_; } @@ -599,6 +608,7 @@ public boolean getChunkedValue() { * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } @@ -621,6 +631,7 @@ public com.google.protobuf.ByteString getResumeToken() { * * @return Whether the stats field is set. */ + @java.lang.Override public boolean hasStats() { return stats_ != null; } @@ -640,6 +651,7 @@ public boolean hasStats() { * * @return The stats. */ + @java.lang.Override public com.google.spanner.v1.ResultSetStats getStats() { return stats_ == null ? com.google.spanner.v1.ResultSetStats.getDefaultInstance() : stats_; } @@ -657,6 +669,7 @@ public com.google.spanner.v1.ResultSetStats getStats() { * * .google.spanner.v1.ResultSetStats stats = 5; */ + @java.lang.Override public com.google.spanner.v1.ResultSetStatsOrBuilder getStatsOrBuilder() { return getStats(); } @@ -2700,6 +2713,7 @@ public java.util.List getValuesBuilderList() * * @return The chunkedValue. */ + @java.lang.Override public boolean getChunkedValue() { return chunkedValue_; } @@ -2759,6 +2773,7 @@ public Builder clearChunkedValue() { * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Partition.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Partition.java index e777307a97..6c366b815b 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Partition.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Partition.java @@ -124,6 +124,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } @@ -454,6 +455,7 @@ public Builder mergeFrom( * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionOptions.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionOptions.java index 7eda296a71..9f51c4c833 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionOptions.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionOptions.java @@ -130,6 +130,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The partitionSizeBytes. */ + @java.lang.Override public long getPartitionSizeBytes() { return partitionSizeBytes_; } @@ -153,6 +154,7 @@ public long getPartitionSizeBytes() { * * @return The maxPartitions. */ + @java.lang.Override public long getMaxPartitions() { return maxPartitions_; } @@ -503,6 +505,7 @@ public Builder mergeFrom( * * @return The partitionSizeBytes. */ + @java.lang.Override public long getPartitionSizeBytes() { return partitionSizeBytes_; } @@ -568,6 +571,7 @@ public Builder clearPartitionSizeBytes() { * * @return The maxPartitions. */ + @java.lang.Override public long getMaxPartitions() { return maxPartitions_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionQueryRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionQueryRequest.java index d68ca74362..f7fc78454c 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionQueryRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionQueryRequest.java @@ -208,6 +208,7 @@ protected com.google.protobuf.MapField internalGetMapField(int number) { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -232,6 +233,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -258,6 +260,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -273,6 +276,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionSelector getTransaction() { return transaction_ == null ? com.google.spanner.v1.TransactionSelector.getDefaultInstance() @@ -288,6 +292,7 @@ public com.google.spanner.v1.TransactionSelector getTransaction() { * * .google.spanner.v1.TransactionSelector transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilder() { return getTransaction(); } @@ -313,6 +318,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * * @return The sql. */ + @java.lang.Override public java.lang.String getSql() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -343,6 +349,7 @@ public java.lang.String getSql() { * * @return The bytes for sql. */ + @java.lang.Override public com.google.protobuf.ByteString getSqlBytes() { java.lang.Object ref = sql_; if (ref instanceof java.lang.String) { @@ -375,6 +382,7 @@ public com.google.protobuf.ByteString getSqlBytes() { * * @return Whether the params field is set. */ + @java.lang.Override public boolean hasParams() { return params_ != null; } @@ -396,6 +404,7 @@ public boolean hasParams() { * * @return The params. */ + @java.lang.Override public com.google.protobuf.Struct getParams() { return params_ == null ? com.google.protobuf.Struct.getDefaultInstance() : params_; } @@ -415,6 +424,7 @@ public com.google.protobuf.Struct getParams() { * * .google.protobuf.Struct params = 4; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getParamsOrBuilder() { return getParams(); } @@ -462,6 +472,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -469,6 +480,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -488,6 +500,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -506,6 +519,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -530,6 +544,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -555,6 +570,7 @@ public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { * * @return Whether the partitionOptions field is set. */ + @java.lang.Override public boolean hasPartitionOptions() { return partitionOptions_ != null; } @@ -569,6 +585,7 @@ public boolean hasPartitionOptions() { * * @return The partitionOptions. */ + @java.lang.Override public com.google.spanner.v1.PartitionOptions getPartitionOptions() { return partitionOptions_ == null ? com.google.spanner.v1.PartitionOptions.getDefaultInstance() @@ -583,6 +600,7 @@ public com.google.spanner.v1.PartitionOptions getPartitionOptions() { * * .google.spanner.v1.PartitionOptions partition_options = 6; */ + @java.lang.Override public com.google.spanner.v1.PartitionOptionsOrBuilder getPartitionOptionsOrBuilder() { return getPartitionOptions(); } @@ -1788,6 +1806,7 @@ public int getParamTypesCount() { * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public boolean containsParamTypes(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1795,6 +1814,7 @@ public boolean containsParamTypes(java.lang.String key) { return internalGetParamTypes().getMap().containsKey(key); } /** Use {@link #getParamTypesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getParamTypes() { return getParamTypesMap(); @@ -1814,6 +1834,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public java.util.Map getParamTypesMap() { return internalGetParamTypes().getMap(); } @@ -1832,6 +1853,7 @@ public java.util.Map getParamTypes * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrDefault( java.lang.String key, com.google.spanner.v1.Type defaultValue) { if (key == null) { @@ -1856,6 +1878,7 @@ public com.google.spanner.v1.Type getParamTypesOrDefault( * * map<string, .google.spanner.v1.Type> param_types = 5; */ + @java.lang.Override public com.google.spanner.v1.Type getParamTypesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionReadRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionReadRequest.java index 705f4db806..0639cae76b 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionReadRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionReadRequest.java @@ -203,6 +203,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -227,6 +228,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -253,6 +255,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -268,6 +271,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionSelector getTransaction() { return transaction_ == null ? com.google.spanner.v1.TransactionSelector.getDefaultInstance() @@ -283,6 +287,7 @@ public com.google.spanner.v1.TransactionSelector getTransaction() { * * .google.spanner.v1.TransactionSelector transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilder() { return getTransaction(); } @@ -300,6 +305,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * * @return The table. */ + @java.lang.Override public java.lang.String getTable() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -322,6 +328,7 @@ public java.lang.String getTable() { * * @return The bytes for table. */ + @java.lang.Override public com.google.protobuf.ByteString getTableBytes() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -349,6 +356,7 @@ public com.google.protobuf.ByteString getTableBytes() { * * @return The index. */ + @java.lang.Override public java.lang.String getIndex() { java.lang.Object ref = index_; if (ref instanceof java.lang.String) { @@ -373,6 +381,7 @@ public java.lang.String getIndex() { * * @return The bytes for index. */ + @java.lang.Override public com.google.protobuf.ByteString getIndexBytes() { java.lang.Object ref = index_; if (ref instanceof java.lang.String) { @@ -468,6 +477,7 @@ public com.google.protobuf.ByteString getColumnsBytes(int index) { * * @return Whether the keySet field is set. */ + @java.lang.Override public boolean hasKeySet() { return keySet_ != null; } @@ -487,6 +497,7 @@ public boolean hasKeySet() { * * @return The keySet. */ + @java.lang.Override public com.google.spanner.v1.KeySet getKeySet() { return keySet_ == null ? com.google.spanner.v1.KeySet.getDefaultInstance() : keySet_; } @@ -504,6 +515,7 @@ public com.google.spanner.v1.KeySet getKeySet() { * * .google.spanner.v1.KeySet key_set = 6 [(.google.api.field_behavior) = REQUIRED]; */ + @java.lang.Override public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { return getKeySet(); } @@ -521,6 +533,7 @@ public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { * * @return Whether the partitionOptions field is set. */ + @java.lang.Override public boolean hasPartitionOptions() { return partitionOptions_ != null; } @@ -535,6 +548,7 @@ public boolean hasPartitionOptions() { * * @return The partitionOptions. */ + @java.lang.Override public com.google.spanner.v1.PartitionOptions getPartitionOptions() { return partitionOptions_ == null ? com.google.spanner.v1.PartitionOptions.getDefaultInstance() @@ -549,6 +563,7 @@ public com.google.spanner.v1.PartitionOptions getPartitionOptions() { * * .google.spanner.v1.PartitionOptions partition_options = 9; */ + @java.lang.Override public com.google.spanner.v1.PartitionOptionsOrBuilder getPartitionOptionsOrBuilder() { return getPartitionOptions(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionResponse.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionResponse.java index d92ec9654e..7ee074e71c 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionResponse.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PartitionResponse.java @@ -145,6 +145,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.v1.Partition partitions = 1; */ + @java.lang.Override public java.util.List getPartitionsList() { return partitions_; } @@ -157,6 +158,7 @@ public java.util.List getPartitionsList() { * * repeated .google.spanner.v1.Partition partitions = 1; */ + @java.lang.Override public java.util.List getPartitionsOrBuilderList() { return partitions_; @@ -170,6 +172,7 @@ public java.util.List getPartitionsList() { * * repeated .google.spanner.v1.Partition partitions = 1; */ + @java.lang.Override public int getPartitionsCount() { return partitions_.size(); } @@ -182,6 +185,7 @@ public int getPartitionsCount() { * * repeated .google.spanner.v1.Partition partitions = 1; */ + @java.lang.Override public com.google.spanner.v1.Partition getPartitions(int index) { return partitions_.get(index); } @@ -194,6 +198,7 @@ public com.google.spanner.v1.Partition getPartitions(int index) { * * repeated .google.spanner.v1.Partition partitions = 1; */ + @java.lang.Override public com.google.spanner.v1.PartitionOrBuilder getPartitionsOrBuilder(int index) { return partitions_.get(index); } @@ -211,6 +216,7 @@ public com.google.spanner.v1.PartitionOrBuilder getPartitionsOrBuilder(int index * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -225,6 +231,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.Transaction getTransaction() { return transaction_ == null ? com.google.spanner.v1.Transaction.getDefaultInstance() @@ -239,6 +246,7 @@ public com.google.spanner.v1.Transaction getTransaction() { * * .google.spanner.v1.Transaction transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionOrBuilder getTransactionOrBuilder() { return getTransaction(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PlanNode.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PlanNode.java index c7900922b1..ce3920eccb 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PlanNode.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/PlanNode.java @@ -317,6 +317,10 @@ public Kind findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } @@ -557,6 +561,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The childIndex. */ + @java.lang.Override public int getChildIndex() { return childIndex_; } @@ -577,6 +582,7 @@ public int getChildIndex() { * * @return The type. */ + @java.lang.Override public java.lang.String getType() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { @@ -602,6 +608,7 @@ public java.lang.String getType() { * * @return The bytes for type. */ + @java.lang.Override public com.google.protobuf.ByteString getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { @@ -634,6 +641,7 @@ public com.google.protobuf.ByteString getTypeBytes() { * * @return The variable. */ + @java.lang.Override public java.lang.String getVariable() { java.lang.Object ref = variable_; if (ref instanceof java.lang.String) { @@ -663,6 +671,7 @@ public java.lang.String getVariable() { * * @return The bytes for variable. */ + @java.lang.Override public com.google.protobuf.ByteString getVariableBytes() { java.lang.Object ref = variable_; if (ref instanceof java.lang.String) { @@ -1039,6 +1048,7 @@ public Builder mergeFrom( * * @return The childIndex. */ + @java.lang.Override public int getChildIndex() { return childIndex_; } @@ -1630,6 +1640,7 @@ protected com.google.protobuf.MapField internalGetMapField(int number) { * * @return The description. */ + @java.lang.Override public java.lang.String getDescription() { java.lang.Object ref = description_; if (ref instanceof java.lang.String) { @@ -1652,6 +1663,7 @@ public java.lang.String getDescription() { * * @return The bytes for description. */ + @java.lang.Override public com.google.protobuf.ByteString getDescriptionBytes() { java.lang.Object ref = description_; if (ref instanceof java.lang.String) { @@ -1704,6 +1716,7 @@ public int getSubqueriesCount() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public boolean containsSubqueries(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1711,6 +1724,7 @@ public boolean containsSubqueries(java.lang.String key) { return internalGetSubqueries().getMap().containsKey(key); } /** Use {@link #getSubqueriesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getSubqueries() { return getSubqueriesMap(); @@ -1728,6 +1742,7 @@ public java.util.Map getSubqueries() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public java.util.Map getSubqueriesMap() { return internalGetSubqueries().getMap(); } @@ -1744,6 +1759,7 @@ public java.util.Map getSubqueriesMap() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public int getSubqueriesOrDefault(java.lang.String key, int defaultValue) { if (key == null) { throw new java.lang.NullPointerException(); @@ -1764,6 +1780,7 @@ public int getSubqueriesOrDefault(java.lang.String key, int defaultValue) { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public int getSubqueriesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -2289,6 +2306,7 @@ public int getSubqueriesCount() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public boolean containsSubqueries(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -2296,6 +2314,7 @@ public boolean containsSubqueries(java.lang.String key) { return internalGetSubqueries().getMap().containsKey(key); } /** Use {@link #getSubqueriesMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getSubqueries() { return getSubqueriesMap(); @@ -2313,6 +2332,7 @@ public java.util.Map getSubqueries() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public java.util.Map getSubqueriesMap() { return internalGetSubqueries().getMap(); } @@ -2329,6 +2349,7 @@ public java.util.Map getSubqueriesMap() { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public int getSubqueriesOrDefault(java.lang.String key, int defaultValue) { if (key == null) { throw new java.lang.NullPointerException(); @@ -2349,6 +2370,7 @@ public int getSubqueriesOrDefault(java.lang.String key, int defaultValue) { * * map<string, int32> subqueries = 2; */ + @java.lang.Override public int getSubqueriesOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -2493,6 +2515,7 @@ public com.google.spanner.v1.PlanNode.ShortRepresentation getDefaultInstanceForT * * @return The index. */ + @java.lang.Override public int getIndex() { return index_; } @@ -2514,6 +2537,7 @@ public int getIndex() { * * @return The enum numeric value on the wire for kind. */ + @java.lang.Override public int getKindValue() { return kind_; } @@ -2532,6 +2556,7 @@ public int getKindValue() { * * @return The kind. */ + @java.lang.Override public com.google.spanner.v1.PlanNode.Kind getKind() { @SuppressWarnings("deprecation") com.google.spanner.v1.PlanNode.Kind result = com.google.spanner.v1.PlanNode.Kind.valueOf(kind_); @@ -2551,6 +2576,7 @@ public com.google.spanner.v1.PlanNode.Kind getKind() { * * @return The displayName. */ + @java.lang.Override public java.lang.String getDisplayName() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -2573,6 +2599,7 @@ public java.lang.String getDisplayName() { * * @return The bytes for displayName. */ + @java.lang.Override public com.google.protobuf.ByteString getDisplayNameBytes() { java.lang.Object ref = displayName_; if (ref instanceof java.lang.String) { @@ -2596,6 +2623,7 @@ public com.google.protobuf.ByteString getDisplayNameBytes() { * * repeated .google.spanner.v1.PlanNode.ChildLink child_links = 4; */ + @java.lang.Override public java.util.List getChildLinksList() { return childLinks_; } @@ -2608,6 +2636,7 @@ public java.util.List getChildLinksLis * * repeated .google.spanner.v1.PlanNode.ChildLink child_links = 4; */ + @java.lang.Override public java.util.List getChildLinksOrBuilderList() { return childLinks_; @@ -2621,6 +2650,7 @@ public java.util.List getChildLinksLis * * repeated .google.spanner.v1.PlanNode.ChildLink child_links = 4; */ + @java.lang.Override public int getChildLinksCount() { return childLinks_.size(); } @@ -2633,6 +2663,7 @@ public int getChildLinksCount() { * * repeated .google.spanner.v1.PlanNode.ChildLink child_links = 4; */ + @java.lang.Override public com.google.spanner.v1.PlanNode.ChildLink getChildLinks(int index) { return childLinks_.get(index); } @@ -2645,6 +2676,7 @@ public com.google.spanner.v1.PlanNode.ChildLink getChildLinks(int index) { * * repeated .google.spanner.v1.PlanNode.ChildLink child_links = 4; */ + @java.lang.Override public com.google.spanner.v1.PlanNode.ChildLinkOrBuilder getChildLinksOrBuilder(int index) { return childLinks_.get(index); } @@ -2662,6 +2694,7 @@ public com.google.spanner.v1.PlanNode.ChildLinkOrBuilder getChildLinksOrBuilder( * * @return Whether the shortRepresentation field is set. */ + @java.lang.Override public boolean hasShortRepresentation() { return shortRepresentation_ != null; } @@ -2676,6 +2709,7 @@ public boolean hasShortRepresentation() { * * @return The shortRepresentation. */ + @java.lang.Override public com.google.spanner.v1.PlanNode.ShortRepresentation getShortRepresentation() { return shortRepresentation_ == null ? com.google.spanner.v1.PlanNode.ShortRepresentation.getDefaultInstance() @@ -2690,6 +2724,7 @@ public com.google.spanner.v1.PlanNode.ShortRepresentation getShortRepresentation * * .google.spanner.v1.PlanNode.ShortRepresentation short_representation = 5; */ + @java.lang.Override public com.google.spanner.v1.PlanNode.ShortRepresentationOrBuilder getShortRepresentationOrBuilder() { return getShortRepresentation(); @@ -2714,6 +2749,7 @@ public com.google.spanner.v1.PlanNode.ShortRepresentation getShortRepresentation * * @return Whether the metadata field is set. */ + @java.lang.Override public boolean hasMetadata() { return metadata_ != null; } @@ -2734,6 +2770,7 @@ public boolean hasMetadata() { * * @return The metadata. */ + @java.lang.Override public com.google.protobuf.Struct getMetadata() { return metadata_ == null ? com.google.protobuf.Struct.getDefaultInstance() : metadata_; } @@ -2752,6 +2789,7 @@ public com.google.protobuf.Struct getMetadata() { * * .google.protobuf.Struct metadata = 6; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { return getMetadata(); } @@ -2772,6 +2810,7 @@ public com.google.protobuf.StructOrBuilder getMetadataOrBuilder() { * * @return Whether the executionStats field is set. */ + @java.lang.Override public boolean hasExecutionStats() { return executionStats_ != null; } @@ -2789,6 +2828,7 @@ public boolean hasExecutionStats() { * * @return The executionStats. */ + @java.lang.Override public com.google.protobuf.Struct getExecutionStats() { return executionStats_ == null ? com.google.protobuf.Struct.getDefaultInstance() @@ -2806,6 +2846,7 @@ public com.google.protobuf.Struct getExecutionStats() { * * .google.protobuf.Struct execution_stats = 7; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getExecutionStatsOrBuilder() { return getExecutionStats(); } @@ -3306,6 +3347,7 @@ public Builder mergeFrom( * * @return The index. */ + @java.lang.Override public int getIndex() { return index_; } @@ -3361,6 +3403,7 @@ public Builder clearIndex() { * * @return The enum numeric value on the wire for kind. */ + @java.lang.Override public int getKindValue() { return kind_; } @@ -3381,6 +3424,7 @@ public int getKindValue() { * @return This builder for chaining. */ public Builder setKindValue(int value) { + kind_ = value; onChanged(); return this; @@ -3400,6 +3444,7 @@ public Builder setKindValue(int value) { * * @return The kind. */ + @java.lang.Override public com.google.spanner.v1.PlanNode.Kind getKind() { @SuppressWarnings("deprecation") com.google.spanner.v1.PlanNode.Kind result = diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlan.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlan.java index 5da2e29f75..d00d511db2 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlan.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlan.java @@ -130,6 +130,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * repeated .google.spanner.v1.PlanNode plan_nodes = 1; */ + @java.lang.Override public java.util.List getPlanNodesList() { return planNodes_; } @@ -144,6 +145,7 @@ public java.util.List getPlanNodesList() { * * repeated .google.spanner.v1.PlanNode plan_nodes = 1; */ + @java.lang.Override public java.util.List getPlanNodesOrBuilderList() { return planNodes_; @@ -159,6 +161,7 @@ public java.util.List getPlanNodesList() { * * repeated .google.spanner.v1.PlanNode plan_nodes = 1; */ + @java.lang.Override public int getPlanNodesCount() { return planNodes_.size(); } @@ -173,6 +176,7 @@ public int getPlanNodesCount() { * * repeated .google.spanner.v1.PlanNode plan_nodes = 1; */ + @java.lang.Override public com.google.spanner.v1.PlanNode getPlanNodes(int index) { return planNodes_.get(index); } @@ -187,6 +191,7 @@ public com.google.spanner.v1.PlanNode getPlanNodes(int index) { * * repeated .google.spanner.v1.PlanNode plan_nodes = 1; */ + @java.lang.Override public com.google.spanner.v1.PlanNodeOrBuilder getPlanNodesOrBuilder(int index) { return planNodes_.get(index); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ReadRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ReadRequest.java index cece0e743a..27e09ed7f3 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ReadRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ReadRequest.java @@ -205,6 +205,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -229,6 +230,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -255,6 +257,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -270,6 +273,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.TransactionSelector getTransaction() { return transaction_ == null ? com.google.spanner.v1.TransactionSelector.getDefaultInstance() @@ -285,6 +289,7 @@ public com.google.spanner.v1.TransactionSelector getTransaction() { * * .google.spanner.v1.TransactionSelector transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilder() { return getTransaction(); } @@ -302,6 +307,7 @@ public com.google.spanner.v1.TransactionSelectorOrBuilder getTransactionOrBuilde * * @return The table. */ + @java.lang.Override public java.lang.String getTable() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -324,6 +330,7 @@ public java.lang.String getTable() { * * @return The bytes for table. */ + @java.lang.Override public com.google.protobuf.ByteString getTableBytes() { java.lang.Object ref = table_; if (ref instanceof java.lang.String) { @@ -351,6 +358,7 @@ public com.google.protobuf.ByteString getTableBytes() { * * @return The index. */ + @java.lang.Override public java.lang.String getIndex() { java.lang.Object ref = index_; if (ref instanceof java.lang.String) { @@ -375,6 +383,7 @@ public java.lang.String getIndex() { * * @return The bytes for index. */ + @java.lang.Override public com.google.protobuf.ByteString getIndexBytes() { java.lang.Object ref = index_; if (ref instanceof java.lang.String) { @@ -474,6 +483,7 @@ public com.google.protobuf.ByteString getColumnsBytes(int index) { * * @return Whether the keySet field is set. */ + @java.lang.Override public boolean hasKeySet() { return keySet_ != null; } @@ -497,6 +507,7 @@ public boolean hasKeySet() { * * @return The keySet. */ + @java.lang.Override public com.google.spanner.v1.KeySet getKeySet() { return keySet_ == null ? com.google.spanner.v1.KeySet.getDefaultInstance() : keySet_; } @@ -518,6 +529,7 @@ public com.google.spanner.v1.KeySet getKeySet() { * * .google.spanner.v1.KeySet key_set = 6 [(.google.api.field_behavior) = REQUIRED]; */ + @java.lang.Override public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { return getKeySet(); } @@ -537,6 +549,7 @@ public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { * * @return The limit. */ + @java.lang.Override public long getLimit() { return limit_; } @@ -559,6 +572,7 @@ public long getLimit() { * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } @@ -579,6 +593,7 @@ public com.google.protobuf.ByteString getResumeToken() { * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } @@ -2050,6 +2065,7 @@ public com.google.spanner.v1.KeySetOrBuilder getKeySetOrBuilder() { * * @return The limit. */ + @java.lang.Override public long getLimit() { return limit_; } @@ -2110,6 +2126,7 @@ public Builder clearLimit() { * * @return The resumeToken. */ + @java.lang.Override public com.google.protobuf.ByteString getResumeToken() { return resumeToken_; } @@ -2177,6 +2194,7 @@ public Builder clearResumeToken() { * * @return The partitionToken. */ + @java.lang.Override public com.google.protobuf.ByteString getPartitionToken() { return partitionToken_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSet.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSet.java index 785ed8efdb..18f72a29bd 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSet.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSet.java @@ -163,6 +163,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the metadata field is set. */ + @java.lang.Override public boolean hasMetadata() { return metadata_ != null; } @@ -177,6 +178,7 @@ public boolean hasMetadata() { * * @return The metadata. */ + @java.lang.Override public com.google.spanner.v1.ResultSetMetadata getMetadata() { return metadata_ == null ? com.google.spanner.v1.ResultSetMetadata.getDefaultInstance() @@ -191,6 +193,7 @@ public com.google.spanner.v1.ResultSetMetadata getMetadata() { * * .google.spanner.v1.ResultSetMetadata metadata = 1; */ + @java.lang.Override public com.google.spanner.v1.ResultSetMetadataOrBuilder getMetadataOrBuilder() { return getMetadata(); } @@ -211,6 +214,7 @@ public com.google.spanner.v1.ResultSetMetadataOrBuilder getMetadataOrBuilder() { * * repeated .google.protobuf.ListValue rows = 2; */ + @java.lang.Override public java.util.List getRowsList() { return rows_; } @@ -228,6 +232,7 @@ public java.util.List getRowsList() { * * repeated .google.protobuf.ListValue rows = 2; */ + @java.lang.Override public java.util.List getRowsOrBuilderList() { return rows_; } @@ -245,6 +250,7 @@ public java.util.List getRowsO * * repeated .google.protobuf.ListValue rows = 2; */ + @java.lang.Override public int getRowsCount() { return rows_.size(); } @@ -262,6 +268,7 @@ public int getRowsCount() { * * repeated .google.protobuf.ListValue rows = 2; */ + @java.lang.Override public com.google.protobuf.ListValue getRows(int index) { return rows_.get(index); } @@ -279,6 +286,7 @@ public com.google.protobuf.ListValue getRows(int index) { * * repeated .google.protobuf.ListValue rows = 2; */ + @java.lang.Override public com.google.protobuf.ListValueOrBuilder getRowsOrBuilder(int index) { return rows_.get(index); } @@ -303,6 +311,7 @@ public com.google.protobuf.ListValueOrBuilder getRowsOrBuilder(int index) { * * @return Whether the stats field is set. */ + @java.lang.Override public boolean hasStats() { return stats_ != null; } @@ -324,6 +333,7 @@ public boolean hasStats() { * * @return The stats. */ + @java.lang.Override public com.google.spanner.v1.ResultSetStats getStats() { return stats_ == null ? com.google.spanner.v1.ResultSetStats.getDefaultInstance() : stats_; } @@ -343,6 +353,7 @@ public com.google.spanner.v1.ResultSetStats getStats() { * * .google.spanner.v1.ResultSetStats stats = 3; */ + @java.lang.Override public com.google.spanner.v1.ResultSetStatsOrBuilder getStatsOrBuilder() { return getStats(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetMetadata.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetMetadata.java index cbb422354b..a9d3e4f45b 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetMetadata.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetMetadata.java @@ -151,6 +151,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return Whether the rowType field is set. */ + @java.lang.Override public boolean hasRowType() { return rowType_ != null; } @@ -171,6 +172,7 @@ public boolean hasRowType() { * * @return The rowType. */ + @java.lang.Override public com.google.spanner.v1.StructType getRowType() { return rowType_ == null ? com.google.spanner.v1.StructType.getDefaultInstance() : rowType_; } @@ -189,6 +191,7 @@ public com.google.spanner.v1.StructType getRowType() { * * .google.spanner.v1.StructType row_type = 1; */ + @java.lang.Override public com.google.spanner.v1.StructTypeOrBuilder getRowTypeOrBuilder() { return getRowType(); } @@ -207,6 +210,7 @@ public com.google.spanner.v1.StructTypeOrBuilder getRowTypeOrBuilder() { * * @return Whether the transaction field is set. */ + @java.lang.Override public boolean hasTransaction() { return transaction_ != null; } @@ -222,6 +226,7 @@ public boolean hasTransaction() { * * @return The transaction. */ + @java.lang.Override public com.google.spanner.v1.Transaction getTransaction() { return transaction_ == null ? com.google.spanner.v1.Transaction.getDefaultInstance() @@ -237,6 +242,7 @@ public com.google.spanner.v1.Transaction getTransaction() { * * .google.spanner.v1.Transaction transaction = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionOrBuilder getTransactionOrBuilder() { return getTransaction(); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetStats.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetStats.java index cb4cb0f130..932da73d04 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetStats.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetStats.java @@ -204,6 +204,7 @@ public RowCountCase getRowCountCase() { * * @return Whether the queryPlan field is set. */ + @java.lang.Override public boolean hasQueryPlan() { return queryPlan_ != null; } @@ -218,6 +219,7 @@ public boolean hasQueryPlan() { * * @return The queryPlan. */ + @java.lang.Override public com.google.spanner.v1.QueryPlan getQueryPlan() { return queryPlan_ == null ? com.google.spanner.v1.QueryPlan.getDefaultInstance() : queryPlan_; } @@ -230,6 +232,7 @@ public com.google.spanner.v1.QueryPlan getQueryPlan() { * * .google.spanner.v1.QueryPlan query_plan = 1; */ + @java.lang.Override public com.google.spanner.v1.QueryPlanOrBuilder getQueryPlanOrBuilder() { return getQueryPlan(); } @@ -254,6 +257,7 @@ public com.google.spanner.v1.QueryPlanOrBuilder getQueryPlanOrBuilder() { * * @return Whether the queryStats field is set. */ + @java.lang.Override public boolean hasQueryStats() { return queryStats_ != null; } @@ -275,6 +279,7 @@ public boolean hasQueryStats() { * * @return The queryStats. */ + @java.lang.Override public com.google.protobuf.Struct getQueryStats() { return queryStats_ == null ? com.google.protobuf.Struct.getDefaultInstance() : queryStats_; } @@ -294,6 +299,7 @@ public com.google.protobuf.Struct getQueryStats() { * * .google.protobuf.Struct query_stats = 2; */ + @java.lang.Override public com.google.protobuf.StructOrBuilder getQueryStatsOrBuilder() { return getQueryStats(); } @@ -310,6 +316,7 @@ public com.google.protobuf.StructOrBuilder getQueryStatsOrBuilder() { * * @return The rowCountExact. */ + @java.lang.Override public long getRowCountExact() { if (rowCountCase_ == 3) { return (java.lang.Long) rowCount_; @@ -330,6 +337,7 @@ public long getRowCountExact() { * * @return The rowCountLowerBound. */ + @java.lang.Override public long getRowCountLowerBound() { if (rowCountCase_ == 4) { return (java.lang.Long) rowCount_; diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/RollbackRequest.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/RollbackRequest.java index 0bd92fe517..93a40a3950 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/RollbackRequest.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/RollbackRequest.java @@ -132,6 +132,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The session. */ + @java.lang.Override public java.lang.String getSession() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -156,6 +157,7 @@ public java.lang.String getSession() { * * @return The bytes for session. */ + @java.lang.Override public com.google.protobuf.ByteString getSessionBytes() { java.lang.Object ref = session_; if (ref instanceof java.lang.String) { @@ -181,6 +183,7 @@ public com.google.protobuf.ByteString getSessionBytes() { * * @return The transactionId. */ + @java.lang.Override public com.google.protobuf.ByteString getTransactionId() { return transactionId_; } @@ -642,6 +645,7 @@ public Builder setSessionBytes(com.google.protobuf.ByteString value) { * * @return The transactionId. */ + @java.lang.Override public com.google.protobuf.ByteString getTransactionId() { return transactionId_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Session.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Session.java index 4c11bf1aad..9fe4f10c7c 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Session.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Session.java @@ -178,6 +178,7 @@ protected com.google.protobuf.MapField internalGetMapField(int number) { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -201,6 +202,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -253,6 +255,7 @@ public int getLabelsCount() { * * map<string, string> labels = 2; */ + @java.lang.Override public boolean containsLabels(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -260,6 +263,7 @@ public boolean containsLabels(java.lang.String key) { return internalGetLabels().getMap().containsKey(key); } /** Use {@link #getLabelsMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getLabels() { return getLabelsMap(); @@ -279,6 +283,7 @@ public java.util.Map getLabels() { * * map<string, string> labels = 2; */ + @java.lang.Override public java.util.Map getLabelsMap() { return internalGetLabels().getMap(); } @@ -297,6 +302,7 @@ public java.util.Map getLabelsMap() { * * map<string, string> labels = 2; */ + @java.lang.Override public java.lang.String getLabelsOrDefault(java.lang.String key, java.lang.String defaultValue) { if (key == null) { throw new java.lang.NullPointerException(); @@ -319,6 +325,7 @@ public java.lang.String getLabelsOrDefault(java.lang.String key, java.lang.Strin * * map<string, string> labels = 2; */ + @java.lang.Override public java.lang.String getLabelsOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -343,6 +350,7 @@ public java.lang.String getLabelsOrThrow(java.lang.String key) { * * @return Whether the createTime field is set. */ + @java.lang.Override public boolean hasCreateTime() { return createTime_ != null; } @@ -357,6 +365,7 @@ public boolean hasCreateTime() { * * @return The createTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getCreateTime() { return createTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() : createTime_; } @@ -369,6 +378,7 @@ public com.google.protobuf.Timestamp getCreateTime() { * * .google.protobuf.Timestamp create_time = 3; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { return getCreateTime(); } @@ -387,6 +397,7 @@ public com.google.protobuf.TimestampOrBuilder getCreateTimeOrBuilder() { * * @return Whether the approximateLastUseTime field is set. */ + @java.lang.Override public boolean hasApproximateLastUseTime() { return approximateLastUseTime_ != null; } @@ -402,6 +413,7 @@ public boolean hasApproximateLastUseTime() { * * @return The approximateLastUseTime. */ + @java.lang.Override public com.google.protobuf.Timestamp getApproximateLastUseTime() { return approximateLastUseTime_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() @@ -417,6 +429,7 @@ public com.google.protobuf.Timestamp getApproximateLastUseTime() { * * .google.protobuf.Timestamp approximate_last_use_time = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getApproximateLastUseTimeOrBuilder() { return getApproximateLastUseTime(); } @@ -985,6 +998,7 @@ public int getLabelsCount() { * * map<string, string> labels = 2; */ + @java.lang.Override public boolean containsLabels(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); @@ -992,6 +1006,7 @@ public boolean containsLabels(java.lang.String key) { return internalGetLabels().getMap().containsKey(key); } /** Use {@link #getLabelsMap()} instead. */ + @java.lang.Override @java.lang.Deprecated public java.util.Map getLabels() { return getLabelsMap(); @@ -1011,6 +1026,7 @@ public java.util.Map getLabels() { * * map<string, string> labels = 2; */ + @java.lang.Override public java.util.Map getLabelsMap() { return internalGetLabels().getMap(); } @@ -1029,6 +1045,7 @@ public java.util.Map getLabelsMap() { * * map<string, string> labels = 2; */ + @java.lang.Override public java.lang.String getLabelsOrDefault( java.lang.String key, java.lang.String defaultValue) { if (key == null) { @@ -1052,6 +1069,7 @@ public java.lang.String getLabelsOrDefault( * * map<string, string> labels = 2; */ + @java.lang.Override public java.lang.String getLabelsOrThrow(java.lang.String key) { if (key == null) { throw new java.lang.NullPointerException(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/StructType.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/StructType.java index ba9262fa6c..4658915dc6 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/StructType.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/StructType.java @@ -320,6 +320,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The name. */ + @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -348,6 +349,7 @@ public java.lang.String getName() { * * @return The bytes for name. */ + @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { @@ -373,6 +375,7 @@ public com.google.protobuf.ByteString getNameBytes() { * * @return Whether the type field is set. */ + @java.lang.Override public boolean hasType() { return type_ != null; } @@ -387,6 +390,7 @@ public boolean hasType() { * * @return The type. */ + @java.lang.Override public com.google.spanner.v1.Type getType() { return type_ == null ? com.google.spanner.v1.Type.getDefaultInstance() : type_; } @@ -399,6 +403,7 @@ public com.google.spanner.v1.Type getType() { * * .google.spanner.v1.Type type = 2; */ + @java.lang.Override public com.google.spanner.v1.TypeOrBuilder getTypeOrBuilder() { return getType(); } @@ -1132,6 +1137,7 @@ public com.google.spanner.v1.StructType.Field getDefaultInstanceForType() { * * repeated .google.spanner.v1.StructType.Field fields = 1; */ + @java.lang.Override public java.util.List getFieldsList() { return fields_; } @@ -1149,6 +1155,7 @@ public java.util.List getFieldsList() { * * repeated .google.spanner.v1.StructType.Field fields = 1; */ + @java.lang.Override public java.util.List getFieldsOrBuilderList() { return fields_; @@ -1167,6 +1174,7 @@ public java.util.List getFieldsList() { * * repeated .google.spanner.v1.StructType.Field fields = 1; */ + @java.lang.Override public int getFieldsCount() { return fields_.size(); } @@ -1184,6 +1192,7 @@ public int getFieldsCount() { * * repeated .google.spanner.v1.StructType.Field fields = 1; */ + @java.lang.Override public com.google.spanner.v1.StructType.Field getFields(int index) { return fields_.get(index); } @@ -1201,6 +1210,7 @@ public com.google.spanner.v1.StructType.Field getFields(int index) { * * repeated .google.spanner.v1.StructType.Field fields = 1; */ + @java.lang.Override public com.google.spanner.v1.StructType.FieldOrBuilder getFieldsOrBuilder(int index) { return fields_.get(index); } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Transaction.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Transaction.java index fec045ddb1..be57d6c504 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Transaction.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Transaction.java @@ -143,6 +143,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The id. */ + @java.lang.Override public com.google.protobuf.ByteString getId() { return id_; } @@ -164,6 +165,7 @@ public com.google.protobuf.ByteString getId() { * * @return Whether the readTimestamp field is set. */ + @java.lang.Override public boolean hasReadTimestamp() { return readTimestamp_ != null; } @@ -182,6 +184,7 @@ public boolean hasReadTimestamp() { * * @return The readTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getReadTimestamp() { return readTimestamp_ == null ? com.google.protobuf.Timestamp.getDefaultInstance() @@ -200,6 +203,7 @@ public com.google.protobuf.Timestamp getReadTimestamp() { * * .google.protobuf.Timestamp read_timestamp = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getReadTimestampOrBuilder() { return getReadTimestamp(); } @@ -562,6 +566,7 @@ public Builder mergeFrom( * * @return The id. */ + @java.lang.Override public com.google.protobuf.ByteString getId() { return id_; } diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionOptions.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionOptions.java index 9aef29d90e..93de3f1b96 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionOptions.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionOptions.java @@ -1765,6 +1765,7 @@ public TimestampBoundCase getTimestampBoundCase() { * * @return The strong. */ + @java.lang.Override public boolean getStrong() { if (timestampBoundCase_ == 1) { return (java.lang.Boolean) timestampBound_; @@ -1790,6 +1791,7 @@ public boolean getStrong() { * * @return Whether the minReadTimestamp field is set. */ + @java.lang.Override public boolean hasMinReadTimestamp() { return timestampBoundCase_ == 2; } @@ -1810,6 +1812,7 @@ public boolean hasMinReadTimestamp() { * * @return The minReadTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getMinReadTimestamp() { if (timestampBoundCase_ == 2) { return (com.google.protobuf.Timestamp) timestampBound_; @@ -1831,6 +1834,7 @@ public com.google.protobuf.Timestamp getMinReadTimestamp() { * * .google.protobuf.Timestamp min_read_timestamp = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getMinReadTimestampOrBuilder() { if (timestampBoundCase_ == 2) { return (com.google.protobuf.Timestamp) timestampBound_; @@ -1860,6 +1864,7 @@ public com.google.protobuf.TimestampOrBuilder getMinReadTimestampOrBuilder() { * * @return Whether the maxStaleness field is set. */ + @java.lang.Override public boolean hasMaxStaleness() { return timestampBoundCase_ == 3; } @@ -1884,6 +1889,7 @@ public boolean hasMaxStaleness() { * * @return The maxStaleness. */ + @java.lang.Override public com.google.protobuf.Duration getMaxStaleness() { if (timestampBoundCase_ == 3) { return (com.google.protobuf.Duration) timestampBound_; @@ -1909,6 +1915,7 @@ public com.google.protobuf.Duration getMaxStaleness() { * * .google.protobuf.Duration max_staleness = 3; */ + @java.lang.Override public com.google.protobuf.DurationOrBuilder getMaxStalenessOrBuilder() { if (timestampBoundCase_ == 3) { return (com.google.protobuf.Duration) timestampBound_; @@ -1937,6 +1944,7 @@ public com.google.protobuf.DurationOrBuilder getMaxStalenessOrBuilder() { * * @return Whether the readTimestamp field is set. */ + @java.lang.Override public boolean hasReadTimestamp() { return timestampBoundCase_ == 4; } @@ -1960,6 +1968,7 @@ public boolean hasReadTimestamp() { * * @return The readTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getReadTimestamp() { if (timestampBoundCase_ == 4) { return (com.google.protobuf.Timestamp) timestampBound_; @@ -1984,6 +1993,7 @@ public com.google.protobuf.Timestamp getReadTimestamp() { * * .google.protobuf.Timestamp read_timestamp = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getReadTimestampOrBuilder() { if (timestampBoundCase_ == 4) { return (com.google.protobuf.Timestamp) timestampBound_; @@ -2011,6 +2021,7 @@ public com.google.protobuf.TimestampOrBuilder getReadTimestampOrBuilder() { * * @return Whether the exactStaleness field is set. */ + @java.lang.Override public boolean hasExactStaleness() { return timestampBoundCase_ == 5; } @@ -2033,6 +2044,7 @@ public boolean hasExactStaleness() { * * @return The exactStaleness. */ + @java.lang.Override public com.google.protobuf.Duration getExactStaleness() { if (timestampBoundCase_ == 5) { return (com.google.protobuf.Duration) timestampBound_; @@ -2056,6 +2068,7 @@ public com.google.protobuf.Duration getExactStaleness() { * * .google.protobuf.Duration exact_staleness = 5; */ + @java.lang.Override public com.google.protobuf.DurationOrBuilder getExactStalenessOrBuilder() { if (timestampBoundCase_ == 5) { return (com.google.protobuf.Duration) timestampBound_; @@ -2077,6 +2090,7 @@ public com.google.protobuf.DurationOrBuilder getExactStalenessOrBuilder() { * * @return The returnReadTimestamp. */ + @java.lang.Override public boolean getReturnReadTimestamp() { return returnReadTimestamp_; } @@ -2645,6 +2659,7 @@ public Builder clearStrong() { * * @return Whether the minReadTimestamp field is set. */ + @java.lang.Override public boolean hasMinReadTimestamp() { return timestampBoundCase_ == 2; } @@ -2665,6 +2680,7 @@ public boolean hasMinReadTimestamp() { * * @return The minReadTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getMinReadTimestamp() { if (minReadTimestampBuilder_ == null) { if (timestampBoundCase_ == 2) { @@ -2832,6 +2848,7 @@ public com.google.protobuf.Timestamp.Builder getMinReadTimestampBuilder() { * * .google.protobuf.Timestamp min_read_timestamp = 2; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getMinReadTimestampOrBuilder() { if ((timestampBoundCase_ == 2) && (minReadTimestampBuilder_ != null)) { return minReadTimestampBuilder_.getMessageOrBuilder(); @@ -2908,6 +2925,7 @@ public com.google.protobuf.TimestampOrBuilder getMinReadTimestampOrBuilder() { * * @return Whether the maxStaleness field is set. */ + @java.lang.Override public boolean hasMaxStaleness() { return timestampBoundCase_ == 3; } @@ -2932,6 +2950,7 @@ public boolean hasMaxStaleness() { * * @return The maxStaleness. */ + @java.lang.Override public com.google.protobuf.Duration getMaxStaleness() { if (maxStalenessBuilder_ == null) { if (timestampBoundCase_ == 3) { @@ -3123,6 +3142,7 @@ public com.google.protobuf.Duration.Builder getMaxStalenessBuilder() { * * .google.protobuf.Duration max_staleness = 3; */ + @java.lang.Override public com.google.protobuf.DurationOrBuilder getMaxStalenessOrBuilder() { if ((timestampBoundCase_ == 3) && (maxStalenessBuilder_ != null)) { return maxStalenessBuilder_.getMessageOrBuilder(); @@ -3202,6 +3222,7 @@ public com.google.protobuf.DurationOrBuilder getMaxStalenessOrBuilder() { * * @return Whether the readTimestamp field is set. */ + @java.lang.Override public boolean hasReadTimestamp() { return timestampBoundCase_ == 4; } @@ -3225,6 +3246,7 @@ public boolean hasReadTimestamp() { * * @return The readTimestamp. */ + @java.lang.Override public com.google.protobuf.Timestamp getReadTimestamp() { if (readTimestampBuilder_ == null) { if (timestampBoundCase_ == 4) { @@ -3410,6 +3432,7 @@ public com.google.protobuf.Timestamp.Builder getReadTimestampBuilder() { * * .google.protobuf.Timestamp read_timestamp = 4; */ + @java.lang.Override public com.google.protobuf.TimestampOrBuilder getReadTimestampOrBuilder() { if ((timestampBoundCase_ == 4) && (readTimestampBuilder_ != null)) { return readTimestampBuilder_.getMessageOrBuilder(); @@ -3487,6 +3510,7 @@ public com.google.protobuf.TimestampOrBuilder getReadTimestampOrBuilder() { * * @return Whether the exactStaleness field is set. */ + @java.lang.Override public boolean hasExactStaleness() { return timestampBoundCase_ == 5; } @@ -3509,6 +3533,7 @@ public boolean hasExactStaleness() { * * @return The exactStaleness. */ + @java.lang.Override public com.google.protobuf.Duration getExactStaleness() { if (exactStalenessBuilder_ == null) { if (timestampBoundCase_ == 5) { @@ -3688,6 +3713,7 @@ public com.google.protobuf.Duration.Builder getExactStalenessBuilder() { * * .google.protobuf.Duration exact_staleness = 5; */ + @java.lang.Override public com.google.protobuf.DurationOrBuilder getExactStalenessOrBuilder() { if ((timestampBoundCase_ == 5) && (exactStalenessBuilder_ != null)) { return exactStalenessBuilder_.getMessageOrBuilder(); @@ -3753,6 +3779,7 @@ public com.google.protobuf.DurationOrBuilder getExactStalenessOrBuilder() { * * @return The returnReadTimestamp. */ + @java.lang.Override public boolean getReturnReadTimestamp() { return returnReadTimestamp_; } @@ -3911,6 +3938,7 @@ public ModeCase getModeCase() { * * @return Whether the readWrite field is set. */ + @java.lang.Override public boolean hasReadWrite() { return modeCase_ == 1; } @@ -3928,6 +3956,7 @@ public boolean hasReadWrite() { * * @return The readWrite. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadWrite getReadWrite() { if (modeCase_ == 1) { return (com.google.spanner.v1.TransactionOptions.ReadWrite) mode_; @@ -3946,6 +3975,7 @@ public com.google.spanner.v1.TransactionOptions.ReadWrite getReadWrite() { * * .google.spanner.v1.TransactionOptions.ReadWrite read_write = 1; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadWriteOrBuilder getReadWriteOrBuilder() { if (modeCase_ == 1) { return (com.google.spanner.v1.TransactionOptions.ReadWrite) mode_; @@ -3968,6 +3998,7 @@ public com.google.spanner.v1.TransactionOptions.ReadWriteOrBuilder getReadWriteO * * @return Whether the partitionedDml field is set. */ + @java.lang.Override public boolean hasPartitionedDml() { return modeCase_ == 3; } @@ -3985,6 +4016,7 @@ public boolean hasPartitionedDml() { * * @return The partitionedDml. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.PartitionedDml getPartitionedDml() { if (modeCase_ == 3) { return (com.google.spanner.v1.TransactionOptions.PartitionedDml) mode_; @@ -4003,6 +4035,7 @@ public com.google.spanner.v1.TransactionOptions.PartitionedDml getPartitionedDml * * .google.spanner.v1.TransactionOptions.PartitionedDml partitioned_dml = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.PartitionedDmlOrBuilder getPartitionedDmlOrBuilder() { if (modeCase_ == 3) { @@ -4026,6 +4059,7 @@ public com.google.spanner.v1.TransactionOptions.PartitionedDml getPartitionedDml * * @return Whether the readOnly field is set. */ + @java.lang.Override public boolean hasReadOnly() { return modeCase_ == 2; } @@ -4043,6 +4077,7 @@ public boolean hasReadOnly() { * * @return The readOnly. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadOnly getReadOnly() { if (modeCase_ == 2) { return (com.google.spanner.v1.TransactionOptions.ReadOnly) mode_; @@ -4061,6 +4096,7 @@ public com.google.spanner.v1.TransactionOptions.ReadOnly getReadOnly() { * * .google.spanner.v1.TransactionOptions.ReadOnly read_only = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadOnlyOrBuilder getReadOnlyOrBuilder() { if (modeCase_ == 2) { return (com.google.spanner.v1.TransactionOptions.ReadOnly) mode_; @@ -4713,6 +4749,7 @@ public Builder clearMode() { * * @return Whether the readWrite field is set. */ + @java.lang.Override public boolean hasReadWrite() { return modeCase_ == 1; } @@ -4730,6 +4767,7 @@ public boolean hasReadWrite() { * * @return The readWrite. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadWrite getReadWrite() { if (readWriteBuilder_ == null) { if (modeCase_ == 1) { @@ -4880,6 +4918,7 @@ public com.google.spanner.v1.TransactionOptions.ReadWrite.Builder getReadWriteBu * * .google.spanner.v1.TransactionOptions.ReadWrite read_write = 1; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadWriteOrBuilder getReadWriteOrBuilder() { if ((modeCase_ == 1) && (readWriteBuilder_ != null)) { return readWriteBuilder_.getMessageOrBuilder(); @@ -4946,6 +4985,7 @@ public com.google.spanner.v1.TransactionOptions.ReadWriteOrBuilder getReadWriteO * * @return Whether the partitionedDml field is set. */ + @java.lang.Override public boolean hasPartitionedDml() { return modeCase_ == 3; } @@ -4963,6 +5003,7 @@ public boolean hasPartitionedDml() { * * @return The partitionedDml. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.PartitionedDml getPartitionedDml() { if (partitionedDmlBuilder_ == null) { if (modeCase_ == 3) { @@ -5117,6 +5158,7 @@ public Builder clearPartitionedDml() { * * .google.spanner.v1.TransactionOptions.PartitionedDml partitioned_dml = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.PartitionedDmlOrBuilder getPartitionedDmlOrBuilder() { if ((modeCase_ == 3) && (partitionedDmlBuilder_ != null)) { @@ -5184,6 +5226,7 @@ public Builder clearPartitionedDml() { * * @return Whether the readOnly field is set. */ + @java.lang.Override public boolean hasReadOnly() { return modeCase_ == 2; } @@ -5201,6 +5244,7 @@ public boolean hasReadOnly() { * * @return The readOnly. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadOnly getReadOnly() { if (readOnlyBuilder_ == null) { if (modeCase_ == 2) { @@ -5351,6 +5395,7 @@ public com.google.spanner.v1.TransactionOptions.ReadOnly.Builder getReadOnlyBuil * * .google.spanner.v1.TransactionOptions.ReadOnly read_only = 2; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions.ReadOnlyOrBuilder getReadOnlyOrBuilder() { if ((modeCase_ == 2) && (readOnlyBuilder_ != null)) { return readOnlyBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionSelector.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionSelector.java index 6d3c3b1bc5..6a7adbcfe9 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionSelector.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TransactionSelector.java @@ -207,6 +207,7 @@ public SelectorCase getSelectorCase() { * * @return Whether the singleUse field is set. */ + @java.lang.Override public boolean hasSingleUse() { return selectorCase_ == 1; } @@ -223,6 +224,7 @@ public boolean hasSingleUse() { * * @return The singleUse. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getSingleUse() { if (selectorCase_ == 1) { return (com.google.spanner.v1.TransactionOptions) selector_; @@ -240,6 +242,7 @@ public com.google.spanner.v1.TransactionOptions getSingleUse() { * * .google.spanner.v1.TransactionOptions single_use = 1; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseOrBuilder() { if (selectorCase_ == 1) { return (com.google.spanner.v1.TransactionOptions) selector_; @@ -259,6 +262,7 @@ public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseOrBuilder() * * @return The id. */ + @java.lang.Override public com.google.protobuf.ByteString getId() { if (selectorCase_ == 2) { return (com.google.protobuf.ByteString) selector_; @@ -280,6 +284,7 @@ public com.google.protobuf.ByteString getId() { * * @return Whether the begin field is set. */ + @java.lang.Override public boolean hasBegin() { return selectorCase_ == 3; } @@ -296,6 +301,7 @@ public boolean hasBegin() { * * @return The begin. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getBegin() { if (selectorCase_ == 3) { return (com.google.spanner.v1.TransactionOptions) selector_; @@ -313,6 +319,7 @@ public com.google.spanner.v1.TransactionOptions getBegin() { * * .google.spanner.v1.TransactionOptions begin = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getBeginOrBuilder() { if (selectorCase_ == 3) { return (com.google.spanner.v1.TransactionOptions) selector_; @@ -750,6 +757,7 @@ public Builder clearSelector() { * * @return Whether the singleUse field is set. */ + @java.lang.Override public boolean hasSingleUse() { return selectorCase_ == 1; } @@ -766,6 +774,7 @@ public boolean hasSingleUse() { * * @return The singleUse. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getSingleUse() { if (singleUseBuilder_ == null) { if (selectorCase_ == 1) { @@ -909,6 +918,7 @@ public com.google.spanner.v1.TransactionOptions.Builder getSingleUseBuilder() { * * .google.spanner.v1.TransactionOptions single_use = 1; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getSingleUseOrBuilder() { if ((selectorCase_ == 1) && (singleUseBuilder_ != null)) { return singleUseBuilder_.getMessageOrBuilder(); @@ -1031,6 +1041,7 @@ public Builder clearId() { * * @return Whether the begin field is set. */ + @java.lang.Override public boolean hasBegin() { return selectorCase_ == 3; } @@ -1047,6 +1058,7 @@ public boolean hasBegin() { * * @return The begin. */ + @java.lang.Override public com.google.spanner.v1.TransactionOptions getBegin() { if (beginBuilder_ == null) { if (selectorCase_ == 3) { @@ -1190,6 +1202,7 @@ public com.google.spanner.v1.TransactionOptions.Builder getBeginBuilder() { * * .google.spanner.v1.TransactionOptions begin = 3; */ + @java.lang.Override public com.google.spanner.v1.TransactionOptionsOrBuilder getBeginOrBuilder() { if ((selectorCase_ == 3) && (beginBuilder_ != null)) { return beginBuilder_.getMessageOrBuilder(); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java index d9895d81e7..eb4454331b 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/Type.java @@ -152,6 +152,7 @@ public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { * * @return The enum numeric value on the wire for code. */ + @java.lang.Override public int getCodeValue() { return code_; } @@ -166,6 +167,7 @@ public int getCodeValue() { * * @return The code. */ + @java.lang.Override public com.google.spanner.v1.TypeCode getCode() { @SuppressWarnings("deprecation") com.google.spanner.v1.TypeCode result = com.google.spanner.v1.TypeCode.valueOf(code_); @@ -186,6 +188,7 @@ public com.google.spanner.v1.TypeCode getCode() { * * @return Whether the arrayElementType field is set. */ + @java.lang.Override public boolean hasArrayElementType() { return arrayElementType_ != null; } @@ -201,6 +204,7 @@ public boolean hasArrayElementType() { * * @return The arrayElementType. */ + @java.lang.Override public com.google.spanner.v1.Type getArrayElementType() { return arrayElementType_ == null ? com.google.spanner.v1.Type.getDefaultInstance() @@ -216,6 +220,7 @@ public com.google.spanner.v1.Type getArrayElementType() { * * .google.spanner.v1.Type array_element_type = 2; */ + @java.lang.Override public com.google.spanner.v1.TypeOrBuilder getArrayElementTypeOrBuilder() { return getArrayElementType(); } @@ -234,6 +239,7 @@ public com.google.spanner.v1.TypeOrBuilder getArrayElementTypeOrBuilder() { * * @return Whether the structType field is set. */ + @java.lang.Override public boolean hasStructType() { return structType_ != null; } @@ -249,6 +255,7 @@ public boolean hasStructType() { * * @return The structType. */ + @java.lang.Override public com.google.spanner.v1.StructType getStructType() { return structType_ == null ? com.google.spanner.v1.StructType.getDefaultInstance() @@ -264,6 +271,7 @@ public com.google.spanner.v1.StructType getStructType() { * * .google.spanner.v1.StructType struct_type = 3; */ + @java.lang.Override public com.google.spanner.v1.StructTypeOrBuilder getStructTypeOrBuilder() { return getStructType(); } @@ -646,6 +654,7 @@ public Builder mergeFrom( * * @return The enum numeric value on the wire for code. */ + @java.lang.Override public int getCodeValue() { return code_; } @@ -662,6 +671,7 @@ public int getCodeValue() { * @return This builder for chaining. */ public Builder setCodeValue(int value) { + code_ = value; onChanged(); return this; @@ -677,6 +687,7 @@ public Builder setCodeValue(int value) { * * @return The code. */ + @java.lang.Override public com.google.spanner.v1.TypeCode getCode() { @SuppressWarnings("deprecation") com.google.spanner.v1.TypeCode result = com.google.spanner.v1.TypeCode.valueOf(code_); diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java index 93368c1239..1f1087e879 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/TypeCode.java @@ -320,6 +320,10 @@ public TypeCode findValueByNumber(int number) { }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } return getDescriptor().getValues().get(ordinal()); } diff --git a/synth.metadata b/synth.metadata index c4d130d795..20d6b58f9c 100644 --- a/synth.metadata +++ b/synth.metadata @@ -11,8 +11,8 @@ "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "d8a17933f650cf605196ef14f03edc246f0562b6", - "internalRef": "312582296" + "sha": "c4e37010d74071851ff24121f522e802231ac86e", + "internalRef": "313460921" } }, { From fd2485a6cd796be573b1be875f567c9ad74f3434 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2020 20:49:00 +1000 Subject: [PATCH 42/55] chore: release 1.58.1-SNAPSHOT (#324) * updated versions.txt [ci skip] * updated samples/pom.xml [ci skip] * updated samples/install-without-bom/pom.xml [ci skip] * updated samples/snippets/pom.xml [ci skip] * updated google-cloud-spanner-bom/pom.xml [ci skip] * updated google-cloud-spanner/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated grpc-google-cloud-spanner-v1/pom.xml [ci skip] * updated pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-database-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-admin-instance-v1/pom.xml [ci skip] * updated proto-google-cloud-spanner-v1/pom.xml [ci skip] * updated samples/snapshot/pom.xml Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- google-cloud-spanner-bom/pom.xml | 18 +++++++++--------- google-cloud-spanner/pom.xml | 4 ++-- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- grpc-google-cloud-spanner-v1/pom.xml | 4 ++-- pom.xml | 16 ++++++++-------- .../pom.xml | 4 ++-- .../pom.xml | 4 ++-- proto-google-cloud-spanner-v1/pom.xml | 4 ++-- samples/snapshot/pom.xml | 2 +- versions.txt | 14 +++++++------- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 3cedbfe62b..4eb8e1e44d 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 1.58.0 + 1.58.1-SNAPSHOT pom com.google.cloud @@ -64,43 +64,43 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.58.0 + 1.58.1-SNAPSHOT com.google.cloud google-cloud-spanner test-jar - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT
diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 13361abf7a..fcab00b988 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 1.58.0 + 1.58.1-SNAPSHOT jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT google-cloud-spanner diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 5bf5bc228b..4c6378e2b0 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 1d3ad4767e..2b4f72478d 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index e7ec2c07b8..3e6e1a0642 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index 0467ead42e..1a8e903676 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 1.58.0 + 1.58.1-SNAPSHOT Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -70,37 +70,37 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT com.google.cloud google-cloud-spanner - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index fcbda36e11..cbf704fe66 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 1.58.0 + 1.58.1-SNAPSHOT proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 3327e40234..6b5568b5ec 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 1.58.0 + 1.58.1-SNAPSHOT proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 264c7126b2..58c8d47066 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 1.58.0 + 1.58.1-SNAPSHOT proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index c32dd0f8fa..26e1b47cbe 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-spanner - 1.58.0 + 1.58.1-SNAPSHOT diff --git a/versions.txt b/versions.txt index 06ec98aee5..117645dc8e 100644 --- a/versions.txt +++ b/versions.txt @@ -1,10 +1,10 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.0 -proto-google-cloud-spanner-v1:1.58.0:1.58.0 -proto-google-cloud-spanner-admin-database-v1:1.58.0:1.58.0 -grpc-google-cloud-spanner-v1:1.58.0:1.58.0 -grpc-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.0 -grpc-google-cloud-spanner-admin-database-v1:1.58.0:1.58.0 -google-cloud-spanner:1.58.0:1.58.0 \ No newline at end of file +proto-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.1-SNAPSHOT +proto-google-cloud-spanner-v1:1.58.0:1.58.1-SNAPSHOT +proto-google-cloud-spanner-admin-database-v1:1.58.0:1.58.1-SNAPSHOT +grpc-google-cloud-spanner-v1:1.58.0:1.58.1-SNAPSHOT +grpc-google-cloud-spanner-admin-instance-v1:1.58.0:1.58.1-SNAPSHOT +grpc-google-cloud-spanner-admin-database-v1:1.58.0:1.58.1-SNAPSHOT +google-cloud-spanner:1.58.0:1.58.1-SNAPSHOT \ No newline at end of file From 75df62c0176137fda1d0a9076b83be06f11228ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 10 Jul 2020 04:08:12 +0200 Subject: [PATCH 43/55] deps: update shared config to 0.9.2 (#328) --- google-cloud-spanner/pom.xml | 10 ---------- pom.xml | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index fcab00b988..5101cf7396 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -102,16 +102,6 @@ - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M4 - - - org.apache.maven.plugins - maven-failsafe-plugin - 3.0.0-M4 - org.apache.maven.plugins maven-dependency-plugin diff --git a/pom.xml b/pom.xml index 1a8e903676..7db35b8aec 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ com.google.cloud google-cloud-shared-config - 0.8.1 + 0.9.2 From ae80642bf50ada20098fab63e1950bcc5a33f535 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 10 Jul 2020 04:40:46 +0200 Subject: [PATCH 44/55] build(deps): update dependency com.google.cloud:google-cloud-shared-config to v0.9.2 (#308) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [com.google.cloud:google-cloud-shared-config](https://togithub.com/googleapis/java-shared-config) | minor | `0.8.1` -> `0.9.2` | --- ### Release Notes
googleapis/java-shared-config ### [`v0.9.2`](https://togithub.com/googleapis/java-shared-config/blob/master/CHANGELOG.md#​092-httpswwwgithubcomgoogleapisjava-shared-configcomparev091v092-2020-07-02) [Compare Source](https://togithub.com/googleapis/java-shared-config/compare/v0.9.1...v0.9.2) ### [`v0.9.1`](https://togithub.com/googleapis/java-shared-config/blob/master/CHANGELOG.md#​091-httpswwwgithubcomgoogleapisjava-shared-configcomparev090v091-2020-07-01) [Compare Source](https://togithub.com/googleapis/java-shared-config/compare/v0.9.0...v0.9.1) ### [`v0.9.0`](https://togithub.com/googleapis/java-shared-config/blob/master/CHANGELOG.md#​090-httpswwwgithubcomgoogleapisjava-shared-configcomparev081v090-2020-06-25) [Compare Source](https://togithub.com/googleapis/java-shared-config/compare/v0.8.1...v0.9.0) ##### Features - add ignore rule for javax annotations to handle error in java11 ([#​171](https://www.github.com/googleapis/java-shared-config/issues/171)) ([cd635ad](https://www.github.com/googleapis/java-shared-config/commit/cd635ad6e8e5d71ac3a30e7656eb788027f1c370)) ##### [0.8.1](https://www.github.com/googleapis/java-shared-config/compare/v0.8.0...v0.8.1) (2020-06-15) ##### Bug Fixes - bump flatten plugin version to fix missing version in profile section issue ([#​159](https://www.github.com/googleapis/java-shared-config/issues/159)) ([5b34939](https://www.github.com/googleapis/java-shared-config/commit/5b349399a590b589718b7049f66c82ee38742372))
--- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-spanner). --- google-cloud-spanner-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 4eb8e1e44d..e736a74215 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -8,7 +8,7 @@ com.google.cloud google-cloud-shared-config - 0.8.1 + 0.9.2 Google Cloud Spanner BOM From a1b87086ad6e69dbad4683904315c6da6649ff09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 10 Jul 2020 04:53:41 +0200 Subject: [PATCH 45/55] tests: fix vpc test failure (#331) --- .../cloud/spanner/DatabaseClientImplTest.java | 26 +++++++++++++++++++ .../cloud/spanner/it/ITVPCNegativeTest.java | 11 +++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index 3a41a46961..9bff8fbc25 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -1457,4 +1457,30 @@ public void testClientIdReusedOnDatabaseNotFound() { } } } + + @Test + public void testBatchCreateSessionsPermissionDenied() { + mockSpanner.setBatchCreateSessionsExecutionTime( + SimulatedExecutionTime.ofStickyException( + Status.PERMISSION_DENIED.withDescription("Not permitted").asRuntimeException())); + try (Spanner spanner = + SpannerOptions.newBuilder() + .setProjectId("my-project") + .setChannelProvider(channelProvider) + .setCredentials(NoCredentials.getInstance()) + .build() + .getService()) { + DatabaseId databaseId = DatabaseId.of("my-project", "my-instance", "my-database"); + DatabaseClient client = spanner.getDatabaseClient(databaseId); + // The following call is non-blocking and will not generate an exception. + ResultSet rs = client.singleUse().executeQuery(SELECT1); + try { + // Actually trying to get any results will cause an exception. + rs.next(); + fail("missing PERMISSION_DENIED exception"); + } catch (SpannerException e) { + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.PERMISSION_DENIED); + } + } + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITVPCNegativeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITVPCNegativeTest.java index 1d64a3dfd4..63c1560e2f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITVPCNegativeTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITVPCNegativeTest.java @@ -38,6 +38,7 @@ import com.google.cloud.spanner.IntegrationTest; import com.google.cloud.spanner.KeySet; import com.google.cloud.spanner.Options; +import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SessionPoolOptions; import com.google.cloud.spanner.Spanner; import com.google.cloud.spanner.SpannerException; @@ -184,11 +185,15 @@ public void deniedGetDatabase() { @Test public void deniedRead() { + // Getting a session and starting a read is non-blocking and will not cause an exception. Trying + // to get results from the result set will. + ResultSet rs = + databaseClient + .singleUse() + .read("nonexistent-table", KeySet.all(), Arrays.asList("nonexistent-col")); try { // Tests that the initial create session request returns a permission denied. - databaseClient - .singleUse() - .read("nonexistent-table", KeySet.all(), Arrays.asList("nonexistent-col")); + rs.next(); fail("Expected PERMISSION_DENIED SpannerException"); } catch (SpannerException e) { checkExceptionForVPCError(e); From 45acd8960c961d48e91a7b1546efa64d9e9ae576 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 10 Jul 2020 04:56:22 +0200 Subject: [PATCH 46/55] deps: update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.3 (#334) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7db35b8aec..4cb4ec4544 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ com.google.cloud google-cloud-shared-dependencies - 0.8.2 + 0.8.3 pom import From fb26abe692f8eeaa208c4421887547d1bc575f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 10 Jul 2020 05:47:36 +0200 Subject: [PATCH 47/55] test: fix potential race condition in Async ResultSet (#333) If an AsyncResultSet was paused directly after receiving its last row and then cancelled while in paused mode, there was a small chance that the callback would not be called a last time to indicate to the user that the result set had been cancelled. Updates #327 --- .../java/com/google/cloud/spanner/AsyncResultSetImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java index f277388b0b..07b5c8c7bb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java @@ -381,11 +381,11 @@ public Void call() throws Exception { while (!stop) { waitIfPaused(); startCallbackIfNecessary(); - synchronized (monitor) { - stop = state.shouldStop || cursorReturnedDoneOrException; - } // Make sure we wait until the callback runner has actually finished. consumingLatch.await(); + synchronized (monitor) { + stop = cursorReturnedDoneOrException; + } } } finally { if (executorProvider.shouldAutoClose()) { From 26be103da1117c4940550fad1672c66e6edfbdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 14 Jul 2020 05:05:04 +0200 Subject: [PATCH 48/55] fix: set gRPC keep-alive to 120 seconds (#339) --- .../java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 9f7eaa8e8f..26e6101e02 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -309,7 +309,7 @@ public GapicSpannerRpc(final SpannerOptions options) { // Set a keepalive time of 120 seconds to help long running // commit GRPC calls succeed - .setKeepAliveTime(Duration.ofSeconds(GRPC_KEEPALIVE_SECONDS * 1000)) + .setKeepAliveTime(Duration.ofSeconds(GRPC_KEEPALIVE_SECONDS)) // Then check if SpannerOptions provides an InterceptorProvider. Create a default // SpannerInterceptorProvider if none is provided From 1a4f4fd675a1580c87ad1d53c650a20bd2ff4811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 14 Jul 2020 05:09:26 +0200 Subject: [PATCH 49/55] fix: fix potential unnecessary transaction retry (#337) A transaction could in some circumstances be retried after an abort using the previous transaction id. This would cause the retry to abort directly as well, and then start a new transaction. This extra loop has now been removed. Fixes #327 --- .../java/com/google/cloud/spanner/TransactionRunnerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java index c10b713285..21812aa96a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java @@ -654,7 +654,7 @@ private T runInternal(final TransactionCallable txCallable) { new Callable() { @Override public T call() { - if (txn.isAborted()) { + if (attempt.get() > 0) { txn = session.newTransaction(); } checkState( From b547e31d095be3cf1646e0e9c07bfc467ecc3c22 Mon Sep 17 00:00:00 2001 From: Thiago Nunes Date: Tue, 14 Jul 2020 13:31:09 +1000 Subject: [PATCH 50/55] fix: runs sample tests in java 8 and java 11 (#345) Adds configuration files in kokoro to run sample tests in java 8 and java 11. These were added in the continuous, nightly and presubmit builds. --- .kokoro/continuous/samples/common.cfg | 25 +++++++++++++++ .kokoro/continuous/samples/samples-java11.cfg | 7 ++++ .kokoro/continuous/samples/samples-java8.cfg | 7 ++++ .kokoro/nightly/samples/common.cfg | 32 +++++++++++++++++++ .kokoro/nightly/samples/samples-java11.cfg | 7 ++++ .kokoro/nightly/samples/samples-java8.cfg | 7 ++++ .kokoro/presubmit/samples/common.cfg | 27 ++++++++++++++++ .kokoro/presubmit/samples/samples-java11.cfg | 7 ++++ .kokoro/presubmit/samples/samples-java8.cfg | 7 ++++ 9 files changed, 126 insertions(+) create mode 100644 .kokoro/continuous/samples/common.cfg create mode 100644 .kokoro/continuous/samples/samples-java11.cfg create mode 100644 .kokoro/continuous/samples/samples-java8.cfg create mode 100644 .kokoro/nightly/samples/common.cfg create mode 100644 .kokoro/nightly/samples/samples-java11.cfg create mode 100644 .kokoro/nightly/samples/samples-java8.cfg create mode 100644 .kokoro/presubmit/samples/common.cfg create mode 100644 .kokoro/presubmit/samples/samples-java11.cfg create mode 100644 .kokoro/presubmit/samples/samples-java8.cfg diff --git a/.kokoro/continuous/samples/common.cfg b/.kokoro/continuous/samples/common.cfg new file mode 100644 index 0000000000..e6b577f86f --- /dev/null +++ b/.kokoro/continuous/samples/common.cfg @@ -0,0 +1,25 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "JOB_TYPE" + value: "samples" +} + +env_vars: { + key: "GCLOUD_PROJECT" + value: "gcloud-devel" +} + +env_vars: { + key: "GOOGLE_APPLICATION_CREDENTIALS" + value: "keystore/73713_java_it_service_account" +} + +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "java_it_service_account" + } + } +} diff --git a/.kokoro/continuous/samples/samples-java11.cfg b/.kokoro/continuous/samples/samples-java11.cfg new file mode 100644 index 0000000000..709f2b4c73 --- /dev/null +++ b/.kokoro/continuous/samples/samples-java11.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java11" +} diff --git a/.kokoro/continuous/samples/samples-java8.cfg b/.kokoro/continuous/samples/samples-java8.cfg new file mode 100644 index 0000000000..3b017fc80f --- /dev/null +++ b/.kokoro/continuous/samples/samples-java8.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java8" +} diff --git a/.kokoro/nightly/samples/common.cfg b/.kokoro/nightly/samples/common.cfg new file mode 100644 index 0000000000..be513e11d6 --- /dev/null +++ b/.kokoro/nightly/samples/common.cfg @@ -0,0 +1,32 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "JOB_TYPE" + value: "samples" +} + +# TODO: remove this after we've migrated all tests and scripts +env_vars: { + key: "GCLOUD_PROJECT" + value: "java-docs-samples-testing" +} + +env_vars: { + key: "GOOGLE_CLOUD_PROJECT" + value: "java-docs-samples-testing" +} + +env_vars: { + key: "GOOGLE_APPLICATION_CREDENTIALS" + value: "secret_manager/java-docs-samples-service-account" +} + +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-docs-samples-service-account" +} + +env_vars: { + key: "ENABLE_BUILD_COP" + value: "true" +} diff --git a/.kokoro/nightly/samples/samples-java11.cfg b/.kokoro/nightly/samples/samples-java11.cfg new file mode 100644 index 0000000000..709f2b4c73 --- /dev/null +++ b/.kokoro/nightly/samples/samples-java11.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java11" +} diff --git a/.kokoro/nightly/samples/samples-java8.cfg b/.kokoro/nightly/samples/samples-java8.cfg new file mode 100644 index 0000000000..3b017fc80f --- /dev/null +++ b/.kokoro/nightly/samples/samples-java8.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java8" +} diff --git a/.kokoro/presubmit/samples/common.cfg b/.kokoro/presubmit/samples/common.cfg new file mode 100644 index 0000000000..51c9224422 --- /dev/null +++ b/.kokoro/presubmit/samples/common.cfg @@ -0,0 +1,27 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "JOB_TYPE" + value: "samples" +} + +# TODO: remove this after we've migrated all tests and scripts +env_vars: { + key: "GCLOUD_PROJECT" + value: "java-docs-samples-testing" +} + +env_vars: { + key: "GOOGLE_CLOUD_PROJECT" + value: "java-docs-samples-testing" +} + +env_vars: { + key: "GOOGLE_APPLICATION_CREDENTIALS" + value: "secret_manager/java-docs-samples-service-account" +} + +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-docs-samples-service-account" +} diff --git a/.kokoro/presubmit/samples/samples-java11.cfg b/.kokoro/presubmit/samples/samples-java11.cfg new file mode 100644 index 0000000000..709f2b4c73 --- /dev/null +++ b/.kokoro/presubmit/samples/samples-java11.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java11" +} diff --git a/.kokoro/presubmit/samples/samples-java8.cfg b/.kokoro/presubmit/samples/samples-java8.cfg new file mode 100644 index 0000000000..3b017fc80f --- /dev/null +++ b/.kokoro/presubmit/samples/samples-java8.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/java8" +} From 8aa591e306f3a97e5ba8ef8fee3683ec6444078a Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 13 Jul 2020 21:25:56 -0700 Subject: [PATCH 51/55] chore: changes without context (#329) --- README.md | 2 +- synth.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e47c69bbd..23bd5c6cde 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 1.57.0 + 1.58.0 ``` diff --git a/synth.metadata b/synth.metadata index 20d6b58f9c..c750841d4c 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-spanner.git", - "sha": "122a997681ef10b95dbb036d35d724fe7c5ecf6e" + "sha": "fd2485a6cd796be573b1be875f567c9ad74f3434" } }, { From 60dd9fbc419ac959a300b64fef84ef5f801548e5 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 13 Jul 2020 22:40:26 -0700 Subject: [PATCH 52/55] chore: re-generated to pick up changes from googleapis (#330) * chore: changes without context autosynth cannot find the source of changes triggered by earlier changes in this repository, or by version upgrades to tools such as linters. * chore: set Ruby namespace in proto options PiperOrigin-RevId: 316144276 Source-Author: Google APIs Source-Date: Fri Jun 12 11:38:22 2020 -0700 Source-Repo: googleapis/googleapis Source-Sha: b5653ef55579186841dee924592248d821902a12 Source-Link: https://github.com/googleapis/googleapis/commit/b5653ef55579186841dee924592248d821902a12 * chore: fully qualify response type in longrunning_operation.info for CreateBackup in the same fashion as all other longrunning operations PiperOrigin-RevId: 320022685 Source-Author: Google APIs Source-Date: Tue Jul 7 11:19:52 2020 -0700 Source-Repo: googleapis/googleapis Source-Sha: 4d8706453bf6016ebf1bb241d78b4dc58c92064d Source-Link: https://github.com/googleapis/googleapis/commit/4d8706453bf6016ebf1bb241d78b4dc58c92064d * fix: migrate spanner/database/v1 to grpc_service_config PiperOrigin-RevId: 320114022 Source-Author: Google APIs Source-Date: Tue Jul 7 20:27:27 2020 -0700 Source-Repo: googleapis/googleapis Source-Sha: d8354750a5fe21173832ab9a1f2ce6348cd27d83 Source-Link: https://github.com/googleapis/googleapis/commit/d8354750a5fe21173832ab9a1f2ce6348cd27d83 * fix: migrate spanner/instance/v1 to grpc_service_config PiperOrigin-RevId: 320114042 Source-Author: Google APIs Source-Date: Tue Jul 7 20:27:36 2020 -0700 Source-Repo: googleapis/googleapis Source-Sha: 8bbefeffb4c91fd34e1729bbc51dfc136557d88d Source-Link: https://github.com/googleapis/googleapis/commit/8bbefeffb4c91fd34e1729bbc51dfc136557d88d * fix: migrate spanner/v1 to grpc_service_config PiperOrigin-RevId: 320114059 Source-Author: Google APIs Source-Date: Tue Jul 7 20:27:48 2020 -0700 Source-Repo: googleapis/googleapis Source-Sha: c29c4c519667a51c0e2cfddda9c3a66be77bdf38 Source-Link: https://github.com/googleapis/googleapis/commit/c29c4c519667a51c0e2cfddda9c3a66be77bdf38 * fix: apply SpannerOptionsTest patch (#332) Co-authored-by: Noah Dietz --- .../database/v1/DatabaseAdminClient.java | 1390 ++++++++--------- .../database/v1/DatabaseAdminSettings.java | 150 +- .../database/v1/stub/DatabaseAdminStub.java | 66 +- .../v1/stub/DatabaseAdminStubSettings.java | 410 ++--- .../v1/stub/GrpcDatabaseAdminStub.java | 304 ++-- .../instance/v1/InstanceAdminClient.java | 1276 +++++++-------- .../instance/v1/InstanceAdminSettings.java | 98 +- .../v1/stub/GrpcInstanceAdminStub.java | 176 +-- .../instance/v1/stub/InstanceAdminStub.java | 40 +- .../v1/stub/InstanceAdminStubSettings.java | 282 ++-- .../spanner/v1/stub/SpannerStubSettings.java | 93 +- .../cloud/spanner/SpannerOptionsTest.java | 157 +- .../database/v1/DatabaseAdminClientTest.java | 344 ++-- .../instance/v1/InstanceAdminClientTest.java | 240 +-- .../admin/database/v1/BackupProto.java | 6 +- .../admin/database/v1/CommonProto.java | 5 +- .../v1/SpannerDatabaseAdminProto.java | 110 +- .../spanner/admin/database/v1/backup.proto | 1 + .../spanner/admin/database/v1/common.proto | 1 + .../database/v1/spanner_database_admin.proto | 3 +- .../v1/SpannerInstanceAdminProto.java | 5 +- .../instance/v1/spanner_instance_admin.proto | 1 + .../java/com/google/spanner/v1/KeysProto.java | 5 +- .../com/google/spanner/v1/MutationProto.java | 6 +- .../com/google/spanner/v1/QueryPlanProto.java | 5 +- .../com/google/spanner/v1/ResultSetProto.java | 5 +- .../com/google/spanner/v1/SpannerProto.java | 11 +- .../google/spanner/v1/TransactionProto.java | 5 +- .../java/com/google/spanner/v1/TypeProto.java | 5 +- .../main/proto/google/spanner/v1/keys.proto | 1 + .../proto/google/spanner/v1/mutation.proto | 1 + .../proto/google/spanner/v1/query_plan.proto | 1 + .../proto/google/spanner/v1/result_set.proto | 1 + .../proto/google/spanner/v1/spanner.proto | 1 + .../proto/google/spanner/v1/transaction.proto | 1 + .../main/proto/google/spanner/v1/type.proto | 1 + synth.metadata | 4 +- 37 files changed, 2702 insertions(+), 2509 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java index 112b43e2ef..27dd9c515a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java @@ -210,138 +210,6 @@ public final OperationsClient getOperationsClient() { return operationsClient; } - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Lists Cloud Spanner databases. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   for (Database element : databaseAdminClient.listDatabases(parent).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
-   * }
-   * 
- * - * @param parent Required. The instance whose databases should be listed. Values are of the form - * `projects/<project>/instances/<instance>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final ListDatabasesPagedResponse listDatabases(InstanceName parent) { - ListDatabasesRequest request = - ListDatabasesRequest.newBuilder() - .setParent(parent == null ? null : parent.toString()) - .build(); - return listDatabases(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Lists Cloud Spanner databases. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   for (Database element : databaseAdminClient.listDatabases(parent.toString()).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
-   * }
-   * 
- * - * @param parent Required. The instance whose databases should be listed. Values are of the form - * `projects/<project>/instances/<instance>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final ListDatabasesPagedResponse listDatabases(String parent) { - ListDatabasesRequest request = ListDatabasesRequest.newBuilder().setParent(parent).build(); - return listDatabases(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Lists Cloud Spanner databases. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .build();
-   *   for (Database element : databaseAdminClient.listDatabases(request).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final ListDatabasesPagedResponse listDatabases(ListDatabasesRequest request) { - return listDatabasesPagedCallable().call(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Lists Cloud Spanner databases. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .build();
-   *   ApiFuture<ListDatabasesPagedResponse> future = databaseAdminClient.listDatabasesPagedCallable().futureCall(request);
-   *   // Do something
-   *   for (Database element : future.get().iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
-   * }
-   * 
- */ - public final UnaryCallable - listDatabasesPagedCallable() { - return stub.listDatabasesPagedCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Lists Cloud Spanner databases. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .build();
-   *   while (true) {
-   *     ListDatabasesResponse response = databaseAdminClient.listDatabasesCallable().call(request);
-   *     for (Database element : response.getDatabasesList()) {
-   *       // doThingsWith(element);
-   *     }
-   *     String nextPageToken = response.getNextPageToken();
-   *     if (!Strings.isNullOrEmpty(nextPageToken)) {
-   *       request = request.toBuilder().setPageToken(nextPageToken).build();
-   *     } else {
-   *       break;
-   *     }
-   *   }
-   * }
-   * 
- */ - public final UnaryCallable listDatabasesCallable() { - return stub.listDatabasesCallable(); - } - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Creates a new Cloud Spanner database and starts to prepare it for serving. The returned @@ -520,96 +388,6 @@ public final UnaryCallable createDatabaseCalla return stub.createDatabaseCallable(); } - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Gets the state of a Cloud Spanner database. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
-   *   Database response = databaseAdminClient.getDatabase(name);
-   * }
-   * 
- * - * @param name Required. The name of the requested database. Values are of the form - * `projects/<project>/instances/<instance>/databases/<database>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final Database getDatabase(DatabaseName name) { - GetDatabaseRequest request = - GetDatabaseRequest.newBuilder().setName(name == null ? null : name.toString()).build(); - return getDatabase(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Gets the state of a Cloud Spanner database. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
-   *   Database response = databaseAdminClient.getDatabase(name.toString());
-   * }
-   * 
- * - * @param name Required. The name of the requested database. Values are of the form - * `projects/<project>/instances/<instance>/databases/<database>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final Database getDatabase(String name) { - GetDatabaseRequest request = GetDatabaseRequest.newBuilder().setName(name).build(); - return getDatabase(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Gets the state of a Cloud Spanner database. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
-   *   GetDatabaseRequest request = GetDatabaseRequest.newBuilder()
-   *     .setName(name.toString())
-   *     .build();
-   *   Database response = databaseAdminClient.getDatabase(request);
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - public final Database getDatabase(GetDatabaseRequest request) { - return getDatabaseCallable().call(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Gets the state of a Cloud Spanner database. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
-   *   GetDatabaseRequest request = GetDatabaseRequest.newBuilder()
-   *     .setName(name.toString())
-   *     .build();
-   *   ApiFuture<Database> future = databaseAdminClient.getDatabaseCallable().futureCall(request);
-   *   // Do something
-   *   Database response = future.get();
-   * }
-   * 
- */ - public final UnaryCallable getDatabaseCallable() { - return stub.getDatabaseCallable(); - } - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Updates the schema of a Cloud Spanner database by creating/altering/dropping tables, columns, @@ -736,46 +514,696 @@ public final OperationFuture updateDatabaseDdl * .setDatabase(database.toString()) * .addAllStatements(statements) * .build(); - * OperationFuture<Empty, UpdateDatabaseDdlMetadata> future = databaseAdminClient.updateDatabaseDdlOperationCallable().futureCall(request); - * // Do something - * future.get(); + * OperationFuture<Empty, UpdateDatabaseDdlMetadata> future = databaseAdminClient.updateDatabaseDdlOperationCallable().futureCall(request); + * // Do something + * future.get(); + * } + * + */ + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public final OperationCallable + updateDatabaseDdlOperationCallable() { + return stub.updateDatabaseDdlOperationCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Updates the schema of a Cloud Spanner database by creating/altering/dropping tables, columns, + * indexes, etc. The returned [long-running operation][google.longrunning.Operation] will have a + * name of the format `<database_name>/operations/<operation_id>` and can be used to + * track execution of the schema change(s). The [metadata][google.longrunning.Operation.metadata] + * field type is + * [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata]. The + * operation has no response. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
+   *   List<String> statements = new ArrayList<>();
+   *   UpdateDatabaseDdlRequest request = UpdateDatabaseDdlRequest.newBuilder()
+   *     .setDatabase(database.toString())
+   *     .addAllStatements(statements)
+   *     .build();
+   *   ApiFuture<Operation> future = databaseAdminClient.updateDatabaseDdlCallable().futureCall(request);
+   *   // Do something
+   *   future.get();
+   * }
+   * 
+ */ + public final UnaryCallable updateDatabaseDdlCallable() { + return stub.updateDatabaseDdlCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Starts creating a new Cloud Spanner Backup. The returned backup [long-running + * operation][google.longrunning.Operation] will have a name of the format + * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` + * and can be used to track creation of the backup. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned + * operation will stop the creation and delete the backup. There can be only one pending backup + * creation per database. Backup creation of different databases can run concurrently. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   Backup backup = Backup.newBuilder().build();
+   *   String backupId = "";
+   *   Backup response = databaseAdminClient.createBackupAsync(parent, backup, backupId).get();
+   * }
+   * 
+ * + * @param parent Required. The name of the instance in which the backup will be created. This must + * be the same instance that contains the database the backup will be created from. The backup + * will be stored in the location(s) specified in the instance configuration of this instance. + * Values are of the form `projects/<project>/instances/<instance>`. + * @param backup Required. The backup to create. + * @param backupId Required. The id of the backup to be created. The `backup_id` appended to + * `parent` forms the full backup name of the form + * `projects/<project>/instances/<instance>/backups/<backup_id>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createBackupAsync( + InstanceName parent, Backup backup, String backupId) { + CreateBackupRequest request = + CreateBackupRequest.newBuilder() + .setParent(parent == null ? null : parent.toString()) + .setBackup(backup) + .setBackupId(backupId) + .build(); + return createBackupAsync(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Starts creating a new Cloud Spanner Backup. The returned backup [long-running + * operation][google.longrunning.Operation] will have a name of the format + * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` + * and can be used to track creation of the backup. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned + * operation will stop the creation and delete the backup. There can be only one pending backup + * creation per database. Backup creation of different databases can run concurrently. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   Backup backup = Backup.newBuilder().build();
+   *   String backupId = "";
+   *   Backup response = databaseAdminClient.createBackupAsync(parent.toString(), backup, backupId).get();
+   * }
+   * 
+ * + * @param parent Required. The name of the instance in which the backup will be created. This must + * be the same instance that contains the database the backup will be created from. The backup + * will be stored in the location(s) specified in the instance configuration of this instance. + * Values are of the form `projects/<project>/instances/<instance>`. + * @param backup Required. The backup to create. + * @param backupId Required. The id of the backup to be created. The `backup_id` appended to + * `parent` forms the full backup name of the form + * `projects/<project>/instances/<instance>/backups/<backup_id>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createBackupAsync( + String parent, Backup backup, String backupId) { + CreateBackupRequest request = + CreateBackupRequest.newBuilder() + .setParent(parent) + .setBackup(backup) + .setBackupId(backupId) + .build(); + return createBackupAsync(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Starts creating a new Cloud Spanner Backup. The returned backup [long-running + * operation][google.longrunning.Operation] will have a name of the format + * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` + * and can be used to track creation of the backup. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned + * operation will stop the creation and delete the backup. There can be only one pending backup + * creation per database. Backup creation of different databases can run concurrently. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String backupId = "";
+   *   Backup backup = Backup.newBuilder().build();
+   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setBackupId(backupId)
+   *     .setBackup(backup)
+   *     .build();
+   *   Backup response = databaseAdminClient.createBackupAsync(request).get();
+   * }
+   * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createBackupAsync( + CreateBackupRequest request) { + return createBackupOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Starts creating a new Cloud Spanner Backup. The returned backup [long-running + * operation][google.longrunning.Operation] will have a name of the format + * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` + * and can be used to track creation of the backup. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned + * operation will stop the creation and delete the backup. There can be only one pending backup + * creation per database. Backup creation of different databases can run concurrently. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String backupId = "";
+   *   Backup backup = Backup.newBuilder().build();
+   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setBackupId(backupId)
+   *     .setBackup(backup)
+   *     .build();
+   *   OperationFuture<Backup, CreateBackupMetadata> future = databaseAdminClient.createBackupOperationCallable().futureCall(request);
+   *   // Do something
+   *   Backup response = future.get();
+   * }
+   * 
+ */ + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public final OperationCallable + createBackupOperationCallable() { + return stub.createBackupOperationCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Starts creating a new Cloud Spanner Backup. The returned backup [long-running + * operation][google.longrunning.Operation] will have a name of the format + * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` + * and can be used to track creation of the backup. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned + * operation will stop the creation and delete the backup. There can be only one pending backup + * creation per database. Backup creation of different databases can run concurrently. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String backupId = "";
+   *   Backup backup = Backup.newBuilder().build();
+   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setBackupId(backupId)
+   *     .setBackup(backup)
+   *     .build();
+   *   ApiFuture<Operation> future = databaseAdminClient.createBackupCallable().futureCall(request);
+   *   // Do something
+   *   Operation response = future.get();
+   * }
+   * 
+ */ + public final UnaryCallable createBackupCallable() { + return stub.createBackupCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Create a new database by restoring from a completed backup. The new database must be in the + * same project and in an instance with the same instance configuration as the instance containing + * the backup. The returned database [long-running operation][google.longrunning.Operation] has a + * name of the format + * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, + * and can be used to track the progress of the operation, and to cancel it. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The + * [response][google.longrunning.Operation.response] type is + * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned + * operation will stop the restore and delete the database. There can be only one database being + * restored into an instance at a time. Once the restore operation completes, a new restore + * operation can be initiated, without waiting for the optimize operation associated with the + * first restore to complete. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String databaseId = "";
+   *   BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
+   *   Database response = databaseAdminClient.restoreDatabaseAsync(parent, databaseId, backup).get();
+   * }
+   * 
+ * + * @param parent Required. The name of the instance in which to create the restored database. This + * instance must be in the same project and have the same instance configuration as the + * instance containing the source backup. Values are of the form + * `projects/<project>/instances/<instance>`. + * @param databaseId Required. The id of the database to create and restore to. This database must + * not already exist. The `database_id` appended to `parent` forms the full database name of + * the form + * `projects/<project>/instances/<instance>/databases/<database_id>`. + * @param backup Name of the backup from which to restore. Values are of the form + * `projects/<project>/instances/<instance>/backups/<backup>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture restoreDatabaseAsync( + InstanceName parent, String databaseId, BackupName backup) { + RestoreDatabaseRequest request = + RestoreDatabaseRequest.newBuilder() + .setParent(parent == null ? null : parent.toString()) + .setDatabaseId(databaseId) + .setBackup(backup == null ? null : backup.toString()) + .build(); + return restoreDatabaseAsync(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Create a new database by restoring from a completed backup. The new database must be in the + * same project and in an instance with the same instance configuration as the instance containing + * the backup. The returned database [long-running operation][google.longrunning.Operation] has a + * name of the format + * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, + * and can be used to track the progress of the operation, and to cancel it. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The + * [response][google.longrunning.Operation.response] type is + * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned + * operation will stop the restore and delete the database. There can be only one database being + * restored into an instance at a time. Once the restore operation completes, a new restore + * operation can be initiated, without waiting for the optimize operation associated with the + * first restore to complete. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String databaseId = "";
+   *   BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
+   *   Database response = databaseAdminClient.restoreDatabaseAsync(parent.toString(), databaseId, backup.toString()).get();
+   * }
+   * 
+ * + * @param parent Required. The name of the instance in which to create the restored database. This + * instance must be in the same project and have the same instance configuration as the + * instance containing the source backup. Values are of the form + * `projects/<project>/instances/<instance>`. + * @param databaseId Required. The id of the database to create and restore to. This database must + * not already exist. The `database_id` appended to `parent` forms the full database name of + * the form + * `projects/<project>/instances/<instance>/databases/<database_id>`. + * @param backup Name of the backup from which to restore. Values are of the form + * `projects/<project>/instances/<instance>/backups/<backup>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture restoreDatabaseAsync( + String parent, String databaseId, String backup) { + RestoreDatabaseRequest request = + RestoreDatabaseRequest.newBuilder() + .setParent(parent) + .setDatabaseId(databaseId) + .setBackup(backup) + .build(); + return restoreDatabaseAsync(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Create a new database by restoring from a completed backup. The new database must be in the + * same project and in an instance with the same instance configuration as the instance containing + * the backup. The returned database [long-running operation][google.longrunning.Operation] has a + * name of the format + * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, + * and can be used to track the progress of the operation, and to cancel it. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The + * [response][google.longrunning.Operation.response] type is + * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned + * operation will stop the restore and delete the database. There can be only one database being + * restored into an instance at a time. Once the restore operation completes, a new restore + * operation can be initiated, without waiting for the optimize operation associated with the + * first restore to complete. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String databaseId = "";
+   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setDatabaseId(databaseId)
+   *     .build();
+   *   Database response = databaseAdminClient.restoreDatabaseAsync(request).get();
+   * }
+   * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture restoreDatabaseAsync( + RestoreDatabaseRequest request) { + return restoreDatabaseOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Create a new database by restoring from a completed backup. The new database must be in the + * same project and in an instance with the same instance configuration as the instance containing + * the backup. The returned database [long-running operation][google.longrunning.Operation] has a + * name of the format + * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, + * and can be used to track the progress of the operation, and to cancel it. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The + * [response][google.longrunning.Operation.response] type is + * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned + * operation will stop the restore and delete the database. There can be only one database being + * restored into an instance at a time. Once the restore operation completes, a new restore + * operation can be initiated, without waiting for the optimize operation associated with the + * first restore to complete. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String databaseId = "";
+   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setDatabaseId(databaseId)
+   *     .build();
+   *   OperationFuture<Database, RestoreDatabaseMetadata> future = databaseAdminClient.restoreDatabaseOperationCallable().futureCall(request);
+   *   // Do something
+   *   Database response = future.get();
+   * }
+   * 
+ */ + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public final OperationCallable + restoreDatabaseOperationCallable() { + return stub.restoreDatabaseOperationCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Create a new database by restoring from a completed backup. The new database must be in the + * same project and in an instance with the same instance configuration as the instance containing + * the backup. The returned database [long-running operation][google.longrunning.Operation] has a + * name of the format + * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, + * and can be used to track the progress of the operation, and to cancel it. The + * [metadata][google.longrunning.Operation.metadata] field type is + * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The + * [response][google.longrunning.Operation.response] type is + * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned + * operation will stop the restore and delete the database. There can be only one database being + * restored into an instance at a time. Once the restore operation completes, a new restore + * operation can be initiated, without waiting for the optimize operation associated with the + * first restore to complete. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   String databaseId = "";
+   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .setDatabaseId(databaseId)
+   *     .build();
+   *   ApiFuture<Operation> future = databaseAdminClient.restoreDatabaseCallable().futureCall(request);
+   *   // Do something
+   *   Operation response = future.get();
+   * }
+   * 
+ */ + public final UnaryCallable restoreDatabaseCallable() { + return stub.restoreDatabaseCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists Cloud Spanner databases. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   for (Database element : databaseAdminClient.listDatabases(parent).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param parent Required. The instance whose databases should be listed. Values are of the form + * `projects/<project>/instances/<instance>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListDatabasesPagedResponse listDatabases(InstanceName parent) { + ListDatabasesRequest request = + ListDatabasesRequest.newBuilder() + .setParent(parent == null ? null : parent.toString()) + .build(); + return listDatabases(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists Cloud Spanner databases. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   for (Database element : databaseAdminClient.listDatabases(parent.toString()).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param parent Required. The instance whose databases should be listed. Values are of the form + * `projects/<project>/instances/<instance>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListDatabasesPagedResponse listDatabases(String parent) { + ListDatabasesRequest request = ListDatabasesRequest.newBuilder().setParent(parent).build(); + return listDatabases(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists Cloud Spanner databases. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   for (Database element : databaseAdminClient.listDatabases(request).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListDatabasesPagedResponse listDatabases(ListDatabasesRequest request) { + return listDatabasesPagedCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists Cloud Spanner databases. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   ApiFuture<ListDatabasesPagedResponse> future = databaseAdminClient.listDatabasesPagedCallable().futureCall(request);
+   *   // Do something
+   *   for (Database element : future.get().iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ */ + public final UnaryCallable + listDatabasesPagedCallable() { + return stub.listDatabasesPagedCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists Cloud Spanner databases. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
+   *   ListDatabasesRequest request = ListDatabasesRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   while (true) {
+   *     ListDatabasesResponse response = databaseAdminClient.listDatabasesCallable().call(request);
+   *     for (Database element : response.getDatabasesList()) {
+   *       // doThingsWith(element);
+   *     }
+   *     String nextPageToken = response.getNextPageToken();
+   *     if (!Strings.isNullOrEmpty(nextPageToken)) {
+   *       request = request.toBuilder().setPageToken(nextPageToken).build();
+   *     } else {
+   *       break;
+   *     }
+   *   }
+   * }
+   * 
+ */ + public final UnaryCallable listDatabasesCallable() { + return stub.listDatabasesCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets the state of a Cloud Spanner database. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
+   *   Database response = databaseAdminClient.getDatabase(name);
+   * }
+   * 
+ * + * @param name Required. The name of the requested database. Values are of the form + * `projects/<project>/instances/<instance>/databases/<database>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Database getDatabase(DatabaseName name) { + GetDatabaseRequest request = + GetDatabaseRequest.newBuilder().setName(name == null ? null : name.toString()).build(); + return getDatabase(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets the state of a Cloud Spanner database. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
+   *   Database response = databaseAdminClient.getDatabase(name.toString());
+   * }
+   * 
+ * + * @param name Required. The name of the requested database. Values are of the form + * `projects/<project>/instances/<instance>/databases/<database>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Database getDatabase(String name) { + GetDatabaseRequest request = GetDatabaseRequest.newBuilder().setName(name).build(); + return getDatabase(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets the state of a Cloud Spanner database. + * + *

Sample code: + * + *


+   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
+   *   GetDatabaseRequest request = GetDatabaseRequest.newBuilder()
+   *     .setName(name.toString())
+   *     .build();
+   *   Database response = databaseAdminClient.getDatabase(request);
    * }
    * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public final OperationCallable - updateDatabaseDdlOperationCallable() { - return stub.updateDatabaseDdlOperationCallable(); + public final Database getDatabase(GetDatabaseRequest request) { + return getDatabaseCallable().call(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Updates the schema of a Cloud Spanner database by creating/altering/dropping tables, columns, - * indexes, etc. The returned [long-running operation][google.longrunning.Operation] will have a - * name of the format `<database_name>/operations/<operation_id>` and can be used to - * track execution of the schema change(s). The [metadata][google.longrunning.Operation.metadata] - * field type is - * [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata]. The - * operation has no response. + * Gets the state of a Cloud Spanner database. * *

Sample code: * *


    * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
-   *   List<String> statements = new ArrayList<>();
-   *   UpdateDatabaseDdlRequest request = UpdateDatabaseDdlRequest.newBuilder()
-   *     .setDatabase(database.toString())
-   *     .addAllStatements(statements)
+   *   DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]");
+   *   GetDatabaseRequest request = GetDatabaseRequest.newBuilder()
+   *     .setName(name.toString())
    *     .build();
-   *   ApiFuture<Operation> future = databaseAdminClient.updateDatabaseDdlCallable().futureCall(request);
+   *   ApiFuture<Database> future = databaseAdminClient.getDatabaseCallable().futureCall(request);
    *   // Do something
-   *   future.get();
+   *   Database response = future.get();
    * }
    * 
*/ - public final UnaryCallable updateDatabaseDdlCallable() { - return stub.updateDatabaseDdlCallable(); + public final UnaryCallable getDatabaseCallable() { + return stub.getDatabaseCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD @@ -1316,243 +1744,38 @@ public final TestIamPermissionsResponse testIamPermissions( * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ public final TestIamPermissionsResponse testIamPermissions(TestIamPermissionsRequest request) { - return testIamPermissionsCallable().call(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Returns permissions that the caller has on the specified database or backup resource. - * - *

Attempting this RPC on a non-existent Cloud Spanner database will result in a NOT_FOUND - * error if the user has `spanner.databases.list` permission on the containing Cloud Spanner - * instance. Otherwise returns an empty set of permissions. Calling this method on a backup that - * does not exist will result in a NOT_FOUND error if the user has `spanner.backups.list` - * permission on the containing instance. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   ResourceName resource = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
-   *   List<String> permissions = new ArrayList<>();
-   *   TestIamPermissionsRequest request = TestIamPermissionsRequest.newBuilder()
-   *     .setResource(resource.toString())
-   *     .addAllPermissions(permissions)
-   *     .build();
-   *   ApiFuture<TestIamPermissionsResponse> future = databaseAdminClient.testIamPermissionsCallable().futureCall(request);
-   *   // Do something
-   *   TestIamPermissionsResponse response = future.get();
-   * }
-   * 
- */ - public final UnaryCallable - testIamPermissionsCallable() { - return stub.testIamPermissionsCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Starts creating a new Cloud Spanner Backup. The returned backup [long-running - * operation][google.longrunning.Operation] will have a name of the format - * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` - * and can be used to track creation of the backup. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned - * operation will stop the creation and delete the backup. There can be only one pending backup - * creation per database. Backup creation of different databases can run concurrently. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   Backup backup = Backup.newBuilder().build();
-   *   String backupId = "";
-   *   Backup response = databaseAdminClient.createBackupAsync(parent, backup, backupId).get();
-   * }
-   * 
- * - * @param parent Required. The name of the instance in which the backup will be created. This must - * be the same instance that contains the database the backup will be created from. The backup - * will be stored in the location(s) specified in the instance configuration of this instance. - * Values are of the form `projects/<project>/instances/<instance>`. - * @param backup Required. The backup to create. - * @param backupId Required. The id of the backup to be created. The `backup_id` appended to - * `parent` forms the full backup name of the form - * `projects/<project>/instances/<instance>/backups/<backup_id>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createBackupAsync( - InstanceName parent, Backup backup, String backupId) { - CreateBackupRequest request = - CreateBackupRequest.newBuilder() - .setParent(parent == null ? null : parent.toString()) - .setBackup(backup) - .setBackupId(backupId) - .build(); - return createBackupAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Starts creating a new Cloud Spanner Backup. The returned backup [long-running - * operation][google.longrunning.Operation] will have a name of the format - * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` - * and can be used to track creation of the backup. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned - * operation will stop the creation and delete the backup. There can be only one pending backup - * creation per database. Backup creation of different databases can run concurrently. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   Backup backup = Backup.newBuilder().build();
-   *   String backupId = "";
-   *   Backup response = databaseAdminClient.createBackupAsync(parent.toString(), backup, backupId).get();
-   * }
-   * 
- * - * @param parent Required. The name of the instance in which the backup will be created. This must - * be the same instance that contains the database the backup will be created from. The backup - * will be stored in the location(s) specified in the instance configuration of this instance. - * Values are of the form `projects/<project>/instances/<instance>`. - * @param backup Required. The backup to create. - * @param backupId Required. The id of the backup to be created. The `backup_id` appended to - * `parent` forms the full backup name of the form - * `projects/<project>/instances/<instance>/backups/<backup_id>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createBackupAsync( - String parent, Backup backup, String backupId) { - CreateBackupRequest request = - CreateBackupRequest.newBuilder() - .setParent(parent) - .setBackup(backup) - .setBackupId(backupId) - .build(); - return createBackupAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Starts creating a new Cloud Spanner Backup. The returned backup [long-running - * operation][google.longrunning.Operation] will have a name of the format - * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` - * and can be used to track creation of the backup. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned - * operation will stop the creation and delete the backup. There can be only one pending backup - * creation per database. Backup creation of different databases can run concurrently. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String backupId = "";
-   *   Backup backup = Backup.newBuilder().build();
-   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setBackupId(backupId)
-   *     .setBackup(backup)
-   *     .build();
-   *   Backup response = databaseAdminClient.createBackupAsync(request).get();
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createBackupAsync( - CreateBackupRequest request) { - return createBackupOperationCallable().futureCall(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Starts creating a new Cloud Spanner Backup. The returned backup [long-running - * operation][google.longrunning.Operation] will have a name of the format - * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` - * and can be used to track creation of the backup. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned - * operation will stop the creation and delete the backup. There can be only one pending backup - * creation per database. Backup creation of different databases can run concurrently. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String backupId = "";
-   *   Backup backup = Backup.newBuilder().build();
-   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setBackupId(backupId)
-   *     .setBackup(backup)
-   *     .build();
-   *   OperationFuture<Backup, CreateBackupMetadata> future = databaseAdminClient.createBackupOperationCallable().futureCall(request);
-   *   // Do something
-   *   Backup response = future.get();
-   * }
-   * 
- */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public final OperationCallable - createBackupOperationCallable() { - return stub.createBackupOperationCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Starts creating a new Cloud Spanner Backup. The returned backup [long-running - * operation][google.longrunning.Operation] will have a name of the format - * `projects/<project>/instances/<instance>/backups/<backup>/operations/<operation_id>` - * and can be used to track creation of the backup. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Backup][google.spanner.admin.database.v1.Backup], if successful. Cancelling the returned - * operation will stop the creation and delete the backup. There can be only one pending backup - * creation per database. Backup creation of different databases can run concurrently. + return testIamPermissionsCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Returns permissions that the caller has on the specified database or backup resource. + * + *

Attempting this RPC on a non-existent Cloud Spanner database will result in a NOT_FOUND + * error if the user has `spanner.databases.list` permission on the containing Cloud Spanner + * instance. Otherwise returns an empty set of permissions. Calling this method on a backup that + * does not exist will result in a NOT_FOUND error if the user has `spanner.backups.list` + * permission on the containing instance. * *

Sample code: * *


    * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String backupId = "";
-   *   Backup backup = Backup.newBuilder().build();
-   *   CreateBackupRequest request = CreateBackupRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setBackupId(backupId)
-   *     .setBackup(backup)
+   *   ResourceName resource = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
+   *   List<String> permissions = new ArrayList<>();
+   *   TestIamPermissionsRequest request = TestIamPermissionsRequest.newBuilder()
+   *     .setResource(resource.toString())
+   *     .addAllPermissions(permissions)
    *     .build();
-   *   ApiFuture<Operation> future = databaseAdminClient.createBackupCallable().futureCall(request);
+   *   ApiFuture<TestIamPermissionsResponse> future = databaseAdminClient.testIamPermissionsCallable().futureCall(request);
    *   // Do something
-   *   Operation response = future.get();
+   *   TestIamPermissionsResponse response = future.get();
    * }
    * 
*/ - public final UnaryCallable createBackupCallable() { - return stub.createBackupCallable(); + public final UnaryCallable + testIamPermissionsCallable() { + return stub.testIamPermissionsCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD @@ -1950,229 +2173,6 @@ public final UnaryCallable listBackupsC return stub.listBackupsCallable(); } - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Create a new database by restoring from a completed backup. The new database must be in the - * same project and in an instance with the same instance configuration as the instance containing - * the backup. The returned database [long-running operation][google.longrunning.Operation] has a - * name of the format - * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, - * and can be used to track the progress of the operation, and to cancel it. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The - * [response][google.longrunning.Operation.response] type is - * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned - * operation will stop the restore and delete the database. There can be only one database being - * restored into an instance at a time. Once the restore operation completes, a new restore - * operation can be initiated, without waiting for the optimize operation associated with the - * first restore to complete. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String databaseId = "";
-   *   BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
-   *   Database response = databaseAdminClient.restoreDatabaseAsync(parent, databaseId, backup).get();
-   * }
-   * 
- * - * @param parent Required. The name of the instance in which to create the restored database. This - * instance must be in the same project and have the same instance configuration as the - * instance containing the source backup. Values are of the form - * `projects/<project>/instances/<instance>`. - * @param databaseId Required. The id of the database to create and restore to. This database must - * not already exist. The `database_id` appended to `parent` forms the full database name of - * the form - * `projects/<project>/instances/<instance>/databases/<database_id>`. - * @param backup Name of the backup from which to restore. Values are of the form - * `projects/<project>/instances/<instance>/backups/<backup>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture restoreDatabaseAsync( - InstanceName parent, String databaseId, BackupName backup) { - RestoreDatabaseRequest request = - RestoreDatabaseRequest.newBuilder() - .setParent(parent == null ? null : parent.toString()) - .setDatabaseId(databaseId) - .setBackup(backup == null ? null : backup.toString()) - .build(); - return restoreDatabaseAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Create a new database by restoring from a completed backup. The new database must be in the - * same project and in an instance with the same instance configuration as the instance containing - * the backup. The returned database [long-running operation][google.longrunning.Operation] has a - * name of the format - * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, - * and can be used to track the progress of the operation, and to cancel it. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The - * [response][google.longrunning.Operation.response] type is - * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned - * operation will stop the restore and delete the database. There can be only one database being - * restored into an instance at a time. Once the restore operation completes, a new restore - * operation can be initiated, without waiting for the optimize operation associated with the - * first restore to complete. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String databaseId = "";
-   *   BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]");
-   *   Database response = databaseAdminClient.restoreDatabaseAsync(parent.toString(), databaseId, backup.toString()).get();
-   * }
-   * 
- * - * @param parent Required. The name of the instance in which to create the restored database. This - * instance must be in the same project and have the same instance configuration as the - * instance containing the source backup. Values are of the form - * `projects/<project>/instances/<instance>`. - * @param databaseId Required. The id of the database to create and restore to. This database must - * not already exist. The `database_id` appended to `parent` forms the full database name of - * the form - * `projects/<project>/instances/<instance>/databases/<database_id>`. - * @param backup Name of the backup from which to restore. Values are of the form - * `projects/<project>/instances/<instance>/backups/<backup>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture restoreDatabaseAsync( - String parent, String databaseId, String backup) { - RestoreDatabaseRequest request = - RestoreDatabaseRequest.newBuilder() - .setParent(parent) - .setDatabaseId(databaseId) - .setBackup(backup) - .build(); - return restoreDatabaseAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Create a new database by restoring from a completed backup. The new database must be in the - * same project and in an instance with the same instance configuration as the instance containing - * the backup. The returned database [long-running operation][google.longrunning.Operation] has a - * name of the format - * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, - * and can be used to track the progress of the operation, and to cancel it. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The - * [response][google.longrunning.Operation.response] type is - * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned - * operation will stop the restore and delete the database. There can be only one database being - * restored into an instance at a time. Once the restore operation completes, a new restore - * operation can be initiated, without waiting for the optimize operation associated with the - * first restore to complete. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String databaseId = "";
-   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setDatabaseId(databaseId)
-   *     .build();
-   *   Database response = databaseAdminClient.restoreDatabaseAsync(request).get();
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture restoreDatabaseAsync( - RestoreDatabaseRequest request) { - return restoreDatabaseOperationCallable().futureCall(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Create a new database by restoring from a completed backup. The new database must be in the - * same project and in an instance with the same instance configuration as the instance containing - * the backup. The returned database [long-running operation][google.longrunning.Operation] has a - * name of the format - * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, - * and can be used to track the progress of the operation, and to cancel it. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The - * [response][google.longrunning.Operation.response] type is - * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned - * operation will stop the restore and delete the database. There can be only one database being - * restored into an instance at a time. Once the restore operation completes, a new restore - * operation can be initiated, without waiting for the optimize operation associated with the - * first restore to complete. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String databaseId = "";
-   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setDatabaseId(databaseId)
-   *     .build();
-   *   OperationFuture<Database, RestoreDatabaseMetadata> future = databaseAdminClient.restoreDatabaseOperationCallable().futureCall(request);
-   *   // Do something
-   *   Database response = future.get();
-   * }
-   * 
- */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public final OperationCallable - restoreDatabaseOperationCallable() { - return stub.restoreDatabaseOperationCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Create a new database by restoring from a completed backup. The new database must be in the - * same project and in an instance with the same instance configuration as the instance containing - * the backup. The returned database [long-running operation][google.longrunning.Operation] has a - * name of the format - * `projects/<project>/instances/<instance>/databases/<database>/operations/<operation_id>`, - * and can be used to track the progress of the operation, and to cancel it. The - * [metadata][google.longrunning.Operation.metadata] field type is - * [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. The - * [response][google.longrunning.Operation.response] type is - * [Database][google.spanner.admin.database.v1.Database], if successful. Cancelling the returned - * operation will stop the restore and delete the database. There can be only one database being - * restored into an instance at a time. Once the restore operation completes, a new restore - * operation can be initiated, without waiting for the optimize operation associated with the - * first restore to complete. - * - *

Sample code: - * - *


-   * try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
-   *   InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]");
-   *   String databaseId = "";
-   *   RestoreDatabaseRequest request = RestoreDatabaseRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setDatabaseId(databaseId)
-   *     .build();
-   *   ApiFuture<Operation> future = databaseAdminClient.restoreDatabaseCallable().futureCall(request);
-   *   // Do something
-   *   Operation response = future.get();
-   * }
-   * 
- */ - public final UnaryCallable restoreDatabaseCallable() { - return stub.restoreDatabaseCallable(); - } - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Lists database [longrunning-operations][google.longrunning.Operation]. A database operation has diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java index 53edae1edf..8ae9ec5303 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java @@ -103,12 +103,6 @@ @Generated("by gapic-generator") @BetaApi public class DatabaseAdminSettings extends ClientSettings { - /** Returns the object with the settings used for calls to listDatabases. */ - public PagedCallSettings - listDatabasesSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).listDatabasesSettings(); - } - /** Returns the object with the settings used for calls to createDatabase. */ public UnaryCallSettings createDatabaseSettings() { return ((DatabaseAdminStubSettings) getStubSettings()).createDatabaseSettings(); @@ -122,11 +116,6 @@ public UnaryCallSettings createDatabaseSetting return ((DatabaseAdminStubSettings) getStubSettings()).createDatabaseOperationSettings(); } - /** Returns the object with the settings used for calls to getDatabase. */ - public UnaryCallSettings getDatabaseSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).getDatabaseSettings(); - } - /** Returns the object with the settings used for calls to updateDatabaseDdl. */ public UnaryCallSettings updateDatabaseDdlSettings() { return ((DatabaseAdminStubSettings) getStubSettings()).updateDatabaseDdlSettings(); @@ -140,6 +129,43 @@ public UnaryCallSettings updateDatabaseDdlS return ((DatabaseAdminStubSettings) getStubSettings()).updateDatabaseDdlOperationSettings(); } + /** Returns the object with the settings used for calls to createBackup. */ + public UnaryCallSettings createBackupSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).createBackupSettings(); + } + + /** Returns the object with the settings used for calls to createBackup. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings + createBackupOperationSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).createBackupOperationSettings(); + } + + /** Returns the object with the settings used for calls to restoreDatabase. */ + public UnaryCallSettings restoreDatabaseSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).restoreDatabaseSettings(); + } + + /** Returns the object with the settings used for calls to restoreDatabase. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings + restoreDatabaseOperationSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).restoreDatabaseOperationSettings(); + } + + /** Returns the object with the settings used for calls to listDatabases. */ + public PagedCallSettings + listDatabasesSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).listDatabasesSettings(); + } + + /** Returns the object with the settings used for calls to getDatabase. */ + public UnaryCallSettings getDatabaseSettings() { + return ((DatabaseAdminStubSettings) getStubSettings()).getDatabaseSettings(); + } + /** Returns the object with the settings used for calls to dropDatabase. */ public UnaryCallSettings dropDatabaseSettings() { return ((DatabaseAdminStubSettings) getStubSettings()).dropDatabaseSettings(); @@ -166,19 +192,6 @@ public UnaryCallSettings getIamPolicySettings() { return ((DatabaseAdminStubSettings) getStubSettings()).testIamPermissionsSettings(); } - /** Returns the object with the settings used for calls to createBackup. */ - public UnaryCallSettings createBackupSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).createBackupSettings(); - } - - /** Returns the object with the settings used for calls to createBackup. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings - createBackupOperationSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).createBackupOperationSettings(); - } - /** Returns the object with the settings used for calls to getBackup. */ public UnaryCallSettings getBackupSettings() { return ((DatabaseAdminStubSettings) getStubSettings()).getBackupSettings(); @@ -200,19 +213,6 @@ public UnaryCallSettings deleteBackupSettings() { return ((DatabaseAdminStubSettings) getStubSettings()).listBackupsSettings(); } - /** Returns the object with the settings used for calls to restoreDatabase. */ - public UnaryCallSettings restoreDatabaseSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).restoreDatabaseSettings(); - } - - /** Returns the object with the settings used for calls to restoreDatabase. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings - restoreDatabaseOperationSettings() { - return ((DatabaseAdminStubSettings) getStubSettings()).restoreDatabaseOperationSettings(); - } - /** Returns the object with the settings used for calls to listDatabaseOperations. */ public PagedCallSettings< ListDatabaseOperationsRequest, @@ -328,13 +328,6 @@ public Builder applyToAllUnaryMethods( return this; } - /** Returns the builder for the settings used for calls to listDatabases. */ - public PagedCallSettings.Builder< - ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> - listDatabasesSettings() { - return getStubSettingsBuilder().listDatabasesSettings(); - } - /** Returns the builder for the settings used for calls to createDatabase. */ public UnaryCallSettings.Builder createDatabaseSettings() { return getStubSettingsBuilder().createDatabaseSettings(); @@ -348,11 +341,6 @@ public UnaryCallSettings.Builder createDatabas return getStubSettingsBuilder().createDatabaseOperationSettings(); } - /** Returns the builder for the settings used for calls to getDatabase. */ - public UnaryCallSettings.Builder getDatabaseSettings() { - return getStubSettingsBuilder().getDatabaseSettings(); - } - /** Returns the builder for the settings used for calls to updateDatabaseDdl. */ public UnaryCallSettings.Builder updateDatabaseDdlSettings() { @@ -367,6 +355,44 @@ public UnaryCallSettings.Builder getDatabaseSettin return getStubSettingsBuilder().updateDatabaseDdlOperationSettings(); } + /** Returns the builder for the settings used for calls to createBackup. */ + public UnaryCallSettings.Builder createBackupSettings() { + return getStubSettingsBuilder().createBackupSettings(); + } + + /** Returns the builder for the settings used for calls to createBackup. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings.Builder + createBackupOperationSettings() { + return getStubSettingsBuilder().createBackupOperationSettings(); + } + + /** Returns the builder for the settings used for calls to restoreDatabase. */ + public UnaryCallSettings.Builder restoreDatabaseSettings() { + return getStubSettingsBuilder().restoreDatabaseSettings(); + } + + /** Returns the builder for the settings used for calls to restoreDatabase. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings.Builder + restoreDatabaseOperationSettings() { + return getStubSettingsBuilder().restoreDatabaseOperationSettings(); + } + + /** Returns the builder for the settings used for calls to listDatabases. */ + public PagedCallSettings.Builder< + ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> + listDatabasesSettings() { + return getStubSettingsBuilder().listDatabasesSettings(); + } + + /** Returns the builder for the settings used for calls to getDatabase. */ + public UnaryCallSettings.Builder getDatabaseSettings() { + return getStubSettingsBuilder().getDatabaseSettings(); + } + /** Returns the builder for the settings used for calls to dropDatabase. */ public UnaryCallSettings.Builder dropDatabaseSettings() { return getStubSettingsBuilder().dropDatabaseSettings(); @@ -394,19 +420,6 @@ public UnaryCallSettings.Builder getIamPolicySettin return getStubSettingsBuilder().testIamPermissionsSettings(); } - /** Returns the builder for the settings used for calls to createBackup. */ - public UnaryCallSettings.Builder createBackupSettings() { - return getStubSettingsBuilder().createBackupSettings(); - } - - /** Returns the builder for the settings used for calls to createBackup. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings.Builder - createBackupOperationSettings() { - return getStubSettingsBuilder().createBackupOperationSettings(); - } - /** Returns the builder for the settings used for calls to getBackup. */ public UnaryCallSettings.Builder getBackupSettings() { return getStubSettingsBuilder().getBackupSettings(); @@ -429,19 +442,6 @@ public UnaryCallSettings.Builder deleteBackupSetting return getStubSettingsBuilder().listBackupsSettings(); } - /** Returns the builder for the settings used for calls to restoreDatabase. */ - public UnaryCallSettings.Builder restoreDatabaseSettings() { - return getStubSettingsBuilder().restoreDatabaseSettings(); - } - - /** Returns the builder for the settings used for calls to restoreDatabase. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings.Builder - restoreDatabaseOperationSettings() { - return getStubSettingsBuilder().restoreDatabaseOperationSettings(); - } - /** Returns the builder for the settings used for calls to listDatabaseOperations. */ public PagedCallSettings.Builder< ListDatabaseOperationsRequest, diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStub.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStub.java index fd92157c55..9f060f971a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStub.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStub.java @@ -74,15 +74,6 @@ public OperationsStub getOperationsStub() { throw new UnsupportedOperationException("Not implemented: getOperationsStub()"); } - public UnaryCallable - listDatabasesPagedCallable() { - throw new UnsupportedOperationException("Not implemented: listDatabasesPagedCallable()"); - } - - public UnaryCallable listDatabasesCallable() { - throw new UnsupportedOperationException("Not implemented: listDatabasesCallable()"); - } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") public OperationCallable createDatabaseOperationCallable() { @@ -93,10 +84,6 @@ public UnaryCallable createDatabaseCallable() throw new UnsupportedOperationException("Not implemented: createDatabaseCallable()"); } - public UnaryCallable getDatabaseCallable() { - throw new UnsupportedOperationException("Not implemented: getDatabaseCallable()"); - } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") public OperationCallable updateDatabaseDdlOperationCallable() { @@ -108,6 +95,39 @@ public UnaryCallable updateDatabaseDdlCalla throw new UnsupportedOperationException("Not implemented: updateDatabaseDdlCallable()"); } + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + createBackupOperationCallable() { + throw new UnsupportedOperationException("Not implemented: createBackupOperationCallable()"); + } + + public UnaryCallable createBackupCallable() { + throw new UnsupportedOperationException("Not implemented: createBackupCallable()"); + } + + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + restoreDatabaseOperationCallable() { + throw new UnsupportedOperationException("Not implemented: restoreDatabaseOperationCallable()"); + } + + public UnaryCallable restoreDatabaseCallable() { + throw new UnsupportedOperationException("Not implemented: restoreDatabaseCallable()"); + } + + public UnaryCallable + listDatabasesPagedCallable() { + throw new UnsupportedOperationException("Not implemented: listDatabasesPagedCallable()"); + } + + public UnaryCallable listDatabasesCallable() { + throw new UnsupportedOperationException("Not implemented: listDatabasesCallable()"); + } + + public UnaryCallable getDatabaseCallable() { + throw new UnsupportedOperationException("Not implemented: getDatabaseCallable()"); + } + public UnaryCallable dropDatabaseCallable() { throw new UnsupportedOperationException("Not implemented: dropDatabaseCallable()"); } @@ -129,16 +149,6 @@ public UnaryCallable getIamPolicyCallable() { throw new UnsupportedOperationException("Not implemented: testIamPermissionsCallable()"); } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - createBackupOperationCallable() { - throw new UnsupportedOperationException("Not implemented: createBackupOperationCallable()"); - } - - public UnaryCallable createBackupCallable() { - throw new UnsupportedOperationException("Not implemented: createBackupCallable()"); - } - public UnaryCallable getBackupCallable() { throw new UnsupportedOperationException("Not implemented: getBackupCallable()"); } @@ -159,16 +169,6 @@ public UnaryCallable listBackupsCallabl throw new UnsupportedOperationException("Not implemented: listBackupsCallable()"); } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - restoreDatabaseOperationCallable() { - throw new UnsupportedOperationException("Not implemented: restoreDatabaseOperationCallable()"); - } - - public UnaryCallable restoreDatabaseCallable() { - throw new UnsupportedOperationException("Not implemented: restoreDatabaseCallable()"); - } - public UnaryCallable listDatabaseOperationsPagedCallable() { throw new UnsupportedOperationException( diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java index 53d5767a89..7799b21fc3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java @@ -128,16 +128,22 @@ public class DatabaseAdminStubSettings extends StubSettings - listDatabasesSettings; private final UnaryCallSettings createDatabaseSettings; private final OperationCallSettings createDatabaseOperationSettings; - private final UnaryCallSettings getDatabaseSettings; private final UnaryCallSettings updateDatabaseDdlSettings; private final OperationCallSettings updateDatabaseDdlOperationSettings; + private final UnaryCallSettings createBackupSettings; + private final OperationCallSettings + createBackupOperationSettings; + private final UnaryCallSettings restoreDatabaseSettings; + private final OperationCallSettings + restoreDatabaseOperationSettings; + private final PagedCallSettings< + ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> + listDatabasesSettings; + private final UnaryCallSettings getDatabaseSettings; private final UnaryCallSettings dropDatabaseSettings; private final UnaryCallSettings getDatabaseDdlSettings; @@ -145,17 +151,11 @@ public class DatabaseAdminStubSettings extends StubSettings getIamPolicySettings; private final UnaryCallSettings testIamPermissionsSettings; - private final UnaryCallSettings createBackupSettings; - private final OperationCallSettings - createBackupOperationSettings; private final UnaryCallSettings getBackupSettings; private final UnaryCallSettings updateBackupSettings; private final UnaryCallSettings deleteBackupSettings; private final PagedCallSettings listBackupsSettings; - private final UnaryCallSettings restoreDatabaseSettings; - private final OperationCallSettings - restoreDatabaseOperationSettings; private final PagedCallSettings< ListDatabaseOperationsRequest, ListDatabaseOperationsResponse, @@ -167,12 +167,6 @@ public class DatabaseAdminStubSettings extends StubSettings listBackupOperationsSettings; - /** Returns the object with the settings used for calls to listDatabases. */ - public PagedCallSettings - listDatabasesSettings() { - return listDatabasesSettings; - } - /** Returns the object with the settings used for calls to createDatabase. */ public UnaryCallSettings createDatabaseSettings() { return createDatabaseSettings; @@ -185,11 +179,6 @@ public UnaryCallSettings createDatabaseSetting return createDatabaseOperationSettings; } - /** Returns the object with the settings used for calls to getDatabase. */ - public UnaryCallSettings getDatabaseSettings() { - return getDatabaseSettings; - } - /** Returns the object with the settings used for calls to updateDatabaseDdl. */ public UnaryCallSettings updateDatabaseDdlSettings() { return updateDatabaseDdlSettings; @@ -202,6 +191,41 @@ public UnaryCallSettings updateDatabaseDdlS return updateDatabaseDdlOperationSettings; } + /** Returns the object with the settings used for calls to createBackup. */ + public UnaryCallSettings createBackupSettings() { + return createBackupSettings; + } + + /** Returns the object with the settings used for calls to createBackup. */ + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings + createBackupOperationSettings() { + return createBackupOperationSettings; + } + + /** Returns the object with the settings used for calls to restoreDatabase. */ + public UnaryCallSettings restoreDatabaseSettings() { + return restoreDatabaseSettings; + } + + /** Returns the object with the settings used for calls to restoreDatabase. */ + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings + restoreDatabaseOperationSettings() { + return restoreDatabaseOperationSettings; + } + + /** Returns the object with the settings used for calls to listDatabases. */ + public PagedCallSettings + listDatabasesSettings() { + return listDatabasesSettings; + } + + /** Returns the object with the settings used for calls to getDatabase. */ + public UnaryCallSettings getDatabaseSettings() { + return getDatabaseSettings; + } + /** Returns the object with the settings used for calls to dropDatabase. */ public UnaryCallSettings dropDatabaseSettings() { return dropDatabaseSettings; @@ -228,18 +252,6 @@ public UnaryCallSettings getIamPolicySettings() { return testIamPermissionsSettings; } - /** Returns the object with the settings used for calls to createBackup. */ - public UnaryCallSettings createBackupSettings() { - return createBackupSettings; - } - - /** Returns the object with the settings used for calls to createBackup. */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings - createBackupOperationSettings() { - return createBackupOperationSettings; - } - /** Returns the object with the settings used for calls to getBackup. */ public UnaryCallSettings getBackupSettings() { return getBackupSettings; @@ -261,18 +273,6 @@ public UnaryCallSettings deleteBackupSettings() { return listBackupsSettings; } - /** Returns the object with the settings used for calls to restoreDatabase. */ - public UnaryCallSettings restoreDatabaseSettings() { - return restoreDatabaseSettings; - } - - /** Returns the object with the settings used for calls to restoreDatabase. */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings - restoreDatabaseOperationSettings() { - return restoreDatabaseOperationSettings; - } - /** Returns the object with the settings used for calls to listDatabaseOperations. */ public PagedCallSettings< ListDatabaseOperationsRequest, @@ -360,26 +360,26 @@ public Builder toBuilder() { protected DatabaseAdminStubSettings(Builder settingsBuilder) throws IOException { super(settingsBuilder); - listDatabasesSettings = settingsBuilder.listDatabasesSettings().build(); createDatabaseSettings = settingsBuilder.createDatabaseSettings().build(); createDatabaseOperationSettings = settingsBuilder.createDatabaseOperationSettings().build(); - getDatabaseSettings = settingsBuilder.getDatabaseSettings().build(); updateDatabaseDdlSettings = settingsBuilder.updateDatabaseDdlSettings().build(); updateDatabaseDdlOperationSettings = settingsBuilder.updateDatabaseDdlOperationSettings().build(); + createBackupSettings = settingsBuilder.createBackupSettings().build(); + createBackupOperationSettings = settingsBuilder.createBackupOperationSettings().build(); + restoreDatabaseSettings = settingsBuilder.restoreDatabaseSettings().build(); + restoreDatabaseOperationSettings = settingsBuilder.restoreDatabaseOperationSettings().build(); + listDatabasesSettings = settingsBuilder.listDatabasesSettings().build(); + getDatabaseSettings = settingsBuilder.getDatabaseSettings().build(); dropDatabaseSettings = settingsBuilder.dropDatabaseSettings().build(); getDatabaseDdlSettings = settingsBuilder.getDatabaseDdlSettings().build(); setIamPolicySettings = settingsBuilder.setIamPolicySettings().build(); getIamPolicySettings = settingsBuilder.getIamPolicySettings().build(); testIamPermissionsSettings = settingsBuilder.testIamPermissionsSettings().build(); - createBackupSettings = settingsBuilder.createBackupSettings().build(); - createBackupOperationSettings = settingsBuilder.createBackupOperationSettings().build(); getBackupSettings = settingsBuilder.getBackupSettings().build(); updateBackupSettings = settingsBuilder.updateBackupSettings().build(); deleteBackupSettings = settingsBuilder.deleteBackupSettings().build(); listBackupsSettings = settingsBuilder.listBackupsSettings().build(); - restoreDatabaseSettings = settingsBuilder.restoreDatabaseSettings().build(); - restoreDatabaseOperationSettings = settingsBuilder.restoreDatabaseOperationSettings().build(); listDatabaseOperationsSettings = settingsBuilder.listDatabaseOperationsSettings().build(); listBackupOperationsSettings = settingsBuilder.listBackupOperationsSettings().build(); } @@ -623,20 +623,28 @@ public ApiFuture getFuturePagedResponse( public static class Builder extends StubSettings.Builder { private final ImmutableList> unaryMethodSettingsBuilders; - private final PagedCallSettings.Builder< - ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> - listDatabasesSettings; private final UnaryCallSettings.Builder createDatabaseSettings; private final OperationCallSettings.Builder< CreateDatabaseRequest, Database, CreateDatabaseMetadata> createDatabaseOperationSettings; - private final UnaryCallSettings.Builder getDatabaseSettings; private final UnaryCallSettings.Builder updateDatabaseDdlSettings; private final OperationCallSettings.Builder< UpdateDatabaseDdlRequest, Empty, UpdateDatabaseDdlMetadata> updateDatabaseDdlOperationSettings; + private final UnaryCallSettings.Builder createBackupSettings; + private final OperationCallSettings.Builder + createBackupOperationSettings; + private final UnaryCallSettings.Builder + restoreDatabaseSettings; + private final OperationCallSettings.Builder< + RestoreDatabaseRequest, Database, RestoreDatabaseMetadata> + restoreDatabaseOperationSettings; + private final PagedCallSettings.Builder< + ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> + listDatabasesSettings; + private final UnaryCallSettings.Builder getDatabaseSettings; private final UnaryCallSettings.Builder dropDatabaseSettings; private final UnaryCallSettings.Builder getDatabaseDdlSettings; @@ -644,20 +652,12 @@ public static class Builder extends StubSettings.Builder getIamPolicySettings; private final UnaryCallSettings.Builder testIamPermissionsSettings; - private final UnaryCallSettings.Builder createBackupSettings; - private final OperationCallSettings.Builder - createBackupOperationSettings; private final UnaryCallSettings.Builder getBackupSettings; private final UnaryCallSettings.Builder updateBackupSettings; private final UnaryCallSettings.Builder deleteBackupSettings; private final PagedCallSettings.Builder< ListBackupsRequest, ListBackupsResponse, ListBackupsPagedResponse> listBackupsSettings; - private final UnaryCallSettings.Builder - restoreDatabaseSettings; - private final OperationCallSettings.Builder< - RestoreDatabaseRequest, Database, RestoreDatabaseMetadata> - restoreDatabaseOperationSettings; private final PagedCallSettings.Builder< ListDatabaseOperationsRequest, ListDatabaseOperationsResponse, @@ -676,11 +676,20 @@ public static class Builder extends StubSettings.Builder> definitions = ImmutableMap.builder(); definitions.put( - "idempotent", + "retry_policy_1_codes", + ImmutableSet.copyOf( + Lists.newArrayList( + StatusCode.Code.UNAVAILABLE, StatusCode.Code.DEADLINE_EXCEEDED))); + definitions.put( + "no_retry_2_codes", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put( + "retry_policy_2_codes", ImmutableSet.copyOf( Lists.newArrayList( - StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE))); - definitions.put("non_idempotent", ImmutableSet.copyOf(Lists.newArrayList())); + StatusCode.Code.UNAVAILABLE, StatusCode.Code.DEADLINE_EXCEEDED))); + definitions.put( + "no_retry_1_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -694,12 +703,41 @@ public static class Builder extends StubSettings.Builder>of( - listDatabasesSettings, createDatabaseSettings, - getDatabaseSettings, updateDatabaseDdlSettings, + createBackupSettings, + restoreDatabaseSettings, + listDatabasesSettings, + getDatabaseSettings, dropDatabaseSettings, getDatabaseDdlSettings, setIamPolicySettings, getIamPolicySettings, testIamPermissionsSettings, - createBackupSettings, getBackupSettings, updateBackupSettings, deleteBackupSettings, listBackupsSettings, - restoreDatabaseSettings, listDatabaseOperationsSettings, listBackupOperationsSettings); @@ -789,96 +827,96 @@ private static Builder createDefault() { private static Builder initDefaults(Builder builder) { builder - .listDatabasesSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .createDatabaseSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); builder - .createDatabaseSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .updateDatabaseDdlSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder - .getDatabaseSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .createBackupSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); builder - .updateDatabaseDdlSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .restoreDatabaseSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); + + builder + .listDatabasesSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + + builder + .getDatabaseSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .dropDatabaseSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .getDatabaseDdlSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .setIamPolicySettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_2_params")); builder .getIamPolicySettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_2_params")); builder .testIamPermissionsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); - - builder - .createBackupSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_2_params")); builder .getBackupSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .updateBackupSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); builder .deleteBackupSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .listBackupsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); - - builder - .restoreDatabaseSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .listDatabaseOperationsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .listBackupOperationsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .createDatabaseOperationSettings() .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Database.class)) @@ -900,8 +938,8 @@ private static Builder initDefaults(Builder builder) { .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Empty.class)) @@ -924,8 +962,8 @@ private static Builder initDefaults(Builder builder) { .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Backup.class)) @@ -947,8 +985,8 @@ private static Builder initDefaults(Builder builder) { .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Database.class)) @@ -972,45 +1010,45 @@ private static Builder initDefaults(Builder builder) { protected Builder(DatabaseAdminStubSettings settings) { super(settings); - listDatabasesSettings = settings.listDatabasesSettings.toBuilder(); createDatabaseSettings = settings.createDatabaseSettings.toBuilder(); createDatabaseOperationSettings = settings.createDatabaseOperationSettings.toBuilder(); - getDatabaseSettings = settings.getDatabaseSettings.toBuilder(); updateDatabaseDdlSettings = settings.updateDatabaseDdlSettings.toBuilder(); updateDatabaseDdlOperationSettings = settings.updateDatabaseDdlOperationSettings.toBuilder(); + createBackupSettings = settings.createBackupSettings.toBuilder(); + createBackupOperationSettings = settings.createBackupOperationSettings.toBuilder(); + restoreDatabaseSettings = settings.restoreDatabaseSettings.toBuilder(); + restoreDatabaseOperationSettings = settings.restoreDatabaseOperationSettings.toBuilder(); + listDatabasesSettings = settings.listDatabasesSettings.toBuilder(); + getDatabaseSettings = settings.getDatabaseSettings.toBuilder(); dropDatabaseSettings = settings.dropDatabaseSettings.toBuilder(); getDatabaseDdlSettings = settings.getDatabaseDdlSettings.toBuilder(); setIamPolicySettings = settings.setIamPolicySettings.toBuilder(); getIamPolicySettings = settings.getIamPolicySettings.toBuilder(); testIamPermissionsSettings = settings.testIamPermissionsSettings.toBuilder(); - createBackupSettings = settings.createBackupSettings.toBuilder(); - createBackupOperationSettings = settings.createBackupOperationSettings.toBuilder(); getBackupSettings = settings.getBackupSettings.toBuilder(); updateBackupSettings = settings.updateBackupSettings.toBuilder(); deleteBackupSettings = settings.deleteBackupSettings.toBuilder(); listBackupsSettings = settings.listBackupsSettings.toBuilder(); - restoreDatabaseSettings = settings.restoreDatabaseSettings.toBuilder(); - restoreDatabaseOperationSettings = settings.restoreDatabaseOperationSettings.toBuilder(); listDatabaseOperationsSettings = settings.listDatabaseOperationsSettings.toBuilder(); listBackupOperationsSettings = settings.listBackupOperationsSettings.toBuilder(); unaryMethodSettingsBuilders = ImmutableList.>of( - listDatabasesSettings, createDatabaseSettings, - getDatabaseSettings, updateDatabaseDdlSettings, + createBackupSettings, + restoreDatabaseSettings, + listDatabasesSettings, + getDatabaseSettings, dropDatabaseSettings, getDatabaseDdlSettings, setIamPolicySettings, getIamPolicySettings, testIamPermissionsSettings, - createBackupSettings, getBackupSettings, updateBackupSettings, deleteBackupSettings, listBackupsSettings, - restoreDatabaseSettings, listDatabaseOperationsSettings, listBackupOperationsSettings); } @@ -1031,13 +1069,6 @@ public Builder applyToAllUnaryMethods( return unaryMethodSettingsBuilders; } - /** Returns the builder for the settings used for calls to listDatabases. */ - public PagedCallSettings.Builder< - ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> - listDatabasesSettings() { - return listDatabasesSettings; - } - /** Returns the builder for the settings used for calls to createDatabase. */ public UnaryCallSettings.Builder createDatabaseSettings() { return createDatabaseSettings; @@ -1051,11 +1082,6 @@ public UnaryCallSettings.Builder createDatabas return createDatabaseOperationSettings; } - /** Returns the builder for the settings used for calls to getDatabase. */ - public UnaryCallSettings.Builder getDatabaseSettings() { - return getDatabaseSettings; - } - /** Returns the builder for the settings used for calls to updateDatabaseDdl. */ public UnaryCallSettings.Builder updateDatabaseDdlSettings() { @@ -1070,6 +1096,44 @@ public UnaryCallSettings.Builder getDatabaseSettin return updateDatabaseDdlOperationSettings; } + /** Returns the builder for the settings used for calls to createBackup. */ + public UnaryCallSettings.Builder createBackupSettings() { + return createBackupSettings; + } + + /** Returns the builder for the settings used for calls to createBackup. */ + @BetaApi( + "The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings.Builder + createBackupOperationSettings() { + return createBackupOperationSettings; + } + + /** Returns the builder for the settings used for calls to restoreDatabase. */ + public UnaryCallSettings.Builder restoreDatabaseSettings() { + return restoreDatabaseSettings; + } + + /** Returns the builder for the settings used for calls to restoreDatabase. */ + @BetaApi( + "The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings.Builder + restoreDatabaseOperationSettings() { + return restoreDatabaseOperationSettings; + } + + /** Returns the builder for the settings used for calls to listDatabases. */ + public PagedCallSettings.Builder< + ListDatabasesRequest, ListDatabasesResponse, ListDatabasesPagedResponse> + listDatabasesSettings() { + return listDatabasesSettings; + } + + /** Returns the builder for the settings used for calls to getDatabase. */ + public UnaryCallSettings.Builder getDatabaseSettings() { + return getDatabaseSettings; + } + /** Returns the builder for the settings used for calls to dropDatabase. */ public UnaryCallSettings.Builder dropDatabaseSettings() { return dropDatabaseSettings; @@ -1097,19 +1161,6 @@ public UnaryCallSettings.Builder getIamPolicySettin return testIamPermissionsSettings; } - /** Returns the builder for the settings used for calls to createBackup. */ - public UnaryCallSettings.Builder createBackupSettings() { - return createBackupSettings; - } - - /** Returns the builder for the settings used for calls to createBackup. */ - @BetaApi( - "The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings.Builder - createBackupOperationSettings() { - return createBackupOperationSettings; - } - /** Returns the builder for the settings used for calls to getBackup. */ public UnaryCallSettings.Builder getBackupSettings() { return getBackupSettings; @@ -1132,19 +1183,6 @@ public UnaryCallSettings.Builder deleteBackupSetting return listBackupsSettings; } - /** Returns the builder for the settings used for calls to restoreDatabase. */ - public UnaryCallSettings.Builder restoreDatabaseSettings() { - return restoreDatabaseSettings; - } - - /** Returns the builder for the settings used for calls to restoreDatabase. */ - @BetaApi( - "The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings.Builder - restoreDatabaseOperationSettings() { - return restoreDatabaseOperationSettings; - } - /** Returns the builder for the settings used for calls to listDatabaseOperations. */ public PagedCallSettings.Builder< ListDatabaseOperationsRequest, diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/GrpcDatabaseAdminStub.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/GrpcDatabaseAdminStub.java index aaf318ca90..c3d8b39713 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/GrpcDatabaseAdminStub.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/GrpcDatabaseAdminStub.java @@ -80,16 +80,6 @@ @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class GrpcDatabaseAdminStub extends DatabaseAdminStub { - private static final MethodDescriptor - listDatabasesMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/ListDatabases") - .setRequestMarshaller( - ProtoUtils.marshaller(ListDatabasesRequest.getDefaultInstance())) - .setResponseMarshaller( - ProtoUtils.marshaller(ListDatabasesResponse.getDefaultInstance())) - .build(); private static final MethodDescriptor createDatabaseMethodDescriptor = MethodDescriptor.newBuilder() @@ -99,13 +89,6 @@ public class GrpcDatabaseAdminStub extends DatabaseAdminStub { ProtoUtils.marshaller(CreateDatabaseRequest.getDefaultInstance())) .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) .build(); - private static final MethodDescriptor getDatabaseMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/GetDatabase") - .setRequestMarshaller(ProtoUtils.marshaller(GetDatabaseRequest.getDefaultInstance())) - .setResponseMarshaller(ProtoUtils.marshaller(Database.getDefaultInstance())) - .build(); private static final MethodDescriptor updateDatabaseDdlMethodDescriptor = MethodDescriptor.newBuilder() @@ -115,6 +98,40 @@ public class GrpcDatabaseAdminStub extends DatabaseAdminStub { ProtoUtils.marshaller(UpdateDatabaseDdlRequest.getDefaultInstance())) .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) .build(); + private static final MethodDescriptor + createBackupMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/CreateBackup") + .setRequestMarshaller(ProtoUtils.marshaller(CreateBackupRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) + .build(); + private static final MethodDescriptor + restoreDatabaseMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/RestoreDatabase") + .setRequestMarshaller( + ProtoUtils.marshaller(RestoreDatabaseRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) + .build(); + private static final MethodDescriptor + listDatabasesMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/ListDatabases") + .setRequestMarshaller( + ProtoUtils.marshaller(ListDatabasesRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(ListDatabasesResponse.getDefaultInstance())) + .build(); + private static final MethodDescriptor getDatabaseMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/GetDatabase") + .setRequestMarshaller(ProtoUtils.marshaller(GetDatabaseRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Database.getDefaultInstance())) + .build(); private static final MethodDescriptor dropDatabaseMethodDescriptor = MethodDescriptor.newBuilder() .setType(MethodDescriptor.MethodType.UNARY) @@ -157,14 +174,6 @@ public class GrpcDatabaseAdminStub extends DatabaseAdminStub { .setResponseMarshaller( ProtoUtils.marshaller(TestIamPermissionsResponse.getDefaultInstance())) .build(); - private static final MethodDescriptor - createBackupMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/CreateBackup") - .setRequestMarshaller(ProtoUtils.marshaller(CreateBackupRequest.getDefaultInstance())) - .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) - .build(); private static final MethodDescriptor getBackupMethodDescriptor = MethodDescriptor.newBuilder() .setType(MethodDescriptor.MethodType.UNARY) @@ -195,15 +204,6 @@ public class GrpcDatabaseAdminStub extends DatabaseAdminStub { .setResponseMarshaller( ProtoUtils.marshaller(ListBackupsResponse.getDefaultInstance())) .build(); - private static final MethodDescriptor - restoreDatabaseMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.database.v1.DatabaseAdmin/RestoreDatabase") - .setRequestMarshaller( - ProtoUtils.marshaller(RestoreDatabaseRequest.getDefaultInstance())) - .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) - .build(); private static final MethodDescriptor< ListDatabaseOperationsRequest, ListDatabaseOperationsResponse> listDatabaseOperationsMethodDescriptor = @@ -232,34 +232,34 @@ public class GrpcDatabaseAdminStub extends DatabaseAdminStub { private final BackgroundResource backgroundResources; private final GrpcOperationsStub operationsStub; - private final UnaryCallable listDatabasesCallable; - private final UnaryCallable - listDatabasesPagedCallable; private final UnaryCallable createDatabaseCallable; private final OperationCallable createDatabaseOperationCallable; - private final UnaryCallable getDatabaseCallable; private final UnaryCallable updateDatabaseDdlCallable; private final OperationCallable updateDatabaseDdlOperationCallable; + private final UnaryCallable createBackupCallable; + private final OperationCallable + createBackupOperationCallable; + private final UnaryCallable restoreDatabaseCallable; + private final OperationCallable + restoreDatabaseOperationCallable; + private final UnaryCallable listDatabasesCallable; + private final UnaryCallable + listDatabasesPagedCallable; + private final UnaryCallable getDatabaseCallable; private final UnaryCallable dropDatabaseCallable; private final UnaryCallable getDatabaseDdlCallable; private final UnaryCallable setIamPolicyCallable; private final UnaryCallable getIamPolicyCallable; private final UnaryCallable testIamPermissionsCallable; - private final UnaryCallable createBackupCallable; - private final OperationCallable - createBackupOperationCallable; private final UnaryCallable getBackupCallable; private final UnaryCallable updateBackupCallable; private final UnaryCallable deleteBackupCallable; private final UnaryCallable listBackupsCallable; private final UnaryCallable listBackupsPagedCallable; - private final UnaryCallable restoreDatabaseCallable; - private final OperationCallable - restoreDatabaseOperationCallable; private final UnaryCallable listDatabaseOperationsCallable; private final UnaryCallable @@ -309,54 +309,80 @@ protected GrpcDatabaseAdminStub( this.callableFactory = callableFactory; this.operationsStub = GrpcOperationsStub.create(clientContext, callableFactory); - GrpcCallSettings listDatabasesTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(listDatabasesMethodDescriptor) + GrpcCallSettings createDatabaseTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(createDatabaseMethodDescriptor) .setParamsExtractor( - new RequestParamsExtractor() { + new RequestParamsExtractor() { @Override - public Map extract(ListDatabasesRequest request) { + public Map extract(CreateDatabaseRequest request) { ImmutableMap.Builder params = ImmutableMap.builder(); params.put("parent", String.valueOf(request.getParent())); return params.build(); } }) .build(); - GrpcCallSettings createDatabaseTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(createDatabaseMethodDescriptor) + GrpcCallSettings updateDatabaseDdlTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(updateDatabaseDdlMethodDescriptor) .setParamsExtractor( - new RequestParamsExtractor() { + new RequestParamsExtractor() { @Override - public Map extract(CreateDatabaseRequest request) { + public Map extract(UpdateDatabaseDdlRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("database", String.valueOf(request.getDatabase())); + return params.build(); + } + }) + .build(); + GrpcCallSettings createBackupTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(createBackupMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(CreateBackupRequest request) { ImmutableMap.Builder params = ImmutableMap.builder(); params.put("parent", String.valueOf(request.getParent())); return params.build(); } }) .build(); - GrpcCallSettings getDatabaseTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(getDatabaseMethodDescriptor) + GrpcCallSettings restoreDatabaseTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(restoreDatabaseMethodDescriptor) .setParamsExtractor( - new RequestParamsExtractor() { + new RequestParamsExtractor() { @Override - public Map extract(GetDatabaseRequest request) { + public Map extract(RestoreDatabaseRequest request) { ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("name", String.valueOf(request.getName())); + params.put("parent", String.valueOf(request.getParent())); return params.build(); } }) .build(); - GrpcCallSettings updateDatabaseDdlTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(updateDatabaseDdlMethodDescriptor) + GrpcCallSettings listDatabasesTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(listDatabasesMethodDescriptor) .setParamsExtractor( - new RequestParamsExtractor() { + new RequestParamsExtractor() { @Override - public Map extract(UpdateDatabaseDdlRequest request) { + public Map extract(ListDatabasesRequest request) { ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("database", String.valueOf(request.getDatabase())); + params.put("parent", String.valueOf(request.getParent())); + return params.build(); + } + }) + .build(); + GrpcCallSettings getDatabaseTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(getDatabaseMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(GetDatabaseRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); return params.build(); } }) @@ -428,19 +454,6 @@ public Map extract(TestIamPermissionsRequest request) { } }) .build(); - GrpcCallSettings createBackupTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(createBackupMethodDescriptor) - .setParamsExtractor( - new RequestParamsExtractor() { - @Override - public Map extract(CreateBackupRequest request) { - ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("parent", String.valueOf(request.getParent())); - return params.build(); - } - }) - .build(); GrpcCallSettings getBackupTransportSettings = GrpcCallSettings.newBuilder() .setMethodDescriptor(getBackupMethodDescriptor) @@ -493,19 +506,6 @@ public Map extract(ListBackupsRequest request) { } }) .build(); - GrpcCallSettings restoreDatabaseTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(restoreDatabaseMethodDescriptor) - .setParamsExtractor( - new RequestParamsExtractor() { - @Override - public Map extract(RestoreDatabaseRequest request) { - ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("parent", String.valueOf(request.getParent())); - return params.build(); - } - }) - .build(); GrpcCallSettings listDatabaseOperationsTransportSettings = GrpcCallSettings @@ -536,12 +536,6 @@ public Map extract(ListBackupOperationsRequest request) { }) .build(); - this.listDatabasesCallable = - callableFactory.createUnaryCallable( - listDatabasesTransportSettings, settings.listDatabasesSettings(), clientContext); - this.listDatabasesPagedCallable = - callableFactory.createPagedCallable( - listDatabasesTransportSettings, settings.listDatabasesSettings(), clientContext); this.createDatabaseCallable = callableFactory.createUnaryCallable( createDatabaseTransportSettings, settings.createDatabaseSettings(), clientContext); @@ -551,9 +545,6 @@ public Map extract(ListBackupOperationsRequest request) { settings.createDatabaseOperationSettings(), clientContext, this.operationsStub); - this.getDatabaseCallable = - callableFactory.createUnaryCallable( - getDatabaseTransportSettings, settings.getDatabaseSettings(), clientContext); this.updateDatabaseDdlCallable = callableFactory.createUnaryCallable( updateDatabaseDdlTransportSettings, @@ -565,6 +556,33 @@ public Map extract(ListBackupOperationsRequest request) { settings.updateDatabaseDdlOperationSettings(), clientContext, this.operationsStub); + this.createBackupCallable = + callableFactory.createUnaryCallable( + createBackupTransportSettings, settings.createBackupSettings(), clientContext); + this.createBackupOperationCallable = + callableFactory.createOperationCallable( + createBackupTransportSettings, + settings.createBackupOperationSettings(), + clientContext, + this.operationsStub); + this.restoreDatabaseCallable = + callableFactory.createUnaryCallable( + restoreDatabaseTransportSettings, settings.restoreDatabaseSettings(), clientContext); + this.restoreDatabaseOperationCallable = + callableFactory.createOperationCallable( + restoreDatabaseTransportSettings, + settings.restoreDatabaseOperationSettings(), + clientContext, + this.operationsStub); + this.listDatabasesCallable = + callableFactory.createUnaryCallable( + listDatabasesTransportSettings, settings.listDatabasesSettings(), clientContext); + this.listDatabasesPagedCallable = + callableFactory.createPagedCallable( + listDatabasesTransportSettings, settings.listDatabasesSettings(), clientContext); + this.getDatabaseCallable = + callableFactory.createUnaryCallable( + getDatabaseTransportSettings, settings.getDatabaseSettings(), clientContext); this.dropDatabaseCallable = callableFactory.createUnaryCallable( dropDatabaseTransportSettings, settings.dropDatabaseSettings(), clientContext); @@ -582,15 +600,6 @@ public Map extract(ListBackupOperationsRequest request) { testIamPermissionsTransportSettings, settings.testIamPermissionsSettings(), clientContext); - this.createBackupCallable = - callableFactory.createUnaryCallable( - createBackupTransportSettings, settings.createBackupSettings(), clientContext); - this.createBackupOperationCallable = - callableFactory.createOperationCallable( - createBackupTransportSettings, - settings.createBackupOperationSettings(), - clientContext, - this.operationsStub); this.getBackupCallable = callableFactory.createUnaryCallable( getBackupTransportSettings, settings.getBackupSettings(), clientContext); @@ -606,15 +615,6 @@ public Map extract(ListBackupOperationsRequest request) { this.listBackupsPagedCallable = callableFactory.createPagedCallable( listBackupsTransportSettings, settings.listBackupsSettings(), clientContext); - this.restoreDatabaseCallable = - callableFactory.createUnaryCallable( - restoreDatabaseTransportSettings, settings.restoreDatabaseSettings(), clientContext); - this.restoreDatabaseOperationCallable = - callableFactory.createOperationCallable( - restoreDatabaseTransportSettings, - settings.restoreDatabaseOperationSettings(), - clientContext, - this.operationsStub); this.listDatabaseOperationsCallable = callableFactory.createUnaryCallable( listDatabaseOperationsTransportSettings, @@ -644,15 +644,6 @@ public GrpcOperationsStub getOperationsStub() { return operationsStub; } - public UnaryCallable - listDatabasesPagedCallable() { - return listDatabasesPagedCallable; - } - - public UnaryCallable listDatabasesCallable() { - return listDatabasesCallable; - } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") public OperationCallable createDatabaseOperationCallable() { @@ -663,10 +654,6 @@ public UnaryCallable createDatabaseCallable() return createDatabaseCallable; } - public UnaryCallable getDatabaseCallable() { - return getDatabaseCallable; - } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") public OperationCallable updateDatabaseDdlOperationCallable() { @@ -677,6 +664,39 @@ public UnaryCallable updateDatabaseDdlCalla return updateDatabaseDdlCallable; } + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + createBackupOperationCallable() { + return createBackupOperationCallable; + } + + public UnaryCallable createBackupCallable() { + return createBackupCallable; + } + + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + restoreDatabaseOperationCallable() { + return restoreDatabaseOperationCallable; + } + + public UnaryCallable restoreDatabaseCallable() { + return restoreDatabaseCallable; + } + + public UnaryCallable + listDatabasesPagedCallable() { + return listDatabasesPagedCallable; + } + + public UnaryCallable listDatabasesCallable() { + return listDatabasesCallable; + } + + public UnaryCallable getDatabaseCallable() { + return getDatabaseCallable; + } + public UnaryCallable dropDatabaseCallable() { return dropDatabaseCallable; } @@ -698,16 +718,6 @@ public UnaryCallable getIamPolicyCallable() { return testIamPermissionsCallable; } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - createBackupOperationCallable() { - return createBackupOperationCallable; - } - - public UnaryCallable createBackupCallable() { - return createBackupCallable; - } - public UnaryCallable getBackupCallable() { return getBackupCallable; } @@ -728,16 +738,6 @@ public UnaryCallable listBackupsCallabl return listBackupsCallable; } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - restoreDatabaseOperationCallable() { - return restoreDatabaseOperationCallable; - } - - public UnaryCallable restoreDatabaseCallable() { - return restoreDatabaseCallable; - } - public UnaryCallable listDatabaseOperationsPagedCallable() { return listDatabaseOperationsPagedCallable; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClient.java index 4242e4e42e..fb9c411c00 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClient.java @@ -212,274 +212,810 @@ public final OperationsClient getOperationsClient() { // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists the supported instance configurations for a given project. + * Creates an instance and begins preparing it to begin serving. The returned [long-running + * operation][google.longrunning.Operation] can be used to track the progress of preparing the new + * instance. The instance name is assigned by the caller. If the named instance already exists, + * `CreateInstance` returns `ALREADY_EXISTS`. + * + *

Immediately upon completion of this request: + * + *

* The instance is readable via the API, with all requested attributes but no allocated + * resources. Its state is `CREATING`. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation renders the instance immediately unreadable via the API. + * * The instance can be deleted. * All other attempts to modify the instance are + * rejected. + * + *

Upon completion of the returned operation: + * + *

* Billing for all successfully-allocated resources begins (some types may have lower + * than the requested levels). * Databases can be created in the instance. * The + * instance's allocated resource levels are readable via the API. * The instance's state + * becomes `READY`. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track + * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is + * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(parent).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
+   *   String instanceId = "";
+   *   Instance instance = Instance.newBuilder().build();
+   *   Instance response = instanceAdminClient.createInstanceAsync(parent, instanceId, instance).get();
    * }
    * 
* - * @param parent Required. The name of the project for which a list of supported instance - * configurations is requested. Values are of the form `projects/<project>`. + * @param parent Required. The name of the project in which to create the instance. Values are of + * the form `projects/<project>`. + * @param instanceId Required. The ID of the instance to create. Valid identifiers are of the form + * `[a-z][-a-z0-9]*[a-z0-9]` and must be between 2 and 64 characters in length. + * @param instance Required. The instance to create. The name may be omitted, but if specified + * must be `<parent>/instances/<instance_id>`. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final ListInstanceConfigsPagedResponse listInstanceConfigs(ProjectName parent) { - ListInstanceConfigsRequest request = - ListInstanceConfigsRequest.newBuilder() + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createInstanceAsync( + ProjectName parent, String instanceId, Instance instance) { + CreateInstanceRequest request = + CreateInstanceRequest.newBuilder() .setParent(parent == null ? null : parent.toString()) + .setInstanceId(instanceId) + .setInstance(instance) .build(); - return listInstanceConfigs(request); + return createInstanceAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists the supported instance configurations for a given project. + * Creates an instance and begins preparing it to begin serving. The returned [long-running + * operation][google.longrunning.Operation] can be used to track the progress of preparing the new + * instance. The instance name is assigned by the caller. If the named instance already exists, + * `CreateInstance` returns `ALREADY_EXISTS`. + * + *

Immediately upon completion of this request: + * + *

* The instance is readable via the API, with all requested attributes but no allocated + * resources. Its state is `CREATING`. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation renders the instance immediately unreadable via the API. + * * The instance can be deleted. * All other attempts to modify the instance are + * rejected. + * + *

Upon completion of the returned operation: + * + *

* Billing for all successfully-allocated resources begins (some types may have lower + * than the requested levels). * Databases can be created in the instance. * The + * instance's allocated resource levels are readable via the API. * The instance's state + * becomes `READY`. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track + * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is + * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(parent.toString()).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
+   *   String instanceId = "";
+   *   Instance instance = Instance.newBuilder().build();
+   *   Instance response = instanceAdminClient.createInstanceAsync(parent.toString(), instanceId, instance).get();
    * }
    * 
* - * @param parent Required. The name of the project for which a list of supported instance - * configurations is requested. Values are of the form `projects/<project>`. + * @param parent Required. The name of the project in which to create the instance. Values are of + * the form `projects/<project>`. + * @param instanceId Required. The ID of the instance to create. Valid identifiers are of the form + * `[a-z][-a-z0-9]*[a-z0-9]` and must be between 2 and 64 characters in length. + * @param instance Required. The instance to create. The name may be omitted, but if specified + * must be `<parent>/instances/<instance_id>`. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final ListInstanceConfigsPagedResponse listInstanceConfigs(String parent) { - ListInstanceConfigsRequest request = - ListInstanceConfigsRequest.newBuilder().setParent(parent).build(); - return listInstanceConfigs(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createInstanceAsync( + String parent, String instanceId, Instance instance) { + CreateInstanceRequest request = + CreateInstanceRequest.newBuilder() + .setParent(parent) + .setInstanceId(instanceId) + .setInstance(instance) + .build(); + return createInstanceAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists the supported instance configurations for a given project. + * Creates an instance and begins preparing it to begin serving. The returned [long-running + * operation][google.longrunning.Operation] can be used to track the progress of preparing the new + * instance. The instance name is assigned by the caller. If the named instance already exists, + * `CreateInstance` returns `ALREADY_EXISTS`. + * + *

Immediately upon completion of this request: + * + *

* The instance is readable via the API, with all requested attributes but no allocated + * resources. Its state is `CREATING`. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation renders the instance immediately unreadable via the API. + * * The instance can be deleted. * All other attempts to modify the instance are + * rejected. + * + *

Upon completion of the returned operation: + * + *

* Billing for all successfully-allocated resources begins (some types may have lower + * than the requested levels). * Databases can be created in the instance. * The + * instance's allocated resource levels are readable via the API. * The instance's state + * becomes `READY`. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track + * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is + * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *   String instanceId = "";
+   *   Instance instance = Instance.newBuilder().build();
+   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
    *     .setParent(parent.toString())
+   *     .setInstanceId(instanceId)
+   *     .setInstance(instance)
    *     .build();
-   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(request).iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
+   *   Instance response = instanceAdminClient.createInstanceAsync(request).get();
    * }
    * 
* * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final ListInstanceConfigsPagedResponse listInstanceConfigs( - ListInstanceConfigsRequest request) { - return listInstanceConfigsPagedCallable().call(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture createInstanceAsync( + CreateInstanceRequest request) { + return createInstanceOperationCallable().futureCall(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists the supported instance configurations for a given project. + * Creates an instance and begins preparing it to begin serving. The returned [long-running + * operation][google.longrunning.Operation] can be used to track the progress of preparing the new + * instance. The instance name is assigned by the caller. If the named instance already exists, + * `CreateInstance` returns `ALREADY_EXISTS`. + * + *

Immediately upon completion of this request: + * + *

* The instance is readable via the API, with all requested attributes but no allocated + * resources. Its state is `CREATING`. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation renders the instance immediately unreadable via the API. + * * The instance can be deleted. * All other attempts to modify the instance are + * rejected. + * + *

Upon completion of the returned operation: + * + *

* Billing for all successfully-allocated resources begins (some types may have lower + * than the requested levels). * Databases can be created in the instance. * The + * instance's allocated resource levels are readable via the API. * The instance's state + * becomes `READY`. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track + * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is + * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *   String instanceId = "";
+   *   Instance instance = Instance.newBuilder().build();
+   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
    *     .setParent(parent.toString())
+   *     .setInstanceId(instanceId)
+   *     .setInstance(instance)
    *     .build();
-   *   ApiFuture<ListInstanceConfigsPagedResponse> future = instanceAdminClient.listInstanceConfigsPagedCallable().futureCall(request);
+   *   OperationFuture<Instance, CreateInstanceMetadata> future = instanceAdminClient.createInstanceOperationCallable().futureCall(request);
    *   // Do something
-   *   for (InstanceConfig element : future.get().iterateAll()) {
-   *     // doThingsWith(element);
-   *   }
+   *   Instance response = future.get();
    * }
    * 
*/ - public final UnaryCallable - listInstanceConfigsPagedCallable() { - return stub.listInstanceConfigsPagedCallable(); + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public final OperationCallable + createInstanceOperationCallable() { + return stub.createInstanceOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists the supported instance configurations for a given project. + * Creates an instance and begins preparing it to begin serving. The returned [long-running + * operation][google.longrunning.Operation] can be used to track the progress of preparing the new + * instance. The instance name is assigned by the caller. If the named instance already exists, + * `CreateInstance` returns `ALREADY_EXISTS`. + * + *

Immediately upon completion of this request: + * + *

* The instance is readable via the API, with all requested attributes but no allocated + * resources. Its state is `CREATING`. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation renders the instance immediately unreadable via the API. + * * The instance can be deleted. * All other attempts to modify the instance are + * rejected. + * + *

Upon completion of the returned operation: + * + *

* Billing for all successfully-allocated resources begins (some types may have lower + * than the requested levels). * Databases can be created in the instance. * The + * instance's allocated resource levels are readable via the API. * The instance's state + * becomes `READY`. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track + * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is + * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *   String instanceId = "";
+   *   Instance instance = Instance.newBuilder().build();
+   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
    *     .setParent(parent.toString())
+   *     .setInstanceId(instanceId)
+   *     .setInstance(instance)
    *     .build();
-   *   while (true) {
-   *     ListInstanceConfigsResponse response = instanceAdminClient.listInstanceConfigsCallable().call(request);
-   *     for (InstanceConfig element : response.getInstanceConfigsList()) {
-   *       // doThingsWith(element);
-   *     }
-   *     String nextPageToken = response.getNextPageToken();
-   *     if (!Strings.isNullOrEmpty(nextPageToken)) {
-   *       request = request.toBuilder().setPageToken(nextPageToken).build();
-   *     } else {
-   *       break;
-   *     }
-   *   }
+   *   ApiFuture<Operation> future = instanceAdminClient.createInstanceCallable().futureCall(request);
+   *   // Do something
+   *   Operation response = future.get();
    * }
    * 
*/ - public final UnaryCallable - listInstanceConfigsCallable() { - return stub.listInstanceConfigsCallable(); + public final UnaryCallable createInstanceCallable() { + return stub.createInstanceCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Gets information about a particular instance configuration. + * Updates an instance, and begins allocating or releasing resources as requested. The returned + * [long-running operation][google.longrunning.Operation] can be used to track the progress of + * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. + * + *

Immediately upon completion of this request: + * + *

* For resource types for which a decrease in the instance's allocation has been + * requested, billing is based on the newly-requested level. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation sets its metadata's + * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins + * restoring resources to their pre-request values. The operation is guaranteed to succeed at + * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * + * All other attempts to modify the instance are rejected. * Reading the instance via the API + * continues to give the pre-request resource levels. + * + *

Upon completion of the returned operation: + * + *

* Billing begins for all successfully-allocated resources (some types may have lower + * than the requested levels). * All newly-reserved resources are available for serving the + * instance's tables. * The instance's new resource levels are readable via the API. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track the + * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is + * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. + * + *

Authorization requires `spanner.instances.update` permission on resource + * [name][google.spanner.admin.instance.v1.Instance.name]. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
-   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(name);
+   *   Instance instance = Instance.newBuilder().build();
+   *   FieldMask fieldMask = FieldMask.newBuilder().build();
+   *   Instance response = instanceAdminClient.updateInstanceAsync(instance, fieldMask).get();
    * }
    * 
* - * @param name Required. The name of the requested instance configuration. Values are of the form - * `projects/<project>/instanceConfigs/<config>`. + * @param instance Required. The instance to update, which must always include the instance name. + * Otherwise, only fields mentioned in + * [field_mask][google.spanner.admin.instance.v1.UpdateInstanceRequest.field_mask] need be + * included. + * @param fieldMask Required. A mask specifying which fields in + * [Instance][google.spanner.admin.instance.v1.Instance] should be updated. The field mask + * must always be specified; this prevents any future fields in + * [Instance][google.spanner.admin.instance.v1.Instance] from being erased accidentally by + * clients that do not know about them. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final InstanceConfig getInstanceConfig(InstanceConfigName name) { - GetInstanceConfigRequest request = - GetInstanceConfigRequest.newBuilder() - .setName(name == null ? null : name.toString()) - .build(); - return getInstanceConfig(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture updateInstanceAsync( + Instance instance, FieldMask fieldMask) { + UpdateInstanceRequest request = + UpdateInstanceRequest.newBuilder().setInstance(instance).setFieldMask(fieldMask).build(); + return updateInstanceAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Gets information about a particular instance configuration. + * Updates an instance, and begins allocating or releasing resources as requested. The returned + * [long-running operation][google.longrunning.Operation] can be used to track the progress of + * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. + * + *

Immediately upon completion of this request: + * + *

* For resource types for which a decrease in the instance's allocation has been + * requested, billing is based on the newly-requested level. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation sets its metadata's + * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins + * restoring resources to their pre-request values. The operation is guaranteed to succeed at + * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * + * All other attempts to modify the instance are rejected. * Reading the instance via the API + * continues to give the pre-request resource levels. + * + *

Upon completion of the returned operation: + * + *

* Billing begins for all successfully-allocated resources (some types may have lower + * than the requested levels). * All newly-reserved resources are available for serving the + * instance's tables. * The instance's new resource levels are readable via the API. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track the + * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is + * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. + * + *

Authorization requires `spanner.instances.update` permission on resource + * [name][google.spanner.admin.instance.v1.Instance.name]. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
-   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(name.toString());
+   *   Instance instance = Instance.newBuilder().build();
+   *   FieldMask fieldMask = FieldMask.newBuilder().build();
+   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
+   *     .setInstance(instance)
+   *     .setFieldMask(fieldMask)
+   *     .build();
+   *   Instance response = instanceAdminClient.updateInstanceAsync(request).get();
    * }
    * 
* - * @param name Required. The name of the requested instance configuration. Values are of the form - * `projects/<project>/instanceConfigs/<config>`. + * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final InstanceConfig getInstanceConfig(String name) { - GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder().setName(name).build(); - return getInstanceConfig(request); + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public final OperationFuture updateInstanceAsync( + UpdateInstanceRequest request) { + return updateInstanceOperationCallable().futureCall(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Gets information about a particular instance configuration. + * Updates an instance, and begins allocating or releasing resources as requested. The returned + * [long-running operation][google.longrunning.Operation] can be used to track the progress of + * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. + * + *

Immediately upon completion of this request: + * + *

* For resource types for which a decrease in the instance's allocation has been + * requested, billing is based on the newly-requested level. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation sets its metadata's + * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins + * restoring resources to their pre-request values. The operation is guaranteed to succeed at + * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * + * All other attempts to modify the instance are rejected. * Reading the instance via the API + * continues to give the pre-request resource levels. + * + *

Upon completion of the returned operation: + * + *

* Billing begins for all successfully-allocated resources (some types may have lower + * than the requested levels). * All newly-reserved resources are available for serving the + * instance's tables. * The instance's new resource levels are readable via the API. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track the + * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is + * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. + * + *

Authorization requires `spanner.instances.update` permission on resource + * [name][google.spanner.admin.instance.v1.Instance.name]. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
-   *   GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder()
-   *     .setName(name.toString())
+   *   Instance instance = Instance.newBuilder().build();
+   *   FieldMask fieldMask = FieldMask.newBuilder().build();
+   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
+   *     .setInstance(instance)
+   *     .setFieldMask(fieldMask)
    *     .build();
-   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(request);
+   *   OperationFuture<Instance, UpdateInstanceMetadata> future = instanceAdminClient.updateInstanceOperationCallable().futureCall(request);
+   *   // Do something
+   *   Instance response = future.get();
    * }
    * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final InstanceConfig getInstanceConfig(GetInstanceConfigRequest request) { - return getInstanceConfigCallable().call(request); + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public final OperationCallable + updateInstanceOperationCallable() { + return stub.updateInstanceOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Gets information about a particular instance configuration. + * Updates an instance, and begins allocating or releasing resources as requested. The returned + * [long-running operation][google.longrunning.Operation] can be used to track the progress of + * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. + * + *

Immediately upon completion of this request: + * + *

* For resource types for which a decrease in the instance's allocation has been + * requested, billing is based on the newly-requested level. + * + *

Until completion of the returned operation: + * + *

* Cancelling the operation sets its metadata's + * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins + * restoring resources to their pre-request values. The operation is guaranteed to succeed at + * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * + * All other attempts to modify the instance are rejected. * Reading the instance via the API + * continues to give the pre-request resource levels. + * + *

Upon completion of the returned operation: + * + *

* Billing begins for all successfully-allocated resources (some types may have lower + * than the requested levels). * All newly-reserved resources are available for serving the + * instance's tables. * The instance's new resource levels are readable via the API. + * + *

The returned [long-running operation][google.longrunning.Operation] will have a name of the + * format `<instance_name>/operations/<operation_id>` and can be used to track the + * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is + * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The + * [response][google.longrunning.Operation.response] field type is + * [Instance][google.spanner.admin.instance.v1.Instance], if successful. + * + *

Authorization requires `spanner.instances.update` permission on resource + * [name][google.spanner.admin.instance.v1.Instance.name]. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
-   *   GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder()
-   *     .setName(name.toString())
+   *   Instance instance = Instance.newBuilder().build();
+   *   FieldMask fieldMask = FieldMask.newBuilder().build();
+   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
+   *     .setInstance(instance)
+   *     .setFieldMask(fieldMask)
    *     .build();
-   *   ApiFuture<InstanceConfig> future = instanceAdminClient.getInstanceConfigCallable().futureCall(request);
+   *   ApiFuture<Operation> future = instanceAdminClient.updateInstanceCallable().futureCall(request);
    *   // Do something
-   *   InstanceConfig response = future.get();
+   *   Operation response = future.get();
    * }
    * 
*/ - public final UnaryCallable getInstanceConfigCallable() { - return stub.getInstanceConfigCallable(); + public final UnaryCallable updateInstanceCallable() { + return stub.updateInstanceCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists all instances in the given project. + * Lists the supported instance configurations for a given project. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   for (Instance element : instanceAdminClient.listInstances(parent).iterateAll()) {
+   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(parent).iterateAll()) {
    *     // doThingsWith(element);
    *   }
    * }
    * 
* - * @param parent Required. The name of the project for which a list of instances is requested. - * Values are of the form `projects/<project>`. + * @param parent Required. The name of the project for which a list of supported instance + * configurations is requested. Values are of the form `projects/<project>`. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final ListInstancesPagedResponse listInstances(ProjectName parent) { - ListInstancesRequest request = - ListInstancesRequest.newBuilder() + public final ListInstanceConfigsPagedResponse listInstanceConfigs(ProjectName parent) { + ListInstanceConfigsRequest request = + ListInstanceConfigsRequest.newBuilder() .setParent(parent == null ? null : parent.toString()) .build(); - return listInstances(request); + return listInstanceConfigs(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD /** - * Lists all instances in the given project. + * Lists the supported instance configurations for a given project. * *

Sample code: * *


    * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
    *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   for (Instance element : instanceAdminClient.listInstances(parent.toString()).iterateAll()) {
+   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(parent.toString()).iterateAll()) {
    *     // doThingsWith(element);
    *   }
    * }
    * 
* - * @param parent Required. The name of the project for which a list of instances is requested. + * @param parent Required. The name of the project for which a list of supported instance + * configurations is requested. Values are of the form `projects/<project>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListInstanceConfigsPagedResponse listInstanceConfigs(String parent) { + ListInstanceConfigsRequest request = + ListInstanceConfigsRequest.newBuilder().setParent(parent).build(); + return listInstanceConfigs(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists the supported instance configurations for a given project. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   for (InstanceConfig element : instanceAdminClient.listInstanceConfigs(request).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListInstanceConfigsPagedResponse listInstanceConfigs( + ListInstanceConfigsRequest request) { + return listInstanceConfigsPagedCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists the supported instance configurations for a given project. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   ApiFuture<ListInstanceConfigsPagedResponse> future = instanceAdminClient.listInstanceConfigsPagedCallable().futureCall(request);
+   *   // Do something
+   *   for (InstanceConfig element : future.get().iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ */ + public final UnaryCallable + listInstanceConfigsPagedCallable() { + return stub.listInstanceConfigsPagedCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists the supported instance configurations for a given project. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   ListInstanceConfigsRequest request = ListInstanceConfigsRequest.newBuilder()
+   *     .setParent(parent.toString())
+   *     .build();
+   *   while (true) {
+   *     ListInstanceConfigsResponse response = instanceAdminClient.listInstanceConfigsCallable().call(request);
+   *     for (InstanceConfig element : response.getInstanceConfigsList()) {
+   *       // doThingsWith(element);
+   *     }
+   *     String nextPageToken = response.getNextPageToken();
+   *     if (!Strings.isNullOrEmpty(nextPageToken)) {
+   *       request = request.toBuilder().setPageToken(nextPageToken).build();
+   *     } else {
+   *       break;
+   *     }
+   *   }
+   * }
+   * 
+ */ + public final UnaryCallable + listInstanceConfigsCallable() { + return stub.listInstanceConfigsCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets information about a particular instance configuration. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
+   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(name);
+   * }
+   * 
+ * + * @param name Required. The name of the requested instance configuration. Values are of the form + * `projects/<project>/instanceConfigs/<config>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final InstanceConfig getInstanceConfig(InstanceConfigName name) { + GetInstanceConfigRequest request = + GetInstanceConfigRequest.newBuilder() + .setName(name == null ? null : name.toString()) + .build(); + return getInstanceConfig(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets information about a particular instance configuration. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
+   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(name.toString());
+   * }
+   * 
+ * + * @param name Required. The name of the requested instance configuration. Values are of the form + * `projects/<project>/instanceConfigs/<config>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final InstanceConfig getInstanceConfig(String name) { + GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder().setName(name).build(); + return getInstanceConfig(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets information about a particular instance configuration. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
+   *   GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder()
+   *     .setName(name.toString())
+   *     .build();
+   *   InstanceConfig response = instanceAdminClient.getInstanceConfig(request);
+   * }
+   * 
+ * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final InstanceConfig getInstanceConfig(GetInstanceConfigRequest request) { + return getInstanceConfigCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Gets information about a particular instance configuration. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]");
+   *   GetInstanceConfigRequest request = GetInstanceConfigRequest.newBuilder()
+   *     .setName(name.toString())
+   *     .build();
+   *   ApiFuture<InstanceConfig> future = instanceAdminClient.getInstanceConfigCallable().futureCall(request);
+   *   // Do something
+   *   InstanceConfig response = future.get();
+   * }
+   * 
+ */ + public final UnaryCallable getInstanceConfigCallable() { + return stub.getInstanceConfigCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists all instances in the given project. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   for (Instance element : instanceAdminClient.listInstances(parent).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param parent Required. The name of the project for which a list of instances is requested. + * Values are of the form `projects/<project>`. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListInstancesPagedResponse listInstances(ProjectName parent) { + ListInstancesRequest request = + ListInstancesRequest.newBuilder() + .setParent(parent == null ? null : parent.toString()) + .build(); + return listInstances(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Lists all instances in the given project. + * + *

Sample code: + * + *


+   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   for (Instance element : instanceAdminClient.listInstances(parent.toString()).iterateAll()) {
+   *     // doThingsWith(element);
+   *   }
+   * }
+   * 
+ * + * @param parent Required. The name of the project for which a list of instances is requested. * Values are of the form `projects/<project>`. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ @@ -659,542 +1195,6 @@ public final UnaryCallable getInstanceCallable() { return stub.getInstanceCallable(); } - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Creates an instance and begins preparing it to begin serving. The returned [long-running - * operation][google.longrunning.Operation] can be used to track the progress of preparing the new - * instance. The instance name is assigned by the caller. If the named instance already exists, - * `CreateInstance` returns `ALREADY_EXISTS`. - * - *

Immediately upon completion of this request: - * - *

* The instance is readable via the API, with all requested attributes but no allocated - * resources. Its state is `CREATING`. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation renders the instance immediately unreadable via the API. - * * The instance can be deleted. * All other attempts to modify the instance are - * rejected. - * - *

Upon completion of the returned operation: - * - *

* Billing for all successfully-allocated resources begins (some types may have lower - * than the requested levels). * Databases can be created in the instance. * The - * instance's allocated resource levels are readable via the API. * The instance's state - * becomes `READY`. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track - * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is - * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   String instanceId = "";
-   *   Instance instance = Instance.newBuilder().build();
-   *   Instance response = instanceAdminClient.createInstanceAsync(parent, instanceId, instance).get();
-   * }
-   * 
- * - * @param parent Required. The name of the project in which to create the instance. Values are of - * the form `projects/<project>`. - * @param instanceId Required. The ID of the instance to create. Valid identifiers are of the form - * `[a-z][-a-z0-9]*[a-z0-9]` and must be between 2 and 64 characters in length. - * @param instance Required. The instance to create. The name may be omitted, but if specified - * must be `<parent>/instances/<instance_id>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createInstanceAsync( - ProjectName parent, String instanceId, Instance instance) { - CreateInstanceRequest request = - CreateInstanceRequest.newBuilder() - .setParent(parent == null ? null : parent.toString()) - .setInstanceId(instanceId) - .setInstance(instance) - .build(); - return createInstanceAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Creates an instance and begins preparing it to begin serving. The returned [long-running - * operation][google.longrunning.Operation] can be used to track the progress of preparing the new - * instance. The instance name is assigned by the caller. If the named instance already exists, - * `CreateInstance` returns `ALREADY_EXISTS`. - * - *

Immediately upon completion of this request: - * - *

* The instance is readable via the API, with all requested attributes but no allocated - * resources. Its state is `CREATING`. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation renders the instance immediately unreadable via the API. - * * The instance can be deleted. * All other attempts to modify the instance are - * rejected. - * - *

Upon completion of the returned operation: - * - *

* Billing for all successfully-allocated resources begins (some types may have lower - * than the requested levels). * Databases can be created in the instance. * The - * instance's allocated resource levels are readable via the API. * The instance's state - * becomes `READY`. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track - * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is - * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   String instanceId = "";
-   *   Instance instance = Instance.newBuilder().build();
-   *   Instance response = instanceAdminClient.createInstanceAsync(parent.toString(), instanceId, instance).get();
-   * }
-   * 
- * - * @param parent Required. The name of the project in which to create the instance. Values are of - * the form `projects/<project>`. - * @param instanceId Required. The ID of the instance to create. Valid identifiers are of the form - * `[a-z][-a-z0-9]*[a-z0-9]` and must be between 2 and 64 characters in length. - * @param instance Required. The instance to create. The name may be omitted, but if specified - * must be `<parent>/instances/<instance_id>`. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createInstanceAsync( - String parent, String instanceId, Instance instance) { - CreateInstanceRequest request = - CreateInstanceRequest.newBuilder() - .setParent(parent) - .setInstanceId(instanceId) - .setInstance(instance) - .build(); - return createInstanceAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Creates an instance and begins preparing it to begin serving. The returned [long-running - * operation][google.longrunning.Operation] can be used to track the progress of preparing the new - * instance. The instance name is assigned by the caller. If the named instance already exists, - * `CreateInstance` returns `ALREADY_EXISTS`. - * - *

Immediately upon completion of this request: - * - *

* The instance is readable via the API, with all requested attributes but no allocated - * resources. Its state is `CREATING`. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation renders the instance immediately unreadable via the API. - * * The instance can be deleted. * All other attempts to modify the instance are - * rejected. - * - *

Upon completion of the returned operation: - * - *

* Billing for all successfully-allocated resources begins (some types may have lower - * than the requested levels). * Databases can be created in the instance. * The - * instance's allocated resource levels are readable via the API. * The instance's state - * becomes `READY`. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track - * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is - * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   String instanceId = "";
-   *   Instance instance = Instance.newBuilder().build();
-   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setInstanceId(instanceId)
-   *     .setInstance(instance)
-   *     .build();
-   *   Instance response = instanceAdminClient.createInstanceAsync(request).get();
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture createInstanceAsync( - CreateInstanceRequest request) { - return createInstanceOperationCallable().futureCall(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Creates an instance and begins preparing it to begin serving. The returned [long-running - * operation][google.longrunning.Operation] can be used to track the progress of preparing the new - * instance. The instance name is assigned by the caller. If the named instance already exists, - * `CreateInstance` returns `ALREADY_EXISTS`. - * - *

Immediately upon completion of this request: - * - *

* The instance is readable via the API, with all requested attributes but no allocated - * resources. Its state is `CREATING`. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation renders the instance immediately unreadable via the API. - * * The instance can be deleted. * All other attempts to modify the instance are - * rejected. - * - *

Upon completion of the returned operation: - * - *

* Billing for all successfully-allocated resources begins (some types may have lower - * than the requested levels). * Databases can be created in the instance. * The - * instance's allocated resource levels are readable via the API. * The instance's state - * becomes `READY`. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track - * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is - * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   String instanceId = "";
-   *   Instance instance = Instance.newBuilder().build();
-   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setInstanceId(instanceId)
-   *     .setInstance(instance)
-   *     .build();
-   *   OperationFuture<Instance, CreateInstanceMetadata> future = instanceAdminClient.createInstanceOperationCallable().futureCall(request);
-   *   // Do something
-   *   Instance response = future.get();
-   * }
-   * 
- */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public final OperationCallable - createInstanceOperationCallable() { - return stub.createInstanceOperationCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Creates an instance and begins preparing it to begin serving. The returned [long-running - * operation][google.longrunning.Operation] can be used to track the progress of preparing the new - * instance. The instance name is assigned by the caller. If the named instance already exists, - * `CreateInstance` returns `ALREADY_EXISTS`. - * - *

Immediately upon completion of this request: - * - *

* The instance is readable via the API, with all requested attributes but no allocated - * resources. Its state is `CREATING`. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation renders the instance immediately unreadable via the API. - * * The instance can be deleted. * All other attempts to modify the instance are - * rejected. - * - *

Upon completion of the returned operation: - * - *

* Billing for all successfully-allocated resources begins (some types may have lower - * than the requested levels). * Databases can be created in the instance. * The - * instance's allocated resource levels are readable via the API. * The instance's state - * becomes `READY`. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track - * creation of the instance. The [metadata][google.longrunning.Operation.metadata] field type is - * [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   ProjectName parent = ProjectName.of("[PROJECT]");
-   *   String instanceId = "";
-   *   Instance instance = Instance.newBuilder().build();
-   *   CreateInstanceRequest request = CreateInstanceRequest.newBuilder()
-   *     .setParent(parent.toString())
-   *     .setInstanceId(instanceId)
-   *     .setInstance(instance)
-   *     .build();
-   *   ApiFuture<Operation> future = instanceAdminClient.createInstanceCallable().futureCall(request);
-   *   // Do something
-   *   Operation response = future.get();
-   * }
-   * 
- */ - public final UnaryCallable createInstanceCallable() { - return stub.createInstanceCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Updates an instance, and begins allocating or releasing resources as requested. The returned - * [long-running operation][google.longrunning.Operation] can be used to track the progress of - * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. - * - *

Immediately upon completion of this request: - * - *

* For resource types for which a decrease in the instance's allocation has been - * requested, billing is based on the newly-requested level. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation sets its metadata's - * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins - * restoring resources to their pre-request values. The operation is guaranteed to succeed at - * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * - * All other attempts to modify the instance are rejected. * Reading the instance via the API - * continues to give the pre-request resource levels. - * - *

Upon completion of the returned operation: - * - *

* Billing begins for all successfully-allocated resources (some types may have lower - * than the requested levels). * All newly-reserved resources are available for serving the - * instance's tables. * The instance's new resource levels are readable via the API. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track the - * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is - * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Authorization requires `spanner.instances.update` permission on resource - * [name][google.spanner.admin.instance.v1.Instance.name]. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   Instance instance = Instance.newBuilder().build();
-   *   FieldMask fieldMask = FieldMask.newBuilder().build();
-   *   Instance response = instanceAdminClient.updateInstanceAsync(instance, fieldMask).get();
-   * }
-   * 
- * - * @param instance Required. The instance to update, which must always include the instance name. - * Otherwise, only fields mentioned in - * [field_mask][google.spanner.admin.instance.v1.UpdateInstanceRequest.field_mask] need be - * included. - * @param fieldMask Required. A mask specifying which fields in - * [Instance][google.spanner.admin.instance.v1.Instance] should be updated. The field mask - * must always be specified; this prevents any future fields in - * [Instance][google.spanner.admin.instance.v1.Instance] from being erased accidentally by - * clients that do not know about them. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture updateInstanceAsync( - Instance instance, FieldMask fieldMask) { - UpdateInstanceRequest request = - UpdateInstanceRequest.newBuilder().setInstance(instance).setFieldMask(fieldMask).build(); - return updateInstanceAsync(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Updates an instance, and begins allocating or releasing resources as requested. The returned - * [long-running operation][google.longrunning.Operation] can be used to track the progress of - * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. - * - *

Immediately upon completion of this request: - * - *

* For resource types for which a decrease in the instance's allocation has been - * requested, billing is based on the newly-requested level. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation sets its metadata's - * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins - * restoring resources to their pre-request values. The operation is guaranteed to succeed at - * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * - * All other attempts to modify the instance are rejected. * Reading the instance via the API - * continues to give the pre-request resource levels. - * - *

Upon completion of the returned operation: - * - *

* Billing begins for all successfully-allocated resources (some types may have lower - * than the requested levels). * All newly-reserved resources are available for serving the - * instance's tables. * The instance's new resource levels are readable via the API. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track the - * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is - * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Authorization requires `spanner.instances.update` permission on resource - * [name][google.spanner.admin.instance.v1.Instance.name]. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   Instance instance = Instance.newBuilder().build();
-   *   FieldMask fieldMask = FieldMask.newBuilder().build();
-   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
-   *     .setInstance(instance)
-   *     .setFieldMask(fieldMask)
-   *     .build();
-   *   Instance response = instanceAdminClient.updateInstanceAsync(request).get();
-   * }
-   * 
- * - * @param request The request object containing all of the parameters for the API call. - * @throws com.google.api.gax.rpc.ApiException if the remote call fails - */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public final OperationFuture updateInstanceAsync( - UpdateInstanceRequest request) { - return updateInstanceOperationCallable().futureCall(request); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Updates an instance, and begins allocating or releasing resources as requested. The returned - * [long-running operation][google.longrunning.Operation] can be used to track the progress of - * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. - * - *

Immediately upon completion of this request: - * - *

* For resource types for which a decrease in the instance's allocation has been - * requested, billing is based on the newly-requested level. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation sets its metadata's - * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins - * restoring resources to their pre-request values. The operation is guaranteed to succeed at - * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * - * All other attempts to modify the instance are rejected. * Reading the instance via the API - * continues to give the pre-request resource levels. - * - *

Upon completion of the returned operation: - * - *

* Billing begins for all successfully-allocated resources (some types may have lower - * than the requested levels). * All newly-reserved resources are available for serving the - * instance's tables. * The instance's new resource levels are readable via the API. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track the - * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is - * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Authorization requires `spanner.instances.update` permission on resource - * [name][google.spanner.admin.instance.v1.Instance.name]. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   Instance instance = Instance.newBuilder().build();
-   *   FieldMask fieldMask = FieldMask.newBuilder().build();
-   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
-   *     .setInstance(instance)
-   *     .setFieldMask(fieldMask)
-   *     .build();
-   *   OperationFuture<Instance, UpdateInstanceMetadata> future = instanceAdminClient.updateInstanceOperationCallable().futureCall(request);
-   *   // Do something
-   *   Instance response = future.get();
-   * }
-   * 
- */ - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public final OperationCallable - updateInstanceOperationCallable() { - return stub.updateInstanceOperationCallable(); - } - - // AUTO-GENERATED DOCUMENTATION AND METHOD - /** - * Updates an instance, and begins allocating or releasing resources as requested. The returned - * [long-running operation][google.longrunning.Operation] can be used to track the progress of - * updating the instance. If the named instance does not exist, returns `NOT_FOUND`. - * - *

Immediately upon completion of this request: - * - *

* For resource types for which a decrease in the instance's allocation has been - * requested, billing is based on the newly-requested level. - * - *

Until completion of the returned operation: - * - *

* Cancelling the operation sets its metadata's - * [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins - * restoring resources to their pre-request values. The operation is guaranteed to succeed at - * undoing all resource changes, after which point it terminates with a `CANCELLED` status. * - * All other attempts to modify the instance are rejected. * Reading the instance via the API - * continues to give the pre-request resource levels. - * - *

Upon completion of the returned operation: - * - *

* Billing begins for all successfully-allocated resources (some types may have lower - * than the requested levels). * All newly-reserved resources are available for serving the - * instance's tables. * The instance's new resource levels are readable via the API. - * - *

The returned [long-running operation][google.longrunning.Operation] will have a name of the - * format `<instance_name>/operations/<operation_id>` and can be used to track the - * instance modification. The [metadata][google.longrunning.Operation.metadata] field type is - * [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. The - * [response][google.longrunning.Operation.response] field type is - * [Instance][google.spanner.admin.instance.v1.Instance], if successful. - * - *

Authorization requires `spanner.instances.update` permission on resource - * [name][google.spanner.admin.instance.v1.Instance.name]. - * - *

Sample code: - * - *


-   * try (InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
-   *   Instance instance = Instance.newBuilder().build();
-   *   FieldMask fieldMask = FieldMask.newBuilder().build();
-   *   UpdateInstanceRequest request = UpdateInstanceRequest.newBuilder()
-   *     .setInstance(instance)
-   *     .setFieldMask(fieldMask)
-   *     .build();
-   *   ApiFuture<Operation> future = instanceAdminClient.updateInstanceCallable().futureCall(request);
-   *   // Do something
-   *   Operation response = future.get();
-   * }
-   * 
- */ - public final UnaryCallable updateInstanceCallable() { - return stub.updateInstanceCallable(); - } - // AUTO-GENERATED DOCUMENTATION AND METHOD /** * Deletes an instance. diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java index b64951873c..f9cdab9d26 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java @@ -89,29 +89,6 @@ @Generated("by gapic-generator") @BetaApi public class InstanceAdminSettings extends ClientSettings { - /** Returns the object with the settings used for calls to listInstanceConfigs. */ - public PagedCallSettings< - ListInstanceConfigsRequest, ListInstanceConfigsResponse, ListInstanceConfigsPagedResponse> - listInstanceConfigsSettings() { - return ((InstanceAdminStubSettings) getStubSettings()).listInstanceConfigsSettings(); - } - - /** Returns the object with the settings used for calls to getInstanceConfig. */ - public UnaryCallSettings getInstanceConfigSettings() { - return ((InstanceAdminStubSettings) getStubSettings()).getInstanceConfigSettings(); - } - - /** Returns the object with the settings used for calls to listInstances. */ - public PagedCallSettings - listInstancesSettings() { - return ((InstanceAdminStubSettings) getStubSettings()).listInstancesSettings(); - } - - /** Returns the object with the settings used for calls to getInstance. */ - public UnaryCallSettings getInstanceSettings() { - return ((InstanceAdminStubSettings) getStubSettings()).getInstanceSettings(); - } - /** Returns the object with the settings used for calls to createInstance. */ public UnaryCallSettings createInstanceSettings() { return ((InstanceAdminStubSettings) getStubSettings()).createInstanceSettings(); @@ -138,6 +115,29 @@ public UnaryCallSettings updateInstanceSetting return ((InstanceAdminStubSettings) getStubSettings()).updateInstanceOperationSettings(); } + /** Returns the object with the settings used for calls to listInstanceConfigs. */ + public PagedCallSettings< + ListInstanceConfigsRequest, ListInstanceConfigsResponse, ListInstanceConfigsPagedResponse> + listInstanceConfigsSettings() { + return ((InstanceAdminStubSettings) getStubSettings()).listInstanceConfigsSettings(); + } + + /** Returns the object with the settings used for calls to getInstanceConfig. */ + public UnaryCallSettings getInstanceConfigSettings() { + return ((InstanceAdminStubSettings) getStubSettings()).getInstanceConfigSettings(); + } + + /** Returns the object with the settings used for calls to listInstances. */ + public PagedCallSettings + listInstancesSettings() { + return ((InstanceAdminStubSettings) getStubSettings()).listInstancesSettings(); + } + + /** Returns the object with the settings used for calls to getInstance. */ + public UnaryCallSettings getInstanceSettings() { + return ((InstanceAdminStubSettings) getStubSettings()).getInstanceSettings(); + } + /** Returns the object with the settings used for calls to deleteInstance. */ public UnaryCallSettings deleteInstanceSettings() { return ((InstanceAdminStubSettings) getStubSettings()).deleteInstanceSettings(); @@ -256,6 +256,32 @@ public Builder applyToAllUnaryMethods( return this; } + /** Returns the builder for the settings used for calls to createInstance. */ + public UnaryCallSettings.Builder createInstanceSettings() { + return getStubSettingsBuilder().createInstanceSettings(); + } + + /** Returns the builder for the settings used for calls to createInstance. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings.Builder + createInstanceOperationSettings() { + return getStubSettingsBuilder().createInstanceOperationSettings(); + } + + /** Returns the builder for the settings used for calls to updateInstance. */ + public UnaryCallSettings.Builder updateInstanceSettings() { + return getStubSettingsBuilder().updateInstanceSettings(); + } + + /** Returns the builder for the settings used for calls to updateInstance. */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") + public OperationCallSettings.Builder + updateInstanceOperationSettings() { + return getStubSettingsBuilder().updateInstanceOperationSettings(); + } + /** Returns the builder for the settings used for calls to listInstanceConfigs. */ public PagedCallSettings.Builder< ListInstanceConfigsRequest, @@ -283,32 +309,6 @@ public UnaryCallSettings.Builder getInstanceSettin return getStubSettingsBuilder().getInstanceSettings(); } - /** Returns the builder for the settings used for calls to createInstance. */ - public UnaryCallSettings.Builder createInstanceSettings() { - return getStubSettingsBuilder().createInstanceSettings(); - } - - /** Returns the builder for the settings used for calls to createInstance. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings.Builder - createInstanceOperationSettings() { - return getStubSettingsBuilder().createInstanceOperationSettings(); - } - - /** Returns the builder for the settings used for calls to updateInstance. */ - public UnaryCallSettings.Builder updateInstanceSettings() { - return getStubSettingsBuilder().updateInstanceSettings(); - } - - /** Returns the builder for the settings used for calls to updateInstance. */ - @BetaApi( - "The surface for long-running operations is not stable yet and may change in the future.") - public OperationCallSettings.Builder - updateInstanceOperationSettings() { - return getStubSettingsBuilder().updateInstanceOperationSettings(); - } - /** Returns the builder for the settings used for calls to deleteInstance. */ public UnaryCallSettings.Builder deleteInstanceSettings() { return getStubSettingsBuilder().deleteInstanceSettings(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/GrpcInstanceAdminStub.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/GrpcInstanceAdminStub.java index bbc144e69a..f64f7275cb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/GrpcInstanceAdminStub.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/GrpcInstanceAdminStub.java @@ -66,6 +66,24 @@ @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class GrpcInstanceAdminStub extends InstanceAdminStub { + private static final MethodDescriptor + createInstanceMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.instance.v1.InstanceAdmin/CreateInstance") + .setRequestMarshaller( + ProtoUtils.marshaller(CreateInstanceRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) + .build(); + private static final MethodDescriptor + updateInstanceMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.spanner.admin.instance.v1.InstanceAdmin/UpdateInstance") + .setRequestMarshaller( + ProtoUtils.marshaller(UpdateInstanceRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) + .build(); private static final MethodDescriptor listInstanceConfigsMethodDescriptor = MethodDescriptor.newBuilder() @@ -103,24 +121,6 @@ public class GrpcInstanceAdminStub extends InstanceAdminStub { .setRequestMarshaller(ProtoUtils.marshaller(GetInstanceRequest.getDefaultInstance())) .setResponseMarshaller(ProtoUtils.marshaller(Instance.getDefaultInstance())) .build(); - private static final MethodDescriptor - createInstanceMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.instance.v1.InstanceAdmin/CreateInstance") - .setRequestMarshaller( - ProtoUtils.marshaller(CreateInstanceRequest.getDefaultInstance())) - .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) - .build(); - private static final MethodDescriptor - updateInstanceMethodDescriptor = - MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) - .setFullMethodName("google.spanner.admin.instance.v1.InstanceAdmin/UpdateInstance") - .setRequestMarshaller( - ProtoUtils.marshaller(UpdateInstanceRequest.getDefaultInstance())) - .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) - .build(); private static final MethodDescriptor deleteInstanceMethodDescriptor = MethodDescriptor.newBuilder() @@ -159,6 +159,12 @@ public class GrpcInstanceAdminStub extends InstanceAdminStub { private final BackgroundResource backgroundResources; private final GrpcOperationsStub operationsStub; + private final UnaryCallable createInstanceCallable; + private final OperationCallable + createInstanceOperationCallable; + private final UnaryCallable updateInstanceCallable; + private final OperationCallable + updateInstanceOperationCallable; private final UnaryCallable listInstanceConfigsCallable; private final UnaryCallable @@ -168,12 +174,6 @@ public class GrpcInstanceAdminStub extends InstanceAdminStub { private final UnaryCallable listInstancesPagedCallable; private final UnaryCallable getInstanceCallable; - private final UnaryCallable createInstanceCallable; - private final OperationCallable - createInstanceOperationCallable; - private final UnaryCallable updateInstanceCallable; - private final OperationCallable - updateInstanceOperationCallable; private final UnaryCallable deleteInstanceCallable; private final UnaryCallable setIamPolicyCallable; private final UnaryCallable getIamPolicyCallable; @@ -220,6 +220,32 @@ protected GrpcInstanceAdminStub( this.callableFactory = callableFactory; this.operationsStub = GrpcOperationsStub.create(clientContext, callableFactory); + GrpcCallSettings createInstanceTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(createInstanceMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(CreateInstanceRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("parent", String.valueOf(request.getParent())); + return params.build(); + } + }) + .build(); + GrpcCallSettings updateInstanceTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(updateInstanceMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(UpdateInstanceRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("instance.name", String.valueOf(request.getInstance().getName())); + return params.build(); + } + }) + .build(); GrpcCallSettings listInstanceConfigsTransportSettings = GrpcCallSettings.newBuilder() @@ -273,32 +299,6 @@ public Map extract(GetInstanceRequest request) { } }) .build(); - GrpcCallSettings createInstanceTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(createInstanceMethodDescriptor) - .setParamsExtractor( - new RequestParamsExtractor() { - @Override - public Map extract(CreateInstanceRequest request) { - ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("parent", String.valueOf(request.getParent())); - return params.build(); - } - }) - .build(); - GrpcCallSettings updateInstanceTransportSettings = - GrpcCallSettings.newBuilder() - .setMethodDescriptor(updateInstanceMethodDescriptor) - .setParamsExtractor( - new RequestParamsExtractor() { - @Override - public Map extract(UpdateInstanceRequest request) { - ImmutableMap.Builder params = ImmutableMap.builder(); - params.put("instance.name", String.valueOf(request.getInstance().getName())); - return params.build(); - } - }) - .build(); GrpcCallSettings deleteInstanceTransportSettings = GrpcCallSettings.newBuilder() .setMethodDescriptor(deleteInstanceMethodDescriptor) @@ -353,6 +353,24 @@ public Map extract(TestIamPermissionsRequest request) { }) .build(); + this.createInstanceCallable = + callableFactory.createUnaryCallable( + createInstanceTransportSettings, settings.createInstanceSettings(), clientContext); + this.createInstanceOperationCallable = + callableFactory.createOperationCallable( + createInstanceTransportSettings, + settings.createInstanceOperationSettings(), + clientContext, + this.operationsStub); + this.updateInstanceCallable = + callableFactory.createUnaryCallable( + updateInstanceTransportSettings, settings.updateInstanceSettings(), clientContext); + this.updateInstanceOperationCallable = + callableFactory.createOperationCallable( + updateInstanceTransportSettings, + settings.updateInstanceOperationSettings(), + clientContext, + this.operationsStub); this.listInstanceConfigsCallable = callableFactory.createUnaryCallable( listInstanceConfigsTransportSettings, @@ -377,24 +395,6 @@ public Map extract(TestIamPermissionsRequest request) { this.getInstanceCallable = callableFactory.createUnaryCallable( getInstanceTransportSettings, settings.getInstanceSettings(), clientContext); - this.createInstanceCallable = - callableFactory.createUnaryCallable( - createInstanceTransportSettings, settings.createInstanceSettings(), clientContext); - this.createInstanceOperationCallable = - callableFactory.createOperationCallable( - createInstanceTransportSettings, - settings.createInstanceOperationSettings(), - clientContext, - this.operationsStub); - this.updateInstanceCallable = - callableFactory.createUnaryCallable( - updateInstanceTransportSettings, settings.updateInstanceSettings(), clientContext); - this.updateInstanceOperationCallable = - callableFactory.createOperationCallable( - updateInstanceTransportSettings, - settings.updateInstanceOperationSettings(), - clientContext, - this.operationsStub); this.deleteInstanceCallable = callableFactory.createUnaryCallable( deleteInstanceTransportSettings, settings.deleteInstanceSettings(), clientContext); @@ -418,6 +418,26 @@ public GrpcOperationsStub getOperationsStub() { return operationsStub; } + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + createInstanceOperationCallable() { + return createInstanceOperationCallable; + } + + public UnaryCallable createInstanceCallable() { + return createInstanceCallable; + } + + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + updateInstanceOperationCallable() { + return updateInstanceOperationCallable; + } + + public UnaryCallable updateInstanceCallable() { + return updateInstanceCallable; + } + public UnaryCallable listInstanceConfigsPagedCallable() { return listInstanceConfigsPagedCallable; @@ -445,26 +465,6 @@ public UnaryCallable getInstanceCallable() { return getInstanceCallable; } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - createInstanceOperationCallable() { - return createInstanceOperationCallable; - } - - public UnaryCallable createInstanceCallable() { - return createInstanceCallable; - } - - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - updateInstanceOperationCallable() { - return updateInstanceOperationCallable; - } - - public UnaryCallable updateInstanceCallable() { - return updateInstanceCallable; - } - public UnaryCallable deleteInstanceCallable() { return deleteInstanceCallable; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStub.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStub.java index 77334eb1a2..085a696307 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStub.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStub.java @@ -60,6 +60,26 @@ public OperationsStub getOperationsStub() { throw new UnsupportedOperationException("Not implemented: getOperationsStub()"); } + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + createInstanceOperationCallable() { + throw new UnsupportedOperationException("Not implemented: createInstanceOperationCallable()"); + } + + public UnaryCallable createInstanceCallable() { + throw new UnsupportedOperationException("Not implemented: createInstanceCallable()"); + } + + @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallable + updateInstanceOperationCallable() { + throw new UnsupportedOperationException("Not implemented: updateInstanceOperationCallable()"); + } + + public UnaryCallable updateInstanceCallable() { + throw new UnsupportedOperationException("Not implemented: updateInstanceCallable()"); + } + public UnaryCallable listInstanceConfigsPagedCallable() { throw new UnsupportedOperationException("Not implemented: listInstanceConfigsPagedCallable()"); @@ -87,26 +107,6 @@ public UnaryCallable getInstanceCallable() { throw new UnsupportedOperationException("Not implemented: getInstanceCallable()"); } - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - createInstanceOperationCallable() { - throw new UnsupportedOperationException("Not implemented: createInstanceOperationCallable()"); - } - - public UnaryCallable createInstanceCallable() { - throw new UnsupportedOperationException("Not implemented: createInstanceCallable()"); - } - - @BetaApi("The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallable - updateInstanceOperationCallable() { - throw new UnsupportedOperationException("Not implemented: updateInstanceOperationCallable()"); - } - - public UnaryCallable updateInstanceCallable() { - throw new UnsupportedOperationException("Not implemented: updateInstanceCallable()"); - } - public UnaryCallable deleteInstanceCallable() { throw new UnsupportedOperationException("Not implemented: deleteInstanceCallable()"); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java index c975119498..4c31214912 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java @@ -114,6 +114,12 @@ public class InstanceAdminStubSettings extends StubSettings createInstanceSettings; + private final OperationCallSettings + createInstanceOperationSettings; + private final UnaryCallSettings updateInstanceSettings; + private final OperationCallSettings + updateInstanceOperationSettings; private final PagedCallSettings< ListInstanceConfigsRequest, ListInstanceConfigsResponse, ListInstanceConfigsPagedResponse> listInstanceConfigsSettings; @@ -123,41 +129,12 @@ public class InstanceAdminStubSettings extends StubSettings listInstancesSettings; private final UnaryCallSettings getInstanceSettings; - private final UnaryCallSettings createInstanceSettings; - private final OperationCallSettings - createInstanceOperationSettings; - private final UnaryCallSettings updateInstanceSettings; - private final OperationCallSettings - updateInstanceOperationSettings; private final UnaryCallSettings deleteInstanceSettings; private final UnaryCallSettings setIamPolicySettings; private final UnaryCallSettings getIamPolicySettings; private final UnaryCallSettings testIamPermissionsSettings; - /** Returns the object with the settings used for calls to listInstanceConfigs. */ - public PagedCallSettings< - ListInstanceConfigsRequest, ListInstanceConfigsResponse, ListInstanceConfigsPagedResponse> - listInstanceConfigsSettings() { - return listInstanceConfigsSettings; - } - - /** Returns the object with the settings used for calls to getInstanceConfig. */ - public UnaryCallSettings getInstanceConfigSettings() { - return getInstanceConfigSettings; - } - - /** Returns the object with the settings used for calls to listInstances. */ - public PagedCallSettings - listInstancesSettings() { - return listInstancesSettings; - } - - /** Returns the object with the settings used for calls to getInstance. */ - public UnaryCallSettings getInstanceSettings() { - return getInstanceSettings; - } - /** Returns the object with the settings used for calls to createInstance. */ public UnaryCallSettings createInstanceSettings() { return createInstanceSettings; @@ -182,6 +159,29 @@ public UnaryCallSettings updateInstanceSetting return updateInstanceOperationSettings; } + /** Returns the object with the settings used for calls to listInstanceConfigs. */ + public PagedCallSettings< + ListInstanceConfigsRequest, ListInstanceConfigsResponse, ListInstanceConfigsPagedResponse> + listInstanceConfigsSettings() { + return listInstanceConfigsSettings; + } + + /** Returns the object with the settings used for calls to getInstanceConfig. */ + public UnaryCallSettings getInstanceConfigSettings() { + return getInstanceConfigSettings; + } + + /** Returns the object with the settings used for calls to listInstances. */ + public PagedCallSettings + listInstancesSettings() { + return listInstancesSettings; + } + + /** Returns the object with the settings used for calls to getInstance. */ + public UnaryCallSettings getInstanceSettings() { + return getInstanceSettings; + } + /** Returns the object with the settings used for calls to deleteInstance. */ public UnaryCallSettings deleteInstanceSettings() { return deleteInstanceSettings; @@ -272,14 +272,14 @@ public Builder toBuilder() { protected InstanceAdminStubSettings(Builder settingsBuilder) throws IOException { super(settingsBuilder); - listInstanceConfigsSettings = settingsBuilder.listInstanceConfigsSettings().build(); - getInstanceConfigSettings = settingsBuilder.getInstanceConfigSettings().build(); - listInstancesSettings = settingsBuilder.listInstancesSettings().build(); - getInstanceSettings = settingsBuilder.getInstanceSettings().build(); createInstanceSettings = settingsBuilder.createInstanceSettings().build(); createInstanceOperationSettings = settingsBuilder.createInstanceOperationSettings().build(); updateInstanceSettings = settingsBuilder.updateInstanceSettings().build(); updateInstanceOperationSettings = settingsBuilder.updateInstanceOperationSettings().build(); + listInstanceConfigsSettings = settingsBuilder.listInstanceConfigsSettings().build(); + getInstanceConfigSettings = settingsBuilder.getInstanceConfigSettings().build(); + listInstancesSettings = settingsBuilder.listInstancesSettings().build(); + getInstanceSettings = settingsBuilder.getInstanceSettings().build(); deleteInstanceSettings = settingsBuilder.deleteInstanceSettings().build(); setIamPolicySettings = settingsBuilder.setIamPolicySettings().build(); getIamPolicySettings = settingsBuilder.getIamPolicySettings().build(); @@ -404,6 +404,16 @@ public ApiFuture getFuturePagedResponse( public static class Builder extends StubSettings.Builder { private final ImmutableList> unaryMethodSettingsBuilders; + private final UnaryCallSettings.Builder + createInstanceSettings; + private final OperationCallSettings.Builder< + CreateInstanceRequest, Instance, CreateInstanceMetadata> + createInstanceOperationSettings; + private final UnaryCallSettings.Builder + updateInstanceSettings; + private final OperationCallSettings.Builder< + UpdateInstanceRequest, Instance, UpdateInstanceMetadata> + updateInstanceOperationSettings; private final PagedCallSettings.Builder< ListInstanceConfigsRequest, ListInstanceConfigsResponse, @@ -415,16 +425,6 @@ public static class Builder extends StubSettings.Builder listInstancesSettings; private final UnaryCallSettings.Builder getInstanceSettings; - private final UnaryCallSettings.Builder - createInstanceSettings; - private final OperationCallSettings.Builder< - CreateInstanceRequest, Instance, CreateInstanceMetadata> - createInstanceOperationSettings; - private final UnaryCallSettings.Builder - updateInstanceSettings; - private final OperationCallSettings.Builder< - UpdateInstanceRequest, Instance, UpdateInstanceMetadata> - updateInstanceOperationSettings; private final UnaryCallSettings.Builder deleteInstanceSettings; private final UnaryCallSettings.Builder setIamPolicySettings; private final UnaryCallSettings.Builder getIamPolicySettings; @@ -438,11 +438,20 @@ public static class Builder extends StubSettings.Builder> definitions = ImmutableMap.builder(); definitions.put( - "idempotent", + "retry_policy_1_codes", ImmutableSet.copyOf( Lists.newArrayList( - StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE))); - definitions.put("non_idempotent", ImmutableSet.copyOf(Lists.newArrayList())); + StatusCode.Code.UNAVAILABLE, StatusCode.Code.DEADLINE_EXCEEDED))); + definitions.put( + "no_retry_2_codes", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put( + "retry_policy_2_codes", + ImmutableSet.copyOf( + Lists.newArrayList( + StatusCode.Code.UNAVAILABLE, StatusCode.Code.DEADLINE_EXCEEDED))); + definitions.put( + "no_retry_1_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -456,12 +465,41 @@ public static class Builder extends StubSettings.Builder>of( + createInstanceSettings, + updateInstanceSettings, listInstanceConfigsSettings, getInstanceConfigSettings, listInstancesSettings, getInstanceSettings, - createInstanceSettings, - updateInstanceSettings, deleteInstanceSettings, setIamPolicySettings, getIamPolicySettings, @@ -525,61 +563,61 @@ private static Builder createDefault() { private static Builder initDefaults(Builder builder) { builder - .listInstanceConfigsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .createInstanceSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); builder - .getInstanceConfigSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .updateInstanceSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")); builder - .listInstancesSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .listInstanceConfigsSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder - .getInstanceSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .getInstanceConfigSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder - .createInstanceSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .listInstancesSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder - .updateInstanceSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .getInstanceSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .deleteInstanceSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); builder .setIamPolicySettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_2_params")); builder .getIamPolicySettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_2_params")); builder .testIamPermissionsSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")); + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_2_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_2_params")); builder .createInstanceOperationSettings() .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Instance.class)) @@ -601,8 +639,8 @@ private static Builder initDefaults(Builder builder) { .setInitialCallSettings( UnaryCallSettings .newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("non_idempotent")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default")) + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params")) .build()) .setResponseTransformer( ProtoOperationTransformers.ResponseTransformer.create(Instance.class)) @@ -626,14 +664,14 @@ private static Builder initDefaults(Builder builder) { protected Builder(InstanceAdminStubSettings settings) { super(settings); - listInstanceConfigsSettings = settings.listInstanceConfigsSettings.toBuilder(); - getInstanceConfigSettings = settings.getInstanceConfigSettings.toBuilder(); - listInstancesSettings = settings.listInstancesSettings.toBuilder(); - getInstanceSettings = settings.getInstanceSettings.toBuilder(); createInstanceSettings = settings.createInstanceSettings.toBuilder(); createInstanceOperationSettings = settings.createInstanceOperationSettings.toBuilder(); updateInstanceSettings = settings.updateInstanceSettings.toBuilder(); updateInstanceOperationSettings = settings.updateInstanceOperationSettings.toBuilder(); + listInstanceConfigsSettings = settings.listInstanceConfigsSettings.toBuilder(); + getInstanceConfigSettings = settings.getInstanceConfigSettings.toBuilder(); + listInstancesSettings = settings.listInstancesSettings.toBuilder(); + getInstanceSettings = settings.getInstanceSettings.toBuilder(); deleteInstanceSettings = settings.deleteInstanceSettings.toBuilder(); setIamPolicySettings = settings.setIamPolicySettings.toBuilder(); getIamPolicySettings = settings.getIamPolicySettings.toBuilder(); @@ -641,12 +679,12 @@ protected Builder(InstanceAdminStubSettings settings) { unaryMethodSettingsBuilders = ImmutableList.>of( + createInstanceSettings, + updateInstanceSettings, listInstanceConfigsSettings, getInstanceConfigSettings, listInstancesSettings, getInstanceSettings, - createInstanceSettings, - updateInstanceSettings, deleteInstanceSettings, setIamPolicySettings, getIamPolicySettings, @@ -669,6 +707,32 @@ public Builder applyToAllUnaryMethods( return unaryMethodSettingsBuilders; } + /** Returns the builder for the settings used for calls to createInstance. */ + public UnaryCallSettings.Builder createInstanceSettings() { + return createInstanceSettings; + } + + /** Returns the builder for the settings used for calls to createInstance. */ + @BetaApi( + "The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings.Builder + createInstanceOperationSettings() { + return createInstanceOperationSettings; + } + + /** Returns the builder for the settings used for calls to updateInstance. */ + public UnaryCallSettings.Builder updateInstanceSettings() { + return updateInstanceSettings; + } + + /** Returns the builder for the settings used for calls to updateInstance. */ + @BetaApi( + "The surface for use by generated code is not stable yet and may change in the future.") + public OperationCallSettings.Builder + updateInstanceOperationSettings() { + return updateInstanceOperationSettings; + } + /** Returns the builder for the settings used for calls to listInstanceConfigs. */ public PagedCallSettings.Builder< ListInstanceConfigsRequest, @@ -696,32 +760,6 @@ public UnaryCallSettings.Builder getInstanceSettin return getInstanceSettings; } - /** Returns the builder for the settings used for calls to createInstance. */ - public UnaryCallSettings.Builder createInstanceSettings() { - return createInstanceSettings; - } - - /** Returns the builder for the settings used for calls to createInstance. */ - @BetaApi( - "The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings.Builder - createInstanceOperationSettings() { - return createInstanceOperationSettings; - } - - /** Returns the builder for the settings used for calls to updateInstance. */ - public UnaryCallSettings.Builder updateInstanceSettings() { - return updateInstanceSettings; - } - - /** Returns the builder for the settings used for calls to updateInstance. */ - @BetaApi( - "The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings.Builder - updateInstanceOperationSettings() { - return updateInstanceOperationSettings; - } - /** Returns the builder for the settings used for calls to deleteInstance. */ public UnaryCallSettings.Builder deleteInstanceSettings() { return deleteInstanceSettings; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java index f99372d498..e288143469 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java @@ -386,12 +386,17 @@ public static class Builder extends StubSettings.Builder> definitions = ImmutableMap.builder(); definitions.put( - "idempotent", + "retry_policy_1_codes", ImmutableSet.copyOf(Lists.newArrayList(StatusCode.Code.UNAVAILABLE))); - definitions.put("non_idempotent", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); definitions.put( - "long_running", + "retry_policy_3_codes", ImmutableSet.copyOf(Lists.newArrayList(StatusCode.Code.UNAVAILABLE))); + definitions.put( + "retry_policy_2_codes", + ImmutableSet.copyOf(Lists.newArrayList(StatusCode.Code.UNAVAILABLE))); + definitions.put( + "no_retry_1_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -410,29 +415,39 @@ public static class Builder extends StubSettings.Builder> callsWithDefaultSettings = + List> callsWithRetry1 = + Arrays.asList(stubSettings.listSessionsSettings(), stubSettings.commitSettings()); + List> callsWithRetry2 = + Arrays.asList(stubSettings.batchCreateSessionsSettings()); + List> callsWithRetry3 = Arrays.asList( - stubSettings.beginTransactionSettings(), stubSettings.createSessionSettings(), + stubSettings.getSessionSettings(), stubSettings.deleteSessionSettings(), - stubSettings.executeBatchDmlSettings(), stubSettings.executeSqlSettings(), - stubSettings.getSessionSettings(), - stubSettings.listSessionsSettings(), - stubSettings.partitionQuerySettings(), - stubSettings.partitionReadSettings(), + stubSettings.executeBatchDmlSettings(), stubSettings.readSettings(), - stubSettings.rollbackSettings()); - List> callsWithStreamingSettings = + stubSettings.beginTransactionSettings(), + stubSettings.rollbackSettings(), + stubSettings.partitionQuerySettings(), + stubSettings.partitionReadSettings()); + List> callsWithNoRetry1 = Arrays.asList( stubSettings.executeStreamingSqlSettings(), stubSettings.streamingReadSettings()); - List> callsWithLongRunningSettings = - Arrays.asList(stubSettings.commitSettings()); - for (UnaryCallSettings callSettings : callsWithDefaultSettings) { - assertThat(callSettings.getRetrySettings()).isEqualTo(defaultRetrySettings); + for (UnaryCallSettings callSettings : callsWithRetry1) { + assertThat(callSettings.getRetrySettings()).isEqualTo(witRetryPolicy1); } - for (ServerStreamingCallSettings callSettings : callsWithStreamingSettings) { - assertThat(callSettings.getRetrySettings()).isEqualTo(streamingRetrySettings); + for (UnaryCallSettings callSettings : callsWithRetry2) { + assertThat(callSettings.getRetrySettings()).isEqualTo(witRetryPolicy2); } - for (UnaryCallSettings callSettings : callsWithLongRunningSettings) { - assertThat(callSettings.getRetrySettings()).isEqualTo(longRunningRetrySettings); + for (UnaryCallSettings callSettings : callsWithRetry3) { + assertThat(callSettings.getRetrySettings()).isEqualTo(witRetryPolicy3); + } + for (ServerStreamingCallSettings callSettings : callsWithNoRetry1) { + assertThat(callSettings.getRetrySettings()).isEqualTo(noRetry1); } } @@ -213,26 +224,54 @@ public void testSpannerCustomRetrySettings() { @Test public void testDatabaseAdminDefaultRetrySettings() { - RetrySettings defaultRetrySettings = + RetrySettings withRetryPolicy1 = RetrySettings.newBuilder() .setInitialRetryDelay(Duration.ofMillis(1000L)) .setRetryDelayMultiplier(1.3) .setMaxRetryDelay(Duration.ofMillis(32000L)) - .setInitialRpcTimeout(Duration.ofMillis(60000L)) + .setInitialRpcTimeout(Duration.ofMillis(3600000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMillis(60000L)) - .setTotalTimeout(Duration.ofMillis(600000L)) + .setMaxRpcTimeout(Duration.ofMillis(3600000L)) + .setTotalTimeout(Duration.ofMillis(3600000L)) + .build(); + RetrySettings withRetryPolicy2 = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(1000L)) + .setRetryDelayMultiplier(1.3) + .setMaxRetryDelay(Duration.ofMillis(32000L)) + .setInitialRpcTimeout(Duration.ofMillis(30000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(30000L)) + .setTotalTimeout(Duration.ofMillis(30000L)) + .build(); + RetrySettings noRetryPolicy2 = + RetrySettings.newBuilder() + .setInitialRpcTimeout(Duration.ofMillis(30000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(30000L)) + .setTotalTimeout(Duration.ofMillis(30000L)) .build(); SpannerOptions options = SpannerOptions.newBuilder().setProjectId("test-project").build(); DatabaseAdminStubSettings stubSettings = options.getDatabaseAdminStubSettings(); - List> callsWithDefaultSettings = + List> callsWithRetryPolicy1 = Arrays.asList( stubSettings.dropDatabaseSettings(), - stubSettings.getDatabaseDdlSettings(), - stubSettings.getDatabaseSettings()); + stubSettings.getDatabaseSettings(), + stubSettings.getDatabaseDdlSettings()); + List> callsWithRetryPolicy2 = + Arrays.asList(stubSettings.getIamPolicySettings()); + List> callsWithNoRetry2 = + Arrays.asList( + stubSettings.setIamPolicySettings(), stubSettings.testIamPermissionsSettings()); - for (UnaryCallSettings callSettings : callsWithDefaultSettings) { - assertThat(callSettings.getRetrySettings()).isEqualTo(defaultRetrySettings); + for (UnaryCallSettings callSettings : callsWithRetryPolicy1) { + assertThat(callSettings.getRetrySettings()).isEqualTo(withRetryPolicy1); + } + for (UnaryCallSettings callSettings : callsWithRetryPolicy2) { + assertThat(callSettings.getRetrySettings()).isEqualTo(withRetryPolicy2); + } + for (UnaryCallSettings callSettings : callsWithNoRetry2) { + assertThat(callSettings.getRetrySettings()).isEqualTo(noRetryPolicy2); } } @@ -275,28 +314,68 @@ public void testDatabaseAdminCustomRetrySettings() { @Test public void testInstanceAdminDefaultRetrySettings() { - RetrySettings defaultRetrySettings = + RetrySettings withRetryPolicy1 = RetrySettings.newBuilder() .setInitialRetryDelay(Duration.ofMillis(1000L)) .setRetryDelayMultiplier(1.3) .setMaxRetryDelay(Duration.ofMillis(32000L)) - .setInitialRpcTimeout(Duration.ofMillis(60000L)) + .setInitialRpcTimeout(Duration.ofMillis(3600000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMillis(60000L)) - .setTotalTimeout(Duration.ofMillis(600000L)) + .setMaxRpcTimeout(Duration.ofMillis(3600000L)) + .setTotalTimeout(Duration.ofMillis(3600000L)) + .build(); + RetrySettings withRetryPolicy2 = + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(1000L)) + .setRetryDelayMultiplier(1.3) + .setMaxRetryDelay(Duration.ofMillis(32000L)) + .setInitialRpcTimeout(Duration.ofMillis(30000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(30000L)) + .setTotalTimeout(Duration.ofMillis(30000L)) + .build(); + RetrySettings noRetryPolicy1 = + RetrySettings.newBuilder() + .setInitialRpcTimeout(Duration.ofMillis(3600000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(3600000L)) + .setTotalTimeout(Duration.ofMillis(3600000L)) + .build(); + RetrySettings noRetryPolicy2 = + RetrySettings.newBuilder() + .setInitialRpcTimeout(Duration.ofMillis(30000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ofMillis(30000L)) + .setTotalTimeout(Duration.ofMillis(30000L)) .build(); SpannerOptions options = SpannerOptions.newBuilder().setProjectId("test-project").build(); InstanceAdminStubSettings stubSettings = options.getInstanceAdminStubSettings(); - List> callsWithDefaultSettings = + List> callsWithRetryPolicy1 = Arrays.asList( stubSettings.getInstanceConfigSettings(), stubSettings.listInstanceConfigsSettings(), stubSettings.deleteInstanceSettings(), stubSettings.getInstanceSettings(), stubSettings.listInstancesSettings()); + List> callsWithRetryPolicy2 = + Arrays.asList(stubSettings.getIamPolicySettings()); + List> callsWithNoRetryPolicy1 = + Arrays.asList(stubSettings.createInstanceSettings(), stubSettings.updateInstanceSettings()); + List> callsWithNoRetryPolicy2 = + Arrays.asList( + stubSettings.setIamPolicySettings(), stubSettings.testIamPermissionsSettings()); - for (UnaryCallSettings callSettings : callsWithDefaultSettings) { - assertThat(callSettings.getRetrySettings()).isEqualTo(defaultRetrySettings); + for (UnaryCallSettings callSettings : callsWithRetryPolicy1) { + assertThat(callSettings.getRetrySettings()).isEqualTo(withRetryPolicy1); + } + for (UnaryCallSettings callSettings : callsWithRetryPolicy2) { + assertThat(callSettings.getRetrySettings()).isEqualTo(withRetryPolicy2); + } + for (UnaryCallSettings callSettings : callsWithNoRetryPolicy1) { + assertThat(callSettings.getRetrySettings()).isEqualTo(noRetryPolicy1); + } + for (UnaryCallSettings callSettings : callsWithNoRetryPolicy2) { + assertThat(callSettings.getRetrySettings()).isEqualTo(noRetryPolicy2); } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java index 78efb14466..e304a4ef50 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java @@ -121,30 +121,29 @@ public void tearDown() throws Exception { @Test @SuppressWarnings("all") - public void listDatabasesTest() { - String nextPageToken = ""; - Database databasesElement = Database.newBuilder().build(); - List databases = Arrays.asList(databasesElement); - ListDatabasesResponse expectedResponse = - ListDatabasesResponse.newBuilder() - .setNextPageToken(nextPageToken) - .addAllDatabases(databases) + public void createDatabaseTest() throws Exception { + DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + Database expectedResponse = Database.newBuilder().setName(name.toString()).build(); + Operation resultOperation = + Operation.newBuilder() + .setName("createDatabaseTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) .build(); - mockDatabaseAdmin.addResponse(expectedResponse); + mockDatabaseAdmin.addResponse(resultOperation); InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + String createStatement = "createStatement552974828"; - ListDatabasesPagedResponse pagedListResponse = client.listDatabases(parent); - - List resources = Lists.newArrayList(pagedListResponse.iterateAll()); - Assert.assertEquals(1, resources.size()); - Assert.assertEquals(expectedResponse.getDatabasesList().get(0), resources.get(0)); + Database actualResponse = client.createDatabaseAsync(parent, createStatement).get(); + Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockDatabaseAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - ListDatabasesRequest actualRequest = (ListDatabasesRequest) actualRequests.get(0); + CreateDatabaseRequest actualRequest = (CreateDatabaseRequest) actualRequests.get(0); Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); + Assert.assertEquals(createStatement, actualRequest.getCreateStatement()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -153,45 +152,47 @@ public void listDatabasesTest() { @Test @SuppressWarnings("all") - public void listDatabasesExceptionTest() throws Exception { + public void createDatabaseExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockDatabaseAdmin.addException(exception); try { InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + String createStatement = "createStatement552974828"; - client.listDatabases(parent); + client.createDatabaseAsync(parent, createStatement).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception + } catch (ExecutionException e) { + Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); + InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); + Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } @Test @SuppressWarnings("all") - public void createDatabaseTest() throws Exception { - DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - Database expectedResponse = Database.newBuilder().setName(name.toString()).build(); + public void updateDatabaseDdlTest() throws Exception { + Empty expectedResponse = Empty.newBuilder().build(); Operation resultOperation = Operation.newBuilder() - .setName("createDatabaseTest") + .setName("updateDatabaseDdlTest") .setDone(true) .setResponse(Any.pack(expectedResponse)) .build(); mockDatabaseAdmin.addResponse(resultOperation); - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - String createStatement = "createStatement552974828"; + DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + List statements = new ArrayList<>(); - Database actualResponse = client.createDatabaseAsync(parent, createStatement).get(); + Empty actualResponse = client.updateDatabaseDdlAsync(database, statements).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockDatabaseAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - CreateDatabaseRequest actualRequest = (CreateDatabaseRequest) actualRequests.get(0); + UpdateDatabaseDdlRequest actualRequest = (UpdateDatabaseDdlRequest) actualRequests.get(0); - Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); - Assert.assertEquals(createStatement, actualRequest.getCreateStatement()); + Assert.assertEquals(database, DatabaseName.parse(actualRequest.getDatabase())); + Assert.assertEquals(statements, actualRequest.getStatementsList()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -200,15 +201,15 @@ public void createDatabaseTest() throws Exception { @Test @SuppressWarnings("all") - public void createDatabaseExceptionTest() throws Exception { + public void updateDatabaseDdlExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockDatabaseAdmin.addException(exception); try { - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - String createStatement = "createStatement552974828"; + DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + List statements = new ArrayList<>(); - client.createDatabaseAsync(parent, createStatement).get(); + client.updateDatabaseDdlAsync(database, statements).get(); Assert.fail("No exception raised"); } catch (ExecutionException e) { Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); @@ -219,21 +220,38 @@ public void createDatabaseExceptionTest() throws Exception { @Test @SuppressWarnings("all") - public void getDatabaseTest() { - DatabaseName name2 = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - Database expectedResponse = Database.newBuilder().setName(name2.toString()).build(); - mockDatabaseAdmin.addResponse(expectedResponse); + public void createBackupTest() throws Exception { + DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + BackupName name = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); + long sizeBytes = 1796325715L; + Backup expectedResponse = + Backup.newBuilder() + .setDatabase(database.toString()) + .setName(name.toString()) + .setSizeBytes(sizeBytes) + .build(); + Operation resultOperation = + Operation.newBuilder() + .setName("createBackupTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) + .build(); + mockDatabaseAdmin.addResponse(resultOperation); - DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + Backup backup = Backup.newBuilder().build(); + String backupId = "backupId1355353272"; - Database actualResponse = client.getDatabase(name); + Backup actualResponse = client.createBackupAsync(parent, backup, backupId).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockDatabaseAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - GetDatabaseRequest actualRequest = (GetDatabaseRequest) actualRequests.get(0); + CreateBackupRequest actualRequest = (CreateBackupRequest) actualRequests.get(0); - Assert.assertEquals(name, DatabaseName.parse(actualRequest.getName())); + Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); + Assert.assertEquals(backup, actualRequest.getBackup()); + Assert.assertEquals(backupId, actualRequest.getBackupId()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -242,44 +260,51 @@ public void getDatabaseTest() { @Test @SuppressWarnings("all") - public void getDatabaseExceptionTest() throws Exception { + public void createBackupExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockDatabaseAdmin.addException(exception); try { - DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + Backup backup = Backup.newBuilder().build(); + String backupId = "backupId1355353272"; - client.getDatabase(name); + client.createBackupAsync(parent, backup, backupId).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception + } catch (ExecutionException e) { + Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); + InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); + Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } @Test @SuppressWarnings("all") - public void updateDatabaseDdlTest() throws Exception { - Empty expectedResponse = Empty.newBuilder().build(); + public void restoreDatabaseTest() throws Exception { + DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + Database expectedResponse = Database.newBuilder().setName(name.toString()).build(); Operation resultOperation = Operation.newBuilder() - .setName("updateDatabaseDdlTest") + .setName("restoreDatabaseTest") .setDone(true) .setResponse(Any.pack(expectedResponse)) .build(); mockDatabaseAdmin.addResponse(resultOperation); - DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - List statements = new ArrayList<>(); + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + String databaseId = "databaseId816491103"; + BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); - Empty actualResponse = client.updateDatabaseDdlAsync(database, statements).get(); + Database actualResponse = client.restoreDatabaseAsync(parent, databaseId, backup).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockDatabaseAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - UpdateDatabaseDdlRequest actualRequest = (UpdateDatabaseDdlRequest) actualRequests.get(0); + RestoreDatabaseRequest actualRequest = (RestoreDatabaseRequest) actualRequests.get(0); - Assert.assertEquals(database, DatabaseName.parse(actualRequest.getDatabase())); - Assert.assertEquals(statements, actualRequest.getStatementsList()); + Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); + Assert.assertEquals(databaseId, actualRequest.getDatabaseId()); + Assert.assertEquals(backup, BackupName.parse(actualRequest.getBackup())); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -288,15 +313,16 @@ public void updateDatabaseDdlTest() throws Exception { @Test @SuppressWarnings("all") - public void updateDatabaseDdlExceptionTest() throws Exception { + public void restoreDatabaseExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockDatabaseAdmin.addException(exception); try { - DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - List statements = new ArrayList<>(); + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + String databaseId = "databaseId816491103"; + BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); - client.updateDatabaseDdlAsync(database, statements).get(); + client.restoreDatabaseAsync(parent, databaseId, backup).get(); Assert.fail("No exception raised"); } catch (ExecutionException e) { Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); @@ -305,6 +331,93 @@ public void updateDatabaseDdlExceptionTest() throws Exception { } } + @Test + @SuppressWarnings("all") + public void listDatabasesTest() { + String nextPageToken = ""; + Database databasesElement = Database.newBuilder().build(); + List databases = Arrays.asList(databasesElement); + ListDatabasesResponse expectedResponse = + ListDatabasesResponse.newBuilder() + .setNextPageToken(nextPageToken) + .addAllDatabases(databases) + .build(); + mockDatabaseAdmin.addResponse(expectedResponse); + + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + + ListDatabasesPagedResponse pagedListResponse = client.listDatabases(parent); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getDatabasesList().get(0), resources.get(0)); + + List actualRequests = mockDatabaseAdmin.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ListDatabasesRequest actualRequest = (ListDatabasesRequest) actualRequests.get(0); + + Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + @SuppressWarnings("all") + public void listDatabasesExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); + mockDatabaseAdmin.addException(exception); + + try { + InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); + + client.listDatabases(parent); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception + } + } + + @Test + @SuppressWarnings("all") + public void getDatabaseTest() { + DatabaseName name2 = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + Database expectedResponse = Database.newBuilder().setName(name2.toString()).build(); + mockDatabaseAdmin.addResponse(expectedResponse); + + DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + + Database actualResponse = client.getDatabase(name); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockDatabaseAdmin.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + GetDatabaseRequest actualRequest = (GetDatabaseRequest) actualRequests.get(0); + + Assert.assertEquals(name, DatabaseName.parse(actualRequest.getName())); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + @SuppressWarnings("all") + public void getDatabaseExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); + mockDatabaseAdmin.addException(exception); + + try { + DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); + + client.getDatabase(name); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception + } + } + @Test @SuppressWarnings("all") public void dropDatabaseTest() { @@ -504,66 +617,6 @@ public void testIamPermissionsExceptionTest() throws Exception { } } - @Test - @SuppressWarnings("all") - public void createBackupTest() throws Exception { - DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - BackupName name = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); - long sizeBytes = 1796325715L; - Backup expectedResponse = - Backup.newBuilder() - .setDatabase(database.toString()) - .setName(name.toString()) - .setSizeBytes(sizeBytes) - .build(); - Operation resultOperation = - Operation.newBuilder() - .setName("createBackupTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) - .build(); - mockDatabaseAdmin.addResponse(resultOperation); - - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - Backup backup = Backup.newBuilder().build(); - String backupId = "backupId1355353272"; - - Backup actualResponse = client.createBackupAsync(parent, backup, backupId).get(); - Assert.assertEquals(expectedResponse, actualResponse); - - List actualRequests = mockDatabaseAdmin.getRequests(); - Assert.assertEquals(1, actualRequests.size()); - CreateBackupRequest actualRequest = (CreateBackupRequest) actualRequests.get(0); - - Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); - Assert.assertEquals(backup, actualRequest.getBackup()); - Assert.assertEquals(backupId, actualRequest.getBackupId()); - Assert.assertTrue( - channelProvider.isHeaderSent( - ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), - GaxGrpcProperties.getDefaultApiClientHeaderPattern())); - } - - @Test - @SuppressWarnings("all") - public void createBackupExceptionTest() throws Exception { - StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); - mockDatabaseAdmin.addException(exception); - - try { - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - Backup backup = Backup.newBuilder().build(); - String backupId = "backupId1355353272"; - - client.createBackupAsync(parent, backup, backupId).get(); - Assert.fail("No exception raised"); - } catch (ExecutionException e) { - Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); - InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); - Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); - } - } - @Test @SuppressWarnings("all") public void getBackupTest() { @@ -744,59 +797,6 @@ public void listBackupsExceptionTest() throws Exception { } } - @Test - @SuppressWarnings("all") - public void restoreDatabaseTest() throws Exception { - DatabaseName name = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); - Database expectedResponse = Database.newBuilder().setName(name.toString()).build(); - Operation resultOperation = - Operation.newBuilder() - .setName("restoreDatabaseTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) - .build(); - mockDatabaseAdmin.addResponse(resultOperation); - - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - String databaseId = "databaseId816491103"; - BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); - - Database actualResponse = client.restoreDatabaseAsync(parent, databaseId, backup).get(); - Assert.assertEquals(expectedResponse, actualResponse); - - List actualRequests = mockDatabaseAdmin.getRequests(); - Assert.assertEquals(1, actualRequests.size()); - RestoreDatabaseRequest actualRequest = (RestoreDatabaseRequest) actualRequests.get(0); - - Assert.assertEquals(parent, InstanceName.parse(actualRequest.getParent())); - Assert.assertEquals(databaseId, actualRequest.getDatabaseId()); - Assert.assertEquals(backup, BackupName.parse(actualRequest.getBackup())); - Assert.assertTrue( - channelProvider.isHeaderSent( - ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), - GaxGrpcProperties.getDefaultApiClientHeaderPattern())); - } - - @Test - @SuppressWarnings("all") - public void restoreDatabaseExceptionTest() throws Exception { - StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); - mockDatabaseAdmin.addException(exception); - - try { - InstanceName parent = InstanceName.of("[PROJECT]", "[INSTANCE]"); - String databaseId = "databaseId816491103"; - BackupName backup = BackupName.of("[PROJECT]", "[INSTANCE]", "[BACKUP]"); - - client.restoreDatabaseAsync(parent, databaseId, backup).get(); - Assert.fail("No exception raised"); - } catch (ExecutionException e) { - Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); - InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); - Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); - } - } - @Test @SuppressWarnings("all") public void listDatabaseOperationsTest() { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java index 406171d3aa..889de79200 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminClientTest.java @@ -109,30 +109,40 @@ public void tearDown() throws Exception { @Test @SuppressWarnings("all") - public void listInstanceConfigsTest() { - String nextPageToken = ""; - InstanceConfig instanceConfigsElement = InstanceConfig.newBuilder().build(); - List instanceConfigs = Arrays.asList(instanceConfigsElement); - ListInstanceConfigsResponse expectedResponse = - ListInstanceConfigsResponse.newBuilder() - .setNextPageToken(nextPageToken) - .addAllInstanceConfigs(instanceConfigs) + public void createInstanceTest() throws Exception { + InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); + InstanceConfigName config = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); + String displayName = "displayName1615086568"; + int nodeCount = 1539922066; + Instance expectedResponse = + Instance.newBuilder() + .setName(name.toString()) + .setConfig(config.toString()) + .setDisplayName(displayName) + .setNodeCount(nodeCount) .build(); - mockInstanceAdmin.addResponse(expectedResponse); + Operation resultOperation = + Operation.newBuilder() + .setName("createInstanceTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) + .build(); + mockInstanceAdmin.addResponse(resultOperation); ProjectName parent = ProjectName.of("[PROJECT]"); + String instanceId = "instanceId-2101995259"; + Instance instance = Instance.newBuilder().build(); - ListInstanceConfigsPagedResponse pagedListResponse = client.listInstanceConfigs(parent); - - List resources = Lists.newArrayList(pagedListResponse.iterateAll()); - Assert.assertEquals(1, resources.size()); - Assert.assertEquals(expectedResponse.getInstanceConfigsList().get(0), resources.get(0)); + Instance actualResponse = client.createInstanceAsync(parent, instanceId, instance).get(); + Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - ListInstanceConfigsRequest actualRequest = (ListInstanceConfigsRequest) actualRequests.get(0); + CreateInstanceRequest actualRequest = (CreateInstanceRequest) actualRequests.get(0); Assert.assertEquals(parent, ProjectName.parse(actualRequest.getParent())); + Assert.assertEquals(instanceId, actualRequest.getInstanceId()); + Assert.assertEquals(instance, actualRequest.getInstance()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -141,39 +151,58 @@ public void listInstanceConfigsTest() { @Test @SuppressWarnings("all") - public void listInstanceConfigsExceptionTest() throws Exception { + public void createInstanceExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { ProjectName parent = ProjectName.of("[PROJECT]"); + String instanceId = "instanceId-2101995259"; + Instance instance = Instance.newBuilder().build(); - client.listInstanceConfigs(parent); + client.createInstanceAsync(parent, instanceId, instance).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception + } catch (ExecutionException e) { + Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); + InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); + Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } @Test @SuppressWarnings("all") - public void getInstanceConfigTest() { - InstanceConfigName name2 = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); + public void updateInstanceTest() throws Exception { + InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); + InstanceConfigName config = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); String displayName = "displayName1615086568"; - InstanceConfig expectedResponse = - InstanceConfig.newBuilder().setName(name2.toString()).setDisplayName(displayName).build(); - mockInstanceAdmin.addResponse(expectedResponse); + int nodeCount = 1539922066; + Instance expectedResponse = + Instance.newBuilder() + .setName(name.toString()) + .setConfig(config.toString()) + .setDisplayName(displayName) + .setNodeCount(nodeCount) + .build(); + Operation resultOperation = + Operation.newBuilder() + .setName("updateInstanceTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) + .build(); + mockInstanceAdmin.addResponse(resultOperation); - InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); + Instance instance = Instance.newBuilder().build(); + FieldMask fieldMask = FieldMask.newBuilder().build(); - InstanceConfig actualResponse = client.getInstanceConfig(name); + Instance actualResponse = client.updateInstanceAsync(instance, fieldMask).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - GetInstanceConfigRequest actualRequest = (GetInstanceConfigRequest) actualRequests.get(0); + UpdateInstanceRequest actualRequest = (UpdateInstanceRequest) actualRequests.get(0); - Assert.assertEquals(name, InstanceConfigName.parse(actualRequest.getName())); + Assert.assertEquals(instance, actualRequest.getInstance()); + Assert.assertEquals(fieldMask, actualRequest.getFieldMask()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -182,44 +211,47 @@ public void getInstanceConfigTest() { @Test @SuppressWarnings("all") - public void getInstanceConfigExceptionTest() throws Exception { + public void updateInstanceExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { - InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); + Instance instance = Instance.newBuilder().build(); + FieldMask fieldMask = FieldMask.newBuilder().build(); - client.getInstanceConfig(name); + client.updateInstanceAsync(instance, fieldMask).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception + } catch (ExecutionException e) { + Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); + InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); + Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } @Test @SuppressWarnings("all") - public void listInstancesTest() { + public void listInstanceConfigsTest() { String nextPageToken = ""; - Instance instancesElement = Instance.newBuilder().build(); - List instances = Arrays.asList(instancesElement); - ListInstancesResponse expectedResponse = - ListInstancesResponse.newBuilder() + InstanceConfig instanceConfigsElement = InstanceConfig.newBuilder().build(); + List instanceConfigs = Arrays.asList(instanceConfigsElement); + ListInstanceConfigsResponse expectedResponse = + ListInstanceConfigsResponse.newBuilder() .setNextPageToken(nextPageToken) - .addAllInstances(instances) + .addAllInstanceConfigs(instanceConfigs) .build(); mockInstanceAdmin.addResponse(expectedResponse); ProjectName parent = ProjectName.of("[PROJECT]"); - ListInstancesPagedResponse pagedListResponse = client.listInstances(parent); + ListInstanceConfigsPagedResponse pagedListResponse = client.listInstanceConfigs(parent); - List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); Assert.assertEquals(1, resources.size()); - Assert.assertEquals(expectedResponse.getInstancesList().get(0), resources.get(0)); + Assert.assertEquals(expectedResponse.getInstanceConfigsList().get(0), resources.get(0)); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - ListInstancesRequest actualRequest = (ListInstancesRequest) actualRequests.get(0); + ListInstanceConfigsRequest actualRequest = (ListInstanceConfigsRequest) actualRequests.get(0); Assert.assertEquals(parent, ProjectName.parse(actualRequest.getParent())); Assert.assertTrue( @@ -230,14 +262,14 @@ public void listInstancesTest() { @Test @SuppressWarnings("all") - public void listInstancesExceptionTest() throws Exception { + public void listInstanceConfigsExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { ProjectName parent = ProjectName.of("[PROJECT]"); - client.listInstances(parent); + client.listInstanceConfigs(parent); Assert.fail("No exception raised"); } catch (InvalidArgumentException e) { // Expected exception @@ -246,30 +278,23 @@ public void listInstancesExceptionTest() throws Exception { @Test @SuppressWarnings("all") - public void getInstanceTest() { - InstanceName name2 = InstanceName.of("[PROJECT]", "[INSTANCE]"); - InstanceConfigName config = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); + public void getInstanceConfigTest() { + InstanceConfigName name2 = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); String displayName = "displayName1615086568"; - int nodeCount = 1539922066; - Instance expectedResponse = - Instance.newBuilder() - .setName(name2.toString()) - .setConfig(config.toString()) - .setDisplayName(displayName) - .setNodeCount(nodeCount) - .build(); + InstanceConfig expectedResponse = + InstanceConfig.newBuilder().setName(name2.toString()).setDisplayName(displayName).build(); mockInstanceAdmin.addResponse(expectedResponse); - InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); + InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); - Instance actualResponse = client.getInstance(name); + InstanceConfig actualResponse = client.getInstanceConfig(name); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - GetInstanceRequest actualRequest = (GetInstanceRequest) actualRequests.get(0); + GetInstanceConfigRequest actualRequest = (GetInstanceConfigRequest) actualRequests.get(0); - Assert.assertEquals(name, InstanceName.parse(actualRequest.getName())); + Assert.assertEquals(name, InstanceConfigName.parse(actualRequest.getName())); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -278,14 +303,14 @@ public void getInstanceTest() { @Test @SuppressWarnings("all") - public void getInstanceExceptionTest() throws Exception { + public void getInstanceConfigExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { - InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); + InstanceConfigName name = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); - client.getInstance(name); + client.getInstanceConfig(name); Assert.fail("No exception raised"); } catch (InvalidArgumentException e) { // Expected exception @@ -294,40 +319,30 @@ public void getInstanceExceptionTest() throws Exception { @Test @SuppressWarnings("all") - public void createInstanceTest() throws Exception { - InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); - InstanceConfigName config = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); - String displayName = "displayName1615086568"; - int nodeCount = 1539922066; - Instance expectedResponse = - Instance.newBuilder() - .setName(name.toString()) - .setConfig(config.toString()) - .setDisplayName(displayName) - .setNodeCount(nodeCount) - .build(); - Operation resultOperation = - Operation.newBuilder() - .setName("createInstanceTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) + public void listInstancesTest() { + String nextPageToken = ""; + Instance instancesElement = Instance.newBuilder().build(); + List instances = Arrays.asList(instancesElement); + ListInstancesResponse expectedResponse = + ListInstancesResponse.newBuilder() + .setNextPageToken(nextPageToken) + .addAllInstances(instances) .build(); - mockInstanceAdmin.addResponse(resultOperation); + mockInstanceAdmin.addResponse(expectedResponse); ProjectName parent = ProjectName.of("[PROJECT]"); - String instanceId = "instanceId-2101995259"; - Instance instance = Instance.newBuilder().build(); - Instance actualResponse = client.createInstanceAsync(parent, instanceId, instance).get(); - Assert.assertEquals(expectedResponse, actualResponse); + ListInstancesPagedResponse pagedListResponse = client.listInstances(parent); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getInstancesList().get(0), resources.get(0)); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - CreateInstanceRequest actualRequest = (CreateInstanceRequest) actualRequests.get(0); + ListInstancesRequest actualRequest = (ListInstancesRequest) actualRequests.get(0); Assert.assertEquals(parent, ProjectName.parse(actualRequest.getParent())); - Assert.assertEquals(instanceId, actualRequest.getInstanceId()); - Assert.assertEquals(instance, actualRequest.getInstance()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -336,58 +351,46 @@ public void createInstanceTest() throws Exception { @Test @SuppressWarnings("all") - public void createInstanceExceptionTest() throws Exception { + public void listInstancesExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { ProjectName parent = ProjectName.of("[PROJECT]"); - String instanceId = "instanceId-2101995259"; - Instance instance = Instance.newBuilder().build(); - client.createInstanceAsync(parent, instanceId, instance).get(); + client.listInstances(parent); Assert.fail("No exception raised"); - } catch (ExecutionException e) { - Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); - InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); - Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); + } catch (InvalidArgumentException e) { + // Expected exception } } @Test @SuppressWarnings("all") - public void updateInstanceTest() throws Exception { - InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); + public void getInstanceTest() { + InstanceName name2 = InstanceName.of("[PROJECT]", "[INSTANCE]"); InstanceConfigName config = InstanceConfigName.of("[PROJECT]", "[INSTANCE_CONFIG]"); String displayName = "displayName1615086568"; int nodeCount = 1539922066; Instance expectedResponse = Instance.newBuilder() - .setName(name.toString()) + .setName(name2.toString()) .setConfig(config.toString()) .setDisplayName(displayName) .setNodeCount(nodeCount) .build(); - Operation resultOperation = - Operation.newBuilder() - .setName("updateInstanceTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) - .build(); - mockInstanceAdmin.addResponse(resultOperation); + mockInstanceAdmin.addResponse(expectedResponse); - Instance instance = Instance.newBuilder().build(); - FieldMask fieldMask = FieldMask.newBuilder().build(); + InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); - Instance actualResponse = client.updateInstanceAsync(instance, fieldMask).get(); + Instance actualResponse = client.getInstance(name); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockInstanceAdmin.getRequests(); Assert.assertEquals(1, actualRequests.size()); - UpdateInstanceRequest actualRequest = (UpdateInstanceRequest) actualRequests.get(0); + GetInstanceRequest actualRequest = (GetInstanceRequest) actualRequests.get(0); - Assert.assertEquals(instance, actualRequest.getInstance()); - Assert.assertEquals(fieldMask, actualRequest.getFieldMask()); + Assert.assertEquals(name, InstanceName.parse(actualRequest.getName())); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -396,20 +399,17 @@ public void updateInstanceTest() throws Exception { @Test @SuppressWarnings("all") - public void updateInstanceExceptionTest() throws Exception { + public void getInstanceExceptionTest() throws Exception { StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT); mockInstanceAdmin.addException(exception); try { - Instance instance = Instance.newBuilder().build(); - FieldMask fieldMask = FieldMask.newBuilder().build(); + InstanceName name = InstanceName.of("[PROJECT]", "[INSTANCE]"); - client.updateInstanceAsync(instance, fieldMask).get(); + client.getInstance(name); Assert.fail("No exception raised"); - } catch (ExecutionException e) { - Assert.assertEquals(InvalidArgumentException.class, e.getCause().getClass()); - InvalidArgumentException apiException = (InvalidArgumentException) e.getCause(); - Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); + } catch (InvalidArgumentException e) { + // Expected exception } } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupProto.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupProto.java index 330156f140..2aaecf7bcd 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupProto.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/BackupProto.java @@ -130,12 +130,14 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + ".Operation\022\027\n\017next_page_token\030\002 \001(\t\"f\n\nB" + "ackupInfo\022\016\n\006backup\030\001 \001(\t\022/\n\013create_time" + "\030\002 \001(\0132\032.google.protobuf.Timestamp\022\027\n\017so" - + "urce_database\030\003 \001(\tB\321\001\n$com.google.spann" + + "urce_database\030\003 \001(\tB\377\001\n$com.google.spann" + "er.admin.database.v1B\013BackupProtoP\001ZHgoo" + "gle.golang.org/genproto/googleapis/spann" + "er/admin/database/v1;database\252\002&Google.C" + "loud.Spanner.Admin.Database.V1\312\002&Google\\" - + "Cloud\\Spanner\\Admin\\Database\\V1b\006proto3" + + "Cloud\\Spanner\\Admin\\Database\\V1\352\002+Google" + + "::Cloud::Spanner::Admin::Database::V1b\006p" + + "roto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CommonProto.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CommonProto.java index 0ea75df21d..657d73efc9 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CommonProto.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CommonProto.java @@ -48,12 +48,13 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "\030\n\020progress_percent\030\001 \001(\005\022.\n\nstart_time\030" + "\002 \001(\0132\032.google.protobuf.Timestamp\022,\n\010end" + "_time\030\003 \001(\0132\032.google.protobuf.TimestampB" - + "\321\001\n$com.google.spanner.admin.database.v1" + + "\377\001\n$com.google.spanner.admin.database.v1" + "B\013CommonProtoP\001ZHgoogle.golang.org/genpr" + "oto/googleapis/spanner/admin/database/v1" + ";database\252\002&Google.Cloud.Spanner.Admin.D" + "atabase.V1\312\002&Google\\Cloud\\Spanner\\Admin\\" - + "Database\\V1b\006proto3" + + "Database\\V1\352\002+Google::Cloud::Spanner::Ad" + + "min::Database::V1b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java index 910a1a9c13..9af8119d2c 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java @@ -180,7 +180,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "a\022\014\n\004name\030\001 \001(\t\022E\n\010progress\030\002 \001(\01323.goog" + "le.spanner.admin.database.v1.OperationPr" + "ogress*5\n\021RestoreSourceType\022\024\n\020TYPE_UNSP" - + "ECIFIED\020\000\022\n\n\006BACKUP\020\0012\362\036\n\rDatabaseAdmin\022" + + "ECIFIED\020\000\022\n\n\006BACKUP\020\0012\223\037\n\rDatabaseAdmin\022" + "\300\001\n\rListDatabases\0226.google.spanner.admin" + ".database.v1.ListDatabasesRequest\0327.goog" + "le.spanner.admin.database.v1.ListDatabas" @@ -233,61 +233,63 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "es/*}:testIamPermissions:\001*ZG\"B/v1/{reso" + "urce=projects/*/instances/*/backups/*}:t" + "estIamPermissions:\001*\332A\024resource,permissi" - + "ons\022\376\001\n\014CreateBackup\0225.google.spanner.ad" + + "ons\022\237\002\n\014CreateBackup\0225.google.spanner.ad" + "min.database.v1.CreateBackupRequest\032\035.go" - + "ogle.longrunning.Operation\"\227\001\202\323\344\223\0025\"+/v1" + + "ogle.longrunning.Operation\"\270\001\202\323\344\223\0025\"+/v1" + "/{parent=projects/*/instances/*}/backups" - + ":\006backup\332A\027parent,backup,backup_id\312A?\n\006B" - + "ackup\0225google.spanner.admin.database.v1." - + "CreateBackupMetadata\022\245\001\n\tGetBackup\0222.goo" - + "gle.spanner.admin.database.v1.GetBackupR" - + "equest\032(.google.spanner.admin.database.v" - + "1.Backup\":\202\323\344\223\002-\022+/v1/{name=projects/*/i" - + "nstances/*/backups/*}\332A\004name\022\310\001\n\014UpdateB" - + "ackup\0225.google.spanner.admin.database.v1" - + ".UpdateBackupRequest\032(.google.spanner.ad" - + "min.database.v1.Backup\"W\202\323\344\223\002<22/v1/{bac" - + "kup.name=projects/*/instances/*/backups/" - + "*}:\006backup\332A\022backup,update_mask\022\231\001\n\014Dele" - + "teBackup\0225.google.spanner.admin.database" - + ".v1.DeleteBackupRequest\032\026.google.protobu" - + "f.Empty\":\202\323\344\223\002-*+/v1/{name=projects/*/in" - + "stances/*/backups/*}\332A\004name\022\270\001\n\013ListBack" - + "ups\0224.google.spanner.admin.database.v1.L" - + "istBackupsRequest\0325.google.spanner.admin" - + ".database.v1.ListBackupsResponse\"<\202\323\344\223\002-" - + "\022+/v1/{parent=projects/*/instances/*}/ba" - + "ckups\332A\006parent\022\261\002\n\017RestoreDatabase\0228.goo" - + "gle.spanner.admin.database.v1.RestoreDat" - + "abaseRequest\032\035.google.longrunning.Operat" - + "ion\"\304\001\202\323\344\223\002:\"5/v1/{parent=projects/*/ins" - + "tances/*}/databases:restore:\001*\332A\031parent," - + "database_id,backup\312Ae\n)google.spanner.ad" - + "min.database.v1.Database\0228google.spanner" - + ".admin.database.v1.RestoreDatabaseMetada" - + "ta\022\344\001\n\026ListDatabaseOperations\022?.google.s" - + "panner.admin.database.v1.ListDatabaseOpe" - + "rationsRequest\032@.google.spanner.admin.da" - + "tabase.v1.ListDatabaseOperationsResponse" - + "\"G\202\323\344\223\0028\0226/v1/{parent=projects/*/instanc" - + "es/*}/databaseOperations\332A\006parent\022\334\001\n\024Li" - + "stBackupOperations\022=.google.spanner.admi" - + "n.database.v1.ListBackupOperationsReques" - + "t\032>.google.spanner.admin.database.v1.Lis" - + "tBackupOperationsResponse\"E\202\323\344\223\0026\0224/v1/{" - + "parent=projects/*/instances/*}/backupOpe" - + "rations\332A\006parent\032x\312A\026spanner.googleapis." - + "com\322A\\https://www.googleapis.com/auth/cl" - + "oud-platform,https://www.googleapis.com/" - + "auth/spanner.adminB\254\002\n$com.google.spanne" - + "r.admin.database.v1B\031SpannerDatabaseAdmi" - + "nProtoP\001ZHgoogle.golang.org/genproto/goo" - + "gleapis/spanner/admin/database/v1;databa" - + "se\252\002&Google.Cloud.Spanner.Admin.Database" - + ".V1\312\002&Google\\Cloud\\Spanner\\Admin\\Databas" - + "e\\V1\352AJ\n\037spanner.googleapis.com/Instance" - + "\022\'projects/{project}/instances/{instance" - + "}b\006proto3" + + ":\006backup\332A\027parent,backup,backup_id\312A`\n\'g" + + "oogle.spanner.admin.database.v1.Backup\0225" + + "google.spanner.admin.database.v1.CreateB" + + "ackupMetadata\022\245\001\n\tGetBackup\0222.google.spa" + + "nner.admin.database.v1.GetBackupRequest\032" + + "(.google.spanner.admin.database.v1.Backu" + + "p\":\202\323\344\223\002-\022+/v1/{name=projects/*/instance" + + "s/*/backups/*}\332A\004name\022\310\001\n\014UpdateBackup\0225" + + ".google.spanner.admin.database.v1.Update" + + "BackupRequest\032(.google.spanner.admin.dat" + + "abase.v1.Backup\"W\202\323\344\223\002<22/v1/{backup.nam" + + "e=projects/*/instances/*/backups/*}:\006bac" + + "kup\332A\022backup,update_mask\022\231\001\n\014DeleteBacku" + + "p\0225.google.spanner.admin.database.v1.Del" + + "eteBackupRequest\032\026.google.protobuf.Empty" + + "\":\202\323\344\223\002-*+/v1/{name=projects/*/instances" + + "/*/backups/*}\332A\004name\022\270\001\n\013ListBackups\0224.g" + + "oogle.spanner.admin.database.v1.ListBack" + + "upsRequest\0325.google.spanner.admin.databa" + + "se.v1.ListBackupsResponse\"<\202\323\344\223\002-\022+/v1/{" + + "parent=projects/*/instances/*}/backups\332A" + + "\006parent\022\261\002\n\017RestoreDatabase\0228.google.spa" + + "nner.admin.database.v1.RestoreDatabaseRe" + + "quest\032\035.google.longrunning.Operation\"\304\001\202" + + "\323\344\223\002:\"5/v1/{parent=projects/*/instances/" + + "*}/databases:restore:\001*\332A\031parent,databas" + + "e_id,backup\312Ae\n)google.spanner.admin.dat" + + "abase.v1.Database\0228google.spanner.admin." + + "database.v1.RestoreDatabaseMetadata\022\344\001\n\026" + + "ListDatabaseOperations\022?.google.spanner." + + "admin.database.v1.ListDatabaseOperations" + + "Request\032@.google.spanner.admin.database." + + "v1.ListDatabaseOperationsResponse\"G\202\323\344\223\002" + + "8\0226/v1/{parent=projects/*/instances/*}/d" + + "atabaseOperations\332A\006parent\022\334\001\n\024ListBacku" + + "pOperations\022=.google.spanner.admin.datab" + + "ase.v1.ListBackupOperationsRequest\032>.goo" + + "gle.spanner.admin.database.v1.ListBackup" + + "OperationsResponse\"E\202\323\344\223\0026\0224/v1/{parent=" + + "projects/*/instances/*}/backupOperations" + + "\332A\006parent\032x\312A\026spanner.googleapis.com\322A\\h" + + "ttps://www.googleapis.com/auth/cloud-pla" + + "tform,https://www.googleapis.com/auth/sp" + + "anner.adminB\332\002\n$com.google.spanner.admin" + + ".database.v1B\031SpannerDatabaseAdminProtoP" + + "\001ZHgoogle.golang.org/genproto/googleapis" + + "/spanner/admin/database/v1;database\252\002&Go" + + "ogle.Cloud.Spanner.Admin.Database.V1\312\002&G" + + "oogle\\Cloud\\Spanner\\Admin\\Database\\V1\352\002+" + + "Google::Cloud::Spanner::Admin::Database:" + + ":V1\352AJ\n\037spanner.googleapis.com/Instance\022" + + "\'projects/{project}/instances/{instance}" + + "b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/backup.proto b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/backup.proto index b883adf34c..e33faddddf 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/backup.proto +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/backup.proto @@ -30,6 +30,7 @@ option java_multiple_files = true; option java_outer_classname = "BackupProto"; option java_package = "com.google.spanner.admin.database.v1"; option php_namespace = "Google\\Cloud\\Spanner\\Admin\\Database\\V1"; +option ruby_package = "Google::Cloud::Spanner::Admin::Database::V1"; // A backup of a Cloud Spanner database. message Backup { diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/common.proto b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/common.proto index 4914cb8ac7..27ecb0a98b 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/common.proto +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/common.proto @@ -26,6 +26,7 @@ option java_multiple_files = true; option java_outer_classname = "CommonProto"; option java_package = "com.google.spanner.admin.database.v1"; option php_namespace = "Google\\Cloud\\Spanner\\Admin\\Database\\V1"; +option ruby_package = "Google::Cloud::Spanner::Admin::Database::V1"; // Encapsulates progress related information for a Cloud Spanner long // running operation. diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto index d48adc8aba..af440c1a36 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto @@ -34,6 +34,7 @@ option java_multiple_files = true; option java_outer_classname = "SpannerDatabaseAdminProto"; option java_package = "com.google.spanner.admin.database.v1"; option php_namespace = "Google\\Cloud\\Spanner\\Admin\\Database\\V1"; +option ruby_package = "Google::Cloud::Spanner::Admin::Database::V1"; option (google.api.resource_definition) = { type: "spanner.googleapis.com/Instance" pattern: "projects/{project}/instances/{instance}" @@ -206,7 +207,7 @@ service DatabaseAdmin { }; option (google.api.method_signature) = "parent,backup,backup_id"; option (google.longrunning.operation_info) = { - response_type: "Backup" + response_type: "google.spanner.admin.database.v1.Backup" metadata_type: "google.spanner.admin.database.v1.CreateBackupMetadata" }; } diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/SpannerInstanceAdminProto.java b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/SpannerInstanceAdminProto.java index 62e2a4dca1..64fee15512 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/SpannerInstanceAdminProto.java +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/java/com/google/spanner/admin/instance/v1/SpannerInstanceAdminProto.java @@ -222,13 +222,14 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "ce,permissions\032x\312A\026spanner.googleapis.co" + "m\322A\\https://www.googleapis.com/auth/clou" + "d-platform,https://www.googleapis.com/au" - + "th/spanner.adminB\337\001\n$com.google.spanner." + + "th/spanner.adminB\215\002\n$com.google.spanner." + "admin.instance.v1B\031SpannerInstanceAdminP" + "rotoP\001ZHgoogle.golang.org/genproto/googl" + "eapis/spanner/admin/instance/v1;instance" + "\252\002&Google.Cloud.Spanner.Admin.Instance.V" + "1\312\002&Google\\Cloud\\Spanner\\Admin\\Instance\\" - + "V1b\006proto3" + + "V1\352\002+Google::Cloud::Spanner::Admin::Inst" + + "ance::V1b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-admin-instance-v1/src/main/proto/google/spanner/admin/instance/v1/spanner_instance_admin.proto b/proto-google-cloud-spanner-admin-instance-v1/src/main/proto/google/spanner/admin/instance/v1/spanner_instance_admin.proto index 6a068baca2..54767bf263 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/src/main/proto/google/spanner/admin/instance/v1/spanner_instance_admin.proto +++ b/proto-google-cloud-spanner-admin-instance-v1/src/main/proto/google/spanner/admin/instance/v1/spanner_instance_admin.proto @@ -33,6 +33,7 @@ option java_multiple_files = true; option java_outer_classname = "SpannerInstanceAdminProto"; option java_package = "com.google.spanner.admin.instance.v1"; option php_namespace = "Google\\Cloud\\Spanner\\Admin\\Instance\\V1"; +option ruby_package = "Google::Cloud::Spanner::Admin::Instance::V1"; // Cloud Spanner Instance Admin API // diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeysProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeysProto.java index 8021353174..9c9b6318d1 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeysProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/KeysProto.java @@ -55,11 +55,12 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "H\001B\020\n\016start_key_typeB\016\n\014end_key_type\"l\n\006" + "KeySet\022(\n\004keys\030\001 \003(\0132\032.google.protobuf.L" + "istValue\022+\n\006ranges\030\002 \003(\0132\033.google.spanne" - + "r.v1.KeyRange\022\013\n\003all\030\003 \001(\010B\222\001\n\025com.googl" + + "r.v1.KeyRange\022\013\n\003all\030\003 \001(\010B\257\001\n\025com.googl" + "e.spanner.v1B\tKeysProtoP\001Z8google.golang" + ".org/genproto/googleapis/spanner/v1;span" + "ner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\C" - + "loud\\Spanner\\V1b\006proto3" + + "loud\\Spanner\\V1\352\002\032Google::Cloud::Spanner" + + "::V1b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/MutationProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/MutationProto.java index 8dd9e0420c..27ce2b4f3a 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/MutationProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/MutationProto.java @@ -63,11 +63,11 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "lues\030\003 \003(\0132\032.google.protobuf.ListValue\032C" + "\n\006Delete\022\r\n\005table\030\001 \001(\t\022*\n\007key_set\030\002 \001(\013" + "2\031.google.spanner.v1.KeySetB\013\n\toperation" - + "B\226\001\n\025com.google.spanner.v1B\rMutationProt" + + "B\263\001\n\025com.google.spanner.v1B\rMutationProt" + "oP\001Z8google.golang.org/genproto/googleap" + "is/spanner/v1;spanner\252\002\027Google.Cloud.Spa" - + "nner.V1\312\002\027Google\\Cloud\\Spanner\\V1b\006proto" - + "3" + + "nner.V1\312\002\027Google\\Cloud\\Spanner\\V1\352\002\032Goog" + + "le::Cloud::Spanner::V1b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlanProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlanProto.java index 4276b984cc..03c05431d0 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlanProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/QueryPlanProto.java @@ -76,11 +76,12 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "ue\030\002 \001(\005:\0028\001\"8\n\004Kind\022\024\n\020KIND_UNSPECIFIED" + "\020\000\022\016\n\nRELATIONAL\020\001\022\n\n\006SCALAR\020\002\"<\n\tQueryP" + "lan\022/\n\nplan_nodes\030\001 \003(\0132\033.google.spanner" - + ".v1.PlanNodeB\227\001\n\025com.google.spanner.v1B\016" + + ".v1.PlanNodeB\264\001\n\025com.google.spanner.v1B\016" + "QueryPlanProtoP\001Z8google.golang.org/genp" + "roto/googleapis/spanner/v1;spanner\252\002\027Goo" + "gle.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Span" - + "ner\\V1b\006proto3" + + "ner\\V1\352\002\032Google::Cloud::Spanner::V1b\006pro" + + "to3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetProto.java index 08e001c03b..48157af205 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/ResultSetProto.java @@ -74,11 +74,12 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "gle.spanner.v1.QueryPlan\022,\n\013query_stats\030" + "\002 \001(\0132\027.google.protobuf.Struct\022\031\n\017row_co" + "unt_exact\030\003 \001(\003H\000\022\037\n\025row_count_lower_bou" - + "nd\030\004 \001(\003H\000B\013\n\trow_countB\232\001\n\025com.google.s" + + "nd\030\004 \001(\003H\000B\013\n\trow_countB\267\001\n\025com.google.s" + "panner.v1B\016ResultSetProtoP\001Z8google.gola" + "ng.org/genproto/googleapis/spanner/v1;sp" + "anner\370\001\001\252\002\027Google.Cloud.Spanner.V1\312\002\027Goo" - + "gle\\Cloud\\Spanner\\V1b\006proto3" + + "gle\\Cloud\\Spanner\\V1\352\002\032Google::Cloud::Sp" + + "anner::V1b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( diff --git a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/SpannerProto.java b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/SpannerProto.java index eb528acbc1..0932ab5d52 100644 --- a/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/SpannerProto.java +++ b/proto-google-cloud-spanner-v1/src/main/java/com/google/spanner/v1/SpannerProto.java @@ -332,13 +332,14 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + ":\001*\032w\312A\026spanner.googleapis.com\322A[https:/" + "/www.googleapis.com/auth/cloud-platform," + "https://www.googleapis.com/auth/spanner." - + "dataB\367\001\n\025com.google.spanner.v1B\014SpannerP" + + "dataB\224\002\n\025com.google.spanner.v1B\014SpannerP" + "rotoP\001Z8google.golang.org/genproto/googl" + "eapis/spanner/v1;spanner\252\002\027Google.Cloud." - + "Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1\352A_\n" - + "\037spanner.googleapis.com/Database\022 Date: Tue, 14 Jul 2020 08:19:49 +0200 Subject: [PATCH 53/55] fix: check if emulator is running if env var is set (#340) * fix: check if emulator is running if env var is set * fix: only test for emulator if no channel provider is set --- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 26e6101e02..b1e571510d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -42,10 +42,12 @@ import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.StreamController; import com.google.api.gax.rpc.TransportChannelProvider; +import com.google.api.gax.rpc.UnavailableException; import com.google.api.gax.rpc.WatchdogProvider; import com.google.api.pathtemplate.PathTemplate; import com.google.cloud.RetryHelper; import com.google.cloud.grpc.GrpcTransportOptions; +import com.google.cloud.spanner.ErrorCode; import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.SpannerOptions; @@ -55,6 +57,7 @@ import com.google.cloud.spanner.admin.database.v1.stub.GrpcDatabaseAdminStub; import com.google.cloud.spanner.admin.instance.v1.stub.GrpcInstanceAdminStub; import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStub; +import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStubSettings; import com.google.cloud.spanner.spi.v1.SpannerRpc.Option; import com.google.cloud.spanner.v1.stub.GrpcSpannerStub; import com.google.cloud.spanner.v1.stub.SpannerStub; @@ -136,6 +139,7 @@ import com.google.spanner.v1.Transaction; import io.grpc.CallCredentials; import io.grpc.Context; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -401,11 +405,57 @@ public GapicSpannerRpc(final SpannerOptions options) { .setStreamWatchdogProvider(watchdogProvider) .build(); this.databaseAdminStub = GrpcDatabaseAdminStub.create(this.databaseAdminStubSettings); + + // Check whether the SPANNER_EMULATOR_HOST env var has been set, and if so, if the emulator is + // actually running. + checkEmulatorConnection(options, channelProvider, credentialsProvider); } catch (Exception e) { throw newSpannerException(e); } } + private static void checkEmulatorConnection( + SpannerOptions options, + TransportChannelProvider channelProvider, + CredentialsProvider credentialsProvider) + throws IOException { + final String emulatorHost = System.getenv("SPANNER_EMULATOR_HOST"); + // Only do the check if the emulator environment variable has been set to localhost. + if (options.getChannelProvider() == null + && emulatorHost != null + && options.getHost() != null + && options.getHost().startsWith("http://localhost") + && options.getHost().endsWith(emulatorHost)) { + // Do a quick check to see if the emulator is actually running. + try { + InstanceAdminStubSettings.Builder testEmulatorSettings = + options + .getInstanceAdminStubSettings() + .toBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(credentialsProvider); + testEmulatorSettings + .listInstanceConfigsSettings() + .setSimpleTimeoutNoRetries(Duration.ofSeconds(10L)); + try (GrpcInstanceAdminStub stub = + GrpcInstanceAdminStub.create(testEmulatorSettings.build())) { + stub.listInstanceConfigsCallable() + .call( + ListInstanceConfigsRequest.newBuilder() + .setParent(String.format("projects/%s", options.getProjectId())) + .build()); + } + } catch (UnavailableException e) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.UNAVAILABLE, + String.format( + "The environment variable SPANNER_EMULATOR_HOST has been set to %s, but no running emulator could be found at that address.\n" + + "Did you forget to start the emulator, or to unset the environment variable?", + emulatorHost)); + } + } + } + private static final class OperationFutureRetryAlgorithm implements ResultRetryAlgorithm> { private static final ImmutableList RETRYABLE_CODES = From f89cd040a308badb46b5f3847242c6474df78df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 14 Jul 2020 13:15:10 +0200 Subject: [PATCH 54/55] test: fix flaky ITTransactionRetryTest (#342) --- .../cloud/spanner/connection/it/ITTransactionRetryTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java index 60e85c7858..1259e2ab8d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITTransactionRetryTest.java @@ -367,9 +367,6 @@ public void testMultipleAborts() { connection.commit(); assertThat(RETRY_STATISTICS.totalSuccessfulRetries >= 3, is(true)); - assertThat( - RETRY_STATISTICS.totalNestedAborts, - is(equalTo(RETRY_STATISTICS.totalSuccessfulRetries - 3))); // verify that the insert succeeded try (ResultSet rs = connection.executeQuery(Statement.of("SELECT COUNT(*) AS C FROM TEST"))) { assertThat(rs.next(), is(true)); From 3dcd9a745fa713ca6dc9e0913b24048c5bd3cbdd Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 15 Jul 2020 04:00:37 +0200 Subject: [PATCH 55/55] chore(deps): update dependency com.google.cloud:libraries-bom to v8.1.0 (#350) --- samples/snippets/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 60797f3fca..9452eb4d39 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 8.0.0 + 8.1.0 pom import