From 8060e5b34d1a571b26bd631a86d6a10b9838d9b8 Mon Sep 17 00:00:00 2001
From: "release-please[bot]"
<55107282+release-please[bot]@users.noreply.github.com>
Date: Mon, 17 Apr 2023 07:50:12 +0000
Subject: [PATCH 01/15] chore(main): release 6.40.2-SNAPSHOT (#2386)
:robot: I have created a release *beep* *boop*
---
### Updating meta-information for bleeding-edge SNAPSHOT release.
---
This PR was generated with [Release Please](https://togithub.com/googleapis/release-please). See [documentation](https://togithub.com/googleapis/release-please#release-please).
---
google-cloud-spanner-bom/pom.xml | 20 +++++++++----------
google-cloud-spanner-executor/pom.xml | 4 ++--
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 | 16 +++++++--------
12 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml
index 334e33464eb..c72af3981da 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
- 6.40.1
+ 6.40.2-SNAPSHOT
pom
com.google.cloud
@@ -53,48 +53,48 @@
com.google.cloud
google-cloud-spanner
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.cloud
google-cloud-spanner-executor
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.cloud
google-cloud-spanner
test-jar
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-admin-instance-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-admin-database-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
proto-google-cloud-spanner-admin-instance-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
proto-google-cloud-spanner-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
proto-google-cloud-spanner-admin-database-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml
index 28db2caaa8d..52d152f0050 100644
--- a/google-cloud-spanner-executor/pom.xml
+++ b/google-cloud-spanner-executor/pom.xml
@@ -5,14 +5,14 @@
4.0.0
com.google.cloud
google-cloud-spanner-executor
- 6.40.1
+ 6.40.2-SNAPSHOT
jar
Google Cloud Spanner Executor
com.google.cloud
google-cloud-spanner-parent
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml
index b2f95ce2bc9..6f77dfeb226 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
- 6.40.1
+ 6.40.2-SNAPSHOT
jar
Google Cloud Spanner
https://github.com/googleapis/java-spanner
@@ -11,7 +11,7 @@
com.google.cloud
google-cloud-spanner-parent
- 6.40.1
+ 6.40.2-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 59c6693a105..1ad665c26fe 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
- 6.40.1
+ 6.40.2-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
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml
index ed44f80a589..417be82d055 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
- 6.40.1
+ 6.40.2-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
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml
index 72b7250ac23..0d78faf31db 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
- 6.40.1
+ 6.40.2-SNAPSHOT
grpc-google-cloud-spanner-v1
GRPC library for grpc-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/pom.xml b/pom.xml
index d10cddf9b19..5ea7a2950ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-spanner-parent
pom
- 6.40.1
+ 6.40.2-SNAPSHOT
Google Cloud Spanner Parent
https://github.com/googleapis/java-spanner
@@ -62,37 +62,37 @@
com.google.api.grpc
proto-google-cloud-spanner-admin-instance-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
proto-google-cloud-spanner-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
proto-google-cloud-spanner-admin-database-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-admin-instance-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-spanner-admin-database-v1
- 6.40.1
+ 6.40.2-SNAPSHOT
com.google.cloud
google-cloud-spanner
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml
index af69d02a9d0..f5e38b90c1c 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
- 6.40.1
+ 6.40.2-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
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml
index fca6f70b069..9c9c77d5364 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
- 6.40.1
+ 6.40.2-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
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml
index 9df60a5df8c..d2d1b2cbc87 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
- 6.40.1
+ 6.40.2-SNAPSHOT
proto-google-cloud-spanner-v1
PROTO library for proto-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 803b88b67b1..0ec7b96557b 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -31,7 +31,7 @@
com.google.cloud
google-cloud-spanner
- 6.40.1
+ 6.40.2-SNAPSHOT
diff --git a/versions.txt b/versions.txt
index 641b9d0fb9e..6d66441bcf9 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,11 +1,11 @@
# Format:
# module:released-version:current-version
-proto-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.1
-proto-google-cloud-spanner-v1:6.40.1:6.40.1
-proto-google-cloud-spanner-admin-database-v1:6.40.1:6.40.1
-grpc-google-cloud-spanner-v1:6.40.1:6.40.1
-grpc-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.1
-grpc-google-cloud-spanner-admin-database-v1:6.40.1:6.40.1
-google-cloud-spanner:6.40.1:6.40.1
-google-cloud-spanner-executor:6.40.1:6.40.1
+proto-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.2-SNAPSHOT
+proto-google-cloud-spanner-v1:6.40.1:6.40.2-SNAPSHOT
+proto-google-cloud-spanner-admin-database-v1:6.40.1:6.40.2-SNAPSHOT
+grpc-google-cloud-spanner-v1:6.40.1:6.40.2-SNAPSHOT
+grpc-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.2-SNAPSHOT
+grpc-google-cloud-spanner-admin-database-v1:6.40.1:6.40.2-SNAPSHOT
+google-cloud-spanner:6.40.1:6.40.2-SNAPSHOT
+google-cloud-spanner-executor:6.40.1:6.40.2-SNAPSHOT
From 2693548dd4de6b5b914bbb4de90608386d4aa4e5 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Mon, 17 Apr 2023 11:48:35 +0100
Subject: [PATCH 02/15] chore(deps): update dependency
com.google.cloud:google-cloud-spanner to v6.40.1 (#2387)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[](https://renovatebot.com)
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [com.google.cloud:google-cloud-spanner](https://togithub.com/googleapis/java-spanner) | `6.40.0` -> `6.40.1` | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) |
---
### Release Notes
googleapis/java-spanner
### [`v6.40.1`](https://togithub.com/googleapis/java-spanner/blob/HEAD/CHANGELOG.md#6401-httpsgithubcomgoogleapisjava-spannercomparev6400v6401-2023-04-17)
[Compare Source](https://togithub.com/googleapis/java-spanner/compare/v6.40.0...v6.40.1)
##### Dependencies
- Update dependency com.google.cloud:google-cloud-monitoring to v3.16.0 ([#2383](https://togithub.com/googleapis/java-spanner/issues/2383)) ([5d5c33a](https://togithub.com/googleapis/java-spanner/commit/5d5c33ae7c01e10112c72777f202187a50b55ac3))
- Update dependency com.google.cloud:google-cloud-trace to v2.15.0 ([#2384](https://togithub.com/googleapis/java-spanner/issues/2384)) ([6b4ce1f](https://togithub.com/googleapis/java-spanner/commit/6b4ce1fc7ffd837fab6250e36269589d95f5b8c6))
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
â™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **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 [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/java-spanner).
---
README.md | 8 ++++----
samples/install-without-bom/pom.xml | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 59f82c45492..69efbdfaad2 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ If you are using Maven without the BOM, add this to your dependencies:
com.google.cloud
google-cloud-spanner
- 6.40.0
+ 6.40.1
```
@@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-spanner'
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-spanner:6.40.0'
+implementation 'com.google.cloud:google-cloud-spanner:6.40.1'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.40.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.40.1"
```
@@ -411,7 +411,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-spanner.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.40.0
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.40.1
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index 3626aa29c27..47eb81f1ed2 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -32,7 +32,7 @@
com.google.cloud
google-cloud-spanner
- 6.40.0
+ 6.40.1
From 02dc53c097bae3f20d7915fecc9c236c4a5f91f9 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Thu, 20 Apr 2023 22:50:36 +0200
Subject: [PATCH 03/15] deps: update dependency
com.google.api.grpc:proto-google-cloud-spanner-executor-v1 to v1.4.0 (#2395)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[](https://renovatebot.com)
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [com.google.api.grpc:proto-google-cloud-spanner-executor-v1](https://togithub.com/googleapis/java-spanner/proto-google-cloud-spanner-executor-v1) ([source](https://togithub.com/googleapis/java-spanner)) | `1.3.0` -> `1.4.0` | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) |
---
### Release Notes
googleapis/java-spanner
### [`v1.4.0`](https://togithub.com/googleapis/java-spanner/compare/1.3.0...1.4.0)
[Compare Source](https://togithub.com/googleapis/java-spanner/compare/1.3.0...1.4.0)
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
â™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **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 [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/java-spanner).
---
README.md | 2 +-
google-cloud-spanner-executor/pom.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 69efbdfaad2..47e2effe583 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ If you are using Maven without the BOM, add this to your dependencies:
If you are using Gradle 5.x or later, add this to your dependencies:
```Groovy
-implementation platform('com.google.cloud:libraries-bom:26.12.0')
+implementation platform('com.google.cloud:libraries-bom:26.13.0')
implementation 'com.google.cloud:google-cloud-spanner'
```
diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml
index 52d152f0050..62038c43c76 100644
--- a/google-cloud-spanner-executor/pom.xml
+++ b/google-cloud-spanner-executor/pom.xml
@@ -81,7 +81,7 @@
com.google.api.grpc
proto-google-cloud-spanner-executor-v1
- 1.3.0
+ 1.4.0
com.google.guava
From f70dacab3a53dfd7edbd8bec8774fee50d722196 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Fri, 21 Apr 2023 08:46:16 +0200
Subject: [PATCH 04/15] chore(deps): update dependency
com.google.cloud:libraries-bom to v26.13.0 (#2393)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* chore(deps): update dependency com.google.cloud:libraries-bom to v26.13.0
* 🦉 Updates from OwlBot post-processor
See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md
---------
Co-authored-by: Owl Bot
---
README.md | 2 +-
samples/native-image/pom.xml | 2 +-
samples/snippets/pom.xml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 47e2effe583..9961a9759f9 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.12.0
+ 26.13.0
pom
import
diff --git a/samples/native-image/pom.xml b/samples/native-image/pom.xml
index effe3e9fecb..aa895a139f6 100644
--- a/samples/native-image/pom.xml
+++ b/samples/native-image/pom.xml
@@ -28,7 +28,7 @@
com.google.cloud
libraries-bom
- 26.12.0
+ 26.13.0
pom
import
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index d71f010f086..48cf09bf081 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -33,7 +33,7 @@
com.google.cloud
libraries-bom
- 26.12.0
+ 26.13.0
pom
import
From 76260eccfc4880c0bfe2987129eced9db5665190 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Fri, 21 Apr 2023 08:46:36 +0200
Subject: [PATCH 05/15] build(deps): update dependency
org.apache.maven.plugins:maven-project-info-reports-plugin to v3.4.3 (#2392)
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 5ea7a2950ae..60b1905dd00 100644
--- a/pom.xml
+++ b/pom.xml
@@ -160,7 +160,7 @@
org.apache.maven.plugins
maven-project-info-reports-plugin
- 3.4.2
+ 3.4.3
From 5474d40b6d1679f31adf8b8f6ea2d14b0a53c8d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?=
Date: Fri, 21 Apr 2023 11:47:30 +0200
Subject: [PATCH 06/15] test: untyped nulls as statement parameters (#2388)
Add tests to verify that untyped null statement parameters work with
both GoogleSQL, PostgreSQL and the emulator.
Verifies that https://github.com/GoogleCloudPlatform/cloud-spanner-emulator/issues/31
has been fixed.
---
.../google/cloud/spanner/it/ITWriteTest.java | 214 ++++++++++++++----
1 file changed, 167 insertions(+), 47 deletions(-)
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 3179093139e..020beb68ef9 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
@@ -27,6 +27,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
@@ -51,6 +52,7 @@
import com.google.cloud.spanner.connection.ConnectionOptions;
import com.google.cloud.spanner.testing.EmulatorSpannerHelper;
import com.google.common.collect.ImmutableList;
+import com.google.protobuf.NullValue;
import io.grpc.Context;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -98,8 +100,7 @@ public static List data() {
private static DatabaseClient googleStandardSQLClient;
private static DatabaseClient postgreSQLClient;
- // TODO: Remove when the emulator supports NUMERIC and JSON
- private static final String GOOGLE_STANDARD_SQL_SCHEMA_WITH_NUMERIC_AND_JSON =
+ private static final String GOOGLE_STANDARD_SQL_SCHEMA =
"CREATE TABLE T ("
+ " K STRING(MAX) NOT NULL,"
+ " BoolValue BOOL,"
@@ -122,13 +123,14 @@ public static List data() {
+ " NumericArrayValue ARRAY,"
+ ") PRIMARY KEY (K)";
- private static final String POSTGRESQL_SCHEMA_WITH_NUMERIC =
+ private static final String POSTGRESQL_SCHEMA =
"CREATE TABLE T ("
+ " K VARCHAR PRIMARY KEY,"
+ " BoolValue BOOL,"
+ " Int64Value BIGINT,"
+ " Float64Value DOUBLE PRECISION,"
+ " StringValue VARCHAR,"
+ + " JsonValue JSONB,"
+ " BytesValue BYTEA,"
+ " TimestampValue TIMESTAMPTZ,"
+ " DateValue DATE,"
@@ -137,31 +139,13 @@ public static List data() {
+ " Int64ArrayValue BIGINT[],"
+ " Float64ArrayValue DOUBLE PRECISION[],"
+ " StringArrayValue VARCHAR[],"
+ + " JsonArrayValue JSONB[],"
+ " BytesArrayValue BYTEA[],"
+ " TimestampArrayValue TIMESTAMPTZ[],"
+ " DateArrayValue DATE[],"
+ " NumericArrayValue NUMERIC[]"
+ ")";
- private static final String GOOGLE_STANDARD_SQL_SCHEMA_WITHOUT_NUMERIC_AND_JSON =
- "CREATE TABLE T ("
- + " K STRING(MAX) NOT NULL,"
- + " BoolValue BOOL,"
- + " Int64Value INT64,"
- + " Float64Value FLOAT64,"
- + " StringValue STRING(MAX),"
- + " BytesValue BYTES(MAX),"
- + " TimestampValue TIMESTAMP OPTIONS (allow_commit_timestamp = true),"
- + " DateValue DATE,"
- + " BoolArrayValue ARRAY,"
- + " Int64ArrayValue ARRAY,"
- + " Float64ArrayValue ARRAY,"
- + " StringArrayValue ARRAY,"
- + " BytesArrayValue ARRAY,"
- + " TimestampArrayValue ARRAY,"
- + " DateArrayValue ARRAY,"
- + ") PRIMARY KEY (K)";
-
/** Sequence used to generate unique keys. */
private static int seq;
@@ -170,21 +154,14 @@ public static List data() {
@BeforeClass
public static void setUpDatabase()
throws ExecutionException, InterruptedException, TimeoutException {
- if (EmulatorSpannerHelper.isUsingEmulator()) {
- Database googleStandardSQLDatabase =
- env.getTestHelper()
- .createTestDatabase(GOOGLE_STANDARD_SQL_SCHEMA_WITHOUT_NUMERIC_AND_JSON);
-
- googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase);
- } else {
- Database googleStandardSQLDatabase =
- env.getTestHelper().createTestDatabase(GOOGLE_STANDARD_SQL_SCHEMA_WITH_NUMERIC_AND_JSON);
+ Database googleStandardSQLDatabase =
+ env.getTestHelper().createTestDatabase(GOOGLE_STANDARD_SQL_SCHEMA);
- googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase);
+ googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase);
+ if (!EmulatorSpannerHelper.isUsingEmulator()) {
Database postgreSQLDatabase =
env.getTestHelper()
- .createTestDatabase(
- Dialect.POSTGRESQL, Collections.singletonList(POSTGRESQL_SCHEMA_WITH_NUMERIC));
+ .createTestDatabase(Dialect.POSTGRESQL, Collections.singletonList(POSTGRESQL_SCHEMA));
postgreSQLClient = env.getTestHelper().getDatabaseClient(postgreSQLDatabase);
}
}
@@ -396,7 +373,6 @@ public void writeStringNull() {
@Test
public void writeJson() {
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
assumeFalse("PostgreSQL does not yet support JSON", dialect.dialect == Dialect.POSTGRESQL);
write(baseInsert().set("JsonValue").to(Value.json("{\"rating\":9,\"open\":true}")).build());
Struct row = readLastRow("JsonValue");
@@ -407,7 +383,6 @@ public void writeJson() {
@Test
public void writeJsonEmpty() {
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
assumeFalse("PostgreSQL does not yet support JSON", dialect.dialect == Dialect.POSTGRESQL);
write(baseInsert().set("JsonValue").to(Value.json("{}")).build());
Struct row = readLastRow("JsonValue");
@@ -418,7 +393,6 @@ public void writeJsonEmpty() {
@Test
public void writeJsonNull() {
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
assumeFalse("PostgreSQL does not yet support JSON", dialect.dialect == Dialect.POSTGRESQL);
write(baseInsert().set("JsonValue").to(Value.json(null)).build());
Struct row = readLastRow("JsonValue");
@@ -588,7 +562,6 @@ public void writeDateNull() {
@Test
public void writeNumeric() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("NumericValue").to("3.141592").build());
Struct row = readLastRow("NumericValue");
assertThat(row.isNull(0)).isFalse();
@@ -601,7 +574,6 @@ public void writeNumeric() {
@Test
public void writeNumericNull() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("NumericValue").to((String) null).build());
Struct row = readLastRow("NumericValue");
assertThat(row.isNull(0)).isTrue();
@@ -751,7 +723,6 @@ public void writeStringArray() {
@Test
public void writeJsonArrayNull() {
assumeFalse("PostgreSQL does not yet support Array", dialect.dialect == Dialect.POSTGRESQL);
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("JsonArrayValue").toJsonArray(null).build());
Struct row = readLastRow("JsonArrayValue");
assertThat(row.isNull(0)).isTrue();
@@ -761,7 +732,6 @@ public void writeJsonArrayNull() {
@Test
public void writeJsonArrayEmpty() {
assumeFalse("PostgreSQL does not yet support Array", dialect.dialect == Dialect.POSTGRESQL);
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("JsonArrayValue").toJsonArray(Collections.emptyList()).build());
Struct row = readLastRow("JsonArrayValue");
assertThat(row.isNull(0)).isFalse();
@@ -772,7 +742,6 @@ public void writeJsonArrayEmpty() {
@Test
public void writeJsonArray() {
assumeFalse("PostgreSQL does not yet support Array", dialect.dialect == Dialect.POSTGRESQL);
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("JsonArrayValue").toJsonArray(Arrays.asList("[]", null, "{}")).build());
Struct row = readLastRow("JsonArrayValue");
assertThat(row.isNull(0)).isFalse();
@@ -783,7 +752,6 @@ public void writeJsonArray() {
@Test
public void writeJsonArrayNoNulls() {
assumeFalse("PostgreSQL does not yet support Array", dialect.dialect == Dialect.POSTGRESQL);
- assumeFalse("Emulator does not yet support JSON", EmulatorSpannerHelper.isUsingEmulator());
write(
baseInsert()
.set("JsonArrayValue")
@@ -878,7 +846,6 @@ public void writeDateArray() {
@Test
public void writeNumericArrayNull() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("NumericArrayValue").toNumericArray(null).build());
Struct row = readLastRow("NumericArrayValue");
assertThat(row.isNull(0)).isTrue();
@@ -886,7 +853,6 @@ public void writeNumericArrayNull() {
@Test
public void writeNumericArrayEmpty() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(baseInsert().set("NumericArrayValue").toNumericArray(ImmutableList.of()).build());
Struct row = readLastRow("NumericArrayValue");
assertThat(row.isNull(0)).isFalse();
@@ -899,7 +865,6 @@ public void writeNumericArrayEmpty() {
@Test
public void writeNumericArray() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(
baseInsert()
.set("NumericArrayValue")
@@ -918,7 +883,6 @@ public void writeNumericArray() {
@Test
public void writeNumericArrayNoNulls() {
- assumeFalse("Emulator does not yet support NUMERIC", EmulatorSpannerHelper.isUsingEmulator());
write(
baseInsert()
.set("NumericArrayValue")
@@ -1013,4 +977,160 @@ public void deadline() {
executor.shutdown();
}
}
+
+ @Test
+ public void testWriteUntypedNullValuesGoogleSQL() {
+ assumeFalse(
+ "PostgreSQL uses a different parameter format", dialect.dialect == Dialect.POSTGRESQL);
+ Value untypedNull =
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
+ assertEquals(
+ Long.valueOf(1L),
+ client
+ .readWriteTransaction()
+ .run(
+ transaction ->
+ transaction.executeUpdate(
+ Statement.newBuilder(
+ "insert into T ("
+ + "K,"
+ + "BoolValue,"
+ + "Int64Value,"
+ + "Float64Value,"
+ + "StringValue,"
+ + "JsonValue,"
+ + "BytesValue,"
+ + "TimestampValue,"
+ + "DateValue,"
+ + "NumericValue,"
+ + "BoolArrayValue,"
+ + "Int64ArrayValue,"
+ + "Float64ArrayValue,"
+ + "StringArrayValue,"
+ + "JsonArrayValue,"
+ + "BytesArrayValue,"
+ + "TimestampArrayValue,"
+ + "DateArrayValue,"
+ + "NumericArrayValue"
+ + ") values (@k, @bool, @int64, @float64, @string, @json, @bytes, @timestamp, @date, @numeric, "
+ + "@boolArray, @int64Array, @float64Array, @stringArray, @jsonArray, @bytesArray, @timestampArray, @dateArray, @numericArray)")
+ .bind("k")
+ .to(uniqueString())
+ .bind("bool")
+ .to(untypedNull)
+ .bind("int64")
+ .to(untypedNull)
+ .bind("float64")
+ .to(untypedNull)
+ .bind("string")
+ .to(untypedNull)
+ .bind("json")
+ .to(untypedNull)
+ .bind("bytes")
+ .to(untypedNull)
+ .bind("timestamp")
+ .to(untypedNull)
+ .bind("date")
+ .to(untypedNull)
+ .bind("numeric")
+ .to(untypedNull)
+ .bind("boolArray")
+ .to(untypedNull)
+ .bind("int64Array")
+ .to(untypedNull)
+ .bind("float64Array")
+ .to(untypedNull)
+ .bind("stringArray")
+ .to(untypedNull)
+ .bind("jsonArray")
+ .to(untypedNull)
+ .bind("bytesArray")
+ .to(untypedNull)
+ .bind("timestampArray")
+ .to(untypedNull)
+ .bind("dateArray")
+ .to(untypedNull)
+ .bind("numericArray")
+ .to(untypedNull)
+ .build())));
+ }
+
+ @Test
+ public void testWriteUntypedNullValuesPostgreSQL() {
+ assumeTrue(
+ "PostgreSQL uses a different parameter format", dialect.dialect == Dialect.POSTGRESQL);
+ Value untypedNull =
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build());
+ assertEquals(
+ Long.valueOf(1L),
+ client
+ .readWriteTransaction()
+ .run(
+ transaction ->
+ transaction.executeUpdate(
+ Statement.newBuilder(
+ "insert into T ("
+ + "K,"
+ + "BoolValue,"
+ + "Int64Value,"
+ + "Float64Value,"
+ + "StringValue,"
+ + "JsonValue,"
+ + "BytesValue,"
+ + "TimestampValue,"
+ + "DateValue,"
+ + "NumericValue,"
+ + "BoolArrayValue,"
+ + "Int64ArrayValue,"
+ + "Float64ArrayValue,"
+ + "StringArrayValue,"
+ + "JsonArrayValue,"
+ + "BytesArrayValue,"
+ + "TimestampArrayValue,"
+ + "DateArrayValue,"
+ + "NumericArrayValue"
+ + ") values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, "
+ + "$11, $12, $13, $14, $15, $16, $17, $18, $19)")
+ .bind("p1")
+ .to(uniqueString())
+ .bind("p2")
+ .to(untypedNull)
+ .bind("p3")
+ .to(untypedNull)
+ .bind("p4")
+ .to(untypedNull)
+ .bind("p5")
+ .to(untypedNull)
+ .bind("p6")
+ .to(untypedNull)
+ .bind("p7")
+ .to(untypedNull)
+ .bind("p8")
+ .to(untypedNull)
+ .bind("p9")
+ .to(untypedNull)
+ .bind("p10")
+ .to(untypedNull)
+ .bind("p11")
+ .to(untypedNull)
+ .bind("p12")
+ .to(untypedNull)
+ .bind("p13")
+ .to(untypedNull)
+ .bind("p14")
+ .to(untypedNull)
+ .bind("p15")
+ .to(untypedNull)
+ .bind("p16")
+ .to(untypedNull)
+ .bind("p17")
+ .to(untypedNull)
+ .bind("p18")
+ .to(untypedNull)
+ .bind("p19")
+ .to(untypedNull)
+ .build())));
+ }
}
From b815cb88ff29fb5b9a5d7998e765548244f287c1 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Tue, 25 Apr 2023 22:10:29 +0200
Subject: [PATCH 07/15] deps: update dependency
com.google.cloud:google-cloud-shared-dependencies to v3.8.0 (#2400)
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 60b1905dd00..5832d98e1cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,7 +54,7 @@
UTF-8
github
google-cloud-spanner-parent
- 3.7.0
+ 3.8.0
From e34084d3d5747ca20e0bf198df3576ae89262740 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Tue, 25 Apr 2023 22:10:59 +0200
Subject: [PATCH 08/15] build(deps): update dependency
org.jacoco:jacoco-maven-plugin to v0.8.10 (#2399)
---
google-cloud-spanner/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml
index 6f77dfeb226..3156365549d 100644
--- a/google-cloud-spanner/pom.xml
+++ b/google-cloud-spanner/pom.xml
@@ -29,7 +29,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8
+ 0.8.10
From 8327f210df86bf681ffed6a78ccc9e8fd899c967 Mon Sep 17 00:00:00 2001
From: Roman Slyusarchuk
Date: Tue, 25 Apr 2023 13:16:14 -0700
Subject: [PATCH 09/15] feat: add TransactionExecutionOptions support to
executor. (#2396)
This PR adds support for TransactionExecutionOptions to Cloud Client Executor Framework.
---
.../executor/spanner/CloudClientExecutor.java | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java
index 55acf44abb2..f4b59505b01 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java
@@ -140,6 +140,7 @@
import com.google.spanner.executor.v1.SpannerAsyncActionResponse;
import com.google.spanner.executor.v1.StartBatchTransactionAction;
import com.google.spanner.executor.v1.StartTransactionAction;
+import com.google.spanner.executor.v1.TransactionExecutionOptions;
import com.google.spanner.executor.v1.UpdateCloudBackupAction;
import com.google.spanner.executor.v1.UpdateCloudDatabaseDdlAction;
import com.google.spanner.executor.v1.UpdateCloudInstanceAction;
@@ -227,13 +228,16 @@ private static class ReadWriteTransaction {
private Mode finishMode;
private SpannerException error;
private final String transactionSeed;
+ private final boolean optimistic;
// Set to true when the transaction runner completed, one of these three could happen: runner
// committed, abandoned or threw an error.
private boolean runnerCompleted;
- public ReadWriteTransaction(DatabaseClient dbClient, String transactionSeed) {
+ public ReadWriteTransaction(
+ DatabaseClient dbClient, String transactionSeed, boolean optimistic) {
this.dbClient = dbClient;
this.transactionSeed = transactionSeed;
+ this.optimistic = optimistic;
this.runnerCompleted = false;
}
@@ -318,7 +322,10 @@ public void startRWTransaction() throws Exception {
Runnable runnable =
() -> {
try {
- runner = dbClient.readWriteTransaction();
+ runner =
+ optimistic
+ ? dbClient.readWriteTransaction(Options.optimisticLock())
+ : dbClient.readWriteTransaction();
LOGGER.log(Level.INFO, String.format("Ready to run callable %s\n", transactionSeed));
runner.run(callable);
transactionSucceeded(runner.getCommitTimestamp().toProto());
@@ -537,7 +544,8 @@ public synchronized void startReadOnlyTxn(
}
/** Start a read-write transaction. */
- public synchronized void startReadWriteTxn(DatabaseClient dbClient, Metadata metadata)
+ public synchronized void startReadWriteTxn(
+ DatabaseClient dbClient, Metadata metadata, TransactionExecutionOptions options)
throws Exception {
if ((rwTxn != null) || (roTxn != null) || (batchTxn != null)) {
throw SpannerExceptionFactory.newSpannerException(
@@ -548,7 +556,7 @@ public synchronized void startReadWriteTxn(DatabaseClient dbClient, Metadata met
String.format(
"There's no active transaction, safe to create rwTxn: %s\n", getTransactionSeed()));
this.metadata = metadata;
- rwTxn = new ReadWriteTransaction(dbClient, transactionSeed);
+ rwTxn = new ReadWriteTransaction(dbClient, transactionSeed, options.getOptimistic());
LOGGER.log(
Level.INFO,
String.format(
@@ -2246,7 +2254,7 @@ private Status executeStartTxn(
Level.INFO,
"Starting read-write transaction %s\n",
executionContext.getTransactionSeed());
- executionContext.startReadWriteTxn(dbClient, metadata);
+ executionContext.startReadWriteTxn(dbClient, metadata, action.getExecutionOptions());
}
executionContext.setDatabaseClient(dbClient);
executionContext.initReadState();
From d46097f9f17d9009d211c8c0f16b3e084f8fdbad Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Thu, 27 Apr 2023 08:09:12 +0200
Subject: [PATCH 10/15] deps: update dependency
com.google.cloud:google-cloud-monitoring to v3.17.0 (#2406)
---
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 47eb81f1ed2..3d1cd1b23ef 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -23,7 +23,7 @@
UTF-8
0.31.1
2.15.0
- 3.16.0
+ 3.17.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 0ec7b96557b..e3ddaf008db 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -23,7 +23,7 @@
UTF-8
0.31.1
2.15.0
- 3.16.0
+ 3.17.0
From 7993be25e9f380071cded2fa4c2bf630d760a53e Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Thu, 27 Apr 2023 09:27:47 +0200
Subject: [PATCH 11/15] deps: update dependency
com.google.cloud:google-cloud-trace to v2.16.0 (#2407)
---
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 3d1cd1b23ef..71c58372966 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -22,7 +22,7 @@
1.8
UTF-8
0.31.1
- 2.15.0
+ 2.16.0
3.17.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index e3ddaf008db..001f912ea11 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -22,7 +22,7 @@
1.8
UTF-8
0.31.1
- 2.15.0
+ 2.16.0
3.17.0
From 8aa7a1dbbf484446ae8eed3cb27d16fc65e6de83 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Thu, 27 Apr 2023 19:25:37 +0200
Subject: [PATCH 12/15] deps: update dependency
org.junit.vintage:junit-vintage-engine to v5.9.3 (#2401)
---
samples/native-image/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/native-image/pom.xml b/samples/native-image/pom.xml
index aa895a139f6..b4028d42b65 100644
--- a/samples/native-image/pom.xml
+++ b/samples/native-image/pom.xml
@@ -103,7 +103,7 @@
org.junit.vintage
junit-vintage-engine
- 5.9.2
+ 5.9.3
test
From 85213c8764fcb7fb12df49baaac9bd00e095f269 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?=
Date: Thu, 27 Apr 2023 19:30:03 +0200
Subject: [PATCH 13/15] feat: make leak detection configurable for connections
(#2405)
Make the leak detection and pre-creation of exceptions for session and
connection leaks configurable for connections.
---
.../spanner/connection/ConnectionImpl.java | 6 ++-
.../spanner/connection/ConnectionOptions.java | 49 ++++++++++++++++++-
.../connection/ConnectionOptionsTest.java | 45 +++++++++++++++++
3 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
index 824c3f237eb..c208f7b85b7 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
@@ -84,7 +84,7 @@ private LeakedConnectionException() {
}
}
- private volatile LeakedConnectionException leakedException = new LeakedConnectionException();
+ private volatile LeakedConnectionException leakedException;;
private final SpannerPool spannerPool;
private AbstractStatementParser statementParser;
/**
@@ -222,6 +222,8 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
/** Create a connection and register it in the SpannerPool. */
ConnectionImpl(ConnectionOptions options) {
Preconditions.checkNotNull(options);
+ this.leakedException =
+ options.isTrackConnectionLeaks() ? new LeakedConnectionException() : null;
this.statementExecutor = new StatementExecutor(options.getStatementExecutionInterceptors());
this.spannerPool = SpannerPool.INSTANCE;
this.options = options;
@@ -251,6 +253,8 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
Preconditions.checkNotNull(spannerPool);
Preconditions.checkNotNull(ddlClient);
Preconditions.checkNotNull(dbClient);
+ this.leakedException =
+ options.isTrackConnectionLeaks() ? new LeakedConnectionException() : null;
this.statementExecutor = new StatementExecutor(Collections.emptyList());
this.spannerPool = spannerPool;
this.options = options;
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
index e44a99c1ecc..f51ea6efc64 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
@@ -172,6 +172,8 @@ public String[] getValidValues() {
private static final RpcPriority DEFAULT_RPC_PRIORITY = null;
private static final boolean DEFAULT_RETURN_COMMIT_STATS = false;
private static final boolean DEFAULT_LENIENT = false;
+ private static final boolean DEFAULT_TRACK_SESSION_LEAKS = true;
+ private static final boolean DEFAULT_TRACK_CONNECTION_LEAKS = true;
private static final String PLAIN_TEXT_PROTOCOL = "http:";
private static final String HOST_PROTOCOL = "https:";
@@ -218,6 +220,10 @@ public String[] getValidValues() {
private static final String DIALECT_PROPERTY_NAME = "dialect";
/** Name of the 'databaseRole' connection property. */
public static final String DATABASE_ROLE_PROPERTY_NAME = "databaseRole";
+ /** Name of the 'trackStackTraceOfSessionCheckout' connection property. */
+ public static final String TRACK_SESSION_LEAKS_PROPERTY_NAME = "trackSessionLeaks";
+ /** Name of the 'trackStackTraceOfConnectionCreation' connection property. */
+ public static final String TRACK_CONNECTION_LEAKS_PROPERTY_NAME = "trackConnectionLeaks";
/** All valid connection properties. */
public static final Set VALID_PROPERTIES =
Collections.unmodifiableSet(
@@ -287,7 +293,25 @@ public String[] getValidValues() {
DIALECT_PROPERTY_NAME, "Sets the dialect to use for this connection."),
ConnectionProperty.createStringProperty(
DATABASE_ROLE_PROPERTY_NAME,
- "Sets the database role to use for this connection. The default is privileges assigned to IAM role"))));
+ "Sets the database role to use for this connection. The default is privileges assigned to IAM role"),
+ ConnectionProperty.createBooleanProperty(
+ TRACK_SESSION_LEAKS_PROPERTY_NAME,
+ "Capture the call stack of the thread that checked out a session of the session pool. This will "
+ + "pre-create a LeakedSessionException already when a session is checked out. This can be disabled, "
+ + "for example if a monitoring system logs the pre-created exception. "
+ + "If disabled, the LeakedSessionException will only be created when an "
+ + "actual session leak is detected. The stack trace of the exception will "
+ + "in that case not contain the call stack of when the session was checked out.",
+ DEFAULT_TRACK_SESSION_LEAKS),
+ ConnectionProperty.createBooleanProperty(
+ TRACK_CONNECTION_LEAKS_PROPERTY_NAME,
+ "Capture the call stack of the thread that created a connection. This will "
+ + "pre-create a LeakedConnectionException already when a connection is created. "
+ + "This can be disabled, for example if a monitoring system logs the pre-created exception. "
+ + "If disabled, the LeakedConnectionException will only be created when an "
+ + "actual connection leak is detected. The stack trace of the exception will "
+ + "in that case not contain the call stack of when the connection was created.",
+ DEFAULT_TRACK_CONNECTION_LEAKS))));
private static final Set INTERNAL_PROPERTIES =
Collections.unmodifiableSet(
@@ -544,6 +568,8 @@ public static Builder newBuilder() {
private final boolean returnCommitStats;
private final boolean autoConfigEmulator;
private final RpcPriority rpcPriority;
+ private final boolean trackSessionLeaks;
+ private final boolean trackConnectionLeaks;
private final boolean autocommit;
private final boolean readOnly;
@@ -588,6 +614,8 @@ private ConnectionOptions(Builder builder) {
this.usePlainText = this.autoConfigEmulator || parseUsePlainText(this.uri);
this.host = determineHost(matcher, autoConfigEmulator, usePlainText);
this.rpcPriority = parseRPCPriority(this.uri);
+ this.trackSessionLeaks = parseTrackSessionLeaks(this.uri);
+ this.trackConnectionLeaks = parseTrackConnectionLeaks(this.uri);
this.instanceId = matcher.group(Builder.INSTANCE_GROUP);
this.databaseName = matcher.group(Builder.DATABASE_GROUP);
@@ -641,11 +669,12 @@ private ConnectionOptions(Builder builder) {
Collections.unmodifiableList(builder.statementExecutionInterceptors);
this.configurator = builder.configurator;
- if (this.minSessions != null || this.maxSessions != null) {
+ if (this.minSessions != null || this.maxSessions != null || !this.trackSessionLeaks) {
SessionPoolOptions.Builder sessionPoolOptionsBuilder =
builder.sessionPoolOptions == null
? SessionPoolOptions.newBuilder()
: builder.sessionPoolOptions.toBuilder();
+ sessionPoolOptionsBuilder.setTrackStackTraceOfSessionCheckout(this.trackSessionLeaks);
sessionPoolOptionsBuilder.setAutoDetectDialect(true);
if (this.minSessions != null) {
sessionPoolOptionsBuilder.setMinSessions(this.minSessions);
@@ -838,6 +867,18 @@ static boolean parseLenient(String uri) {
return value != null ? Boolean.parseBoolean(value) : DEFAULT_LENIENT;
}
+ @VisibleForTesting
+ static boolean parseTrackSessionLeaks(String uri) {
+ String value = parseUriProperty(uri, TRACK_SESSION_LEAKS_PROPERTY_NAME);
+ return value != null ? Boolean.parseBoolean(value) : DEFAULT_TRACK_SESSION_LEAKS;
+ }
+
+ @VisibleForTesting
+ static boolean parseTrackConnectionLeaks(String uri) {
+ String value = parseUriProperty(uri, TRACK_CONNECTION_LEAKS_PROPERTY_NAME);
+ return value != null ? Boolean.parseBoolean(value) : DEFAULT_TRACK_CONNECTION_LEAKS;
+ }
+
@VisibleForTesting
static RpcPriority parseRPCPriority(String uri) {
String value = parseUriProperty(uri, RPC_PRIORITY_NAME);
@@ -1078,6 +1119,10 @@ RpcPriority getRPCPriority() {
return rpcPriority;
}
+ boolean isTrackConnectionLeaks() {
+ return this.trackConnectionLeaks;
+ }
+
/** Interceptors that should be executed after each statement */
List getStatementExecutionInterceptors() {
return statementExecutionInterceptors;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionOptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionOptionsTest.java
index cb862ca3061..ef1ab365577 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionOptionsTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionOptionsTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -489,6 +490,50 @@ public void testMaxSessions() {
assertThat(options.getSessionPoolOptions().getMaxSessions()).isEqualTo(4000);
}
+ @Test
+ public void testTrackSessionLeaks() {
+ ConnectionOptions options =
+ ConnectionOptions.newBuilder()
+ .setUri(
+ "cloudspanner:/projects/test-project-123/instances/test-instance/databases/test-database?trackSessionLeaks=false")
+ .setCredentialsUrl(FILE_TEST_PATH)
+ .build();
+ assertFalse(options.getSessionPoolOptions().isTrackStackTraceOfSessionCheckout());
+ }
+
+ @Test
+ public void testTrackSessionLeaksDefault() {
+ ConnectionOptions options =
+ ConnectionOptions.newBuilder()
+ .setUri(
+ "cloudspanner:/projects/test-project-123/instances/test-instance/databases/test-database")
+ .setCredentialsUrl(FILE_TEST_PATH)
+ .build();
+ assertTrue(options.getSessionPoolOptions().isTrackStackTraceOfSessionCheckout());
+ }
+
+ @Test
+ public void testTrackConnectionLeaks() {
+ ConnectionOptions options =
+ ConnectionOptions.newBuilder()
+ .setUri(
+ "cloudspanner:/projects/test-project-123/instances/test-instance/databases/test-database?trackConnectionLeaks=false")
+ .setCredentialsUrl(FILE_TEST_PATH)
+ .build();
+ assertFalse(options.isTrackConnectionLeaks());
+ }
+
+ @Test
+ public void testTrackConnectionLeaksDefault() {
+ ConnectionOptions options =
+ ConnectionOptions.newBuilder()
+ .setUri(
+ "cloudspanner:/projects/test-project-123/instances/test-instance/databases/test-database")
+ .setCredentialsUrl(FILE_TEST_PATH)
+ .build();
+ assertTrue(options.isTrackConnectionLeaks());
+ }
+
@Test
public void testLocalConnectionError() {
String uri =
From 9695acee9195b50e525d87700e86d701b1d9eed2 Mon Sep 17 00:00:00 2001
From: Yifan Zhou <119901292+yifanzyifanz@users.noreply.github.com>
Date: Fri, 28 Apr 2023 00:21:56 -0700
Subject: [PATCH 14/15] feat: Leader Aware Routing (#2214)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: Add `x-goog-spanner-route-to-leader` header to Spanner RPC contexts for RW/PDML transactions.
The header is added to support leader-aware-routing feature, which aims at reducing cross-regional latency for RW/PDML transactions in a multi-region instance.
* feat: Add knob in SpannerOptions to allow users to opt out leader aware routing feature
* fix: fix broken tests due to the merge
* fix: resolve comments.
* fix: resolve comments and add new tests to verify that the route-to-leader header exists for RW transactions and does not exist for RO transactions or when the leader aware routing feature is disabled.
* fix: Update comments for SpannerOptions.disableLeaderAwareRouting
* 🦉 Updates from OwlBot post-processor
See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md
* feat: Disable leader aware routing by default for public preview
---------
Co-authored-by: Owl Bot
Co-authored-by: Rajat Bhatta <93644539+rajatbhatta@users.noreply.github.com>
---
.../clirr-ignored-differences.xml | 99 ++++++
.../cloud/spanner/AbstractReadContext.java | 23 +-
.../spanner/PartitionedDmlTransaction.java | 2 +-
.../com/google/cloud/spanner/SessionImpl.java | 14 +-
.../google/cloud/spanner/SpannerOptions.java | 25 ++
.../cloud/spanner/TransactionRunnerImpl.java | 11 +-
.../cloud/spanner/spi/v1/GapicSpannerRpc.java | 86 +++--
.../spi/v1/SpannerMetadataProvider.java | 9 +-
.../cloud/spanner/spi/v1/SpannerRpc.java | 68 +++-
.../cloud/spanner/BatchClientImplTest.java | 3 +-
.../PartitionedDmlTransactionTest.java | 23 +-
.../google/cloud/spanner/SessionImplTest.java | 18 +-
.../google/cloud/spanner/SessionPoolTest.java | 11 +-
.../cloud/spanner/SpannerOptionsTest.java | 316 +++++++++---------
.../spanner/TransactionManagerImplTest.java | 17 +-
.../spanner/TransactionRunnerImplTest.java | 16 +-
.../spanner/spi/v1/GapicSpannerRpcTest.java | 182 ++++++++--
.../spi/v1/SpannerMetadataProviderTest.java | 20 +-
18 files changed, 674 insertions(+), 269 deletions(-)
diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml
index 67e9663747c..f158f62ea81 100644
--- a/google-cloud-spanner/clirr-ignored-differences.xml
+++ b/google-cloud-spanner/clirr-ignored-differences.xml
@@ -222,6 +222,105 @@
com/google/cloud/spanner/connection/Connection
com.google.cloud.spanner.ResultSet analyzeUpdateStatement(com.google.cloud.spanner.Statement, com.google.cloud.spanner.ReadContext$QueryAnalyzeMode, com.google.cloud.spanner.Options$UpdateOption[])
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.spanner.v1.Transaction beginTransaction(com.google.spanner.v1.BeginTransactionRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.api.core.ApiFuture beginTransactionAsync(com.google.spanner.v1.BeginTransactionRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.api.core.ApiFuture beginTransactionAsync(com.google.spanner.v1.BeginTransactionRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.spanner.v1.ResultSet executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+ com.google.spanner.v1.ResultSet executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, boolean)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map, boolean)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.api.core.ApiFuture executeQueryAsync(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall read(com.google.spanner.v1.ReadRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+
+
+ 7005
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, boolean)
+
+
+ 7006
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+ com.google.spanner.v1.ResultSet
+
+
+ 7006
+ com/google/cloud/spanner/spi/v1/GapicSpannerRpc
+ com.google.spanner.v1.ResultSet executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.spanner.v1.Transaction beginTransaction(com.google.spanner.v1.BeginTransactionRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.api.core.ApiFuture beginTransactionAsync(com.google.spanner.v1.BeginTransactionRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.spanner.v1.ResultSet executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.api.core.ApiFuture executeQueryAsync(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+
+
+ 7004
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall read(com.google.spanner.v1.ReadRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+
+
+ 7005
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, boolean)
+
+
+ 7006
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall executeQuery(com.google.spanner.v1.ExecuteSqlRequest, com.google.cloud.spanner.spi.v1.SpannerRpc$ResultStreamConsumer, java.util.Map)
+ com.google.spanner.v1.ResultSet
+
+
+ 7006
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ com.google.spanner.v1.ResultSet executeQuery(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map)
+ com.google.cloud.spanner.spi.v1.SpannerRpc$StreamingCall
+
+
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 7facd19c826..e19ace944a5 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
@@ -163,6 +163,11 @@ private SingleReadContext(Builder builder) {
this.bound = builder.bound;
}
+ @Override
+ protected boolean isRouteToLeader() {
+ return false;
+ }
+
@GuardedBy("lock")
@Override
void beforeReadOrQueryLocked() {
@@ -293,6 +298,11 @@ static Builder newBuilder() {
}
}
+ @Override
+ protected boolean isRouteToLeader() {
+ return false;
+ }
+
@Override
void beforeReadOrQuery() {
super.beforeReadOrQuery();
@@ -347,7 +357,8 @@ void initTransaction() {
.setSession(session.getName())
.setOptions(options)
.build();
- Transaction transaction = rpc.beginTransaction(request, session.getOptions());
+ Transaction transaction =
+ rpc.beginTransaction(request, session.getOptions(), isRouteToLeader());
if (!transaction.hasReadTimestamp()) {
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INTERNAL, "Missing expected transaction.read_timestamp metadata field");
@@ -416,6 +427,10 @@ long getSeqNo() {
return seqNo.incrementAndGet();
}
+ protected boolean isRouteToLeader() {
+ return false;
+ }
+
@Override
public final ResultSet read(
String table, KeySet keys, Iterable columns, ReadOption... options) {
@@ -667,7 +682,8 @@ CloseableIterator startStream(@Nullable ByteString resumeToken
request.setTransaction(selector);
}
SpannerRpc.StreamingCall call =
- rpc.executeQuery(request.build(), stream.consumer(), session.getOptions());
+ rpc.executeQuery(
+ request.build(), stream.consumer(), session.getOptions(), isRouteToLeader());
call.request(prefetchChunks);
stream.setCall(call, request.getTransaction().hasBegin());
return stream;
@@ -798,7 +814,8 @@ CloseableIterator startStream(@Nullable ByteString resumeToken
}
builder.setRequestOptions(buildRequestOptions(readOptions));
SpannerRpc.StreamingCall call =
- rpc.read(builder.build(), stream.consumer(), session.getOptions());
+ rpc.read(
+ builder.build(), stream.consumer(), session.getOptions(), isRouteToLeader());
call.request(prefetchChunks);
stream.setCall(call, /* withBeginTransaction = */ builder.getTransaction().hasBegin());
return stream;
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 976f6136db7..36991b18c3d 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
@@ -202,7 +202,7 @@ private ByteString initTransaction() {
TransactionOptions.newBuilder()
.setPartitionedDml(TransactionOptions.PartitionedDml.getDefaultInstance()))
.build();
- Transaction tx = rpc.beginTransaction(request, session.getOptions());
+ Transaction tx = rpc.beginTransaction(request, session.getOptions(), true);
if (tx.getId().isEmpty()) {
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INTERNAL,
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 df6163e93e9..2bef8e3ada4 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
@@ -275,7 +275,7 @@ public AsyncTransactionManagerImpl transactionManagerAsync(TransactionOption...
@Override
public void prepareReadWriteTransaction() {
setActive(null);
- readyTransactionId = beginTransaction();
+ readyTransactionId = beginTransaction(true);
}
@Override
@@ -296,9 +296,9 @@ public void close() {
}
}
- ByteString beginTransaction() {
+ ByteString beginTransaction(boolean routeToLeader) {
try {
- return beginTransactionAsync().get();
+ return beginTransactionAsync(routeToLeader).get();
} catch (ExecutionException e) {
throw SpannerExceptionFactory.newSpannerException(e.getCause() == null ? e : e.getCause());
} catch (InterruptedException e) {
@@ -306,11 +306,11 @@ ByteString beginTransaction() {
}
}
- ApiFuture beginTransactionAsync() {
- return beginTransactionAsync(Options.fromTransactionOptions());
+ ApiFuture beginTransactionAsync(boolean routeToLeader) {
+ return beginTransactionAsync(Options.fromTransactionOptions(), routeToLeader);
}
- ApiFuture beginTransactionAsync(Options transactionOptions) {
+ ApiFuture beginTransactionAsync(Options transactionOptions, boolean routeToLeader) {
final SettableApiFuture res = SettableApiFuture.create();
final Span span = tracer.spanBuilder(SpannerImpl.BEGIN_TRANSACTION).startSpan();
final BeginTransactionRequest request =
@@ -319,7 +319,7 @@ ApiFuture beginTransactionAsync(Options transactionOptions) {
.setOptions(createReadWriteTransactionOptions(transactionOptions))
.build();
final ApiFuture requestFuture =
- spanner.getRpc().beginTransactionAsync(request, options);
+ spanner.getRpc().beginTransactionAsync(request, options, routeToLeader);
requestFuture.addListener(
tracer.withSpan(
span,
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 d6243f59592..6663d3f8e68 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
@@ -132,6 +132,7 @@ public class SpannerOptions extends ServiceOptions {
private final CallCredentialsProvider callCredentialsProvider;
private final CloseableExecutorProvider asyncExecutorProvider;
private final String compressorName;
+ private final boolean leaderAwareRoutingEnabled;
/**
* Interface that can be used to provide {@link CallCredentials} instead of {@link Credentials} to
@@ -600,6 +601,7 @@ private SpannerOptions(Builder builder) {
callCredentialsProvider = builder.callCredentialsProvider;
asyncExecutorProvider = builder.asyncExecutorProvider;
compressorName = builder.compressorName;
+ leaderAwareRoutingEnabled = builder.leaderAwareRoutingEnabled;
}
/**
@@ -700,6 +702,7 @@ public static class Builder
private CloseableExecutorProvider asyncExecutorProvider;
private String compressorName;
private String emulatorHost = System.getenv("SPANNER_EMULATOR_HOST");
+ private boolean leaderAwareRoutingEnabled = false;
private Builder() {
// Manually set retry and polling settings that work.
@@ -1155,6 +1158,24 @@ public Builder setEmulatorHost(String emulatorHost) {
return this;
}
+ /**
+ * Enable leader aware routing. Leader aware routing would route all requests in RW/PDML
+ * transactions to the leader region.
+ */
+ public Builder enableLeaderAwareRouting() {
+ this.leaderAwareRoutingEnabled = true;
+ return this;
+ }
+
+ /**
+ * Disable leader aware routing. Disabling leader aware routing would route all requests in
+ * RW/PDML transactions to any region.
+ */
+ public Builder disableLeaderAwareRouting() {
+ this.leaderAwareRoutingEnabled = false;
+ return this;
+ }
+
@SuppressWarnings("rawtypes")
@Override
public SpannerOptions build() {
@@ -1291,6 +1312,10 @@ public String getCompressorName() {
return compressorName;
}
+ public boolean isLeaderAwareRoutingEnabled() {
+ return leaderAwareRoutingEnabled;
+ }
+
/** 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/TransactionRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java
index 3d3b34c4c39..ef937e993bd 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
@@ -198,6 +198,11 @@ private TransactionContextImpl(Builder builder) {
this.finishedAsyncOperations.set(null);
}
+ @Override
+ protected boolean isRouteToLeader() {
+ return true;
+ }
+
private void increaseAsyncOperations() {
synchronized (lock) {
if (runningAsyncOperations == 0) {
@@ -255,7 +260,7 @@ ApiFuture ensureTxnAsync() {
private void createTxnAsync(final SettableApiFuture res) {
span.addAnnotation("Creating Transaction");
- final ApiFuture fut = session.beginTransactionAsync(options);
+ final ApiFuture fut = session.beginTransactionAsync(options, isRouteToLeader());
fut.addListener(
() -> {
try {
@@ -717,7 +722,7 @@ private ResultSet internalExecuteUpdate(
/* withTransactionSelector = */ true);
try {
com.google.spanner.v1.ResultSet resultSet =
- rpc.executeQuery(builder.build(), session.getOptions());
+ rpc.executeQuery(builder.build(), session.getOptions(), isRouteToLeader());
if (resultSet.getMetadata().hasTransaction()) {
onTransactionMetadata(
resultSet.getMetadata().getTransaction(), builder.getTransaction().hasBegin());
@@ -747,7 +752,7 @@ public ApiFuture executeUpdateAsync(Statement statement, UpdateOption... o
// Register the update as an async operation that must finish before the transaction may
// commit.
increaseAsyncOperations();
- resultSet = rpc.executeQueryAsync(builder.build(), session.getOptions());
+ resultSet = rpc.executeQueryAsync(builder.build(), session.getOptions(), isRouteToLeader());
} catch (Throwable t) {
decreaseAsyncOperations();
throw t;
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 eb8633d0449..4d70a26866c 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
@@ -252,6 +252,7 @@ public class GapicSpannerRpc implements SpannerRpc {
private static final double ADMINISTRATIVE_REQUESTS_RATE_LIMIT = 1.0D;
private static final ConcurrentMap ADMINISTRATIVE_REQUESTS_RATE_LIMITERS =
new ConcurrentHashMap<>();
+ private final boolean leaderAwareRoutingEnabled;
public static GapicSpannerRpc create(SpannerOptions options) {
return new GapicSpannerRpc(options);
@@ -302,6 +303,7 @@ public GapicSpannerRpc(final SpannerOptions options) {
internalHeaderProviderBuilder.getResourceHeaderKey());
this.callCredentialsProvider = options.getCallCredentialsProvider();
this.compressorName = options.getCompressorName();
+ this.leaderAwareRoutingEnabled = options.isLeaderAwareRoutingEnabled();
if (initializeStubs) {
// First check if SpannerOptions provides a TransportChannelProvider. Create one
@@ -1527,7 +1529,8 @@ public List batchCreateSessions(
requestBuilder.setSessionTemplate(sessionBuilder);
BatchCreateSessionsRequest request = requestBuilder.build();
GrpcCallContext context =
- newCallContext(options, databaseName, request, SpannerGrpc.getBatchCreateSessionsMethod());
+ newCallContext(
+ options, databaseName, request, SpannerGrpc.getBatchCreateSessionsMethod(), true);
return get(spannerStub.batchCreateSessionsCallable().futureCall(request, context))
.getSessionList();
}
@@ -1551,7 +1554,7 @@ public Session createSession(
requestBuilder.setSession(sessionBuilder);
CreateSessionRequest request = requestBuilder.build();
GrpcCallContext context =
- newCallContext(options, databaseName, request, SpannerGrpc.getCreateSessionMethod());
+ newCallContext(options, databaseName, request, SpannerGrpc.getCreateSessionMethod(), true);
return get(spannerStub.createSessionCallable().futureCall(request, context));
}
@@ -1571,9 +1574,13 @@ public ApiFuture asyncDeleteSession(String sessionName, @Nullable Map options) {
+ ReadRequest request,
+ ResultStreamConsumer consumer,
+ @Nullable Map
diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml
index 62038c43c76..d13c5f2a726 100644
--- a/google-cloud-spanner-executor/pom.xml
+++ b/google-cloud-spanner-executor/pom.xml
@@ -5,14 +5,14 @@
4.0.0
com.google.cloud
google-cloud-spanner-executor
- 6.40.2-SNAPSHOT
+ 6.41.0
jar
Google Cloud Spanner Executor
com.google.cloud
google-cloud-spanner-parent
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml
index 3156365549d..617d7cd48aa 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
- 6.40.2-SNAPSHOT
+ 6.41.0
jar
Google Cloud Spanner
https://github.com/googleapis/java-spanner
@@ -11,7 +11,7 @@
com.google.cloud
google-cloud-spanner-parent
- 6.40.2-SNAPSHOT
+ 6.41.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 1ad665c26fe..1b72f13e8cf 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
- 6.40.2-SNAPSHOT
+ 6.41.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
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml
index 417be82d055..50a96471291 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
- 6.40.2-SNAPSHOT
+ 6.41.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
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml
index 0d78faf31db..3adcf0d831a 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
- 6.40.2-SNAPSHOT
+ 6.41.0
grpc-google-cloud-spanner-v1
GRPC library for grpc-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/pom.xml b/pom.xml
index 5832d98e1cc..140627e37f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-spanner-parent
pom
- 6.40.2-SNAPSHOT
+ 6.41.0
Google Cloud Spanner Parent
https://github.com/googleapis/java-spanner
@@ -62,37 +62,37 @@
com.google.api.grpc
proto-google-cloud-spanner-admin-instance-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.api.grpc
proto-google-cloud-spanner-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.api.grpc
proto-google-cloud-spanner-admin-database-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.api.grpc
grpc-google-cloud-spanner-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-instance-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-database-v1
- 6.40.2-SNAPSHOT
+ 6.41.0
com.google.cloud
google-cloud-spanner
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml
index f5e38b90c1c..d7fa0946a8b 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
- 6.40.2-SNAPSHOT
+ 6.41.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
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml
index 9c9c77d5364..d23136ba700 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
- 6.40.2-SNAPSHOT
+ 6.41.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
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml
index d2d1b2cbc87..a9c8352ed01 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
- 6.40.2-SNAPSHOT
+ 6.41.0
proto-google-cloud-spanner-v1
PROTO library for proto-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 001f912ea11..865cd43ece9 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -31,7 +31,7 @@
com.google.cloud
google-cloud-spanner
- 6.40.2-SNAPSHOT
+ 6.41.0
diff --git a/versions.txt b/versions.txt
index 6d66441bcf9..21d06554b43 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,11 +1,11 @@
# Format:
# module:released-version:current-version
-proto-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.2-SNAPSHOT
-proto-google-cloud-spanner-v1:6.40.1:6.40.2-SNAPSHOT
-proto-google-cloud-spanner-admin-database-v1:6.40.1:6.40.2-SNAPSHOT
-grpc-google-cloud-spanner-v1:6.40.1:6.40.2-SNAPSHOT
-grpc-google-cloud-spanner-admin-instance-v1:6.40.1:6.40.2-SNAPSHOT
-grpc-google-cloud-spanner-admin-database-v1:6.40.1:6.40.2-SNAPSHOT
-google-cloud-spanner:6.40.1:6.40.2-SNAPSHOT
-google-cloud-spanner-executor:6.40.1:6.40.2-SNAPSHOT
+proto-google-cloud-spanner-admin-instance-v1:6.41.0:6.41.0
+proto-google-cloud-spanner-v1:6.41.0:6.41.0
+proto-google-cloud-spanner-admin-database-v1:6.41.0:6.41.0
+grpc-google-cloud-spanner-v1:6.41.0:6.41.0
+grpc-google-cloud-spanner-admin-instance-v1:6.41.0:6.41.0
+grpc-google-cloud-spanner-admin-database-v1:6.41.0:6.41.0
+google-cloud-spanner:6.41.0:6.41.0
+google-cloud-spanner-executor:6.41.0:6.41.0