diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml index 6b856abdef3..336ac2c8cab 100644 --- a/.github/workflows/hermetic_library_generation.yaml +++ b/.github/workflows/hermetic_library_generation.yaml @@ -37,7 +37,7 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} - - uses: googleapis/sdk-platform-java/.github/scripts@v2.56.2 + - uses: googleapis/sdk-platform-java/.github/scripts@v2.58.0 if: env.SHOULD_RUN == 'true' with: base_ref: ${{ github.base_ref }} diff --git a/.github/workflows/samples.yaml b/.github/workflows/samples.yaml index 36e725f6aa2..37e2b4054f9 100644 --- a/.github/workflows/samples.yaml +++ b/.github/workflows/samples.yaml @@ -8,7 +8,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-java@v1 with: - java-version: 8 + java-version: 11 - name: Run checkstyle run: mvn -P lint --quiet --batch-mode checkstyle:check working-directory: samples/snippets diff --git a/.github/workflows/unmanaged_dependency_check.yaml b/.github/workflows/unmanaged_dependency_check.yaml index eaf32470034..1579829ae26 100644 --- a/.github/workflows/unmanaged_dependency_check.yaml +++ b/.github/workflows/unmanaged_dependency_check.yaml @@ -17,6 +17,6 @@ jobs: # repository .kokoro/build.sh - name: Unmanaged dependency check - uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.46.2 + uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.48.0 with: bom-path: google-cloud-spanner-bom/pom.xml diff --git a/.kokoro/presubmit/graalvm-native-a.cfg b/.kokoro/presubmit/graalvm-native-a.cfg index d0c29521333..d72ed3f0e3b 100644 --- a/.kokoro/presubmit/graalvm-native-a.cfg +++ b/.kokoro/presubmit/graalvm-native-a.cfg @@ -3,7 +3,7 @@ # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.46.2" # {x-version-update:google-cloud-shared-dependencies:current} + value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.48.0" # {x-version-update:google-cloud-shared-dependencies:current} } env_vars: { diff --git a/.kokoro/presubmit/graalvm-native-b.cfg b/.kokoro/presubmit/graalvm-native-b.cfg index 962c305ff7f..f2e296b8475 100644 --- a/.kokoro/presubmit/graalvm-native-b.cfg +++ b/.kokoro/presubmit/graalvm-native-b.cfg @@ -3,7 +3,7 @@ # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.46.2" # {x-version-update:google-cloud-shared-dependencies:current} + value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.48.0" # {x-version-update:google-cloud-shared-dependencies:current} } env_vars: { diff --git a/.kokoro/presubmit/graalvm-native-c.cfg b/.kokoro/presubmit/graalvm-native-c.cfg index 87b5dff65a3..68512fbff55 100644 --- a/.kokoro/presubmit/graalvm-native-c.cfg +++ b/.kokoro/presubmit/graalvm-native-c.cfg @@ -3,7 +3,7 @@ # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.46.2" # {x-version-update:google-cloud-shared-dependencies:current} + value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.48.0" # {x-version-update:google-cloud-shared-dependencies:current} } env_vars: { diff --git a/.kokoro/presubmit/samples.cfg b/.kokoro/presubmit/samples.cfg new file mode 100644 index 00000000000..2cabe201bcd --- /dev/null +++ b/.kokoro/presubmit/samples.cfg @@ -0,0 +1,38 @@ +# 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" +} + +env_vars: { + key: "JOB_TYPE" + value: "samples" +} + +# TODO: remove this after we've migrated all tests and scripts +env_vars: { + key: "GCLOUD_PROJECT" + value: "gcloud-devel" +} + +env_vars: { + key: "GOOGLE_CLOUD_PROJECT" + value: "gcloud-devel" +} + +env_vars: { + key: "GOOGLE_APPLICATION_CREDENTIALS" + value: "secret_manager/java-it-service-account" +} + +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-it-service-account" +} + +env_vars: { + key: "ENABLE_BUILD_COP" + value: "true" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 05eee459cb8..68989f1bc61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [6.93.0](https://github.com/googleapis/java-spanner/compare/v6.92.0...v6.93.0) (2025-05-09) + + +### Features + +* Enable AFE and gRPC metrics for DP ([#3852](https://github.com/googleapis/java-spanner/issues/3852)) ([203baae](https://github.com/googleapis/java-spanner/commit/203baae3996378435095cb90e3b2c7ee71a643cd)) + + +### Bug Fixes + +* Change server timing duration attribute to float as per w3c ([#3851](https://github.com/googleapis/java-spanner/issues/3851)) ([da8dd8d](https://github.com/googleapis/java-spanner/commit/da8dd8da3171a073d7b450d4413936351a4c1060)) +* **deps:** Update the Java code generator (gapic-generator-java) to 2.57.0 ([23b985c](https://github.com/googleapis/java-spanner/commit/23b985c9a04837b0b38f2cfc5d96469e1d664d67)) +* Non-ASCII Unicode characters in code ([#3844](https://github.com/googleapis/java-spanner/issues/3844)) ([85a0820](https://github.com/googleapis/java-spanner/commit/85a0820505889ae6482a9e4f845cd53430dd6b44)) +* Only close and return sessions once ([#3846](https://github.com/googleapis/java-spanner/issues/3846)) ([32b2373](https://github.com/googleapis/java-spanner/commit/32b2373d62cac3047d9686c56af278c706d7c488)) + ## [6.92.0](https://github.com/googleapis/java-spanner/compare/v6.91.1...v6.92.0) (2025-04-29) diff --git a/README.md b/README.md index 1bcd0fcc4e6..c52608bfba3 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.57.0 + 26.60.0 pom import @@ -41,7 +41,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-spanner - 6.89.0 + 6.93.0 ``` @@ -49,20 +49,20 @@ 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.59.0') +implementation platform('com.google.cloud:libraries-bom:26.60.0') 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.92.0' +implementation 'com.google.cloud:google-cloud-spanner:6.93.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.92.0" +libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.93.0" ``` ## Authentication @@ -575,6 +575,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Tag Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/TagSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/TagSample.java) | | Tracing Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/TracingSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/TracingSample.java) | | Transaction Timeout Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/TransactionTimeoutExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/TransactionTimeoutExample.java) | +| Unnamed Parameters Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UnnamedParametersExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UnnamedParametersExample.java) | | Update Backup Schedule Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateBackupScheduleSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateBackupScheduleSample.java) | | Update Database Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java) | | Update Database With Default Leader Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java) | @@ -728,7 +729,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.92.0 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.93.0 [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/benchmarks/pom.xml b/benchmarks/pom.xml index 61a13d2ff5f..deee9a5ee5f 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -24,7 +24,7 @@ com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT @@ -34,7 +34,7 @@ UTF-8 UTF-8 2.10.1 - 1.45.0 + 1.47.0 @@ -56,6 +56,11 @@ exporter-metrics 0.33.0 + + com.google.cloud + google-cloud-monitoring + 3.63.0 + io.opentelemetry @@ -85,19 +90,14 @@ io.opentelemetry opentelemetry-bom - 1.46.0 + 1.47.0 pom import com.google.cloud google-cloud-spanner - 6.89.0 - - - commons-cli - commons-cli - 1.9.0 + 6.93.0 com.google.auto.value @@ -140,8 +140,9 @@ - com.coveo + com.spotify.fmt fmt-maven-plugin + 2.27 diff --git a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/AbstractRunner.java b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/AbstractRunner.java index 76460891299..b233cedaf22 100644 --- a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/AbstractRunner.java +++ b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/AbstractRunner.java @@ -18,46 +18,80 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; abstract class AbstractRunner implements BenchmarkRunner { - static final int TOTAL_RECORDS = 1000000; - static final String SELECT_QUERY = "SELECT ID FROM FOO WHERE ID = @id"; - static final String UPDATE_QUERY = "UPDATE FOO SET BAR=1 WHERE ID = @id"; + static final int TOTAL_RECORDS = 100000; + static final String TABLE_NAME = "Employees"; + static final String SELECT_QUERY = String.format("SELECT ID FROM %s WHERE ID = @id", TABLE_NAME); + static final String UPDATE_QUERY = + String.format("UPDATE %s SET Name=Google WHERE ID = @id", TABLE_NAME); static final String ID_COLUMN_NAME = "id"; - static final String SERVER_URL = "https://staging-wrenchworks.sandbox.googleapis.com"; + static final Map SERVER_URL_MAPPING = new HashMap<>(); - private final AtomicInteger operationCounter = new AtomicInteger(); + static { + SERVER_URL_MAPPING.put( + Environment.CLOUD_DEVEL, "https://staging-wrenchworks.sandbox.googleapis.com"); + SERVER_URL_MAPPING.put(Environment.PROD, "https://spanner.googleapis.com"); + } + + Map timerConfigurations = new HashMap<>(); + private final Set completedClients = new HashSet<>(); + private final Set finishedClients = new HashSet<>(); + + protected void initiateTimer(int clientId, String message, Instant endTime) { + TimerConfiguration timerConfiguration = + timerConfigurations.getOrDefault(clientId, new TimerConfiguration()); + timerConfiguration.setMessage(message); + timerConfiguration.setEndTime(endTime); + timerConfigurations.put(clientId, timerConfiguration); + } - protected void incOperations() { - operationCounter.incrementAndGet(); + protected void setBenchmarkingCompleted(int clientId) { + this.completedClients.add(clientId); } protected List collectResults( ExecutorService service, List>> results, - int numClients, - int numOperations) + BenchmarkingConfiguration configuration) throws Exception { - int totalOperations = numClients * numOperations; + while (!(finishedClients.size() == configuration.getNumOfClients())) + for (int i = 0; i < configuration.getNumOfClients(); i++) { + TimerConfiguration timerConfiguration = + timerConfigurations.getOrDefault(i, new TimerConfiguration()); + long totalSeconds = + ChronoUnit.SECONDS.between(Instant.now(), timerConfiguration.getEndTime()); + if (completedClients.contains(i)) { + if (!finishedClients.contains(i)) { + System.out.printf("Client %s: Completed", i); + finishedClients.add(i); + } + } else { + System.out.printf( + "Client %s: %s %s Minutes %s Seconds\r", + i + 1, timerConfiguration.getMessage(), totalSeconds / 60, totalSeconds % 60); + } + //noinspection BusyWait + Thread.sleep(1000L); + } service.shutdown(); - while (!service.isTerminated()) { - //noinspection BusyWait - Thread.sleep(1000L); - System.out.printf("\r%d/%d", operationCounter.get(), totalOperations); - } - System.out.println(); if (!service.awaitTermination(60L, TimeUnit.MINUTES)) { throw new TimeoutException(); } - List allResults = new ArrayList<>(numClients * numOperations); + List allResults = new ArrayList<>(); for (Future> result : results) { allResults.addAll(result.get()); } @@ -77,4 +111,25 @@ protected String generateRandomString() { ThreadLocalRandom.current().nextBytes(bytes); return new String(bytes, StandardCharsets.UTF_8); } + + static class TimerConfiguration { + private Instant endTime = Instant.now(); + private String message = "Waiting for benchmarks to start..."; + + Instant getEndTime() { + return endTime; + } + + void setEndTime(Instant endTime) { + this.endTime = endTime; + } + + String getMessage() { + return message; + } + + void setMessage(String message) { + this.message = message; + } + } } diff --git a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkRunner.java b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkRunner.java index 7a731887a86..4f8a77c3a1d 100644 --- a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkRunner.java +++ b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkRunner.java @@ -19,17 +19,18 @@ import java.time.Duration; import java.util.List; -public interface BenchmarkRunner { +interface BenchmarkRunner { enum TransactionType { - READ_ONLY_SINGLE_USE, + READ_ONLY_SINGLE_USE_READ, + READ_ONLY_SINGLE_USE_QUERY, READ_ONLY_MULTI_USE, READ_WRITE } - List execute( - TransactionType transactionType, - int numClients, - int numOperations, - int waitMillis, - boolean useMultiplexedSession); + enum Environment { + PROD, + CLOUD_DEVEL + } + + List execute(BenchmarkingConfiguration configuration); } diff --git a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkingConfiguration.java b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkingConfiguration.java new file mode 100644 index 00000000000..e3003cf58a1 --- /dev/null +++ b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/BenchmarkingConfiguration.java @@ -0,0 +1,115 @@ +/* + * Copyright 2025 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.benchmark; + +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.benchmark.BenchmarkRunner.Environment; +import com.google.cloud.spanner.benchmark.BenchmarkRunner.TransactionType; + +class BenchmarkingConfiguration { + + private DatabaseId databaseId; + private int numOfClients; + private int staleness; + private int warmupTime; + private int executionTime; + private int waitBetweenRequests; + private boolean useMultiplexSession; + private TransactionType transactionType; + private Environment environment; + + int getExecutionTime() { + return executionTime; + } + + BenchmarkingConfiguration setExecutionTime(int executionTime) { + this.executionTime = executionTime; + return this; + } + + DatabaseId getDatabaseId() { + return databaseId; + } + + BenchmarkingConfiguration setDatabaseId(DatabaseId databaseId) { + this.databaseId = databaseId; + return this; + } + + int getNumOfClients() { + return numOfClients; + } + + BenchmarkingConfiguration setNumOfClients(int numOfClients) { + this.numOfClients = numOfClients; + return this; + } + + int getStaleness() { + return staleness; + } + + BenchmarkingConfiguration setStaleness(int staleness) { + this.staleness = staleness; + return this; + } + + int getWarmupTime() { + return warmupTime; + } + + BenchmarkingConfiguration setWarmupTime(int warmupTime) { + this.warmupTime = warmupTime; + return this; + } + + int getWaitBetweenRequests() { + return waitBetweenRequests; + } + + BenchmarkingConfiguration setWaitBetweenRequests(int waitBetweenRequests) { + this.waitBetweenRequests = waitBetweenRequests; + return this; + } + + boolean isUseMultiplexSession() { + return useMultiplexSession; + } + + BenchmarkingConfiguration setUseMultiplexSession(boolean useMultiplexSession) { + this.useMultiplexSession = useMultiplexSession; + return this; + } + + TransactionType getTransactionType() { + return transactionType; + } + + BenchmarkingConfiguration setTransactionType(TransactionType transactionType) { + this.transactionType = transactionType; + return this; + } + + Environment getEnvironment() { + return environment; + } + + BenchmarkingConfiguration setEnvironment(Environment environment) { + this.environment = environment; + return this; + } +} diff --git a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/JavaClientRunner.java b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/JavaClientRunner.java index 6fc0842f376..ebe8f3bbaab 100644 --- a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/JavaClientRunner.java +++ b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/JavaClientRunner.java @@ -20,6 +20,8 @@ import com.google.cloud.opentelemetry.trace.TraceExporter; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeySet; import com.google.cloud.spanner.ReadOnlyTransaction; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SessionPoolOptions; @@ -28,12 +30,11 @@ import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.TimestampBound; import com.google.common.base.Stopwatch; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.DoubleHistogram; -import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.export.MetricExporter; @@ -44,12 +45,14 @@ import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; class JavaClientRunner extends AbstractRunner { private final DatabaseId databaseId; @@ -61,12 +64,7 @@ class JavaClientRunner extends AbstractRunner { } @Override - public List execute( - TransactionType transactionType, - int numClients, - int numOperations, - int waitMillis, - boolean useMultiplexedSession) { + public List execute(BenchmarkingConfiguration configuration) { // setup open telemetry metrics and traces // setup open telemetry metrics and traces SpanExporter traceExporter = TraceExporter.createWithDefaultConfiguration(); @@ -93,7 +91,7 @@ public List execute( .build(); SessionPoolOptions sessionPoolOptions = SessionPoolOptionsHelper.setUseMultiplexedSession( - SessionPoolOptions.newBuilder(), useMultiplexedSession) + SessionPoolOptions.newBuilder(), configuration.isUseMultiplexSession()) .build(); SpannerOptions.enableOpenTelemetryMetrics(); SpannerOptions.enableOpenTelemetryTraces(); @@ -102,67 +100,71 @@ public List execute( .setOpenTelemetry(openTelemetry) .setProjectId(databaseId.getInstanceId().getProject()) .setSessionPoolOption(sessionPoolOptions) - .setHost(SERVER_URL) - .build(); - // Register query stats metric. - // This should be done once before start recording the data. - Meter meter = openTelemetry.getMeter("cloud.google.com/java"); - DoubleHistogram endToEndLatencies = - meter - .histogramBuilder("spanner/end_end_elapsed") - .setDescription("The execution of end to end latency") - .setUnit("ms") + .setHost(SERVER_URL_MAPPING.get(configuration.getEnvironment())) .build(); try (Spanner spanner = options.getService()) { DatabaseClient databaseClient = spanner.getDatabaseClient(databaseId); - List>> results = new ArrayList<>(numClients); - ExecutorService service = Executors.newFixedThreadPool(numClients); - for (int client = 0; client < numClients; client++) { - results.add( - service.submit( - () -> - runBenchmark( - databaseClient, - transactionType, - numOperations, - waitMillis, - endToEndLatencies))); + List>> results = new ArrayList<>(configuration.getNumOfClients()); + ExecutorService service = Executors.newFixedThreadPool(configuration.getNumOfClients()); + for (int client = 0; client < configuration.getNumOfClients(); client++) { + int clientId = client; + results.add(service.submit(() -> runBenchmark(databaseClient, clientId, configuration))); } - return collectResults(service, results, numClients, numOperations); + return collectResults(service, results, configuration); } catch (Throwable t) { throw SpannerExceptionFactory.asSpannerException(t); } } private List runBenchmark( - DatabaseClient databaseClient, - TransactionType transactionType, - int numOperations, - int waitMillis, - DoubleHistogram endToEndLatencies) { - List results = new ArrayList<>(numOperations); + DatabaseClient databaseClient, int clientId, BenchmarkingConfiguration configuration) { + List results = new ArrayList<>(); // Execute one query to make sure everything has been warmed up. - executeTransaction(databaseClient, transactionType, endToEndLatencies); + warmUp(databaseClient, clientId, configuration); + runBenchmark(databaseClient, clientId, configuration, results); + setBenchmarkingCompleted(clientId); + return results; + } - for (int i = 0; i < numOperations; i++) { + private void runBenchmark( + DatabaseClient databaseClient, + int clientId, + BenchmarkingConfiguration configuration, + List results) { + Instant endTime = Instant.now().plus(Duration.ofMinutes(configuration.getExecutionTime())); + initiateTimer(clientId, "Remaining execution time", endTime); + while (endTime.isAfter(Instant.now())) { try { - randomWait(waitMillis); - results.add(executeTransaction(databaseClient, transactionType, endToEndLatencies)); - incOperations(); + randomWait(configuration.getWaitBetweenRequests()); + results.add( + executeTransaction( + databaseClient, configuration.getTransactionType(), configuration.getStaleness())); } catch (InterruptedException interruptedException) { throw SpannerExceptionFactory.propagateInterrupt(interruptedException); } } - return results; + } + + private void warmUp( + DatabaseClient databaseClient, int clientId, BenchmarkingConfiguration configuration) { + Instant endTime = Instant.now().plus(Duration.ofMinutes(configuration.getWarmupTime())); + initiateTimer(clientId, "Remaining warmup time", endTime); + while (endTime.isAfter(Instant.now())) { + executeTransaction( + databaseClient, configuration.getTransactionType(), configuration.getStaleness()); + } } private Duration executeTransaction( - DatabaseClient client, TransactionType transactionType, DoubleHistogram endToEndLatencies) { + DatabaseClient client, TransactionType transactionType, int staleness) { Stopwatch watch = Stopwatch.createStarted(); switch (transactionType) { - case READ_ONLY_SINGLE_USE: - executeSingleUseReadOnlyTransaction(client); + case READ_ONLY_SINGLE_USE_READ: + executeSingleUseReadOnlyTransactionWithRead(client, staleness); + break; + case READ_ONLY_SINGLE_USE_QUERY: + executeSingleUseReadOnlyTransactionWithQuery(client, staleness); break; case READ_ONLY_MULTI_USE: executeMultiUseReadOnlyTransaction(client); @@ -171,13 +173,34 @@ private Duration executeTransaction( executeReadWriteTransaction(client); break; } - Duration elapsedTime = watch.elapsed(); - endToEndLatencies.record(elapsedTime.toMillis()); - return elapsedTime; + return watch.elapsed(); + } + + private void executeSingleUseReadOnlyTransactionWithRead(DatabaseClient client, int staleness) { + List columns = new ArrayList<>(); + int key = getRandomKey(); + columns.add("ID"); + try (ResultSet resultSet = + client + .singleUse(TimestampBound.ofExactStaleness(staleness, TimeUnit.SECONDS)) + .read(TABLE_NAME, KeySet.singleKey(Key.of(key)), columns)) { + while (resultSet.next()) { + for (int i = 0; i < resultSet.getColumnCount(); i++) { + if (resultSet.isNull(i)) { + numNullValues++; + } else { + numNonNullValues++; + } + } + } + } } - private void executeSingleUseReadOnlyTransaction(DatabaseClient client) { - try (ResultSet resultSet = client.singleUse().executeQuery(getRandomisedReadStatement())) { + private void executeSingleUseReadOnlyTransactionWithQuery(DatabaseClient client, int staleness) { + try (ResultSet resultSet = + client + .singleUse(TimestampBound.ofExactStaleness(staleness, TimeUnit.SECONDS)) + .executeQuery(getRandomisedReadStatement())) { while (resultSet.next()) { for (int i = 0; i < resultSet.getColumnCount(); i++) { if (resultSet.isNull(i)) { @@ -225,12 +248,14 @@ private void executeReadWriteTransaction(DatabaseClient client) { } static Statement getRandomisedReadStatement() { - int randomKey = ThreadLocalRandom.current().nextInt(TOTAL_RECORDS); - return Statement.newBuilder(SELECT_QUERY).bind(ID_COLUMN_NAME).to(randomKey).build(); + return Statement.newBuilder(SELECT_QUERY).bind(ID_COLUMN_NAME).to(getRandomKey()).build(); } static Statement getRandomisedUpdateStatement() { - int randomKey = ThreadLocalRandom.current().nextInt(TOTAL_RECORDS); - return Statement.newBuilder(UPDATE_QUERY).bind(ID_COLUMN_NAME).to(randomKey).build(); + return Statement.newBuilder(UPDATE_QUERY).bind(ID_COLUMN_NAME).to(getRandomKey()).build(); + } + + static int getRandomKey() { + return ThreadLocalRandom.current().nextInt(TOTAL_RECORDS); } } diff --git a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/LatencyBenchmark.java b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/LatencyBenchmark.java index 46083f1fee0..d3c2d71e955 100644 --- a/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/LatencyBenchmark.java +++ b/benchmarks/src/main/java/com/google/cloud/spanner/benchmark/LatencyBenchmark.java @@ -18,6 +18,7 @@ import com.google.api.core.InternalApi; import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.benchmark.BenchmarkRunner.Environment; import com.google.cloud.spanner.benchmark.BenchmarkRunner.TransactionType; import com.google.common.annotations.VisibleForTesting; import java.time.Duration; @@ -65,10 +66,17 @@ private static CommandLine parseCommandLine(String[] args) throws ParseException options.addOption( "c", "clients", true, "The number of clients that will be executing queries in parallel."); options.addOption( - "o", - "operations", + "wu", + "warmupTime", true, - "The number of operations that each client will execute. Defaults to 1000."); + "Total warm up time before running actual benchmarking. Defaults to 7 minutes."); + options.addOption( + "et", + "executionTime", + true, + "Total execution time of the benchmarking. Defaults to 30 minutes."); + options.addOption( + "st", "staleness", true, "Total Staleness for Reads and Queries. Defaults to 15 seconds."); options.addOption( "w", "wait", @@ -78,12 +86,16 @@ private static CommandLine parseCommandLine(String[] args) throws ParseException + " second."); options.addOption( "t", - "transaction", + "transactionType", true, "The type of transaction to execute. Must be either READ_ONLY or READ_WRITE. Defaults to" + " READ_ONLY."); - options.addOption("m", "multiplexed", true, "Use multiplexed sessions. Defaults to false."); - options.addOption("w", "wait", true, "Wait time in millis. Defaults to zero."); + options.addOption( + "e", + "environment", + true, + "Spanner Environment. Must be either PROD or CLOUD_DEVEL. Default to CLOUD_DEVEL"); + options.addOption("m", "multiplexed", true, "Use multiplexed sessions. Defaults to true."); options.addOption("name", true, "Name of this test run"); CommandLineParser parser = new DefaultParser(); return parser.parse(options, args); @@ -97,34 +109,54 @@ private static CommandLine parseCommandLine(String[] args) throws ParseException public void run(CommandLine commandLine) { int clients = - commandLine.hasOption('c') ? Integer.parseInt(commandLine.getOptionValue('c')) : 16; - int operations = - commandLine.hasOption('o') ? Integer.parseInt(commandLine.getOptionValue('o')) : 1000; + commandLine.hasOption('c') ? Integer.parseInt(commandLine.getOptionValue('c')) : 1; + int executionTime = + commandLine.hasOption("et") ? Integer.parseInt(commandLine.getOptionValue("et")) : 30; + int warmUpTime = + commandLine.hasOption("wu") ? Integer.parseInt(commandLine.getOptionValue("wu")) : 7; int waitMillis = commandLine.hasOption('w') ? Integer.parseInt(commandLine.getOptionValue('w')) : 0; + int staleness = + commandLine.hasOption("st") ? Integer.parseInt(commandLine.getOptionValue("st")) : 15; TransactionType transactionType = commandLine.hasOption('t') ? TransactionType.valueOf(commandLine.getOptionValue('t').toUpperCase(Locale.ENGLISH)) - : TransactionType.READ_ONLY_SINGLE_USE; + : TransactionType.READ_ONLY_SINGLE_USE_QUERY; boolean useMultiplexedSession = - commandLine.hasOption('m') ? Boolean.parseBoolean(commandLine.getOptionValue('m')) : false; + !commandLine.hasOption('m') || Boolean.parseBoolean(commandLine.getOptionValue('m')); + Environment environment = + commandLine.hasOption('e') + ? Environment.valueOf(commandLine.getOptionValue('e').toUpperCase(Locale.ENGLISH)) + : Environment.CLOUD_DEVEL; + + BenchmarkingConfiguration configuration = + new BenchmarkingConfiguration() + .setDatabaseId(databaseId) + .setNumOfClients(clients) + .setExecutionTime(executionTime) + .setWarmupTime(warmUpTime) + .setStaleness(staleness) + .setTransactionType(transactionType) + .setUseMultiplexSession(useMultiplexedSession) + .setWaitBetweenRequests(waitMillis) + .setEnvironment(environment); System.out.println(); System.out.println("Running benchmark with the following options"); - System.out.printf("Database: %s\n", databaseId); - System.out.printf("Clients: %d\n", clients); - System.out.printf("Operations: %d\n", operations); - System.out.printf("Transaction type: %s\n", transactionType); - System.out.printf("Use Multiplexed Sessions: %s\n", useMultiplexedSession); - System.out.printf("Wait between queries: %dms\n", waitMillis); + System.out.printf("Database: %s\n", configuration.getDatabaseId()); + System.out.printf("Clients: %d\n", configuration.getNumOfClients()); + System.out.printf("Total Warm up Time: %d mins\n", configuration.getWarmupTime()); + System.out.printf("Total Execution Time: %d mins\n", configuration.getExecutionTime()); + System.out.printf("Staleness: %d secs\n", configuration.getStaleness()); + System.out.printf("Transaction type: %s\n", configuration.getTransactionType()); + System.out.printf("Use Multiplexed Sessions: %s\n", configuration.isUseMultiplexSession()); + System.out.printf("Wait between requests: %dms\n", configuration.getWaitBetweenRequests()); List javaClientResults = null; System.out.println(); System.out.println("Running benchmark for Java Client Library"); - JavaClientRunner javaClientRunner = new JavaClientRunner(databaseId); - javaClientResults = - javaClientRunner.execute( - transactionType, clients, operations, waitMillis, useMultiplexedSession); + JavaClientRunner javaClientRunner = new JavaClientRunner(configuration.getDatabaseId()); + javaClientResults = javaClientRunner.execute(configuration); printResults("Java Client Library", javaClientResults); } diff --git a/generation_config.yaml b/generation_config.yaml index 287eba4ba07..4bb3f10afe7 100644 --- a/generation_config.yaml +++ b/generation_config.yaml @@ -1,6 +1,6 @@ -gapic_generator_version: 2.56.2 -googleapis_commitish: 2eec62dc7ed836c8d9f73fb313afb8f48c361bef -libraries_bom_version: 26.59.0 +gapic_generator_version: 2.58.0 +googleapis_commitish: 5c929307255b1726cdc72855ffc67014fc897d11 +libraries_bom_version: 26.60.0 libraries: - api_shortname: spanner name_pretty: Cloud Spanner diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 356aa51b9d8..3e61f186a1d 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,12 +3,12 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT pom com.google.cloud sdk-platform-java-config - 3.46.2 + 3.48.0 Google Cloud Spanner BOM @@ -53,43 +53,43 @@ com.google.cloud google-cloud-spanner - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.cloud google-cloud-spanner test-jar - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT @@ -100,7 +100,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + 3.14.0 1.8 1.8 diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml index 9f25a583a4f..eb754408bb2 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.92.1-SNAPSHOT + 6.93.1-SNAPSHOT jar Google Cloud Spanner Executor com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT @@ -64,7 +64,7 @@ com.google.cloud google-cloud-trace - 2.53.0 + 2.62.0 io.grpc @@ -137,7 +137,7 @@ com.google.api.grpc proto-google-cloud-trace-v1 - 2.53.0 + 2.62.0 com.google.api.grpc @@ -175,7 +175,7 @@ commons-io commons-io - 2.18.0 + 2.19.0 @@ -202,7 +202,7 @@ org.apache.maven.surefire surefire-junit4 - 3.5.2 + 3.5.3 test @@ -267,7 +267,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.5.2 + 3.5.3 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 f7fa02a9958..08cda1a8085 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 @@ -176,6 +176,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -2898,6 +2899,9 @@ private com.google.spanner.executor.v1.ValueList buildStruct(StructReader struct case DATE: value.setDateDaysValue(daysFromDate(struct.getDate(i))); break; + case UUID: + value.setStringValue(struct.getUuid(i).toString()); + break; case NUMERIC: String ascii = struct.getBigDecimal(i).toPlainString(); value.setStringValue(ascii); @@ -3044,6 +3048,25 @@ private com.google.spanner.executor.v1.ValueList buildStruct(StructReader struct com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.DATE).build()); } break; + case UUID: + { + com.google.spanner.executor.v1.ValueList.Builder builder = + com.google.spanner.executor.v1.ValueList.newBuilder(); + List values = struct.getUuidList(i); + for (UUID uuidValue : values) { + com.google.spanner.executor.v1.Value.Builder valueProto = + com.google.spanner.executor.v1.Value.newBuilder(); + if (uuidValue == null) { + builder.addValue(valueProto.setIsNull(true).build()); + } else { + builder.addValue(valueProto.setStringValue(uuidValue.toString()).build()); + } + } + value.setArrayValue(builder.build()); + value.setArrayType( + com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.UUID).build()); + } + break; case TIMESTAMP: { com.google.spanner.executor.v1.ValueList.Builder builder = @@ -3227,6 +3250,7 @@ private static com.google.cloud.spanner.Key keyProtoToCloudKey( case BYTES: case FLOAT64: case DATE: + case UUID: case TIMESTAMP: case NUMERIC: case JSON: @@ -3260,6 +3284,8 @@ private static com.google.cloud.spanner.Key keyProtoToCloudKey( if (type.getCode() == TypeCode.NUMERIC) { String ascii = part.getStringValue(); cloudKey.append(new BigDecimal(ascii)); + } else if (type.getCode() == TypeCode.UUID) { + cloudKey.append(UUID.fromString(part.getStringValue())); } else { cloudKey.append(part.getStringValue()); } @@ -3314,6 +3340,9 @@ private static com.google.cloud.spanner.Value valueProtoToCloudValue( case DATE: return com.google.cloud.spanner.Value.date( value.hasIsNull() ? null : dateFromDays(value.getDateDaysValue())); + case UUID: + return com.google.cloud.spanner.Value.uuid( + value.hasIsNull() ? null : UUID.fromString(value.getStringValue())); case NUMERIC: { if (value.hasIsNull()) { @@ -3438,6 +3467,20 @@ private static com.google.cloud.spanner.Value valueProtoToCloudValue( .collect(Collectors.toList()), CloudClientExecutor::dateFromDays)); } + case UUID: + if (value.hasIsNull()) { + return com.google.cloud.spanner.Value.uuidArray(null); + } else { + return com.google.cloud.spanner.Value.uuidArray( + unmarshallValueList( + value.getArrayValue().getValueList().stream() + .map(com.google.spanner.executor.v1.Value::getIsNull) + .collect(Collectors.toList()), + value.getArrayValue().getValueList().stream() + .map(com.google.spanner.executor.v1.Value::getStringValue) + .collect(Collectors.toList()), + UUID::fromString)); + } case NUMERIC: { if (value.hasIsNull()) { @@ -3603,6 +3646,8 @@ private static com.google.cloud.spanner.Type typeProtoToCloudType( return com.google.cloud.spanner.Type.float64(); case DATE: return com.google.cloud.spanner.Type.date(); + case UUID: + return com.google.cloud.spanner.Type.uuid(); case TIMESTAMP: return com.google.cloud.spanner.Type.timestamp(); case NUMERIC: @@ -3659,6 +3704,8 @@ private static com.google.spanner.v1.Type cloudTypeToTypeProto(@Nonnull Type clo return com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.TIMESTAMP).build(); case DATE: return com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.DATE).build(); + case UUID: + return com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.UUID).build(); case NUMERIC: return com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.NUMERIC).build(); case PG_NUMERIC: diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 15911018d49..1de24c21c6c 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.92.1-SNAPSHOT + 6.93.1-SNAPSHOT jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT google-cloud-spanner @@ -28,7 +28,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.13 @@ -269,12 +269,12 @@ com.google.cloud google-cloud-monitoring - 3.54.0 + 3.63.0 com.google.api.grpc proto-google-cloud-monitoring-v3 - 3.57.0 + 3.63.0 com.google.auth @@ -421,7 +421,7 @@ org.json json - 20240303 + 20250107 test @@ -468,13 +468,13 @@ com.google.cloud google-cloud-trace - 2.51.0 + 2.62.0 test com.google.api.grpc proto-google-cloud-trace-v1 - 2.51.0 + 2.62.0 test diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java index d8ee9fc416e..2eb7c8d2971 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java @@ -97,8 +97,8 @@ class BuiltInMetricsRecorder extends OpenTelemetryMetricsRecorder { * @param attributes Map of the attributes to store */ void recordServerTimingHeaderMetrics( - Long gfeLatency, - Long afeLatency, + Float gfeLatency, + Float afeLatency, Long gfeHeaderMissingCount, Long afeHeaderMissingCount, Map attributes) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsTracer.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsTracer.java index 488cf3890c3..f94af1160e4 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsTracer.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsTracer.java @@ -37,8 +37,8 @@ class BuiltInMetricsTracer extends MetricsTracer implements ApiTracer { private final BuiltInMetricsRecorder builtInOpenTelemetryMetricsRecorder; // These are RPC specific attributes and pertain to a specific API Trace private final Map attributes = new HashMap<>(); - private Long gfeLatency = null; - private Long afeLatency = null; + private Float gfeLatency = null; + private Float afeLatency = null; private long gfeHeaderMissingCount = 0; private long afeHeaderMissingCount = 0; @@ -119,11 +119,11 @@ public void attemptPermanentFailure(Throwable error) { gfeLatency, afeLatency, gfeHeaderMissingCount, afeHeaderMissingCount, attributes); } - void recordGFELatency(Long gfeLatency) { + void recordGFELatency(Float gfeLatency) { this.gfeLatency = gfeLatency; } - void recordAFELatency(Long afeLatency) { + void recordAFELatency(Float afeLatency) { this.afeLatency = afeLatency; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java index afc202342d8..5d3b416788f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java @@ -194,7 +194,7 @@ public void addAttributes(Map attributes) { public void recordGFELatency(Long gfeLatency) { for (ApiTracer child : children) { if (child instanceof BuiltInMetricsTracer) { - ((BuiltInMetricsTracer) child).recordGFELatency(gfeLatency); + ((BuiltInMetricsTracer) child).recordGFELatency(Float.valueOf(gfeLatency)); } } } @@ -210,7 +210,7 @@ public void recordGfeHeaderMissingCount(Long value) { public void recordAFELatency(Long afeLatency) { for (ApiTracer child : children) { if (child instanceof BuiltInMetricsTracer) { - ((BuiltInMetricsTracer) child).recordAFELatency(afeLatency); + ((BuiltInMetricsTracer) child).recordAFELatency(Float.valueOf(afeLatency)); } } } @@ -222,4 +222,20 @@ public void recordAfeHeaderMissingCount(Long value) { } } } + + public void recordGFELatency(Float gfeLatency) { + for (ApiTracer child : children) { + if (child instanceof BuiltInMetricsTracer) { + ((BuiltInMetricsTracer) child).recordGFELatency(gfeLatency); + } + } + } + + public void recordAFELatency(Float afeLatency) { + for (ApiTracer child : children) { + if (child instanceof BuiltInMetricsTracer) { + ((BuiltInMetricsTracer) child).recordAFELatency(afeLatency); + } + } + } } 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 0995c478427..a25e8bfa997 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 @@ -923,8 +923,16 @@ public boolean isEnableBuiltInMetrics() { @Override public boolean isEnableGRPCBuiltInMetrics() { - return "false" - .equalsIgnoreCase(System.getenv(SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS)); + // Enable gRPC built-in metrics if: + // 1. The env var SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS is explicitly set to + // "false", OR + // 2. DirectPath is enabled AND the env var is not set to "true" + // This allows metrics to be enabled by default when DirectPath is on, unless explicitly + // disabled via env. + String grpcDisableEnv = System.getenv("SPANNER_DISABLE_DIRECT_ACCESS_GRPC_BUILTIN_METRICS"); + boolean isDirectPathEnabled = GapicSpannerRpc.isEnableDirectPathXdsEnv(); + return ("false".equalsIgnoreCase(grpcDisableEnv)) + || (isDirectPathEnabled && !"true".equalsIgnoreCase(grpcDisableEnv)); } @Override 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 b91188619aa..6ba935d94e8 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 @@ -1583,6 +1583,7 @@ public final OperationFuture updateDatabaseDdl * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") * .setProtoDescriptors(ByteString.EMPTY) + * .setThroughputMode(true) * .build(); * databaseAdminClient.updateDatabaseDdlAsync(request).get(); * } @@ -1621,6 +1622,7 @@ public final OperationFuture updateDatabaseDdl * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") * .setProtoDescriptors(ByteString.EMPTY) + * .setThroughputMode(true) * .build(); * OperationFuture future = * databaseAdminClient.updateDatabaseDdlOperationCallable().futureCall(request); @@ -1659,6 +1661,7 @@ public final OperationFuture updateDatabaseDdl * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") * .setProtoDescriptors(ByteString.EMPTY) + * .setThroughputMode(true) * .build(); * ApiFuture future = * databaseAdminClient.updateDatabaseDdlCallable().futureCall(request); 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 9811a946200..58b2c78fb2f 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 @@ -556,7 +556,11 @@ Builder setCredentials(Credentials credentials) { return this; } - Builder setStatementExecutorType(StatementExecutorType statementExecutorType) { + /** + * Sets the executor type to use for connections. See {@link StatementExecutorType} for more + * information on what the different options mean. + */ + public Builder setStatementExecutorType(StatementExecutorType statementExecutorType) { this.statementExecutorType = statementExecutorType; return this; } @@ -920,7 +924,11 @@ CredentialsProvider getCredentialsProvider() { return getInitialConnectionPropertyValue(CREDENTIALS_PROVIDER); } - StatementExecutorType getStatementExecutorType() { + /** + * Returns the executor type that is used by connections that are created from this {@link + * ConnectionOptions} instance. + */ + public StatementExecutorType getStatementExecutorType() { return this.statementExecutorType; } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java index ef7ad7e5cdb..d8dcb3c6ae3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlClient.java @@ -35,6 +35,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; /** * Convenience class for executing Data Definition Language statements on transactions that support @@ -137,7 +138,21 @@ OperationFuture executeDdl( dbBuilder.setProtoDescriptors(protoDescriptors); } Database db = dbBuilder.build(); - return dbAdminClient.updateDatabaseDdl(db, statements, null); + return dbAdminClient.updateDatabaseDdl( + db, + statements.stream().map(DdlClient::stripTrailingSemicolon).collect(Collectors.toList()), + null); + } + + static String stripTrailingSemicolon(String input) { + if (!input.contains(";")) { + return input; + } + String trimmed = input.trim(); + if (trimmed.endsWith(";")) { + return trimmed.substring(0, trimmed.length() - 1); + } + return input; } /** Returns true if the statement is a `CREATE DATABASE ...` statement. */ diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java index 60b1acfb60a..8c521b7500e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java @@ -163,6 +163,7 @@ static class SpannerPoolKey { private final boolean enableEndToEndTracing; private final String clientCertificate; private final String clientCertificateKey; + private final boolean isExperimentalHost; @VisibleForTesting static SpannerPoolKey of(ConnectionOptions options) { @@ -196,6 +197,7 @@ private SpannerPoolKey(ConnectionOptions options) throws IOException { this.enableEndToEndTracing = options.isEndToEndTracingEnabled(); this.clientCertificate = options.getClientCertificate(); this.clientCertificateKey = options.getClientCertificateKey(); + this.isExperimentalHost = options.isExperimentalHost(); } @Override @@ -220,7 +222,8 @@ public boolean equals(Object o) { && Objects.equals(this.enableApiTracing, other.enableApiTracing) && Objects.equals(this.enableEndToEndTracing, other.enableEndToEndTracing) && Objects.equals(this.clientCertificate, other.clientCertificate) - && Objects.equals(this.clientCertificateKey, other.clientCertificateKey); + && Objects.equals(this.clientCertificateKey, other.clientCertificateKey) + && Objects.equals(this.isExperimentalHost, other.isExperimentalHost); } @Override @@ -241,7 +244,8 @@ public int hashCode() { this.enableApiTracing, this.enableEndToEndTracing, this.clientCertificate, - this.clientCertificateKey); + this.clientCertificateKey, + this.isExperimentalHost); } } @@ -405,6 +409,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) { if (key.clientCertificate != null && key.clientCertificateKey != null) { builder.useClientCert(key.clientCertificate, key.clientCertificateKey); } + if (key.isExperimentalHost) { + builder.setExperimentalHost(key.host); + } if (options.getConfigurator() != null) { options.getConfigurator().configure(builder); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java index 6e410f31e83..b022158b917 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementExecutor.java @@ -172,9 +172,23 @@ private static ListeningExecutorService createExecutorService(StatementExecutorT */ private final List interceptors; - enum StatementExecutorType { + /** The executor type that is used for statements that are executed on a connection. */ + public enum StatementExecutorType { + /** + * Use a platform thread per connection. This allows async execution of statements, but costs + * more resources than the other options. + */ PLATFORM_THREAD, + /** + * Use a virtual thread per connection. This allows async execution of statements. Virtual + * threads are only supported on Java 21 and higher. + */ VIRTUAL_THREAD, + /** + * Use the calling thread for execution. This does not support async execution of statements. + * This option is used by drivers that do not support async execution, such as JDBC and + * PGAdapter. + */ DIRECT_EXECUTOR, } 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 fa5719c95c4..c43bbe1f11b 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 @@ -367,8 +367,7 @@ public GapicSpannerRpc(final SpannerOptions options) { .withEncoding(compressorName)) .setHeaderProvider(headerProviderWithUserAgent) .setAllowNonDefaultServiceAccount(true); - String directPathXdsEnv = System.getenv("GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"); - boolean isAttemptDirectPathXds = Boolean.parseBoolean(directPathXdsEnv); + boolean isAttemptDirectPathXds = isEnableDirectPathXdsEnv(); if (isAttemptDirectPathXds) { defaultChannelProviderBuilder.setAttemptDirectPath(true); defaultChannelProviderBuilder.setAttemptDirectPathXds(); @@ -678,7 +677,19 @@ private static boolean isEmulatorEnabled(SpannerOptions options, String emulator } public static boolean isEnableAFEServerTiming() { - return "false".equalsIgnoreCase(System.getenv("SPANNER_DISABLE_AFE_SERVER_TIMING")); + // Enable AFE metrics and add AFE header if: + // 1. The env var SPANNER_DISABLE_AFE_SERVER_TIMING is explicitly set to "false", OR + // 2. DirectPath is enabled AND the env var is not set to "true" + // This allows metrics to be enabled by default when DirectPath is on, unless explicitly + // disabled via env. + String afeDisableEnv = System.getenv("SPANNER_DISABLE_AFE_SERVER_TIMING"); + boolean isDirectPathEnabled = isEnableDirectPathXdsEnv(); + return ("false".equalsIgnoreCase(afeDisableEnv)) + || (isDirectPathEnabled && !"true".equalsIgnoreCase(afeDisableEnv)); + } + + public static boolean isEnableDirectPathXdsEnv() { + return Boolean.parseBoolean(System.getenv("GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS")); } private static final RetrySettings ADMIN_REQUESTS_LIMIT_EXCEEDED_RETRY_SETTINGS = diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java index 0f132593565..e3bc848dc1e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/HeaderInterceptor.java @@ -76,7 +76,7 @@ class HeaderInterceptor implements ClientInterceptor { private static final Metadata.Key GOOGLE_CLOUD_RESOURCE_PREFIX_KEY = Metadata.Key.of("google-cloud-resource-prefix", Metadata.ASCII_STRING_MARSHALLER); private static final Pattern SERVER_TIMING_PATTERN = - Pattern.compile("(?[a-zA-Z0-9_-]+);\\s*dur=(?\\d+)"); + Pattern.compile("(?[a-zA-Z0-9_-]+);\\s*dur=(?\\d+(\\.\\d+)?)"); private static final Pattern GOOGLE_CLOUD_RESOURCE_PREFIX_PATTERN = Pattern.compile( ".*projects/(?\\p{ASCII}[^/]*)(/instances/(?\\p{ASCII}[^/]*))?(/databases/(?\\p{ASCII}[^/]*))?"); @@ -133,7 +133,8 @@ public void onHeaders(Metadata metadata) { Boolean isDirectPathUsed = isDirectPathUsed(getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR)); addDirectPathUsedAttribute(compositeTracer, isDirectPathUsed); - processHeader(metadata, tagContext, attributes, span, compositeTracer); + processHeader( + metadata, tagContext, attributes, span, compositeTracer, isDirectPathUsed); super.onHeaders(metadata); } }, @@ -151,7 +152,8 @@ private void processHeader( TagContext tagContext, Attributes attributes, Span span, - CompositeTracer compositeTracer) { + CompositeTracer compositeTracer, + boolean isDirectPathUsed) { MeasureMap measureMap = STATS_RECORDER.newMeasureMap(); String serverTiming = metadata.get(SERVER_TIMING_HEADER_KEY); try { @@ -162,17 +164,17 @@ private void processHeader( // would fail to parse it correctly. To make the parsing more robust, the logic has been // updated to handle multiple metrics gracefully. - Map serverTimingMetrics = parseServerTimingHeader(serverTiming); + Map serverTimingMetrics = parseServerTimingHeader(serverTiming); if (serverTimingMetrics.containsKey(GFE_TIMING_HEADER)) { - long gfeLatency = serverTimingMetrics.get(GFE_TIMING_HEADER); + float gfeLatency = serverTimingMetrics.get(GFE_TIMING_HEADER); - measureMap.put(SPANNER_GFE_LATENCY, gfeLatency); + measureMap.put(SPANNER_GFE_LATENCY, (long) gfeLatency); measureMap.put(SPANNER_GFE_HEADER_MISSING_COUNT, 0L); measureMap.record(tagContext); - spannerRpcMetrics.recordGfeLatency(gfeLatency, attributes); + spannerRpcMetrics.recordGfeLatency((long) gfeLatency, attributes); spannerRpcMetrics.recordGfeHeaderMissingCount(0L, attributes); - if (compositeTracer != null) { + if (compositeTracer != null && !isDirectPathUsed) { compositeTracer.recordGFELatency(gfeLatency); } if (span != null) { @@ -181,7 +183,7 @@ private void processHeader( } else { measureMap.put(SPANNER_GFE_HEADER_MISSING_COUNT, 1L).record(tagContext); spannerRpcMetrics.recordGfeHeaderMissingCount(1L, attributes); - if (compositeTracer != null) { + if (compositeTracer != null && !isDirectPathUsed) { compositeTracer.recordGfeHeaderMissingCount(1L); } } @@ -189,7 +191,7 @@ private void processHeader( // Record AFE metrics if (compositeTracer != null && GapicSpannerRpc.isEnableAFEServerTiming()) { if (serverTimingMetrics.containsKey(AFE_TIMING_HEADER)) { - long afeLatency = serverTimingMetrics.get(AFE_TIMING_HEADER); + float afeLatency = serverTimingMetrics.get(AFE_TIMING_HEADER); compositeTracer.recordAFELatency(afeLatency); } else { compositeTracer.recordAfeHeaderMissingCount(1L); @@ -200,8 +202,8 @@ private void processHeader( } } - private Map parseServerTimingHeader(String serverTiming) { - Map serverTimingMetrics = new HashMap<>(); + private Map parseServerTimingHeader(String serverTiming) { + Map serverTimingMetrics = new HashMap<>(); if (serverTiming != null) { Matcher matcher = SERVER_TIMING_PATTERN.matcher(serverTiming); while (matcher.find()) { @@ -209,7 +211,7 @@ private Map parseServerTimingHeader(String serverTiming) { String durationStr = matcher.group("duration"); if (metricName != null && durationStr != null) { - serverTimingMetrics.put(metricName, Long.valueOf(durationStr)); + serverTimingMetrics.put(metricName, Float.valueOf(durationStr)); } } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractNettyMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractNettyMockServerTest.java index afb550b5c6a..a763f98cf0f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractNettyMockServerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractNettyMockServerTest.java @@ -31,7 +31,7 @@ import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -44,11 +44,10 @@ abstract class AbstractNettyMockServerTest { protected static InetSocketAddress address; static ExecutorService executor; protected static LocalChannelProvider channelProvider; - protected static AtomicInteger fakeServerTiming = - new AtomicInteger(new Random().nextInt(1000) + 1); - - protected static AtomicInteger fakeAFEServerTiming = - new AtomicInteger(new Random().nextInt(500) + 1); + protected static final AtomicReference fakeServerTiming = + new AtomicReference<>((float) (new Random().nextDouble() * 1000) + 1); + protected static final AtomicReference fakeAFEServerTiming = + new AtomicReference<>((float) new Random().nextInt(500) + 1); protected Spanner spanner; @@ -76,7 +75,7 @@ public void sendHeaders(Metadata headers) { headers.put( Metadata.Key.of("server-timing", Metadata.ASCII_STRING_MARSHALLER), String.format( - "afe; dur=%d, gfet4t7; dur=%d", + "afe; dur=%f, gfet4t7; dur=%f", fakeAFEServerTiming.get(), fakeServerTiming.get())); super.sendHeaders(headers); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetryBuiltInMetricsTracerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetryBuiltInMetricsTracerTest.java index 9392e202b7a..55c5cf47714 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetryBuiltInMetricsTracerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetryBuiltInMetricsTracerTest.java @@ -34,6 +34,7 @@ import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime; import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult; import com.google.cloud.spanner.connection.RandomResultSetGenerator; +import com.google.cloud.spanner.spi.v1.GapicSpannerRpc; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.Range; @@ -84,7 +85,7 @@ public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractNettyMockServ Attributes.builder().put(BuiltInMetricsConstant.DIRECT_PATH_USED_KEY, "false").build(); ; - private static final long MIN_LATENCY = 0; + private static final double MIN_LATENCY = 0; private DatabaseClient client; @@ -159,7 +160,7 @@ public void testMetricsSingleUseQuery() { assertFalse(resultSet.next()); } - long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS); + double elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS); Attributes expectedAttributes = expectedCommonBaseAttributes.toBuilder() .putAll(expectedCommonRequestAttributes) @@ -170,13 +171,14 @@ public void testMetricsSingleUseQuery() { MetricData operationLatencyMetricData = getMetricData(metricReader, BuiltInMetricsConstant.OPERATION_LATENCIES_NAME); assertNotNull(operationLatencyMetricData); - long operationLatencyValue = getAggregatedValue(operationLatencyMetricData, expectedAttributes); + double operationLatencyValue = + getAggregatedValue(operationLatencyMetricData, expectedAttributes); assertThat(operationLatencyValue).isIn(Range.closed(MIN_LATENCY, elapsed)); MetricData attemptLatencyMetricData = getMetricData(metricReader, BuiltInMetricsConstant.ATTEMPT_LATENCIES_NAME); assertNotNull(attemptLatencyMetricData); - long attemptLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes); + double attemptLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes); assertThat(attemptLatencyValue).isIn(Range.closed(MIN_LATENCY, elapsed)); MetricData operationCountMetricData = @@ -189,16 +191,23 @@ public void testMetricsSingleUseQuery() { assertNotNull(attemptCountMetricData); assertThat(getAggregatedValue(attemptCountMetricData, expectedAttributes)).isEqualTo(1); - MetricData gfeLatencyMetricData = - getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME); - long gfeLatencyValue = getAggregatedValue(gfeLatencyMetricData, expectedAttributes); - assertEquals(fakeServerTiming.get(), gfeLatencyValue, 0); - assertFalse( checkIfMetricExists(metricReader, BuiltInMetricsConstant.GFE_CONNECTIVITY_ERROR_NAME)); - assertFalse(checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME)); assertFalse( checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_CONNECTIVITY_ERROR_NAME)); + if (GapicSpannerRpc.isEnableDirectPathXdsEnv()) { + // AFE metrics are enabled for DirectPath. + MetricData afeLatencyMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME); + double afeLatencyValue = getAggregatedValue(afeLatencyMetricData, expectedAttributes); + assertEquals(fakeAFEServerTiming.get(), afeLatencyValue, 1e-6); + } else { + MetricData gfeLatencyMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME); + double gfeLatencyValue = getAggregatedValue(gfeLatencyMetricData, expectedAttributes); + assertEquals(fakeServerTiming.get(), gfeLatencyValue, 1e-6); + assertFalse(checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME)); + } } private boolean isJava8() { @@ -229,7 +238,7 @@ public void testMetricsSingleUseQueryWithAfeEnabled() throws Exception { assertFalse(resultSet.next()); } - long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS); + double elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS); Attributes expectedAttributes = expectedCommonBaseAttributes.toBuilder() .putAll(expectedCommonRequestAttributes) @@ -240,14 +249,14 @@ public void testMetricsSingleUseQueryWithAfeEnabled() throws Exception { MetricData operationLatencyMetricData = getMetricData(metricReader, BuiltInMetricsConstant.OPERATION_LATENCIES_NAME); assertNotNull(operationLatencyMetricData); - long operationLatencyValue = + double operationLatencyValue = getAggregatedValue(operationLatencyMetricData, expectedAttributes); assertThat(operationLatencyValue).isIn(Range.closed(MIN_LATENCY, elapsed)); MetricData attemptLatencyMetricData = getMetricData(metricReader, BuiltInMetricsConstant.ATTEMPT_LATENCIES_NAME); assertNotNull(attemptLatencyMetricData); - long attemptLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes); + double attemptLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes); assertThat(attemptLatencyValue).isIn(Range.closed(MIN_LATENCY, elapsed)); MetricData operationCountMetricData = @@ -260,20 +269,19 @@ public void testMetricsSingleUseQueryWithAfeEnabled() throws Exception { assertNotNull(attemptCountMetricData); assertThat(getAggregatedValue(attemptCountMetricData, expectedAttributes)).isEqualTo(1); - MetricData gfeLatencyMetricData = - getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME); - long gfeLatencyValue = getAggregatedValue(gfeLatencyMetricData, expectedAttributes); - assertEquals(fakeServerTiming.get(), gfeLatencyValue, 0); - assertFalse( checkIfMetricExists(metricReader, BuiltInMetricsConstant.GFE_CONNECTIVITY_ERROR_NAME)); - - MetricData afeLatencyMetricData = - getMetricData(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME); - long afeLatencyValue = getAggregatedValue(afeLatencyMetricData, expectedAttributes); - assertEquals(fakeAFEServerTiming.get(), afeLatencyValue, 0); assertFalse( checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_CONNECTIVITY_ERROR_NAME)); + MetricData afeLatencyMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME); + double afeLatencyValue = getAggregatedValue(afeLatencyMetricData, expectedAttributes); + assertEquals(fakeAFEServerTiming.get(), afeLatencyValue, 1e-6); + + MetricData gfeLatencyMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME); + double gfeLatencyValue = getAggregatedValue(gfeLatencyMetricData, expectedAttributes); + assertEquals(fakeServerTiming.get(), gfeLatencyValue, 1e-6); } finally { writeableEnvironmentVariables.remove("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"); } @@ -402,7 +410,7 @@ public void testNoNetworkConnection() { // Attempt count should have a failed metric point for CreateSession. assertEquals( - 1, getAggregatedValue(attemptCountMetricData, expectedAttributesCreateSessionFailed)); + 1, getAggregatedValue(attemptCountMetricData, expectedAttributesCreateSessionFailed), 0); } @Test @@ -444,13 +452,20 @@ public void testNoServerTimingHeader() throws IOException, InterruptedException .put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.ExecuteSql") .build(); - MetricData gfeConnectivityMetricData = - getMetricData(metricReader, BuiltInMetricsConstant.GFE_CONNECTIVITY_ERROR_NAME); - assertThat(getAggregatedValue(gfeConnectivityMetricData, expectedAttributes)).isEqualTo(1); assertFalse(checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_LATENCIES_NAME)); assertFalse(checkIfMetricExists(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME)); - assertFalse( - checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_CONNECTIVITY_ERROR_NAME)); + if (GapicSpannerRpc.isEnableDirectPathXdsEnv()) { + MetricData afeConnectivityMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.AFE_CONNECTIVITY_ERROR_NAME); + assertThat(getAggregatedValue(afeConnectivityMetricData, expectedAttributes)).isEqualTo(1); + } else { + MetricData gfeConnectivityMetricData = + getMetricData(metricReader, BuiltInMetricsConstant.GFE_CONNECTIVITY_ERROR_NAME); + assertThat(getAggregatedValue(gfeConnectivityMetricData, expectedAttributes)).isEqualTo(1); + assertFalse( + checkIfMetricExists(metricReader, BuiltInMetricsConstant.AFE_CONNECTIVITY_ERROR_NAME)); + } + spannerNoHeader.close(); serverNoHeader.shutdown(); serverNoHeader.awaitTermination(); @@ -509,14 +524,14 @@ private boolean checkIfMetricExists(InMemoryMetricReader reader, String metricNa return false; } - private long getAggregatedValue(MetricData metricData, Attributes attributes) { + private float getAggregatedValue(MetricData metricData, Attributes attributes) { switch (metricData.getType()) { case HISTOGRAM: return metricData.getHistogramData().getPoints().stream() .filter(pd -> pd.getAttributes().equals(attributes)) - .map(data -> (long) data.getSum() / data.getCount()) + .map(data -> (float) data.getSum() / data.getCount()) .findFirst() - .orElse(0L); + .orElse(0F); case LONG_SUM: return metricData.getLongSumData().getPoints().stream() .filter(pd -> pd.getAttributes().equals(attributes)) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java index e71b912233d..3585421e32c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DdlTest.java @@ -364,4 +364,47 @@ public void testSetsDefaultSequenceKindAndRetriesBatch() { "create table bar (id2 int64 auto_increment primary key", ((UpdateDatabaseDdlRequest) requests.get(0)).getStatements(1)); } + + @Test + public void testStripTrailingSemicolon() { + addUpdateDdlResponse(); + addUpdateDdlResponse(); + addUpdateDdlResponse(); + addUpdateDdlResponse(); + try (Connection connection = createConnection()) { + connection.execute(Statement.of("drop table foo;")); + connection.execute(Statement.of("drop table foo \n\t;\n\t ")); + connection.execute(Statement.of("drop table foo")); + + connection.startBatchDdl(); + connection.execute(Statement.of("create table foo (id1 int64 auto_increment primary key;")); + connection.execute( + Statement.of("create table foo (id1 int64 auto_increment primary key \n\t;\n\t ")); + connection.execute(Statement.of("create table foo (id2 int64 auto_increment primary key")); + connection.runBatch(); + } + assertEquals(4, mockDatabaseAdmin.getRequests().size()); + assertEquals( + "drop table foo", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(0)).getStatements(0)); + assertEquals( + "drop table foo \n\t", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(1)).getStatements(0)); + assertEquals( + "drop table foo", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(2)).getStatements(0)); + + assertEquals( + 3, + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(3)).getStatementsCount()); + assertEquals( + "create table foo (id1 int64 auto_increment primary key", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(3)).getStatements(0)); + assertEquals( + "create table foo (id1 int64 auto_increment primary key \n\t", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(3)).getStatements(1)); + assertEquals( + "create table foo (id2 int64 auto_increment primary key", + ((UpdateDatabaseDdlRequest) mockDatabaseAdmin.getRequests().get(3)).getStatements(2)); + } } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITUuidTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITUuidTest.java index 17e6369bf02..561602abfe2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITUuidTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITUuidTest.java @@ -399,7 +399,7 @@ public void uuidAsKeyParameter() { return null; }); - verifyKeyContents(Arrays.asList(uuid1, uuid2)); + verifyKeyContents(Arrays.asList(uuid2, uuid1)); } private void verifyKeyContents(List uuids) { diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 945eda59f56..ffab007ac8c 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.92.1-SNAPSHOT + 6.93.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 - 6.92.1-SNAPSHOT + 6.93.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 977f31c1529..1ac0f904fa0 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.92.1-SNAPSHOT + 6.93.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 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-executor-v1/pom.xml b/grpc-google-cloud-spanner-executor-v1/pom.xml index 4da1b80ccbe..72b93fe0a0f 100644 --- a/grpc-google-cloud-spanner-executor-v1/pom.xml +++ b/grpc-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT grpc-google-cloud-spanner-executor-v1 GRPC library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index 8d478945b85..5068d9f5c6a 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.92.1-SNAPSHOT + 6.93.1-SNAPSHOT grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index 064767ba74c..3d0a51e7949 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -14,7 +14,7 @@ com.google.cloud sdk-platform-java-config - 3.46.2 + 3.48.0 @@ -61,47 +61,47 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT com.google.cloud google-cloud-spanner - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT @@ -153,7 +153,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + 3.14.0 1.8 1.8 @@ -171,7 +171,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 3.8.0 + 3.9.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 788d278114f..bbe9f8912f3 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.92.1-SNAPSHOT + 6.93.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 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT 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 2e692633260..5f00550cff2 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 @@ -149,325 +149,332 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { static { java.lang.String[] descriptorData = { - "\n" - + "=google/spanner/admin/database/v1/spanner_database_admin.proto\022 google.spanner." + "\n=google/spanner/admin/database/v1/spann" + + "er_database_admin.proto\022 google.spanner." + "admin.database.v1\032\034google/api/annotation" + "s.proto\032\027google/api/client.proto\032\037google" + "/api/field_behavior.proto\032\031google/api/re" + "source.proto\032\036google/iam/v1/iam_policy.p" + "roto\032\032google/iam/v1/policy.proto\032#google" - + "/longrunning/operations.proto\032\033google/protobuf/empty.proto\032" - + " google/protobuf/field_mask.proto\032\034google/protobuf/struct.pro" + + "/longrunning/operations.proto\032\033google/pr" + + "otobuf/empty.proto\032 google/protobuf/fiel" + + "d_mask.proto\032\034google/protobuf/struct.pro" + "to\032\037google/protobuf/timestamp.proto\032-goo" - + "gle/spanner/admin/database/v1/backup.proto\0326google/spanner/admin/database/v1/bac" - + "kup_schedule.proto\032-google/spanner/admin/database/v1/common.proto\"\253\001\n" - + "\013RestoreInfo\022H\n" - + "\013source_type\030\001" - + " \001(\01623.google.spanner.admin.database.v1.RestoreSourceType\022C\n" - + "\013backup_info\030\002" - + " \001(\0132,.google.spanner.admin.database.v1.BackupInfoH\000B\r\n" - + "\013source_info\"\312\006\n" - + "\010Database\022\021\n" - + "\004name\030\001 \001(\tB\003\340A\002\022D\n" - + "\005state\030\002" - + " \001(\01620.google.spanner.admin.database.v1.Database.StateB\003\340A\003\0224\n" - + "\013create_time\030\003 \001(\0132\032.google.protobuf.TimestampB\003\340A\003\022H\n" - + "\014restore_info\030\004" - + " \001(\0132-.google.spanner.admin.database.v1.RestoreInfoB\003\340A\003\022R\n" - + "\021encryption_config\030\005" - + " \001(\01322.google.spanner.admin.database.v1.EncryptionConfigB\003\340A\003\022N\n" - + "\017encryption_info\030\010" - + " \003(\01320.google.spanner.admin.database.v1.EncryptionInfoB\003\340A\003\022%\n" - + "\030version_retention_period\030\006 \001(\tB\003\340A\003\022>\n" - + "\025earliest_version_time\030\007" - + " \001(\0132\032.google.protobuf.TimestampB\003\340A\003\022\033\n" - + "\016default_leader\030\t \001(\tB\003\340A\003\022P\n" - + "\020database_dialect\030\n" - + " \001(\01621.google.spanner.admin.database.v1.DatabaseDialectB\003\340A\003\022\036\n" - + "\026enable_drop_protection\030\013 \001(\010\022\030\n" - + "\013reconciling\030\014 \001(\010B\003\340A\003\"M\n" - + "\005State\022\025\n" - + "\021STATE_UNSPECIFIED\020\000\022\014\n" - + "\010CREATING\020\001\022\t\n" - + "\005READY\020\002\022\024\n" - + "\020READY_OPTIMIZING\020\003:b\352A_\n" - + "\037spanner.googleapis.com/Database\022\332A\006pare" - + "nt\202\323\344\223\002/\022-/v1/{parent=projects/*/instances/*}/databases\022\244\002\n" - + "\016CreateDatabase\0227.google.spanner.admin.database.v1.CreateData" - + "baseRequest\032\035.google.longrunning.Operation\"\271\001\312Ad\n" - + ")google.spanner.admin.database.v1.Database\0227google.spanner.admin.databa" - + "se.v1.CreateDatabaseMetadata\332A\027parent,cr" - + "eate_statement\202\323\344\223\0022\"-/v1/{parent=projects/*/instances/*}/databases:\001*\022\255\001\n" - + "\013GetDatabase\0224.google.spanner.admin.database.v" - + "1.GetDatabaseRequest\032*.google.spanner.ad" - + "min.database.v1.Database\"<\332A\004name\202\323\344\223\002/\022" - + "-/v1/{name=projects/*/instances/*/databases/*}\022\357\001\n" - + "\016UpdateDatabase\0227.google.spann" - + "er.admin.database.v1.UpdateDatabaseRequest\032\035.google.longrunning.Operation\"\204\001\312A\"\n" - + "\010Database\022\026UpdateDatabaseMetadata\332A\024data" - + "base,update_mask\202\323\344\223\002B26/v1/{database.na" - + "me=projects/*/instances/*/databases/*}:\010database\022\235\002\n" - + "\021UpdateDatabaseDdl\022:.google.spanner.admin.database.v1.UpdateDatabase" - + "DdlRequest\032\035.google.longrunning.Operation\"\254\001\312AS\n" - + "\025google.protobuf.Empty\022:google.spanner.admin.database.v1.UpdateDatabaseD" - + "dlMetadata\332A\023database,statements\202\323\344\223\002:25" - + "/v1/{database=projects/*/instances/*/databases/*}/ddl:\001*\022\243\001\n" - + "\014DropDatabase\0225.google.spanner.admin.database.v1.DropDatabas" - + "eRequest\032\026.google.protobuf.Empty\"D\332A\010dat" - + "abase\202\323\344\223\0023*1/v1/{database=projects/*/instances/*/databases/*}\022\315\001\n" - + "\016GetDatabaseDdl\0227.google.spanner.admin.database.v1.Get" - + "DatabaseDdlRequest\0328.google.spanner.admi" - + "n.database.v1.GetDatabaseDdlResponse\"H\332A" - + "\010database\202\323\344\223\0027\0225/v1/{database=projects/*/instances/*/databases/*}/ddl\022\302\002\n" - + "\014SetIamPolicy\022\".google.iam.v1.SetIamPolicyRequ" - + "est\032\025.google.iam.v1.Policy\"\366\001\332A\017resource" - + ",policy\202\323\344\223\002\335\001\">/v1/{resource=projects/*" - + "/instances/*/databases/*}:setIamPolicy:\001*ZA\"/v1/{resource=projects/*/i" - + "nstances/*/databases/*}:getIamPolicy:\001*ZA\".google.spanner.admin.database.v1.ListBa" - + "ckupOperationsResponse\"E\332A\006parent\202\323\344\223\0026\022" - + "4/v1/{parent=projects/*/instances/*}/backupOperations\022\334\001\n" - + "\021ListDatabaseRoles\022:.google.spanner.admin.database.v1.ListDatab" - + "aseRolesRequest\032;.google.spanner.admin.d" - + "atabase.v1.ListDatabaseRolesResponse\"N\332A" - + "\006parent\202\323\344\223\002?\022=/v1/{parent=projects/*/instances/*/databases/*}/databaseRoles\022\350\001\n" - + "\016AddSplitPoints\0227.google.spanner.admin.d" - + "atabase.v1.AddSplitPointsRequest\0328.google.spanner.admin.database.v1.AddSplitPoin" - + "tsResponse\"c\332A\025database,split_points\202\323\344\223" - + "\002E\"@/v1/{database=projects/*/instances/*/databases/*}:addSplitPoints:\001*\022\216\002\n" - + "\024CreateBackupSchedule\022=.google.spanner.admin." - + "database.v1.CreateBackupScheduleRequest\0320.google.spanner.admin.database.v1.Backu" - + "pSchedule\"\204\001\332A)parent,backup_schedule,ba" - + "ckup_schedule_id\202\323\344\223\002R\"?/v1/{parent=proj" - + "ects/*/instances/*/databases/*}/backupSchedules:\017backup_schedule\022\321\001\n" - + "\021GetBackupSchedule\022:.google.spanner.admin.database.v" - + "1.GetBackupScheduleRequest\0320.google.span" - + "ner.admin.database.v1.BackupSchedule\"N\332A" - + "\004name\202\323\344\223\002A\022?/v1/{name=projects/*/instances/*/databases/*/backupSchedules/*}\022\220\002\n" - + "\024UpdateBackupSchedule\022=.google.spanner.admin.database.v1.UpdateBackupScheduleReq" - + "uest\0320.google.spanner.admin.database.v1." - + "BackupSchedule\"\206\001\332A\033backup_schedule,upda" - + "te_mask\202\323\344\223\002b2O/v1/{backup_schedule.name" - + "=projects/*/instances/*/databases/*/backupSchedules/*}:\017backup_schedule\022\275\001\n" - + "\024DeleteBackupSchedule\022=.google.spanner.admin." - + "database.v1.DeleteBackupScheduleRequest\032" - + "\026.google.protobuf.Empty\"N\332A\004name\202\323\344\223\002A*?" - + "/v1/{name=projects/*/instances/*/databases/*/backupSchedules/*}\022\344\001\n" - + "\023ListBackupSchedules\022<.google.spanner.admin.database." - + "v1.ListBackupSchedulesRequest\032=.google.spanner.admin.database.v1.ListBackupSched" - + "ulesResponse\"P\332A\006parent\202\323\344\223\002A\022?/v1/{pare" - + "nt=projects/*/instances/*/databases/*}/b" - + "ackupSchedules\032x\312A\026spanner.googleapis.co" - + "m\322A\\https://www.googleapis.com/auth/clou" - + "d-platform,https://www.googleapis.com/auth/spanner.adminB\326\003\n" - + "$com.google.spanner.admin.database.v1B\031SpannerDatabaseAdminP" - + "rotoP\001ZFcloud.google.com/go/spanner/admi" - + "n/database/apiv1/databasepb;databasepb\252\002" - + "&Google.Cloud.Spanner.Admin.Database.V1\312" - + "\002&Google\\Cloud\\Spanner\\Admin\\Database\\V1" - + "\352\002+Google::Cloud::Spanner::Admin::Database::V1\352AJ\n" - + "\037spanner.googleapis.com/Instan" - + "ce\022\'projects/{project}/instances/{instance}\352A{\n" - + "(spanner.googleapis.com/InstancePartition\022Oprojects/{project}/instances/{" - + "instance}/instancePartitions/{instance_partition}b\006proto3" + + "gle/spanner/admin/database/v1/backup.pro" + + "to\0326google/spanner/admin/database/v1/bac" + + "kup_schedule.proto\032-google/spanner/admin" + + "/database/v1/common.proto\"\253\001\n\013RestoreInf" + + "o\022H\n\013source_type\030\001 \001(\01623.google.spanner." + + "admin.database.v1.RestoreSourceType\022C\n\013b" + + "ackup_info\030\002 \001(\0132,.google.spanner.admin." + + "database.v1.BackupInfoH\000B\r\n\013source_info\"" + + "\312\006\n\010Database\022\021\n\004name\030\001 \001(\tB\003\340A\002\022D\n\005state" + + "\030\002 \001(\01620.google.spanner.admin.database.v" + + "1.Database.StateB\003\340A\003\0224\n\013create_time\030\003 \001" + + "(\0132\032.google.protobuf.TimestampB\003\340A\003\022H\n\014r" + + "estore_info\030\004 \001(\0132-.google.spanner.admin" + + ".database.v1.RestoreInfoB\003\340A\003\022R\n\021encrypt" + + "ion_config\030\005 \001(\01322.google.spanner.admin." + + "database.v1.EncryptionConfigB\003\340A\003\022N\n\017enc" + + "ryption_info\030\010 \003(\01320.google.spanner.admi" + + "n.database.v1.EncryptionInfoB\003\340A\003\022%\n\030ver" + + "sion_retention_period\030\006 \001(\tB\003\340A\003\022>\n\025earl" + + "iest_version_time\030\007 \001(\0132\032.google.protobu" + + "f.TimestampB\003\340A\003\022\033\n\016default_leader\030\t \001(\t" + + "B\003\340A\003\022P\n\020database_dialect\030\n \001(\01621.google" + + ".spanner.admin.database.v1.DatabaseDiale" + + "ctB\003\340A\003\022\036\n\026enable_drop_protection\030\013 \001(\010\022" + + "\030\n\013reconciling\030\014 \001(\010B\003\340A\003\"M\n\005State\022\025\n\021ST" + + "ATE_UNSPECIFIED\020\000\022\014\n\010CREATING\020\001\022\t\n\005READY" + + "\020\002\022\024\n\020READY_OPTIMIZING\020\003:b\352A_\n\037spanner.g" + + "oogleapis.com/Database\022\332A\006parent\202\323\344\223\002/\022-" + + "/v1/{parent=projects/*/instances/*}/data" + + "bases\022\244\002\n\016CreateDatabase\0227.google.spanne" + + "r.admin.database.v1.CreateDatabaseReques" + + "t\032\035.google.longrunning.Operation\"\271\001\312Ad\n)" + + "google.spanner.admin.database.v1.Databas" + + "e\0227google.spanner.admin.database.v1.Crea" + + "teDatabaseMetadata\332A\027parent,create_state" + + "ment\202\323\344\223\0022\"-/v1/{parent=projects/*/insta" + + "nces/*}/databases:\001*\022\255\001\n\013GetDatabase\0224.g" + + "oogle.spanner.admin.database.v1.GetDatab" + + "aseRequest\032*.google.spanner.admin.databa" + + "se.v1.Database\"<\332A\004name\202\323\344\223\002/\022-/v1/{name" + + "=projects/*/instances/*/databases/*}\022\357\001\n" + + "\016UpdateDatabase\0227.google.spanner.admin.d" + + "atabase.v1.UpdateDatabaseRequest\032\035.googl" + + "e.longrunning.Operation\"\204\001\312A\"\n\010Database\022" + + "\026UpdateDatabaseMetadata\332A\024database,updat" + + "e_mask\202\323\344\223\002B26/v1/{database.name=project" + + "s/*/instances/*/databases/*}:\010database\022\235" + + "\002\n\021UpdateDatabaseDdl\022:.google.spanner.ad" + + "min.database.v1.UpdateDatabaseDdlRequest" + + "\032\035.google.longrunning.Operation\"\254\001\312AS\n\025g" + + "oogle.protobuf.Empty\022:google.spanner.adm" + + "in.database.v1.UpdateDatabaseDdlMetadata" + + "\332A\023database,statements\202\323\344\223\002:25/v1/{datab" + + "ase=projects/*/instances/*/databases/*}/" + + "ddl:\001*\022\243\001\n\014DropDatabase\0225.google.spanner" + + ".admin.database.v1.DropDatabaseRequest\032\026" + + ".google.protobuf.Empty\"D\332A\010database\202\323\344\223\002" + + "3*1/v1/{database=projects/*/instances/*/" + + "databases/*}\022\315\001\n\016GetDatabaseDdl\0227.google" + + ".spanner.admin.database.v1.GetDatabaseDd" + + "lRequest\0328.google.spanner.admin.database" + + ".v1.GetDatabaseDdlResponse\"H\332A\010database\202" + + "\323\344\223\0027\0225/v1/{database=projects/*/instance" + + "s/*/databases/*}/ddl\022\302\002\n\014SetIamPolicy\022\"." + + "google.iam.v1.SetIamPolicyRequest\032\025.goog" + + "le.iam.v1.Policy\"\366\001\332A\017resource,policy\202\323\344" + + "\223\002\335\001\">/v1/{resource=projects/*/instances" + + "/*/databases/*}:setIamPolicy:\001*ZA\"/v1/{resource=projects/*/instances/*" + + "/databases/*}:getIamPolicy:\001*ZA\".google.sp" + + "anner.admin.database.v1.ListBackupOperat" + + "ionsResponse\"E\332A\006parent\202\323\344\223\0026\0224/v1/{pare" + + "nt=projects/*/instances/*}/backupOperati" + + "ons\022\334\001\n\021ListDatabaseRoles\022:.google.spann" + + "er.admin.database.v1.ListDatabaseRolesRe" + + "quest\032;.google.spanner.admin.database.v1" + + ".ListDatabaseRolesResponse\"N\332A\006parent\202\323\344" + + "\223\002?\022=/v1/{parent=projects/*/instances/*/" + + "databases/*}/databaseRoles\022\350\001\n\016AddSplitP" + + "oints\0227.google.spanner.admin.database.v1" + + ".AddSplitPointsRequest\0328.google.spanner." + + "admin.database.v1.AddSplitPointsResponse" + + "\"c\332A\025database,split_points\202\323\344\223\002E\"@/v1/{d" + + "atabase=projects/*/instances/*/databases" + + "/*}:addSplitPoints:\001*\022\216\002\n\024CreateBackupSc" + + "hedule\022=.google.spanner.admin.database.v" + + "1.CreateBackupScheduleRequest\0320.google.s" + + "panner.admin.database.v1.BackupSchedule\"" + + "\204\001\332A)parent,backup_schedule,backup_sched" + + "ule_id\202\323\344\223\002R\"?/v1/{parent=projects/*/ins" + + "tances/*/databases/*}/backupSchedules:\017b" + + "ackup_schedule\022\321\001\n\021GetBackupSchedule\022:.g" + + "oogle.spanner.admin.database.v1.GetBacku" + + "pScheduleRequest\0320.google.spanner.admin." + + "database.v1.BackupSchedule\"N\332A\004name\202\323\344\223\002" + + "A\022?/v1/{name=projects/*/instances/*/data" + + "bases/*/backupSchedules/*}\022\220\002\n\024UpdateBac" + + "kupSchedule\022=.google.spanner.admin.datab" + + "ase.v1.UpdateBackupScheduleRequest\0320.goo" + + "gle.spanner.admin.database.v1.BackupSche" + + "dule\"\206\001\332A\033backup_schedule,update_mask\202\323\344" + + "\223\002b2O/v1/{backup_schedule.name=projects/" + + "*/instances/*/databases/*/backupSchedule" + + "s/*}:\017backup_schedule\022\275\001\n\024DeleteBackupSc" + + "hedule\022=.google.spanner.admin.database.v" + + "1.DeleteBackupScheduleRequest\032\026.google.p" + + "rotobuf.Empty\"N\332A\004name\202\323\344\223\002A*?/v1/{name=" + + "projects/*/instances/*/databases/*/backu" + + "pSchedules/*}\022\344\001\n\023ListBackupSchedules\022<." + + "google.spanner.admin.database.v1.ListBac" + + "kupSchedulesRequest\032=.google.spanner.adm" + + "in.database.v1.ListBackupSchedulesRespon" + + "se\"P\332A\006parent\202\323\344\223\002A\022?/v1/{parent=project" + + "s/*/instances/*/databases/*}/backupSched" + + "ules\032x\312A\026spanner.googleapis.com\322A\\https:" + + "//www.googleapis.com/auth/cloud-platform" + + ",https://www.googleapis.com/auth/spanner" + + ".adminB\326\003\n$com.google.spanner.admin.data" + + "base.v1B\031SpannerDatabaseAdminProtoP\001ZFcl" + + "oud.google.com/go/spanner/admin/database" + + "/apiv1/databasepb;databasepb\252\002&Google.Cl" + + "oud.Spanner.Admin.Database.V1\312\002&Google\\C" + + "loud\\Spanner\\Admin\\Database\\V1\352\002+Google:" + + ":Cloud::Spanner::Admin::Database::V1\352AJ\n" + + "\037spanner.googleapis.com/Instance\022\'projec" + + "ts/{project}/instances/{instance}\352A{\n(sp" + + "anner.googleapis.com/InstancePartition\022O" + + "projects/{project}/instances/{instance}/" + + "instancePartitions/{instance_partition}b" + + "\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( @@ -582,7 +589,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_google_spanner_admin_database_v1_UpdateDatabaseDdlRequest_descriptor, new java.lang.String[] { - "Database", "Statements", "OperationId", "ProtoDescriptors", + "Database", "Statements", "OperationId", "ProtoDescriptors", "ThroughputMode", }); internal_static_google_spanner_admin_database_v1_DdlStatementActionInfo_descriptor = getDescriptor().getMessageTypes().get(10); 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 b8ff463ee20..55dc816476c 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 @@ -332,6 +332,27 @@ public com.google.protobuf.ByteString getProtoDescriptors() { return protoDescriptors_; } + public static final int THROUGHPUT_MODE_FIELD_NUMBER = 5; + private boolean throughputMode_ = false; + + /** + * + * + *
+   * Optional. This field is exposed to be used by the Spanner Migration Tool.
+   * For more details, see
+   * [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool).
+   * 
+ * + * bool throughput_mode = 5 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The throughputMode. + */ + @java.lang.Override + public boolean getThroughputMode() { + return throughputMode_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -358,6 +379,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io if (!protoDescriptors_.isEmpty()) { output.writeBytes(4, protoDescriptors_); } + if (throughputMode_ != false) { + output.writeBool(5, throughputMode_); + } getUnknownFields().writeTo(output); } @@ -384,6 +408,9 @@ public int getSerializedSize() { if (!protoDescriptors_.isEmpty()) { size += com.google.protobuf.CodedOutputStream.computeBytesSize(4, protoDescriptors_); } + if (throughputMode_ != false) { + size += com.google.protobuf.CodedOutputStream.computeBoolSize(5, throughputMode_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -404,6 +431,7 @@ public boolean equals(final java.lang.Object obj) { if (!getStatementsList().equals(other.getStatementsList())) return false; if (!getOperationId().equals(other.getOperationId())) return false; if (!getProtoDescriptors().equals(other.getProtoDescriptors())) return false; + if (getThroughputMode() != other.getThroughputMode()) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -425,6 +453,8 @@ public int hashCode() { hash = (53 * hash) + getOperationId().hashCode(); hash = (37 * hash) + PROTO_DESCRIPTORS_FIELD_NUMBER; hash = (53 * hash) + getProtoDescriptors().hashCode(); + hash = (37 * hash) + THROUGHPUT_MODE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(getThroughputMode()); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -585,6 +615,7 @@ public Builder clear() { statements_ = com.google.protobuf.LazyStringArrayList.emptyList(); operationId_ = ""; protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + throughputMode_ = false; return this; } @@ -636,6 +667,9 @@ private void buildPartial0( if (((from_bitField0_ & 0x00000008) != 0)) { result.protoDescriptors_ = protoDescriptors_; } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.throughputMode_ = throughputMode_; + } } @java.lang.Override @@ -708,6 +742,9 @@ public Builder mergeFrom(com.google.spanner.admin.database.v1.UpdateDatabaseDdlR if (other.getProtoDescriptors() != com.google.protobuf.ByteString.EMPTY) { setProtoDescriptors(other.getProtoDescriptors()); } + if (other.getThroughputMode() != false) { + setThroughputMode(other.getThroughputMode()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -759,6 +796,12 @@ public Builder mergeFrom( bitField0_ |= 0x00000008; break; } // case 34 + case 40: + { + throughputMode_ = input.readBool(); + bitField0_ |= 0x00000010; + break; + } // case 40 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { @@ -1390,6 +1433,68 @@ public Builder clearProtoDescriptors() { return this; } + private boolean throughputMode_; + + /** + * + * + *
+     * Optional. This field is exposed to be used by the Spanner Migration Tool.
+     * For more details, see
+     * [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool).
+     * 
+ * + * bool throughput_mode = 5 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The throughputMode. + */ + @java.lang.Override + public boolean getThroughputMode() { + return throughputMode_; + } + + /** + * + * + *
+     * Optional. This field is exposed to be used by the Spanner Migration Tool.
+     * For more details, see
+     * [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool).
+     * 
+ * + * bool throughput_mode = 5 [(.google.api.field_behavior) = OPTIONAL]; + * + * @param value The throughputMode to set. + * @return This builder for chaining. + */ + public Builder setThroughputMode(boolean value) { + + throughputMode_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + /** + * + * + *
+     * Optional. This field is exposed to be used by the Spanner Migration Tool.
+     * For more details, see
+     * [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool).
+     * 
+ * + * bool throughput_mode = 5 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return This builder for chaining. + */ + public Builder clearThroughputMode() { + bitField0_ = (bitField0_ & ~0x00000010); + throughputMode_ = false; + onChanged(); + return this; + } + @java.lang.Override public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java index 755576518a9..cfa0c4d916d 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java @@ -199,4 +199,19 @@ public interface UpdateDatabaseDdlRequestOrBuilder * @return The protoDescriptors. */ com.google.protobuf.ByteString getProtoDescriptors(); + + /** + * + * + *
+   * Optional. This field is exposed to be used by the Spanner Migration Tool.
+   * For more details, see
+   * [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool).
+   * 
+ * + * bool throughput_mode = 5 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The throughputMode. + */ + boolean getThroughputMode(); } 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 084f98c68b8..36e06f1e1f0 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 @@ -813,6 +813,11 @@ message UpdateDatabaseDdlRequest { // For more details, see protobuffer [self // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description). bytes proto_descriptors = 4 [(google.api.field_behavior) = OPTIONAL]; + + // Optional. This field is exposed to be used by the Spanner Migration Tool. + // For more details, see + // [SMT](https://github.com/GoogleCloudPlatform/spanner-migration-tool). + bool throughput_mode = 5 [(google.api.field_behavior) = OPTIONAL]; } // Action information extracted from a DDL statement. This proto is used to diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index d81fbe63350..1952aa4afb3 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.92.1-SNAPSHOT + 6.93.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 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-executor-v1/pom.xml b/proto-google-cloud-spanner-executor-v1/pom.xml index 701c635e3ef..a8f7eba0992 100644 --- a/proto-google-cloud-spanner-executor-v1/pom.xml +++ b/proto-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT proto-google-cloud-spanner-executor-v1 Proto library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 6bdd874682d..f7ecbb58caf 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.92.1-SNAPSHOT + 6.93.1-SNAPSHOT proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 065b9b81b63..51fed236a68 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.2.0 + 1.2.2 @@ -23,8 +23,8 @@ 1.8 UTF-8 0.31.1 - 2.54.0 - 3.54.0 + 2.62.0 + 3.63.0
@@ -33,7 +33,7 @@ com.google.cloud google-cloud-spanner - 6.89.0 + 6.93.0 @@ -145,7 +145,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.5.2 + 3.5.3 10 false diff --git a/samples/pom.xml b/samples/pom.xml index 7f027400da9..d72a58cea5d 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -18,7 +18,7 @@ com.google.cloud.samples shared-configuration - 1.2.0 + 1.2.2 @@ -39,7 +39,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.3 + 3.1.4 true diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 1d84c1ab5fb..63f28bb2006 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -14,7 +14,7 @@ com.google.cloud.samples shared-configuration - 1.2.0 + 1.2.2 @@ -23,8 +23,8 @@ 1.8 UTF-8 0.31.1 - 2.54.0 - 3.54.0 + 2.62.0 + 3.63.0
@@ -32,7 +32,7 @@ com.google.cloud google-cloud-spanner - 6.92.1-SNAPSHOT + 6.93.1-SNAPSHOT @@ -144,7 +144,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.5.2 + 3.5.3 10 false diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 71949e27f82..2769859850f 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -16,7 +16,7 @@ com.google.cloud.samples shared-configuration - 1.2.0 + 1.2.2 @@ -34,7 +34,7 @@ com.google.cloud libraries-bom - 26.57.0 + 26.60.0 pom import @@ -126,7 +126,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.5.2 + 3.5.3 10 false @@ -155,7 +155,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 3.5.2 + 3.5.3 10 false diff --git a/samples/snippets/src/main/java/com/example/spanner/DatabaseAddSplitPointsSample.java b/samples/snippets/src/main/java/com/example/spanner/DatabaseAddSplitPointsSample.java index 05c650dbfb7..390ac6c3b21 100644 --- a/samples/snippets/src/main/java/com/example/spanner/DatabaseAddSplitPointsSample.java +++ b/samples/snippets/src/main/java/com/example/spanner/DatabaseAddSplitPointsSample.java @@ -66,8 +66,7 @@ static void addSplitPoints(String projectId, String instanceId, String databaseI com.google.spanner.admin.database.v1.SplitPoints splitPointForTable = SplitPoints.newBuilder() .setTable("Singers") - .setKeys( - 0, + .addKeys( com.google.spanner.admin.database.v1.SplitPoints.Key.newBuilder() .setKeyParts( ListValue.newBuilder() @@ -79,8 +78,7 @@ static void addSplitPoints(String projectId, String instanceId, String databaseI com.google.spanner.admin.database.v1.SplitPoints splitPointForIndex = SplitPoints.newBuilder() .setIndex("SingersByFirstLastName") - .setKeys( - 0, + .addKeys( com.google.spanner.admin.database.v1.SplitPoints.Key.newBuilder() .setKeyParts( ListValue.newBuilder() @@ -93,16 +91,14 @@ static void addSplitPoints(String projectId, String instanceId, String databaseI com.google.spanner.admin.database.v1.SplitPoints splitPointForIndexWitTableKey = SplitPoints.newBuilder() .setIndex("SingersByFirstLastName") - .setKeys( - 0, + .addKeys( com.google.spanner.admin.database.v1.SplitPoints.Key.newBuilder() .setKeyParts( ListValue.newBuilder() .addValues(Value.newBuilder().setStringValue("Jane").build()) .addValues(Value.newBuilder().setStringValue("Doe").build()) .build())) - .setKeys( - 1, + .addKeys( com.google.spanner.admin.database.v1.SplitPoints.Key.newBuilder() .setKeyParts( ListValue.newBuilder() diff --git a/samples/snippets/src/main/java/com/example/spanner/UnnamedParametersExample.java b/samples/snippets/src/main/java/com/example/spanner/UnnamedParametersExample.java new file mode 100644 index 00000000000..3c73a7591d1 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/spanner/UnnamedParametersExample.java @@ -0,0 +1,84 @@ +/* + * Copyright 2025 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.example.spanner; + +import com.google.cloud.Timestamp; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.DatabaseId; +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.cloud.spanner.Statement.StatementFactory; +import java.time.LocalDate; + +public class UnnamedParametersExample { + + static void executeQueryWithUnnamedParameters() { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + + executeQueryWithUnnamedParameters(projectId, instanceId, databaseId); + } + + static void executeQueryWithUnnamedParameters( + String projectId, String instanceId, String databaseId) { + try (Spanner spanner = + SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) { + + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); + StatementFactory statementFactory = client.getStatementFactory(); + + // Insert a row with unnamed parameters + client + .readWriteTransaction() + .run( + transaction -> { + Statement statement = statementFactory + .withUnnamedParameters("INSERT INTO Students(StudentId, Name, IsNRI, AvgMarks, " + + "JoinedAt, PinCode, CreatedAt) VALUES(?, ?, ?, ?, ?, ?, ?)", + 1000001, + "Google", + false, + (float) 34.5, + LocalDate.of(2024, 3, 31), + "123456", + Timestamp.now()); + transaction.executeUpdate(statement); + + return null; + }); + System.out.println("Row is inserted."); + + // Query the table with unnamed parameters + try (ResultSet resultSet = + client + .singleUse() + .executeQuery( + statementFactory.withUnnamedParameters( + "SELECT * FROM Students WHERE StudentId = ?", 1000001))) { + while (resultSet.next()) { + System.out.println(resultSet.getString("Name")); + } + } + System.out.println("Row is fetched."); + } + } +} diff --git a/samples/snippets/src/test/java/com/example/spanner/DatabaseAddSplitPointsIT.java b/samples/snippets/src/test/java/com/example/spanner/DatabaseAddSplitPointsIT.java index 7b2be314250..c9215b78cdc 100644 --- a/samples/snippets/src/test/java/com/example/spanner/DatabaseAddSplitPointsIT.java +++ b/samples/snippets/src/test/java/com/example/spanner/DatabaseAddSplitPointsIT.java @@ -46,7 +46,8 @@ public void setup() throws ExecutionException, InterruptedException { .get(); } - @Test + // TODO: Enable the test once the issue with split points is resolved + // @Test public void testAddSplits() throws Exception { final String out = SampleRunner.runSample( diff --git a/samples/snippets/src/test/java/com/example/spanner/UnnamedParametersIT.java b/samples/snippets/src/test/java/com/example/spanner/UnnamedParametersIT.java new file mode 100644 index 00000000000..d6c900dd60e --- /dev/null +++ b/samples/snippets/src/test/java/com/example/spanner/UnnamedParametersIT.java @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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.example.spanner; + +import static org.junit.Assert.assertTrue; + +import com.google.cloud.spanner.DatabaseId; +import com.google.common.collect.ImmutableList; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; + +public class UnnamedParametersIT extends SampleTestBase { + private static String databaseId; + + @Before + public void setup() throws ExecutionException, InterruptedException { + databaseId = idGenerator.generateDatabaseId(); + databaseAdminClient + .createDatabase( + databaseAdminClient + .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) + .build(), + ImmutableList.of( + "CREATE TABLE Students (" + + " StudentId INT64 NOT NULL PRIMARY KEY," + + " Name STRING(1024) NOT NULL," + + " IsNRI BOOL NOT NULL," + + " AvgMarks FLOAT32 NOT NULL," + + " JoinedAt DATE NOT NULL," + + " PinCode INT64 NOT NULL," + + " CreatedAt TIMESTAMP NOT NULL" + + ")")) + .get(); + } + + @Test + public void testUnnamedParameters() throws Exception { + final String out = + SampleRunner.runSample( + () -> UnnamedParametersExample.executeQueryWithUnnamedParameters(projectId, instanceId, + databaseId)); + assertTrue(out.contains("Row is inserted.")); + assertTrue(out.contains("Google")); + assertTrue(out.contains("Row is fetched.")); + } +} diff --git a/versions.txt b/versions.txt index 550467d1d2f..35aa969add6 100644 --- a/versions.txt +++ b/versions.txt @@ -1,13 +1,13 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:6.92.0:6.92.1-SNAPSHOT -proto-google-cloud-spanner-v1:6.92.0:6.92.1-SNAPSHOT -proto-google-cloud-spanner-admin-database-v1:6.92.0:6.92.1-SNAPSHOT -grpc-google-cloud-spanner-v1:6.92.0:6.92.1-SNAPSHOT -grpc-google-cloud-spanner-admin-instance-v1:6.92.0:6.92.1-SNAPSHOT -grpc-google-cloud-spanner-admin-database-v1:6.92.0:6.92.1-SNAPSHOT -google-cloud-spanner:6.92.0:6.92.1-SNAPSHOT -google-cloud-spanner-executor:6.92.0:6.92.1-SNAPSHOT -proto-google-cloud-spanner-executor-v1:6.92.0:6.92.1-SNAPSHOT -grpc-google-cloud-spanner-executor-v1:6.92.0:6.92.1-SNAPSHOT +proto-google-cloud-spanner-admin-instance-v1:6.93.0:6.93.1-SNAPSHOT +proto-google-cloud-spanner-v1:6.93.0:6.93.1-SNAPSHOT +proto-google-cloud-spanner-admin-database-v1:6.93.0:6.93.1-SNAPSHOT +grpc-google-cloud-spanner-v1:6.93.0:6.93.1-SNAPSHOT +grpc-google-cloud-spanner-admin-instance-v1:6.93.0:6.93.1-SNAPSHOT +grpc-google-cloud-spanner-admin-database-v1:6.93.0:6.93.1-SNAPSHOT +google-cloud-spanner:6.93.0:6.93.1-SNAPSHOT +google-cloud-spanner-executor:6.93.0:6.93.1-SNAPSHOT +proto-google-cloud-spanner-executor-v1:6.93.0:6.93.1-SNAPSHOT +grpc-google-cloud-spanner-executor-v1:6.93.0:6.93.1-SNAPSHOT