diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f11916e766b..3354ee1c842 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -4,9 +4,5 @@
# For syntax help see:
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
-# The @googleapis/api-spanner-java is the default owner for changes in this repo
-* @googleapis/yoshi-java @googleapis/api-spanner-java
-**/*.java @googleapis/api-spanner-java
-
-# The java-samples-reviewers team is the default owner for samples changes
-samples/**/*.java @googleapis/java-samples-reviewers @googleapis/api-spanner-java
+# The @googleapis/spanner-team is the default owner for changes in this repo
+* @googleapis/cloud-sdk-java-team @googleapis/spanner-team
diff --git a/.github/generated-files-bot.yml b/.github/generated-files-bot.yml
index c644a24e112..e58cdcbad65 100644
--- a/.github/generated-files-bot.yml
+++ b/.github/generated-files-bot.yml
@@ -6,6 +6,7 @@ externalManifests:
file: '.github/readme/synth.metadata/synth.metadata'
jsonpath: '$.generatedFiles[*]'
ignoreAuthors:
+- 'cloud-java-bot'
- 'renovate-bot'
- 'yoshi-automation'
- 'release-please[bot]'
diff --git a/.github/release-please.yml b/.github/release-please.yml
index 2853b1763cf..5ddaeef6217 100644
--- a/.github/release-please.yml
+++ b/.github/release-please.yml
@@ -3,42 +3,29 @@ bumpMinorPreMajor: true
handleGHRelease: true
branches:
- branch: 3.3.x
- releaseType: java-yoshi
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 4.0.x
- releaseType: java-yoshi
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 5.2.x
- releaseType: java-yoshi
- bumpMinorPreMajor: true
- handleGHRelease: true
- - releaseType: java-lts
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.4.4-sp
- - releaseType: java-backport
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.14.x
- - releaseType: java-yoshi
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.23.x
- - releaseType: java-yoshi
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.33.x
- - releaseType: java-backport
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.55.x
- - releaseType: java-backport
- bumpMinorPreMajor: true
- handleGHRelease: true
- branch: 6.67.x
+ - branch: 6.4.4-sp
+ releaseType: java-lts
+ - branch: 6.14.x
+ releaseType: java-backport
+ - branch: 6.23.x
+ - branch: 6.33.x
+ - branch: 6.55.x
+ releaseType: java-backport
+ - branch: 6.67.x
+ releaseType: java-backport
+ - branch: 6.66.x
+ releaseType: java-backport
+ - branch: 6.88.x
+ releaseType: java-backport
+ - branch: 6.96.x
+ releaseType: java-backport
+ - branch: 6.95.x
+ releaseType: java-backport
+ - branch: protobuf-4.x-rc
+ manifest: true
- releaseType: java-backport
bumpMinorPreMajor: true
handleGHRelease: true
- branch: 6.66.x
+ branch: 6.109.x
diff --git a/.github/scripts/update_generation_config.sh b/.github/scripts/update_generation_config.sh
index 561a313040f..74d0e6cc410 100644
--- a/.github/scripts/update_generation_config.sh
+++ b/.github/scripts/update_generation_config.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-set -e
+set -ex
# This script should be run at the root of the repository.
# This script is used to update googleapis_commitish, gapic_generator_version,
# and libraries_bom_version in generation configuration at the time of running
@@ -15,8 +15,27 @@ set -e
function get_latest_released_version() {
local group_id=$1
local artifact_id=$2
- latest=$(curl -s "https://search.maven.org/solrsearch/select?q=g:${group_id}+AND+a:${artifact_id}&core=gav&rows=500&wt=json" | jq -r '.response.docs[] | select(.v | test("^[0-9]+(\\.[0-9]+)*$")) | .v' | sort -V | tail -n 1)
- echo "${latest}"
+ group_id_url_path="$(sed 's|\.|/|g' <<< "${group_id}")"
+ url="https://repo1.maven.org/maven2/${group_id_url_path}/${artifact_id}/maven-metadata.xml"
+ xml_content=$(curl -s --fail "${url}")
+
+ # 1. Extract all version tags
+ # 2. Strip the XML tags to leave just the version numbers
+ # 3. Filter for strictly numbers.numbers.numbers (e.g., 2.54.0)
+ # 4. Sort by version (V) and take the last one (tail -n 1)
+ latest=$(echo "${xml_content}" \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+ | sed -E 's/<[^>]+>//g' \
+ | sort -V \
+ | tail -n 1)
+
+ if [[ -z "${latest}" ]]; then
+ echo "The latest version of ${group_id}:${artifact_id} is empty."
+ echo "The returned json from maven.org is invalid: ${json_content}"
+ exit 1
+ else
+ echo "${latest}"
+ fi
}
# Update a key to a new value in the generation config.
@@ -28,11 +47,23 @@ function update_config() {
sed -i -e "s/^${key_word}.*$/${key_word}: ${new_value}/" "${file}"
}
+# Update an action to a new version in GitHub action.
+function update_action() {
+ local key_word=$1
+ local new_value=$2
+ local file=$3
+ echo "Update ${key_word} to ${new_value} in ${file}"
+ # use a different delimiter because the key_word contains "/".
+ sed -i -e "s|${key_word}@v.*$|${key_word}@v${new_value}|" "${file}"
+}
+
# The parameters of this script is:
# 1. base_branch, the base branch of the result pull request.
# 2. repo, organization/repo-name, e.g., googleapis/google-cloud-java
# 3. [optional] generation_config, the path to the generation configuration,
# the default value is generation_config.yaml in the repository root.
+# 4. [optional] workflow, the library generation workflow file,
+# the default value is .github/workflows/hermetic_library_generation.yaml.
while [[ $# -gt 0 ]]; do
key="$1"
case "${key}" in
@@ -48,6 +79,10 @@ case "${key}" in
generation_config="$2"
shift
;;
+ --workflow)
+ workflow="$2"
+ shift
+ ;;
*)
echo "Invalid option: [$1]"
exit 1
@@ -71,21 +106,34 @@ if [ -z "${generation_config}" ]; then
echo "Use default generation config: ${generation_config}"
fi
+if [ -z "${workflow}" ]; then
+ workflow=".github/workflows/hermetic_library_generation.yaml"
+ echo "Use default library generation workflow file: ${workflow}"
+fi
+
current_branch="generate-libraries-${base_branch}"
title="chore: Update generation configuration at $(date)"
-# try to find a open pull request associated with the branch
+git checkout "${base_branch}"
+# Try to find a open pull request associated with the branch
pr_num=$(gh pr list -s open -H "${current_branch}" -q . --json number | jq ".[] | .number")
-# create a branch if there's no open pull request associated with the
+# Create a branch if there's no open pull request associated with the
# branch; otherwise checkout the pull request.
if [ -z "${pr_num}" ]; then
git checkout -b "${current_branch}"
+ # Push the current branch to remote so that we can
+ # compare the commits later.
+ git push -u origin "${current_branch}"
else
gh pr checkout "${pr_num}"
fi
+# Only allow fast-forward merging; exit with non-zero result if there's merging
+# conflict.
+git merge -m "chore: merge ${base_branch} into ${current_branch}" "${base_branch}"
+
mkdir tmp-googleapis
-# use partial clone because only commit history is needed.
+# Use partial clone because only commit history is needed.
git clone --filter=blob:none https://github.com/googleapis/googleapis.git tmp-googleapis
pushd tmp-googleapis
git pull
@@ -94,25 +142,43 @@ popd
rm -rf tmp-googleapis
update_config "googleapis_commitish" "${latest_commit}" "${generation_config}"
-# update gapic-generator-java version to the latest
+# Update gapic-generator-java version to the latest
latest_version=$(get_latest_released_version "com.google.api" "gapic-generator-java")
update_config "gapic_generator_version" "${latest_version}" "${generation_config}"
-# update libraries-bom version to the latest
+# Update composite action version to latest gapic-generator-java version
+update_action "googleapis/sdk-platform-java/.github/scripts" \
+ "${latest_version}" \
+ "${workflow}"
+
+# Update libraries-bom version to the latest
latest_version=$(get_latest_released_version "com.google.cloud" "libraries-bom")
update_config "libraries_bom_version" "${latest_version}" "${generation_config}"
-git add "${generation_config}"
+git add "${generation_config}" "${workflow}"
changed_files=$(git diff --cached --name-only)
if [[ "${changed_files}" == "" ]]; then
echo "The latest generation config is not changed."
echo "Skip committing to the pull request."
+else
+ git commit -m "${title}"
+fi
+
+# There are potentially at most two commits: merge commit and change commit.
+# We want to exit the script if no commit happens (otherwise this will be an
+# infinite loop).
+# `git cherry` is a way to find whether the local branch has commits that are
+# not in the remote branch.
+# If we find any such commit, push them to remote branch.
+unpushed_commit=$(git cherry -v "origin/${current_branch}" | wc -l)
+if [[ "${unpushed_commit}" -eq 0 ]]; then
+ echo "No unpushed commits, exit"
exit 0
fi
-git commit -m "${title}"
+
if [ -z "${pr_num}" ]; then
git remote add remote_repo https://cloud-java-bot:"${GH_TOKEN}@github.com/${repo}.git"
- git fetch -q --unshallow remote_repo
+ git fetch -q remote_repo
git push -f remote_repo "${current_branch}"
gh pr create --title "${title}" --head "${current_branch}" --body "${title}" --base "${base_branch}"
else
diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml
index d779decd658..66933646d40 100644
--- a/.github/sync-repo-settings.yaml
+++ b/.github/sync-repo-settings.yaml
@@ -14,13 +14,10 @@ branchProtectionRules:
- units (8)
- units (11)
- 'Kokoro - Test: Integration'
- - 'Kokoro - Test: Integration with Multiplexed Sessions'
- cla/google
- checkstyle
- compile (8)
- compile (11)
- - units-with-multiplexed-session (8)
- - units-with-multiplexed-session (11)
- unmanaged_dependency_check
- library_generation
- pattern: 3.3.x
@@ -154,13 +151,90 @@ branchProtectionRules:
- units (8)
- units (11)
- 'Kokoro - Test: Integration'
- - 'Kokoro - Test: Integration with Multiplexed Sessions'
- cla/google
- checkstyle
- compile (8)
- compile (11)
- units-with-multiplexed-session (8)
- units-with-multiplexed-session (11)
+ - pattern: 6.88.x
+ isAdminEnforced: true
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ - dependencies (17)
+ - lint
+ - javadoc
+ - units (8)
+ - units (11)
+ - 'Kokoro - Test: Integration'
+ - cla/google
+ - checkstyle
+ - compile (8)
+ - compile (11)
+ - units-with-multiplexed-session (8)
+ - units-with-multiplexed-session (11)
+ - unmanaged_dependency_check
+ - library_generation
+ - pattern: 6.96.x
+ isAdminEnforced: true
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ - dependencies (17)
+ - lint
+ - javadoc
+ - units (8)
+ - units (11)
+ - 'Kokoro - Test: Integration'
+ - cla/google
+ - checkstyle
+ - compile (8)
+ - compile (11)
+ - units-with-multiplexed-session (8)
+ - units-with-multiplexed-session (11)
+ - unmanaged_dependency_check
+ - library_generation
+ - pattern: 6.95.x
+ isAdminEnforced: true
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ - dependencies (17)
+ - lint
+ - javadoc
+ - units (8)
+ - units (11)
+ - 'Kokoro - Test: Integration'
+ - cla/google
+ - checkstyle
+ - compile (8)
+ - compile (11)
+ - units-with-multiplexed-session (8)
+ - units-with-multiplexed-session (11)
+ - unmanaged_dependency_check
+ - library_generation
+ - pattern: 6.109.x
+ isAdminEnforced: true
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ - dependencies (17)
+ - lint
+ - javadoc
+ - units (8)
+ - units (11)
+ - 'Kokoro - Test: Integration'
+ - cla/google
+ - checkstyle
+ - compile (8)
+ - compile (11)
+ - unmanaged_dependency_check
+ - library_generation
permissionRules:
- team: yoshi-admins
permission: admin
diff --git a/.github/trusted-contribution.yml b/.github/trusted-contribution.yml
index a0ba1f7d907..88d3ac9bf1a 100644
--- a/.github/trusted-contribution.yml
+++ b/.github/trusted-contribution.yml
@@ -1,3 +1,9 @@
trustedContributors:
- renovate-bot
- gcf-owl-bot[bot]
+
+annotations:
+- type: comment
+ text: "/gcbrun"
+- type: label
+ text: "kokoro:force-run"
diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml
index 18d92e5a28d..0cda6b04f72 100644
--- a/.github/workflows/auto-release.yaml
+++ b/.github/workflows/auto-release.yaml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
if: contains(github.head_ref, 'release-please')
steps:
- - uses: actions/github-script@v7
+ - uses: actions/github-script@v8
with:
github-token: ${{secrets.YOSHI_APPROVER_TOKEN}}
debug: true
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ee28d7f8a66..ae7ec53f5d7 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -25,7 +25,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- java: [11, 17, 21]
+ java: [11, 17, 21, 25]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
@@ -36,24 +36,6 @@ jobs:
- run: .kokoro/build.sh
env:
JOB_TYPE: test
- units-with-multiplexed-session:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- java: [ 11, 17, 21 ]
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v3
- with:
- distribution: temurin
- java-version: ${{matrix.java}}
- - run: java -version
- - run: .kokoro/build.sh
- env:
- JOB_TYPE: test
- GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
- GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS: true
units-java8:
# Building using Java 17 and run the tests with Java 8 runtime
name: "units (8)"
@@ -73,27 +55,6 @@ jobs:
- run: .kokoro/build.sh
env:
JOB_TYPE: test
- units-with-multiplexed-session8:
- # Building using Java 17 and run the tests with Java 8 runtime
- name: "units-with-multiplexed-session (8)"
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v3
- with:
- java-version: 8
- distribution: temurin
- - run: echo "SUREFIRE_JVM_OPT=-Djvm=${JAVA_HOME}/bin/java" >> $GITHUB_ENV
- shell: bash
- - uses: actions/setup-java@v3
- with:
- java-version: 17
- distribution: temurin
- - run: .kokoro/build.sh
- env:
- JOB_TYPE: test
- GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
- GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS: true
windows:
runs-on: windows-latest
steps:
diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml
index 35aa3b151d6..e8f02234113 100644
--- a/.github/workflows/hermetic_library_generation.yaml
+++ b/.github/workflows/hermetic_library_generation.yaml
@@ -32,14 +32,14 @@ jobs:
else
echo "SHOULD_RUN=true" >> $GITHUB_ENV
fi
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
if: env.SHOULD_RUN == 'true'
with:
fetch-depth: 0
- token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
- - uses: googleapis/sdk-platform-java/.github/scripts@v2.50.0
+ token: ${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}
+ - uses: googleapis/sdk-platform-java/.github/scripts@v2.68.0
if: env.SHOULD_RUN == 'true'
with:
base_ref: ${{ github.base_ref }}
head_ref: ${{ github.head_ref }}
- token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
+ token: ${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml b/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml
deleted file mode 100644
index bd7dfef3972..00000000000
--- a/.github/workflows/integration-tests-against-emulator-with-multiplexed-session.yaml
+++ /dev/null
@@ -1,42 +0,0 @@
-on:
- push:
- branches:
- - main
- pull_request:
-name: integration-tests-against-emulator-with-multiplexed-session
-jobs:
- units:
- runs-on: ubuntu-latest
-
- services:
- emulator:
- image: gcr.io/cloud-spanner-emulator/emulator:latest
- ports:
- - 9010:9010
- - 9020:9020
-
- steps:
- - uses: actions/checkout@v4
- - uses: stCarolas/setup-maven@v5
- with:
- maven-version: 3.8.1
- # Build with JDK 11 and run tests with JDK 8
- - uses: actions/setup-java@v4
- with:
- java-version: 11
- distribution: temurin
- - name: Compiling main library
- run: .kokoro/build.sh
- - uses: actions/setup-java@v4
- with:
- java-version: 8
- distribution: temurin
- - name: Running tests
- run: |
- mvn -V -B -Dspanner.testenv.instance="" -Penable-integration-tests \
- -DtrimStackTrace=false -Dclirr.skip=true -Denforcer.skip=true \
- -Dmaven.main.skip=true -fae verify
- env:
- JOB_TYPE: test
- SPANNER_EMULATOR_HOST: localhost:9010
- GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
diff --git a/.github/workflows/integration-tests-against-emulator.yaml b/.github/workflows/integration-tests-against-emulator.yaml
index f4ac97a8fe5..c1f81dd8f2b 100644
--- a/.github/workflows/integration-tests-against-emulator.yaml
+++ b/.github/workflows/integration-tests-against-emulator.yaml
@@ -16,18 +16,18 @@ jobs:
- 9020:9020
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- uses: stCarolas/setup-maven@v5
with:
maven-version: 3.8.1
# Build with JDK 11 and run tests with JDK 8
- - uses: actions/setup-java@v4
+ - uses: actions/setup-java@v5
with:
java-version: 11
distribution: temurin
- name: Compiling main library
run: .kokoro/build.sh
- - uses: actions/setup-java@v4
+ - uses: actions/setup-java@v5
with:
java-version: 8
distribution: temurin
diff --git a/.github/workflows/renovate_config_check.yaml b/.github/workflows/renovate_config_check.yaml
index 7c5ec7865e1..47b9e87c98b 100644
--- a/.github/workflows/renovate_config_check.yaml
+++ b/.github/workflows/renovate_config_check.yaml
@@ -7,7 +7,7 @@ on:
jobs:
renovate_bot_config_validation:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- name: Checkout code
@@ -16,7 +16,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
- node-version: '20'
+ node-version: '22'
- name: Install Renovate and Config Validator
run: |
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 f5298fed0f2..fc713448ef8 100644
--- a/.github/workflows/unmanaged_dependency_check.yaml
+++ b/.github/workflows/unmanaged_dependency_check.yaml
@@ -5,8 +5,8 @@ jobs:
unmanaged_dependency_check:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v6
+ - uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 11
@@ -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.40.0
+ uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.58.0
with:
bom-path: google-cloud-spanner-bom/pom.xml
diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml
index f15c807853d..8de9d67eae7 100644
--- a/.github/workflows/update_generation_config.yaml
+++ b/.github/workflows/update_generation_config.yaml
@@ -28,7 +28,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
- token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
+ fetch-depth: 0
+ token: ${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}
+ - name: Install Dependencies
+ shell: bash
+ run: sudo apt-get update && sudo apt-get install -y libxml2-utils
- name: Update params in generation config to latest
shell: bash
run: |
@@ -36,7 +40,8 @@ jobs:
[ -z "$(git config user.email)" ] && git config --global user.email "cloud-java-bot@google.com"
[ -z "$(git config user.name)" ] && git config --global user.name "cloud-java-bot"
bash .github/scripts/update_generation_config.sh \
- --base_branch "${base_branch}"\
+ --base_branch "${base_branch}" \
--repo ${{ github.repository }}
env:
- GH_TOKEN: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
+ GH_TOKEN: ${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}
+
diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index d603c59859b..caeff7a8b95 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -82,7 +82,7 @@ test)
RETURN_CODE=$?
;;
lint)
- mvn com.coveo:fmt-maven-plugin:check
+ mvn com.spotify.fmt:fmt-maven-plugin:check
RETURN_CODE=$?
;;
javadoc)
@@ -105,21 +105,6 @@ integration)
RETURN_CODE=$?
;;
integration-directpath-enabled)
- mvn -B ${INTEGRATION_TEST_ARGS} \
- -ntp \
- -Penable-integration-tests \
- -Djava.net.preferIPv4Stack=true \
- -DtrimStackTrace=false \
- -Dclirr.skip=true \
- -Denforcer.skip=true \
- -Dmaven.main.skip=true \
- -Dspanner.testenv.instance=projects/span-cloud-testing/instances/spanner-java-client-directpath \
- -Dspanner.gce.config.project_id=span-cloud-testing \
- -fae \
- verify
- RETURN_CODE=$?
- ;;
-integration-multiplexed-sessions-enabled)
mvn -B ${INTEGRATION_TEST_ARGS} \
-ntp \
-Penable-integration-tests \
@@ -129,7 +114,7 @@ integration-multiplexed-sessions-enabled)
-Denforcer.skip=true \
-Dmaven.main.skip=true \
-Dspanner.gce.config.project_id=gcloud-devel \
- -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests-multiplexed-sessions \
+ -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests-directpath \
-fae \
verify
RETURN_CODE=$?
@@ -160,7 +145,7 @@ integration-cloud-devel-directpath-enabled)
-Denforcer.skip=true \
-Dmaven.main.skip=true \
-Dspanner.gce.config.server_url=https://staging-wrenchworks.sandbox.googleapis.com \
- -Dspanner.testenv.instance=projects/span-cloud-testing/instances/spanner-java-client-directpath \
+ -Dspanner.testenv.instance=projects/span-cloud-testing/instances/cloud-spanner-java-directpath \
-Dspanner.gce.config.project_id=span-cloud-testing \
-fae \
verify
@@ -184,12 +169,14 @@ integration-cloud-staging|integration-cloud-staging-directpath-enabled)
;;
graalvm)
# Run Unit and Integration Tests with Native Image
- mvn test -Pnative -Penable-integration-tests -Dspanner.gce.config.project_id=gcloud-devel -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests
+ # NOTE: These integration tests run on the Emulator.
+ mvn test -Pnative -Penable-integration-tests -Dspanner.gce.config.project_id=gcloud-devel -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests-graalvm
RETURN_CODE=$?
;;
graalvm17)
# Run Unit and Integration Tests with Native Image
- mvn test -Pnative -Penable-integration-tests -Dspanner.gce.config.project_id=gcloud-devel -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests
+ # NOTE: These integration tests run on the Emulator.
+ mvn test -Pnative -Penable-integration-tests -Dspanner.gce.config.project_id=gcloud-devel -Dspanner.testenv.instance=projects/gcloud-devel/instances/java-client-integration-tests-graalvm
RETURN_CODE=$?
;;
slowtests)
@@ -206,12 +193,17 @@ slowtests)
verify
RETURN_CODE=$?
;;
-samples)
+samples|samples-slow-tests)
SAMPLES_DIR=samples
+ PROFILES=''
# only run ITs in snapshot/ on presubmit PRs. run ITs in all 3 samples/ subdirectories otherwise.
if [[ ! -z ${KOKORO_GITHUB_PULL_REQUEST_NUMBER} ]]
then
SAMPLES_DIR=samples/snapshot
+ elif [[ ${JOB_TYPE} = 'samples-slow-tests' ]]
+ then
+ SAMPLES_DIR=samples/snippets
+ PROFILES='-Pslow-tests,!integration-tests'
fi
if [[ -f ${SAMPLES_DIR}/pom.xml ]]
@@ -227,6 +219,7 @@ samples)
-DtrimStackTrace=false \
-Dclirr.skip=true \
-Denforcer.skip=true \
+ ${PROFILES} \
-fae \
verify
RETURN_CODE=$?
diff --git a/.kokoro/continuous/integration-cloud-devel-directpath-enabled.cfg b/.kokoro/continuous/integration-cloud-devel-directpath-enabled.cfg
index f73563d19a7..c17e92f53e5 100644
--- a/.kokoro/continuous/integration-cloud-devel-directpath-enabled.cfg
+++ b/.kokoro/continuous/integration-cloud-devel-directpath-enabled.cfg
@@ -27,6 +27,6 @@ env_vars: {
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
}
diff --git a/.kokoro/continuous/integration-cloud-staging-directpath-enabled.cfg b/.kokoro/continuous/integration-cloud-staging-directpath-enabled.cfg
index 7bc2e7fed21..e9a9ef9c76f 100644
--- a/.kokoro/continuous/integration-cloud-staging-directpath-enabled.cfg
+++ b/.kokoro/continuous/integration-cloud-staging-directpath-enabled.cfg
@@ -27,6 +27,6 @@ env_vars: {
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
}
diff --git a/.kokoro/continuous/java8.cfg b/.kokoro/continuous/java8.cfg
deleted file mode 100644
index 495cc7bacd6..00000000000
--- a/.kokoro/continuous/java8.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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: "REPORT_COVERAGE"
- value: "true"
-}
diff --git a/.kokoro/nightly/integration-cloud-devel-directpath-enabled.cfg b/.kokoro/nightly/integration-cloud-devel-directpath-enabled.cfg
index c1fc3da819e..fa53b07d62f 100644
--- a/.kokoro/nightly/integration-cloud-devel-directpath-enabled.cfg
+++ b/.kokoro/nightly/integration-cloud-devel-directpath-enabled.cfg
@@ -22,7 +22,6 @@ env_vars: {
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
}
-
diff --git a/.kokoro/nightly/integration-cloud-staging-directpath-enabled.cfg b/.kokoro/nightly/integration-cloud-staging-directpath-enabled.cfg
index 29444d79a60..c951f87b5ae 100644
--- a/.kokoro/nightly/integration-cloud-staging-directpath-enabled.cfg
+++ b/.kokoro/nightly/integration-cloud-staging-directpath-enabled.cfg
@@ -22,6 +22,6 @@ env_vars: {
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
}
diff --git a/.kokoro/nightly/integration-directpath-enabled.cfg b/.kokoro/nightly/integration-directpath-enabled.cfg
index e8d750a34a7..9d77a33d84d 100644
--- a/.kokoro/nightly/integration-directpath-enabled.cfg
+++ b/.kokoro/nightly/integration-directpath-enabled.cfg
@@ -37,6 +37,6 @@ env_vars: {
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
}
diff --git a/.kokoro/presubmit/java11-samples.cfg b/.kokoro/nightly/java11-samples-slow-tests.cfg
similarity index 87%
rename from .kokoro/presubmit/java11-samples.cfg
rename to .kokoro/nightly/java11-samples-slow-tests.cfg
index 2812301e787..7246153b048 100644
--- a/.kokoro/presubmit/java11-samples.cfg
+++ b/.kokoro/nightly/java11-samples-slow-tests.cfg
@@ -8,7 +8,7 @@ env_vars: {
env_vars: {
key: "JOB_TYPE"
- value: "samples"
+ value: "samples-slow-tests"
}
# TODO: remove this after we've migrated all tests and scripts
@@ -32,3 +32,8 @@ env_vars: {
value: "java-it-service-account"
}
+env_vars: {
+ key: "ENABLE_BUILD_COP"
+ value: "true"
+}
+
diff --git a/.kokoro/nightly/java7.cfg b/.kokoro/nightly/java7.cfg
deleted file mode 100644
index cb24f44eea3..00000000000
--- a/.kokoro/nightly/java7.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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/java7"
-}
diff --git a/.kokoro/nightly/java8-win.cfg b/.kokoro/nightly/java8-win.cfg
deleted file mode 100644
index b219b38ad4a..00000000000
--- a/.kokoro/nightly/java8-win.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-build_file: "java-spanner/.kokoro/build.bat"
diff --git a/.kokoro/presubmit/clirr.cfg b/.kokoro/presubmit/clirr.cfg
deleted file mode 100644
index ec572442e2e..00000000000
--- a/.kokoro/presubmit/clirr.cfg
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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: "clirr"
-}
\ No newline at end of file
diff --git a/.kokoro/presubmit/graalvm-native.cfg b/.kokoro/presubmit/graalvm-native-a.cfg
similarity index 77%
rename from .kokoro/presubmit/graalvm-native.cfg
rename to .kokoro/presubmit/graalvm-native-a.cfg
index a836c97f04b..de4ac9dbfa6 100644
--- a/.kokoro/presubmit/graalvm-native.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.40.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.58.0" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
@@ -31,3 +31,8 @@ env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "java-it-service-account"
}
+
+env_vars: {
+ key: "IT_SERVICE_ACCOUNT_EMAIL"
+ value: "it-service-account@gcloud-devel.iam.gserviceaccount.com"
+}
\ No newline at end of file
diff --git a/.kokoro/presubmit/graalvm-native-17.cfg b/.kokoro/presubmit/graalvm-native-b.cfg
similarity index 74%
rename from .kokoro/presubmit/graalvm-native-17.cfg
rename to .kokoro/presubmit/graalvm-native-b.cfg
index 82ed3a43e49..d8ae3b32223 100644
--- a/.kokoro/presubmit/graalvm-native-17.cfg
+++ b/.kokoro/presubmit/graalvm-native-b.cfg
@@ -3,12 +3,12 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.40.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.58.0" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
key: "JOB_TYPE"
- value: "graalvm17"
+ value: "graalvm"
}
# TODO: remove this after we've migrated all tests and scripts
@@ -30,4 +30,9 @@ env_vars: {
env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "java-it-service-account"
+}
+
+env_vars: {
+ key: "IT_SERVICE_ACCOUNT_EMAIL"
+ value: "it-service-account@gcloud-devel.iam.gserviceaccount.com"
}
\ No newline at end of file
diff --git a/.kokoro/presubmit/java8-samples.cfg b/.kokoro/presubmit/graalvm-native-c.cfg
similarity index 67%
rename from .kokoro/presubmit/java8-samples.cfg
rename to .kokoro/presubmit/graalvm-native-c.cfg
index 49a231b9f2a..0e9d1203a7e 100644
--- a/.kokoro/presubmit/java8-samples.cfg
+++ b/.kokoro/presubmit/graalvm-native-c.cfg
@@ -3,12 +3,12 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-kokoro-resources/java8"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.58.0" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
key: "JOB_TYPE"
- value: "samples"
+ value: "graalvm"
}
# TODO: remove this after we've migrated all tests and scripts
@@ -32,3 +32,7 @@ env_vars: {
value: "java-it-service-account"
}
+env_vars: {
+ key: "IT_SERVICE_ACCOUNT_EMAIL"
+ value: "it-service-account@gcloud-devel.iam.gserviceaccount.com"
+}
\ No newline at end of file
diff --git a/.kokoro/presubmit/integration-cloud-devel.cfg b/.kokoro/presubmit/integration-cloud-devel.cfg
deleted file mode 100644
index 94b698199e1..00000000000
--- a/.kokoro/presubmit/integration-cloud-devel.cfg
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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: "integration-cloud-devel"
-}
-
-env_vars: {
- key: "GOOGLE_APPLICATION_CREDENTIALS"
- value: "secret_manager/java-client-testing"
-}
-
-env_vars: {
- key: "SECRET_MANAGER_KEYS"
- value: "java-client-testing"
-}
diff --git a/.kokoro/presubmit/integration-directpath-enabled.cfg b/.kokoro/presubmit/integration-directpath-enabled.cfg
index e619d7e8207..1a921363936 100644
--- a/.kokoro/presubmit/integration-directpath-enabled.cfg
+++ b/.kokoro/presubmit/integration-directpath-enabled.cfg
@@ -24,15 +24,15 @@ env_vars: {
env_vars: {
key: "GOOGLE_APPLICATION_CREDENTIALS"
- value: "secret_manager/java-client-testing"
+ value: "secret_manager/java-it-service-account"
}
env_vars: {
key: "SECRET_MANAGER_KEYS"
- value: "java-client-testing"
+ value: "java-it-service-account"
}
env_vars: {
- key: "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
+ key: "GOOGLE_SPANNER_ENABLE_DIRECT_ACCESS"
value: "true"
-}
+}
\ No newline at end of file
diff --git a/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg b/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg
deleted file mode 100644
index 49edd2e8df6..00000000000
--- a/.kokoro/presubmit/integration-multiplexed-sessions-enabled.cfg
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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: "integration-multiplexed-sessions-enabled"
-}
-
-# 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: "GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS"
- value: "true"
-}
-
-env_vars: {
- key: "GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS"
- value: "true"
-}
diff --git a/.kokoro/presubmit/java11.cfg b/.kokoro/presubmit/java11.cfg
deleted file mode 100644
index 709f2b4c73d..00000000000
--- a/.kokoro/presubmit/java11.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-# Configure the docker image for kokoro-trampoline.
-env_vars: {
- key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-kokoro-resources/java11"
-}
diff --git a/.kokoro/presubmit/java7.cfg b/.kokoro/presubmit/java7.cfg
deleted file mode 100644
index cb24f44eea3..00000000000
--- a/.kokoro/presubmit/java7.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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/java7"
-}
diff --git a/.kokoro/presubmit/java8-osx.cfg b/.kokoro/presubmit/java8-osx.cfg
deleted file mode 100644
index 63f547222f5..00000000000
--- a/.kokoro/presubmit/java8-osx.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-build_file: "java-spanner/.kokoro/build.sh"
diff --git a/.kokoro/presubmit/java8-win.cfg b/.kokoro/presubmit/java8-win.cfg
deleted file mode 100644
index b219b38ad4a..00000000000
--- a/.kokoro/presubmit/java8-win.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Format: //devtools/kokoro/config/proto/build.proto
-
-build_file: "java-spanner/.kokoro/build.bat"
diff --git a/.kokoro/presubmit/java8.cfg b/.kokoro/presubmit/java8.cfg
deleted file mode 100644
index 495cc7bacd6..00000000000
--- a/.kokoro/presubmit/java8.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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: "REPORT_COVERAGE"
- value: "true"
-}
diff --git a/.kokoro/presubmit/linkage-monitor.cfg b/.kokoro/presubmit/linkage-monitor.cfg
deleted file mode 100644
index 083448f9f80..00000000000
--- a/.kokoro/presubmit/linkage-monitor.cfg
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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: "TRAMPOLINE_BUILD_FILE"
- value: "github/java-spanner/.kokoro/linkage-monitor.sh"
-}
\ No newline at end of file
diff --git a/.kokoro/presubmit/lint.cfg b/.kokoro/presubmit/lint.cfg
deleted file mode 100644
index 6d323c8ae76..00000000000
--- a/.kokoro/presubmit/lint.cfg
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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: "lint"
-}
\ No newline at end of file
diff --git a/.kokoro/presubmit/samples.cfg b/.kokoro/presubmit/samples.cfg
index 724216504ef..2cabe201bcd 100644
--- a/.kokoro/presubmit/samples.cfg
+++ b/.kokoro/presubmit/samples.cfg
@@ -31,3 +31,8 @@ env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "java-it-service-account"
}
+
+env_vars: {
+ key: "ENABLE_BUILD_COP"
+ value: "true"
+}
diff --git a/.readme-partials.yaml b/.readme-partials.yaml
index 65ae24d8b58..392f727e622 100644
--- a/.readme-partials.yaml
+++ b/.readme-partials.yaml
@@ -52,217 +52,30 @@ custom_content: |
## Metrics
- ### Available client-side metrics:
-
- * `spanner/max_in_use_sessions`: This returns the maximum
- number of sessions that have been in use during the last maintenance window
- interval, so as to provide an indication of the amount of activity currently
- in the database.
-
- * `spanner/max_allowed_sessions`: This shows the maximum
- number of sessions allowed.
-
- * `spanner/num_sessions_in_pool`: This metric allows users to
- see instance-level and database-level data for the total number of sessions in
- the pool at this very moment.
-
- * `spanner/num_acquired_sessions`: This metric allows
- users to see the total number of acquired sessions.
-
- * `spanner/num_released_sessions`: This metric allows
- users to see the total number of released (destroyed) sessions.
-
- * `spanner/get_session_timeouts`: This gives you an
- indication of the total number of get session timed-out instead of being
- granted (the thread that requested the session is placed in a wait queue where
- it waits until a session is released into the pool by another thread) due to
- pool exhaustion since the server process started.
-
- * `spanner/gfe_latency`: This metric shows latency between
- Google's network receiving an RPC and reading back the first byte of the response.
-
- * `spanner/gfe_header_missing_count`: This metric shows the
- number of RPC responses received without the server-timing header, most likely
- indicating that the RPC never reached Google's network.
-
- ### Instrument with OpenTelemetry
-
- Cloud Spanner client supports [OpenTelemetry Metrics](https://opentelemetry.io/),
- which gives insight into the client internals and aids in debugging/troubleshooting
- production issues. OpenTelemetry metrics will provide you with enough data to enable you to
- spot, and investigate the cause of any unusual deviations from normal behavior.
-
- All Cloud Spanner Metrics are prefixed with `spanner/` and uses `cloud.google.com/java` as [Instrumentation Scope](https://opentelemetry.io/docs/concepts/instrumentation-scope/). The
- metrics will be tagged with:
- * `database`: the target database name.
- * `instance_id`: the instance id of the target Spanner instance.
- * `client_id`: the user defined database client id.
-
- By default, the functionality is disabled. You need to add OpenTelemetry dependencies, enable OpenTelemetry metrics and must configure the OpenTelemetry with appropriate exporters at the startup of your application:
-
- #### OpenTelemetry Dependencies
- If you are using Maven, add this to your pom.xml file
- ```xml
-
- io.opentelemetry
- opentelemetry-sdk
- {opentelemetry.version}
-
-
- io.opentelemetry
- opentelemetry-sdk-metrics
- {opentelemetry.version}
-
-
- io.opentelemetry
- opentelemetry-exporter-otlp
- {opentelemetry.version}
-
- ```
- If you are using Gradle, add this to your dependencies
- ```Groovy
- compile 'io.opentelemetry:opentelemetry-sdk:{opentelemetry.version}'
- compile 'io.opentelemetry:opentelemetry-sdk-metrics:{opentelemetry.version}'
- compile 'io.opentelemetry:opentelemetry-exporter-oltp:{opentelemetry.version}'
- ```
-
- #### OpenTelemetry Configuration
- By default, all metrics are disabled. To enable metrics and configure the OpenTelemetry follow below:
-
- ```java
- // Enable OpenTelemetry metrics before injecting OpenTelemetry object.
- SpannerOptions.enableOpenTelemetryMetrics();
-
- SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
- // Use Otlp exporter or any other exporter of your choice.
- .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build())
- .build())
- .build();
-
- OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
- .setMeterProvider(sdkMeterProvider)
- .build()
-
- SpannerOptions options = SpannerOptions.newBuilder()
- // Inject OpenTelemetry object via Spanner Options or register OpenTelemetry object as Global
- .setOpenTelemetry(openTelemetry)
- .build();
-
- Spanner spanner = options.getService();
- ```
+ Cloud Spanner client supports [client-side metrics](https://cloud.google.com/spanner/docs/view-manage-client-side-metrics) that you can use along with server-side metrics to optimize performance and troubleshoot performance issues if they occur.
- #### OpenTelemetry SQL Statement Tracing
- The OpenTelemetry traces that are generated by the Java client include any request and transaction
- tags that have been set. The traces can also include the SQL statements that are executed and the
- name of the thread that executes the statement. Enable this with the `enableExtendedTracing`
- option:
+ Client-side metrics are measured from the time a request leaves your application to the time your application receives the response.
+ In contrast, server-side metrics are measured from the time Spanner receives a request until the last byte of data is sent to the client.
+
+ These metrics are enabled by default. You can opt out of using client-side metrics with the following code:
```
SpannerOptions options = SpannerOptions.newBuilder()
- .setOpenTelemetry(openTelemetry)
- .setEnableExtendedTracing(true)
+ .setBuiltInMetricsEnabled(false)
.build();
```
- This option can also be enabled by setting the environment variable
- `SPANNER_ENABLE_EXTENDED_TRACING=true`.
-
- #### OpenTelemetry API Tracing
- You can enable tracing of each API call that the Spanner client executes with the `enableApiTracing`
- option. These traces also include any retry attempts for an API call:
-
- ```
- SpannerOptions options = SpannerOptions.newBuilder()
- .setOpenTelemetry(openTelemetry)
- .setEnableApiTracing(true)
- .build();
- ```
-
- This option can also be enabled by setting the environment variable
- `SPANNER_ENABLE_API_TRACING=true`.
+ You can also disable these metrics by setting `SPANNER_DISABLE_BUILTIN_METRICS` to `true`.
- > Note: The attribute keys that are used for additional information about retry attempts and the number of requests might change in a future release.
-
-
- ### Instrument with OpenCensus
-
- > Note: OpenCensus project is deprecated. See [Sunsetting OpenCensus](https://opentelemetry.io/blog/2023/sunsetting-opencensus/).
- We recommend migrating to OpenTelemetry, the successor project.
-
- Cloud Spanner client supports [Opencensus Metrics](https://opencensus.io/stats/),
- which gives insight into the client internals and aids in debugging/troubleshooting
- production issues. OpenCensus metrics will provide you with enough data to enable you to
- spot, and investigate the cause of any unusual deviations from normal behavior.
-
- All Cloud Spanner Metrics are prefixed with `cloud.google.com/java/spanner`
-
- The metrics are tagged with:
- * `database`: the target database name.
- * `instance_id`: the instance id of the target Spanner instance.
- * `client_id`: the user defined database client id.
- * `library_version`: the version of the library that you're using.
-
-
- By default, the functionality is disabled. You need to include opencensus-impl
- dependency to collect the data and exporter dependency to export to backend.
-
- [Click here](https://medium.com/google-cloud/troubleshooting-cloud-spanner-applications-with-opencensus-2cf424c4c590) for more information.
-
- #### OpenCensus Dependencies
-
- If you are using Maven, add this to your pom.xml file
- ```xml
-
- io.opencensus
- opencensus-impl
- 0.30.0
- runtime
-
-
- io.opencensus
- opencensus-exporter-stats-stackdriver
- 0.30.0
-
- ```
- If you are using Gradle, add this to your dependencies
- ```Groovy
- compile 'io.opencensus:opencensus-impl:0.30.0'
- compile 'io.opencensus:opencensus-exporter-stats-stackdriver:0.30.0'
- ```
-
- #### Configure the OpenCensus Exporter
-
- At the start of your application configure the exporter:
-
- ```java
- import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
- // Enable OpenCensus exporters to export metrics to Stackdriver Monitoring.
- // Exporters use Application Default Credentials to authenticate.
- // See https://developers.google.com/identity/protocols/application-default-credentials
- // for more details.
- // The minimum reporting period for Stackdriver is 1 minute.
- StackdriverStatsExporter.createAndRegister();
- ```
- #### Enable RPC Views
-
- By default, all session metrics are enabled. To enable RPC views, use either of the following method:
-
- ```java
- // Register views for GFE metrics, including gfe_latency and gfe_header_missing_count.
- SpannerRpcViews.registerGfeLatencyAndHeaderMissingCountViews();
-
- // Register GFE Latency view.
- SpannerRpcViews.registerGfeLatencyView();
-
- // Register GFE Header Missing Count view.
- SpannerRpcViews.registerGfeHeaderMissingCountView();
- ```
+ > Note: Client-side metrics needs `monitoring.timeSeries.create` IAM permission to export metrics data. Ask your administrator to grant your service account the [Monitoring Metric Writer](https://cloud.google.com/iam/docs/roles-permissions/monitoring#monitoring.metricWriter) (roles/monitoring.metricWriter) IAM role on the project.
## Traces
Cloud Spanner client supports OpenTelemetry Traces, which gives insight into the client internals and aids in debugging/troubleshooting production issues.
By default, the functionality is disabled. You need to add OpenTelemetry dependencies, enable OpenTelemetry traces and must configure the OpenTelemetry with appropriate exporters at the startup of your application.
+ See [Configure client-side tracing](https://cloud.google.com/spanner/docs/set-up-tracing#configure-client-side-tracing) for more details on configuring traces.
+
#### OpenTelemetry Dependencies
If you are using Maven, add this to your pom.xml file
@@ -348,10 +161,33 @@ custom_content: |
`SPANNER_ENABLE_API_TRACING=true`.
> Note: The attribute keys that are used for additional information about retry attempts and the number of requests might change in a future release.
+
+ #### End-to-end Tracing
+
+ In addition to client-side tracing, you can opt in for [end-to-end tracing](https://cloud.google.com/spanner/docs/tracing-overview#end-to-end-side-tracing). End-to-end tracing helps you understand and debug latency issues that are specific to Spanner such as the following:
+ * Identify whether the latency is due to network latency between your application and Spanner, or if the latency is occurring within Spanner.
+ * Identify the Google Cloud regions that your application requests are being routed through and if there is a cross-region request. A cross-region request usually means higher latencies between your application and Spanner.
+
+ ```
+ SpannerOptions options = SpannerOptions.newBuilder()
+ .setOpenTelemetry(openTelemetry)
+ .setEnableEndToEndTracing(true)
+ .build();
+ ```
+
+ Refer to [Configure end-to-end tracing](https://cloud.google.com/spanner/docs/set-up-tracing#configure-end-to-end-tracing) to configure end-to-end tracing and to understand its attributes.
+
+ > Note: End-to-end traces can only be exported to [Cloud Trace](https://cloud.google.com/trace/docs).
+
+
+ ## Instrument with OpenCensus
+ > Note: OpenCensus project is deprecated. See [Sunsetting OpenCensus](https://opentelemetry.io/blog/2023/sunsetting-opencensus/).
+ We recommend migrating to OpenTelemetry, the successor project.
+
## Migrate from OpenCensus to OpenTelemetry
- > Using the [OpenTelemetry OpenCensus Bridge](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-opencensus-shim), you can immediately begin exporting your metrics and traces with OpenTelemetry
+ > Using the [OpenTelemetry OpenCensus Bridge](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-opencensus-shim), you can immediately begin exporting your metrics and traces with OpenTelemetry.
#### Disable OpenCensus metrics
Disable OpenCensus metrics for Spanner by including the following code if you still possess OpenCensus dependencies and exporter.
diff --git a/.repo-metadata.json b/.repo-metadata.json
index 670b37d595a..44368d809da 100644
--- a/.repo-metadata.json
+++ b/.repo-metadata.json
@@ -13,7 +13,7 @@
"api_id": "spanner.googleapis.com",
"library_type": "GAPIC_COMBO",
"requires_billing": true,
- "codeowner_team": "@googleapis/api-spanner-java",
+ "codeowner_team": "@googleapis/spanner-team",
"excluded_poms": "google-cloud-spanner-bom",
"issue_tracker": "https://issuetracker.google.com/issues?q=componentid:190851%2B%20status:open",
"recommended_package": "com.google.cloud.spanner",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1436e341430..917ff872041 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,720 @@
# Changelog
+## [6.113.0](https://github.com/googleapis/java-spanner/compare/v6.112.0...v6.113.0) (2026-03-25)
+
+
+### Features
+
+* Switch Eef metrics to using built in open telemetry ([#4385](https://github.com/googleapis/java-spanner/issues/4385)) ([0d0ad41](https://github.com/googleapis/java-spanner/commit/0d0ad4194dbfe46c505abcd237c93cbd39197331))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.68.0 ([bb63e92](https://github.com/googleapis/java-spanner/commit/bb63e929e96ee54e849e6295c074d4f4586c99f3))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.58.0 ([#4390](https://github.com/googleapis/java-spanner/issues/4390)) ([7f35761](https://github.com/googleapis/java-spanner/commit/7f357615c24ebb313043eabeae397f689866ad50))
+* Update googleapis/sdk-platform-java action to v2.68.0 ([#4389](https://github.com/googleapis/java-spanner/issues/4389)) ([737dfac](https://github.com/googleapis/java-spanner/commit/737dfac5972c921c8fd50a1e3c7c11652f67874d))
+
+## [6.112.0](https://github.com/googleapis/java-spanner/compare/v6.111.1...v6.112.0) (2026-03-17)
+
+
+### Features
+
+* Ability to update credentials on long running client ([#4371](https://github.com/googleapis/java-spanner/issues/4371)) ([e238990](https://github.com/googleapis/java-spanner/commit/e238990077badb063b1b05b0d71f58859434f7ee))
+* Add SI, adapt, split point related proto ([7aa4d90](https://github.com/googleapis/java-spanner/commit/7aa4d90cd4f001713ee2b0b5113303a748b237e0))
+* **spanner:** Include cache updates and routing hint into BeginTransaction and Commit request/response respectively ([7aa4d90](https://github.com/googleapis/java-spanner/commit/7aa4d90cd4f001713ee2b0b5113303a748b237e0))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.67.0 ([7aa4d90](https://github.com/googleapis/java-spanner/commit/7aa4d90cd4f001713ee2b0b5113303a748b237e0))
+* Fix unclosed literal error for consecutive backslashes ([#4387](https://github.com/googleapis/java-spanner/issues/4387)) ([f4884a8](https://github.com/googleapis/java-spanner/commit/f4884a83d15dcff6e246c7db47c8bafc3369a0a3))
+
+## [6.111.1](https://github.com/googleapis/java-spanner/compare/v6.111.0...v6.111.1) (2026-03-03)
+
+
+### Bug Fixes
+
+* Retry CreateSession also when waitForMinSessions is zero ([#4360](https://github.com/googleapis/java-spanner/issues/4360)) ([9263972](https://github.com/googleapis/java-spanner/commit/92639722793a994032761155013e506c9693b464))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.57.0 ([#4358](https://github.com/googleapis/java-spanner/issues/4358)) ([1ce4b8e](https://github.com/googleapis/java-spanner/commit/1ce4b8e24bac44c89f742f0afb395ae4c711abfd))
+* Update googleapis/sdk-platform-java action to v2.67.0 ([#4359](https://github.com/googleapis/java-spanner/issues/4359)) ([23781d9](https://github.com/googleapis/java-spanner/commit/23781d9f05db66d033d4d9125707a9988e1697db))
+
+## [6.111.0](https://github.com/googleapis/java-spanner/compare/v6.110.0...v6.111.0) (2026-02-13)
+
+
+### Features
+
+* Add E2E fallback to the spanner client. ([#4282](https://github.com/googleapis/java-spanner/issues/4282)) ([d36bd21](https://github.com/googleapis/java-spanner/commit/d36bd21a09cdd2006e53a43b6984d2a68ea24d3e))
+
+
+### Bug Fixes
+
+* Rollback transactions that are waiting for tx-id to be returned ([#4342](https://github.com/googleapis/java-spanner/issues/4342)) ([866a8c2](https://github.com/googleapis/java-spanner/commit/866a8c2d23f0d5edee1d98ead7d002b1981d5339))
+
+## [6.110.0](https://github.com/googleapis/java-spanner/compare/v6.109.0...v6.110.0) (2026-02-11)
+
+
+### Features
+
+* Add gRPC A66/A94 metrics ([#4333](https://github.com/googleapis/java-spanner/issues/4333)) ([485c700](https://github.com/googleapis/java-spanner/commit/485c70046e3e67dac899011580f9c350bdb31a6d))
+* ClientContext and secure parameters support ([#4316](https://github.com/googleapis/java-spanner/issues/4316)) ([6356ef2](https://github.com/googleapis/java-spanner/commit/6356ef2ce1ef87898e7bc4a6bc11174f629a9b5b))
+* Next release from main branch is 6.110.0 ([#4338](https://github.com/googleapis/java-spanner/issues/4338)) ([95ac7a7](https://github.com/googleapis/java-spanner/commit/95ac7a71463bfca4bb22f2e4ae61da97b97169ce))
+* **spanner:** Include cache updates into the ResultSet response ([aa53a43](https://github.com/googleapis/java-spanner/commit/aa53a43bdce6f4215fea8695837ad2c538598896))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.66.1 ([aa53a43](https://github.com/googleapis/java-spanner/commit/aa53a43bdce6f4215fea8695837ad2c538598896))
+* Preserve channel configurator for grpc-gcp and add opt-out for gcp OTel metrics ([#4329](https://github.com/googleapis/java-spanner/issues/4329)) ([2565137](https://github.com/googleapis/java-spanner/commit/25651378831fcd98ef48802872fe82a42cfa4942))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.56.1 ([#4331](https://github.com/googleapis/java-spanner/issues/4331)) ([2fd403f](https://github.com/googleapis/java-spanner/commit/2fd403f3c994b1b038e876be6e58ecadf731d848))
+
+## [6.109.0](https://github.com/googleapis/java-spanner/compare/v6.108.0...v6.109.0) (2026-02-02)
+
+
+### Features
+
+* Adding Send and Ack Mutation Support for Cloud Spanner Queue ([#4298](https://github.com/googleapis/java-spanner/issues/4298)) ([4b637ac](https://github.com/googleapis/java-spanner/commit/4b637ac0e4d6d696f3da8ae7fbac31c877aceba9))
+
+
+### Documentation
+
+* Add snippet for ReadLockMode configuration at client and transaction ([#4305](https://github.com/googleapis/java-spanner/issues/4305)) ([0fd4098](https://github.com/googleapis/java-spanner/commit/0fd40983b3bbb2f753e07036cedea9e7b9e26132))
+
+## [6.108.0](https://github.com/googleapis/java-spanner/compare/v6.107.0...v6.108.0) (2026-01-28)
+
+
+### Features
+
+* Add a ClientContext field to Spanner requests ([da6880e](https://github.com/googleapis/java-spanner/commit/da6880e425b7be55b11ba400046692e7af09bccb))
+* Add ChannelFinder server interfaces ([#4293](https://github.com/googleapis/java-spanner/issues/4293)) ([0b7a32e](https://github.com/googleapis/java-spanner/commit/0b7a32e7a24c027387a768a75632022a29562ef6))
+* Exposing total CPU related fields in AutoscalingConfig ([da6880e](https://github.com/googleapis/java-spanner/commit/da6880e425b7be55b11ba400046692e7af09bccb))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.66.0 ([da6880e](https://github.com/googleapis/java-spanner/commit/da6880e425b7be55b11ba400046692e7af09bccb))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.56.0 ([#4313](https://github.com/googleapis/java-spanner/issues/4313)) ([f7d0abc](https://github.com/googleapis/java-spanner/commit/f7d0abc241acb4c58d0ac3c60a7b18f5512275df))
+* Update googleapis/sdk-platform-java action to v2.66.0 ([#4314](https://github.com/googleapis/java-spanner/issues/4314)) ([d09a900](https://github.com/googleapis/java-spanner/commit/d09a900e26223eb9d646e33d29fc5692b8aba36a))
+
+## [6.107.0](https://github.com/googleapis/java-spanner/compare/v6.106.0...v6.107.0) (2026-01-16)
+
+
+### Features
+
+* Add Dynamic Channel Pooling (DCP) support to Connection API ([#4299](https://github.com/googleapis/java-spanner/issues/4299)) ([bba03a4](https://github.com/googleapis/java-spanner/commit/bba03a44dbfbd59288ecd33e3e53276809ad69b1))
+* Add SsFormat encoding library ([#4292](https://github.com/googleapis/java-spanner/issues/4292)) ([338a9b1](https://github.com/googleapis/java-spanner/commit/338a9b1409cafedcdef674bdff09a72c3f2cd772))
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.82.0 ([#4227](https://github.com/googleapis/java-spanner/issues/4227)) ([22bc6cf](https://github.com/googleapis/java-spanner/commit/22bc6cf3431f6e507d384f6e86a36503f1175ee7))
+* Update dependency com.google.cloud:google-cloud-monitoring to v3.83.0 ([#4169](https://github.com/googleapis/java-spanner/issues/4169)) ([61ae915](https://github.com/googleapis/java-spanner/commit/61ae915242a3c8a0aa1385bc1367f67df2c209d6))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.55.1 ([#4302](https://github.com/googleapis/java-spanner/issues/4302)) ([52acc0c](https://github.com/googleapis/java-spanner/commit/52acc0c620fec0aa67ecd81d634eec271fe4e429))
+* Update dependency net.bytebuddy:byte-buddy to v1.18.4 ([#4244](https://github.com/googleapis/java-spanner/issues/4244)) ([c8e4d91](https://github.com/googleapis/java-spanner/commit/c8e4d912155ab6829498822dcf0783fac5fe2747))
+* Update google.cloud.monitoring.version to v3.83.0 ([#4270](https://github.com/googleapis/java-spanner/issues/4270)) ([7ae68c8](https://github.com/googleapis/java-spanner/commit/7ae68c8e889f44f1057310bc45b70c086af9c385))
+* Update googleapis/sdk-platform-java action to v2.65.1 ([#4301](https://github.com/googleapis/java-spanner/issues/4301)) ([7d98f4e](https://github.com/googleapis/java-spanner/commit/7d98f4e12843826c18cbb8e0998c8687c94fc3d2))
+
+## [6.106.0](https://github.com/googleapis/java-spanner/compare/v6.105.0...v6.106.0) (2026-01-07)
+
+
+### Features
+
+* Support SHOW DEFAULT_TRANSACTION_ISOLATION for PG databases ([#4285](https://github.com/googleapis/java-spanner/issues/4285)) ([aec0515](https://github.com/googleapis/java-spanner/commit/aec051514dd3d122a7231eb6d25d1aaec8d90bda))
+
+
+### Bug Fixes
+
+* Adjust the initial polling delay for ddl operations ([#4275](https://github.com/googleapis/java-spanner/issues/4275)) ([8d36967](https://github.com/googleapis/java-spanner/commit/8d36967d010bed8f5a4a0c32f9ec1b5fe7d33e1d))
+* Retry creation of multiplexed session ([#4288](https://github.com/googleapis/java-spanner/issues/4288)) ([735e29e](https://github.com/googleapis/java-spanner/commit/735e29ed394faea9f5e697b5934a1f4895055d56))
+
+## [6.105.0](https://github.com/googleapis/java-spanner/compare/v6.104.0...v6.105.0) (2025-12-16)
+
+
+### Features
+
+* Add support of dynamic channel pooling ([#4265](https://github.com/googleapis/java-spanner/issues/4265)) ([923a14a](https://github.com/googleapis/java-spanner/commit/923a14aad99ff6fc91868f02d657145dd0f31c18))
+* Include RequestID in requests and errors ([#4263](https://github.com/googleapis/java-spanner/issues/4263)) ([afd7d6b](https://github.com/googleapis/java-spanner/commit/afd7d6b008f13d7a4d1a3b7f924122bd41d14b59))
+* Make grpc-gcp default enabled ([#4239](https://github.com/googleapis/java-spanner/issues/4239)) ([bb82f9e](https://github.com/googleapis/java-spanner/commit/bb82f9e55c40cac29b090e54be780c2e42545ee1))
+
+
+### Bug Fixes
+
+* Refine connecitivity metrics to capture RPCs with no response he… ([#4252](https://github.com/googleapis/java-spanner/issues/4252)) ([7b49412](https://github.com/googleapis/java-spanner/commit/7b4941221969f48d077ff459214c7d1e65ef843c))
+* Retry as PDML dit not retry Resource limit exceeded ([#4258](https://github.com/googleapis/java-spanner/issues/4258)) ([c735d42](https://github.com/googleapis/java-spanner/commit/c735d42875092b0d1482fe641b99645f288cdf4f)), closes [#4253](https://github.com/googleapis/java-spanner/issues/4253)
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.54.2 ([#4261](https://github.com/googleapis/java-spanner/issues/4261)) ([61dfd62](https://github.com/googleapis/java-spanner/commit/61dfd620637da6ef76b699edbad1095c26b81950))
+* Update googleapis/sdk-platform-java action to v2.64.2 ([#4262](https://github.com/googleapis/java-spanner/issues/4262)) ([f9505a9](https://github.com/googleapis/java-spanner/commit/f9505a97bdd9f6da7dd5ab1b60b47f7ed0a70402))
+
+## [6.104.0](https://github.com/googleapis/java-spanner/compare/v6.103.0...v6.104.0) (2025-12-03)
+
+
+### Features
+
+* Include PostgreSQL error code in exceptions ([#4236](https://github.com/googleapis/java-spanner/issues/4236)) ([5874f8b](https://github.com/googleapis/java-spanner/commit/5874f8b3e65adc3e78832866ebe667cd746e2d7f))
+
+
+### Bug Fixes
+
+* Backslash at end of string literal was misinterpreted ([#4246](https://github.com/googleapis/java-spanner/issues/4246)) ([477ca51](https://github.com/googleapis/java-spanner/commit/477ca51baf6cd1a0a5773bd53677f64195100ae2))
+* Fix transaction tag issue with the blind-write ([#4243](https://github.com/googleapis/java-spanner/issues/4243)) ([cf2ba69](https://github.com/googleapis/java-spanner/commit/cf2ba695cdb4038dc8e3ca3e9859231a2203da60))
+
+## [6.103.0](https://github.com/googleapis/java-spanner/compare/v6.102.1...v6.103.0) (2025-11-17)
+
+
+### Features
+
+* Add grpc.xds.resource_type label to xDS client metrics ([#4222](https://github.com/googleapis/java-spanner/issues/4222)) ([97bed3c](https://github.com/googleapis/java-spanner/commit/97bed3cf1a9df542acc4685c2ce4dbfa629b2cd3))
+* Exposing AutoscalingConfig in InstancePartition ([22edecf](https://github.com/googleapis/java-spanner/commit/22edecf8518844860c3cb47883544efd36cbc311))
+
+
+### Bug Fixes
+
+* Add env var to allow disabling directpath bound token ([#4189](https://github.com/googleapis/java-spanner/issues/4189)) ([0ca9541](https://github.com/googleapis/java-spanner/commit/0ca95412c778e3478cb66e4bea124396326c6056))
+* Allow DML THEN RETURN with retryAbortsInternally=false ([#4225](https://github.com/googleapis/java-spanner/issues/4225)) ([f49cc47](https://github.com/googleapis/java-spanner/commit/f49cc47e663836696ef151738510e68324e139dc))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.64.1 ([22edecf](https://github.com/googleapis/java-spanner/commit/22edecf8518844860c3cb47883544efd36cbc311))
+* Remove URL encoding in project name ([#4188](https://github.com/googleapis/java-spanner/issues/4188)) ([abba0c1](https://github.com/googleapis/java-spanner/commit/abba0c1730ea792407bea073ea65da55128cd764))
+
+
+### Dependencies
+
+* Update actions/checkout action to v5 ([#4166](https://github.com/googleapis/java-spanner/issues/4166)) ([50a56f7](https://github.com/googleapis/java-spanner/commit/50a56f7d47541dd581f7b425df36a080ecc11a74))
+* Update all tracing and telemetry dependencies ([#4230](https://github.com/googleapis/java-spanner/issues/4230)) ([d60124c](https://github.com/googleapis/java-spanner/commit/d60124cbe317d4c2489ea35de81943cfd2b8f697))
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.79.0 ([#4172](https://github.com/googleapis/java-spanner/issues/4172)) ([3a329fd](https://github.com/googleapis/java-spanner/commit/3a329fdb2fc68ff9d19717b534dd667f931d51fd))
+* Update dependency com.google.auto.value:auto-value-annotations to v1.11.1 ([#4216](https://github.com/googleapis/java-spanner/issues/4216)) ([84150c7](https://github.com/googleapis/java-spanner/commit/84150c73bbed2a6d58408ae0b8bd59709fc751db))
+* Update dependency com.google.cloud:google-cloud-trace to v2.79.0 ([#4174](https://github.com/googleapis/java-spanner/issues/4174)) ([3e93ca0](https://github.com/googleapis/java-spanner/commit/3e93ca077b94ad06867e3c9fdfe19527855423a2))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.54.1 ([#4193](https://github.com/googleapis/java-spanner/issues/4193)) ([ad235cf](https://github.com/googleapis/java-spanner/commit/ad235cfc9041f52c2f7b76f67eeaa6c03c5840aa))
+* Update dependency commons-cli:commons-cli to v1.11.0 ([#4218](https://github.com/googleapis/java-spanner/issues/4218)) ([33449ba](https://github.com/googleapis/java-spanner/commit/33449baf64a3d5b78fff323737ffeb28c8a9461b))
+* Update dependency commons-io:commons-io to v2.21.0 ([#4198](https://github.com/googleapis/java-spanner/issues/4198)) ([1f31169](https://github.com/googleapis/java-spanner/commit/1f3116947069ac11c948b510e6a9a7a8a6aa6061))
+* Update dependency net.bytebuddy:byte-buddy to v1.18.1 ([#4214](https://github.com/googleapis/java-spanner/issues/4214)) ([0c1d843](https://github.com/googleapis/java-spanner/commit/0c1d843ad42f213d4d9ec2d98a12e21e991ac010))
+* Update dependency net.bytebuddy:byte-buddy-agent to v1.18.1 ([#4215](https://github.com/googleapis/java-spanner/issues/4215)) ([76ce01b](https://github.com/googleapis/java-spanner/commit/76ce01b99e5c1274e9103c27ebc6bbdf482bebcd))
+* Update opentelemetry.version to v1.56.0 ([#4167](https://github.com/googleapis/java-spanner/issues/4167)) ([a24f219](https://github.com/googleapis/java-spanner/commit/a24f21930978583a0b8d7d39130fa0fc3fec7b2d))
+
+## [6.102.1](https://github.com/googleapis/java-spanner/compare/v6.102.0...v6.102.1) (2025-10-23)
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.63.0 ([c1a8238](https://github.com/googleapis/java-spanner/commit/c1a8238af33a083411f63cf6276eb683ee67ac6a))
+* Do a quick check if the application runs on GCP ([#4163](https://github.com/googleapis/java-spanner/issues/4163)) ([b9d7daf](https://github.com/googleapis/java-spanner/commit/b9d7daf000c0fb8b67142c6161bb578cadf49b18))
+* Migrate away from GoogleCredentials.fromStream() usages ([#4151](https://github.com/googleapis/java-spanner/issues/4151)) ([94d0474](https://github.com/googleapis/java-spanner/commit/94d0474ace62ea1059e5b69243f0b6eef31ddd06))
+
+
+### Dependencies
+
+* Update actions/checkout action to v5 ([#4158](https://github.com/googleapis/java-spanner/issues/4158)) ([b32ebcf](https://github.com/googleapis/java-spanner/commit/b32ebcf96bbf696b1eb84204622463fac59be017))
+* Update actions/checkout action to v5 ([#4161](https://github.com/googleapis/java-spanner/issues/4161)) ([02a17c6](https://github.com/googleapis/java-spanner/commit/02a17c6e6253e026cb3c6360eb925a322143b518))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.53.0 ([#4178](https://github.com/googleapis/java-spanner/issues/4178)) ([24fe194](https://github.com/googleapis/java-spanner/commit/24fe194fa3595b2ab817b9fc4cd57840250fef1f))
+* Update dependency net.bytebuddy:byte-buddy to v1.17.8 ([#4154](https://github.com/googleapis/java-spanner/issues/4154)) ([c911381](https://github.com/googleapis/java-spanner/commit/c911381c2ca9cd46fbeb831c659aaf55f21437f2))
+* Update dependency net.bytebuddy:byte-buddy-agent to v1.17.8 ([#4155](https://github.com/googleapis/java-spanner/issues/4155)) ([3075df7](https://github.com/googleapis/java-spanner/commit/3075df714b1787512174b3f18cbc802359d442dc))
+* Update googleapis/sdk-platform-java action to v2.63.0 ([#4179](https://github.com/googleapis/java-spanner/issues/4179)) ([5f48191](https://github.com/googleapis/java-spanner/commit/5f481913d60372fccf399c5c0e168b7d0c553ba0))
+
+
+### Documentation
+
+* Add warning for encoded credential ([#4182](https://github.com/googleapis/java-spanner/issues/4182)) ([92620f9](https://github.com/googleapis/java-spanner/commit/92620f969908a8ba7fcf92d0b350a8c4d05398f8))
+
+## [6.102.0](https://github.com/googleapis/java-spanner/compare/v6.101.1...v6.102.0) (2025-10-08)
+
+
+### Features
+
+* Add connection property for gRPC interceptor provider ([#4149](https://github.com/googleapis/java-spanner/issues/4149)) ([deb8dff](https://github.com/googleapis/java-spanner/commit/deb8dff6c01c37a3158e8f4a28ef5e821d10092a))
+* Support statement_timeout in connection url ([#4103](https://github.com/googleapis/java-spanner/issues/4103)) ([542c6aa](https://github.com/googleapis/java-spanner/commit/542c6aa63bfdd526070f14cb76921dd34527c1f9))
+
+
+### Bug Fixes
+
+* Automatically set default_sequence_kind for CREATE SEQUENCE ([#4105](https://github.com/googleapis/java-spanner/issues/4105)) ([3beea6a](https://github.com/googleapis/java-spanner/commit/3beea6ac4eb53b70db34e0a2d2e33e56f450c88b))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.62.3 ([7047a3a](https://github.com/googleapis/java-spanner/commit/7047a3ae31aae51e9e23758fe004b93855a0ee4b))
+
+
+### Dependencies
+
+* Update actions/checkout action to v5 ([#4069](https://github.com/googleapis/java-spanner/issues/4069)) ([4c88eb9](https://github.com/googleapis/java-spanner/commit/4c88eb91a321aa718f957296012f9e7501c7caec))
+* Update actions/checkout action to v5 ([#4106](https://github.com/googleapis/java-spanner/issues/4106)) ([14ebdb3](https://github.com/googleapis/java-spanner/commit/14ebdb35c33442c4e0f70d63dce3425edb730525))
+* Update actions/setup-java action to v5 ([#4071](https://github.com/googleapis/java-spanner/issues/4071)) ([e23134a](https://github.com/googleapis/java-spanner/commit/e23134a2f864e8abd2890ac3a81ff6b668afbe63))
+* Update all dependencies ([#4099](https://github.com/googleapis/java-spanner/issues/4099)) ([b262edc](https://github.com/googleapis/java-spanner/commit/b262edcfc4713bb64986bc4acd3f02b69d3367f8))
+* Update dependency com.google.api.grpc:grpc-google-cloud-monitoring-v3 to v3.77.0 ([#4117](https://github.com/googleapis/java-spanner/issues/4117)) ([2451ca2](https://github.com/googleapis/java-spanner/commit/2451ca2abe1dd2de3907b88e8d18beab1a15a634))
+* Update dependency com.google.api.grpc:proto-google-cloud-monitoring-v3 to v3.77.0 ([#4143](https://github.com/googleapis/java-spanner/issues/4143)) ([6c9dc26](https://github.com/googleapis/java-spanner/commit/6c9dc26330cf66f196adc2203323a482e08f0325))
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.76.0 ([#4144](https://github.com/googleapis/java-spanner/issues/4144)) ([d566a42](https://github.com/googleapis/java-spanner/commit/d566a4295be018070169ba082a018394a2e60b45))
+* Update dependency com.google.cloud:google-cloud-monitoring to v3.77.0 ([#4145](https://github.com/googleapis/java-spanner/issues/4145)) ([8917c05](https://github.com/googleapis/java-spanner/commit/8917c054410e4035d6d4e201e43599d5ddc1fadd))
+* Update dependency com.google.cloud:google-cloud-monitoring to v3.77.0 ([#4146](https://github.com/googleapis/java-spanner/issues/4146)) ([4ebea1a](https://github.com/googleapis/java-spanner/commit/4ebea1adf726069084087ce46900f3174658055c))
+* Update dependency com.google.cloud:google-cloud-trace to v2.76.0 ([#4147](https://github.com/googleapis/java-spanner/issues/4147)) ([4b1d4af](https://github.com/googleapis/java-spanner/commit/4b1d4af19336e493af38a1e58c95786da3892d34))
+* Update dependency com.google.cloud:google-cloud-trace to v2.76.0 ([#4148](https://github.com/googleapis/java-spanner/issues/4148)) ([8f91a89](https://github.com/googleapis/java-spanner/commit/8f91a894771653213b6fcded5795349ad7ea6724))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.52.3 ([#4107](https://github.com/googleapis/java-spanner/issues/4107)) ([8a8a042](https://github.com/googleapis/java-spanner/commit/8a8a042494b092b3dddd0c9606a63197d8a23555))
+* Update dependency org.json:json to v20250517 ([#3881](https://github.com/googleapis/java-spanner/issues/3881)) ([5658c83](https://github.com/googleapis/java-spanner/commit/5658c8378aa2e8028d4ef7dfaf94b647f33cd812))
+* Update googleapis/sdk-platform-java action to v2.62.3 ([#4108](https://github.com/googleapis/java-spanner/issues/4108)) ([65913ec](https://github.com/googleapis/java-spanner/commit/65913ec0638fec4ea536cf42f8fe25460133f68e))
+
+## [6.101.1](https://github.com/googleapis/java-spanner/compare/v6.101.0...v6.101.1) (2025-09-26)
+
+
+### Bug Fixes
+
+* Potential NullPointerException in LocalConnectionChecker ([#4092](https://github.com/googleapis/java-spanner/issues/4092)) ([3b9f597](https://github.com/googleapis/java-spanner/commit/3b9f597ba60199a16556824568b24908ce938a69))
+
+## [6.101.0](https://github.com/googleapis/java-spanner/compare/v6.100.0...v6.101.0) (2025-09-26)
+
+
+### Features
+
+* Add transaction_timeout connection property ([#4056](https://github.com/googleapis/java-spanner/issues/4056)) ([cdc52d4](https://github.com/googleapis/java-spanner/commit/cdc52d49b39c57e7255f4e09fb33a41f4810397d))
+* TPC support ([#4055](https://github.com/googleapis/java-spanner/issues/4055)) ([7625cce](https://github.com/googleapis/java-spanner/commit/7625cce9ad48b14a1cff9c2ede86a066ea292bef))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.62.2 ([8d6cbf6](https://github.com/googleapis/java-spanner/commit/8d6cbf6bea9cbd823b8f0070516e34b4d8428e87))
+* Potential NullPointerException in Value#hashCode ([#4046](https://github.com/googleapis/java-spanner/issues/4046)) ([74abb34](https://github.com/googleapis/java-spanner/commit/74abb341e2ea42bbf0a2de4ec3e3555335b5fd9f))
+* Recalculate remaining statement timeout after retry ([#4053](https://github.com/googleapis/java-spanner/issues/4053)) ([5e26596](https://github.com/googleapis/java-spanner/commit/5e26596f4f9c924260da0908920854d8ddfc626b))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.52.2 ([#4057](https://github.com/googleapis/java-spanner/issues/4057)) ([d782aff](https://github.com/googleapis/java-spanner/commit/d782aff63ff81e1b760690d4dee3e566028d522e))
+
+## [6.100.0](https://github.com/googleapis/java-spanner/compare/v6.99.0...v6.100.0) (2025-09-11)
+
+
+### Features
+
+* Read_lock_mode support for connections ([#4031](https://github.com/googleapis/java-spanner/issues/4031)) ([261abb4](https://github.com/googleapis/java-spanner/commit/261abb4b9c5ff00fac2d816a31926b23264657c4))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.62.1 ([e9773a7](https://github.com/googleapis/java-spanner/commit/e9773a7aa27a414d56093b4e09e0f197a07b5980))
+* Disable afe_connectivity_error_count metric ([#4041](https://github.com/googleapis/java-spanner/issues/4041)) ([f89c1c0](https://github.com/googleapis/java-spanner/commit/f89c1c0517ba6b895f405b0085b8df41aac952be))
+* Skip session delete in case of multiplexed sessions ([#4029](https://github.com/googleapis/java-spanner/issues/4029)) ([8bcb09d](https://github.com/googleapis/java-spanner/commit/8bcb09d141fe986c92ccacbaa9a45302c5c8e79d))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.52.1 ([#4034](https://github.com/googleapis/java-spanner/issues/4034)) ([13bfa7c](https://github.com/googleapis/java-spanner/commit/13bfa7c68c7ea887e679fb5504dceb85cbb43cb9))
+
+
+### Documentation
+
+* A comment for field `ranges` in message `.google.spanner.v1.KeySet` is changed ([e9773a7](https://github.com/googleapis/java-spanner/commit/e9773a7aa27a414d56093b4e09e0f197a07b5980))
+
+## [6.99.0](https://github.com/googleapis/java-spanner/compare/v6.98.1...v6.99.0) (2025-08-26)
+
+
+### Features
+
+* Support read lock mode for R/W transactions ([#4010](https://github.com/googleapis/java-spanner/issues/4010)) ([7d752d6](https://github.com/googleapis/java-spanner/commit/7d752d686e638b6266aab3a5188c01641d2f9adc))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.62.0 ([52c68db](https://github.com/googleapis/java-spanner/commit/52c68db5c75f24a066c2e828ed79917c824f699b))
+* GetCommitResponse() should return error if tx has not committed ([#4021](https://github.com/googleapis/java-spanner/issues/4021)) ([a2c179f](https://github.com/googleapis/java-spanner/commit/a2c179f2e7c19d295bdbf9cf1bbd1c5562dd9e21))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.52.0 ([#4024](https://github.com/googleapis/java-spanner/issues/4024)) ([7e3294f](https://github.com/googleapis/java-spanner/commit/7e3294f6d42bddb4cfff67334118f615c90c3bb7))
+
+## [6.98.1](https://github.com/googleapis/java-spanner/compare/v6.98.0...v6.98.1) (2025-08-11)
+
+
+### Bug Fixes
+
+* Add missing span.end calls for AsyncTransactionManager ([#4012](https://github.com/googleapis/java-spanner/issues/4012)) ([1a4adb4](https://github.com/googleapis/java-spanner/commit/1a4adb4d70c3a3822fa6bda93d689f2dae1835fa))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.61.0 ([8156ef3](https://github.com/googleapis/java-spanner/commit/8156ef31d93932c14f9fdd13c8c5e5b7ce370ba5))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.51.0 ([#4013](https://github.com/googleapis/java-spanner/issues/4013)) ([4e90c29](https://github.com/googleapis/java-spanner/commit/4e90c29ce3447d14411368e45a39c7b0965cb40a))
+
+## [6.98.0](https://github.com/googleapis/java-spanner/compare/v6.97.1...v6.98.0) (2025-07-31)
+
+
+### Features
+
+* Proto changes for an internal api ([675e90b](https://github.com/googleapis/java-spanner/commit/675e90b4582b4fc968118121e6c23ec98ee178e9))
+* **spanner:** A new field `snapshot_timestamp` is added to message `.google.spanner.v1.CommitResponse` ([675e90b](https://github.com/googleapis/java-spanner/commit/675e90b4582b4fc968118121e6c23ec98ee178e9))
+* Support Exemplar ([#3997](https://github.com/googleapis/java-spanner/issues/3997)) ([fcf0a01](https://github.com/googleapis/java-spanner/commit/fcf0a0182a33f229e865e4593635efaed34d6dac))
+* Use multiplex sessions for RW and Partition Ops ([#3996](https://github.com/googleapis/java-spanner/issues/3996)) ([a882204](https://github.com/googleapis/java-spanner/commit/a882204e07a2084b228c14fb37ac53e4e33d0f59))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.60.2 ([675e90b](https://github.com/googleapis/java-spanner/commit/675e90b4582b4fc968118121e6c23ec98ee178e9))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.50.2 ([#4004](https://github.com/googleapis/java-spanner/issues/4004)) ([986c0e0](https://github.com/googleapis/java-spanner/commit/986c0e07fddecd51cd310a9759ce1d41c1f5c657))
+
+## [6.97.1](https://github.com/googleapis/java-spanner/compare/v6.97.0...v6.97.1) (2025-07-15)
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.50.1 ([#3992](https://github.com/googleapis/java-spanner/issues/3992)) ([69ffd72](https://github.com/googleapis/java-spanner/commit/69ffd7282220b8b12c6b9b64d8856ff88068ffa2))
+* Update googleapis/sdk-platform-java action to v2.60.1 ([#3926](https://github.com/googleapis/java-spanner/issues/3926)) ([7001b7f](https://github.com/googleapis/java-spanner/commit/7001b7faaff581e26ec81c4db2c99a1e8726d5eb))
+
+## [6.97.0](https://github.com/googleapis/java-spanner/compare/v6.96.1...v6.97.0) (2025-07-10)
+
+
+### Features
+
+* Next release from main branch is 6.97.0 ([#3984](https://github.com/googleapis/java-spanner/issues/3984)) ([5651f61](https://github.com/googleapis/java-spanner/commit/5651f6160e1e655f118aa2e7f0203a47cd6914c0))
+
+
+### Bug Fixes
+
+* Drop max message size ([#3987](https://github.com/googleapis/java-spanner/issues/3987)) ([3eee899](https://github.com/googleapis/java-spanner/commit/3eee89965547dfa49b4282b470f625d43c92f4fd))
+* Return non-empty metadata for DataBoost queries ([#3936](https://github.com/googleapis/java-spanner/issues/3936)) ([79c0684](https://github.com/googleapis/java-spanner/commit/79c06848c0ac4eff8410dd3bd63db8675c202d94))
+
+## [6.96.1](https://github.com/googleapis/java-spanner/compare/v6.96.0...v6.96.1) (2025-06-30)
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.59.0 ([2836042](https://github.com/googleapis/java-spanner/commit/2836042217fe29bb967fe892bd6b492391ded95c))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.50.0 ([#3925](https://github.com/googleapis/java-spanner/issues/3925)) ([1372bbd](https://github.com/googleapis/java-spanner/commit/1372bbd82b7828629cbc407b78878469bc477977))
+
+## [6.96.0](https://github.com/googleapis/java-spanner/compare/v6.95.1...v6.96.0) (2025-06-27)
+
+
+### Features
+
+* Allow JDBC to configure directpath for connection ([#3929](https://github.com/googleapis/java-spanner/issues/3929)) ([d754f1f](https://github.com/googleapis/java-spanner/commit/d754f1f99294d86ec881583f217fa09f291a3d7a))
+* Support getOrNull and getOrDefault in Struct ([#3914](https://github.com/googleapis/java-spanner/issues/3914)) ([1dc5a3e](https://github.com/googleapis/java-spanner/commit/1dc5a3ec0ca9ea530e8691df5c2734c0a1ece559))
+* Use multiplexed sessions for read-only transactions ([#3917](https://github.com/googleapis/java-spanner/issues/3917)) ([37fdc27](https://github.com/googleapis/java-spanner/commit/37fdc27aab4e71ac141c2a2c979f864e97395a97))
+
+
+### Bug Fixes
+
+* Allow zero durations to be set for connections ([#3916](https://github.com/googleapis/java-spanner/issues/3916)) ([43ea4fa](https://github.com/googleapis/java-spanner/commit/43ea4fa68eac00801beb8e58c1eb09e9f32e5ce5))
+
+
+### Documentation
+
+* Add snippet for Repeatable Read configuration at client and transaction ([#3908](https://github.com/googleapis/java-spanner/issues/3908)) ([ff3d212](https://github.com/googleapis/java-spanner/commit/ff3d212c98276c4084f44619916d0444c9652803))
+* Update SpannerSample.java to align with best practices ([#3625](https://github.com/googleapis/java-spanner/issues/3625)) ([7bfc62d](https://github.com/googleapis/java-spanner/commit/7bfc62d3d9e57242e0dfddea090208f8c65f0f8e))
+
+## [6.95.1](https://github.com/googleapis/java-spanner/compare/v6.95.0...v6.95.1) (2025-06-06)
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.49.0 ([#3909](https://github.com/googleapis/java-spanner/issues/3909)) ([3de8502](https://github.com/googleapis/java-spanner/commit/3de8502b98ebb90526fc2339e279f9b710816b3b))
+* Update googleapis/sdk-platform-java action to v2.59.0 ([#3910](https://github.com/googleapis/java-spanner/issues/3910)) ([aed8bd6](https://github.com/googleapis/java-spanner/commit/aed8bd6d5a0b1e0dfab345e0de68f285e8b8aedb))
+
+## [6.95.0](https://github.com/googleapis/java-spanner/compare/v6.94.0...v6.95.0) (2025-06-05)
+
+
+### Features
+
+* Enable ALTS hard bound token in DirectPath ([#3904](https://github.com/googleapis/java-spanner/issues/3904)) ([2b0f2ff](https://github.com/googleapis/java-spanner/commit/2b0f2ff214f4b68dd5957bc4280edb713b77a763))
+* Enable grpc and afe metrics ([#3896](https://github.com/googleapis/java-spanner/issues/3896)) ([706f794](https://github.com/googleapis/java-spanner/commit/706f794f044c2cb1112cfdae6f379e5f2bc3f26f))
+* Last statement sample ([#3830](https://github.com/googleapis/java-spanner/issues/3830)) ([2f62816](https://github.com/googleapis/java-spanner/commit/2f62816b0af9aced1b73e25525f60f8e3e923454))
+* **spanner:** Add new change_stream.proto ([f385698](https://github.com/googleapis/java-spanner/commit/f38569865de7465ae9a37b844a9dd983571d3688))
+
+
+### Bug Fixes
+
+* Directpath_enabled attribute ([#3897](https://github.com/googleapis/java-spanner/issues/3897)) ([53bc510](https://github.com/googleapis/java-spanner/commit/53bc510145921d00bc3df04aa4cf407179ed8d8e))
+
+
+### Dependencies
+
+* Update dependency io.opentelemetry:opentelemetry-bom to v1.50.0 ([#3887](https://github.com/googleapis/java-spanner/issues/3887)) ([94b879c](https://github.com/googleapis/java-spanner/commit/94b879c8c1848fa0b14dbe8cda8390cfe9e8fce6))
+
+## [6.94.0](https://github.com/googleapis/java-spanner/compare/v6.93.0...v6.94.0) (2025-05-21)
+
+
+### Features
+
+* Add throughput_mode to UpdateDatabaseDdlRequest to be used by Spanner Migration Tool. See https://github.com/GoogleCloudPlatform/spanner-migration-tool ([3070f1d](https://github.com/googleapis/java-spanner/commit/3070f1db97788c2a55c553ab8a4de3419d1ccf5c))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.58.0 ([3070f1d](https://github.com/googleapis/java-spanner/commit/3070f1db97788c2a55c553ab8a4de3419d1ccf5c))
+* Remove trailing semicolons in DDL ([#3879](https://github.com/googleapis/java-spanner/issues/3879)) ([ca3a67d](https://github.com/googleapis/java-spanner/commit/ca3a67db715f398943382df1f8a9979905811ff8))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.48.0 ([#3869](https://github.com/googleapis/java-spanner/issues/3869)) ([afa17f7](https://github.com/googleapis/java-spanner/commit/afa17f73beab80639467916bc73b5c96305093aa))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.48.0 ([#3880](https://github.com/googleapis/java-spanner/issues/3880)) ([f3b00b6](https://github.com/googleapis/java-spanner/commit/f3b00b663aa897fda1bc21222d29726e6be630cb))
+* Update dependency com.google.cloud.opentelemetry:exporter-metrics to v0.34.0 ([#3861](https://github.com/googleapis/java-spanner/issues/3861)) ([676b14f](https://github.com/googleapis/java-spanner/commit/676b14f916dea783b40ddec4061bd7af157b5d98))
+* Update dependency commons-io:commons-io to v2.19.0 ([#3863](https://github.com/googleapis/java-spanner/issues/3863)) ([80a6af8](https://github.com/googleapis/java-spanner/commit/80a6af836ca29ec196a2f509831e1d36c557168f))
+* Update dependency io.opentelemetry:opentelemetry-bom to v1.50.0 ([#3865](https://github.com/googleapis/java-spanner/issues/3865)) ([ae63050](https://github.com/googleapis/java-spanner/commit/ae6305089b394be0c1eaf8ff7e188711288d87ad))
+* Update googleapis/sdk-platform-java action to v2.58.0 ([#3870](https://github.com/googleapis/java-spanner/issues/3870)) ([d1e45fa](https://github.com/googleapis/java-spanner/commit/d1e45fa88bb005529bcfb2a6ff2df44065be0fd2))
+* Update opentelemetry.version to v1.50.0 ([#3866](https://github.com/googleapis/java-spanner/issues/3866)) ([f7e09b8](https://github.com/googleapis/java-spanner/commit/f7e09b8148c0e51503255694bd3347c637724b34))
+
+
+### Documentation
+
+* Add samples for unnamed (positional) parameters ([#3849](https://github.com/googleapis/java-spanner/issues/3849)) ([035cadd](https://github.com/googleapis/java-spanner/commit/035cadd5bb77a8f9f6fb25ac8c8e5a3e186d9a22))
+
+## [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)
+
+
+### Features
+
+* [Internal] client-side metrics for afe latency and connectivity error ([#3819](https://github.com/googleapis/java-spanner/issues/3819)) ([a8dba0a](https://github.com/googleapis/java-spanner/commit/a8dba0a83939fdbbc324f0a7aa6c44180462fa3a))
+* Support begin with AbortedException for manager interface ([#3835](https://github.com/googleapis/java-spanner/issues/3835)) ([5783116](https://github.com/googleapis/java-spanner/commit/578311693bed836c8916f4b4ffa0782a468c1af3))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.56.2 ([11bfd90](https://github.com/googleapis/java-spanner/commit/11bfd90daa244dbd31a76bc5a1d2e694e43fa292))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.46.2 ([#3836](https://github.com/googleapis/java-spanner/issues/3836)) ([2ee7f97](https://github.com/googleapis/java-spanner/commit/2ee7f971f3374b01d22e5a7f8f2483cf60c3363d))
+
+## [6.91.1](https://github.com/googleapis/java-spanner/compare/v6.91.0...v6.91.1) (2025-04-21)
+
+
+### Bug Fixes
+
+* SkipHint in the internal parser skipped too much ([#3827](https://github.com/googleapis/java-spanner/issues/3827)) ([fbf7b4c](https://github.com/googleapis/java-spanner/commit/fbf7b4c4324c4d565bfe3950ecf80de02c88f16e))
+
+## [6.91.0](https://github.com/googleapis/java-spanner/compare/v6.90.0...v6.91.0) (2025-04-17)
+
+
+### Features
+
+* [Internal] open telemetry built in metrics for GRPC ([#3709](https://github.com/googleapis/java-spanner/issues/3709)) ([cd76c73](https://github.com/googleapis/java-spanner/commit/cd76c73d838a9ccde2c8c11fc63144a62d76886c))
+* Add java sample for the pre-splitting feature ([#3713](https://github.com/googleapis/java-spanner/issues/3713)) ([e97b92e](https://github.com/googleapis/java-spanner/commit/e97b92ea4728bc8f013ff73478de4af9eaa1793b))
+* Add TransactionMutationLimitExceededException as cause to SpannerBatchUpdateException ([#3723](https://github.com/googleapis/java-spanner/issues/3723)) ([4cf5261](https://github.com/googleapis/java-spanner/commit/4cf52613c6c8280fdb864f5b8d04f8fb6ea55e16))
+* Built in metrics for afe latency and connectivity error ([#3724](https://github.com/googleapis/java-spanner/issues/3724)) ([e13a2f9](https://github.com/googleapis/java-spanner/commit/e13a2f9c5cadd15ab5a565c7dd1c1eec64c09488))
+* Support unnamed parameters ([#3820](https://github.com/googleapis/java-spanner/issues/3820)) ([1afd815](https://github.com/googleapis/java-spanner/commit/1afd815869785588dfd03ffc12e381e32c4aa0fe))
+
+
+### Bug Fixes
+
+* Add default implementations for Interval methods in AbstractStructReader ([#3722](https://github.com/googleapis/java-spanner/issues/3722)) ([97f4544](https://github.com/googleapis/java-spanner/commit/97f45448ecb51bd20699d1f163f78b2a7736b21f))
+* Set transaction isolation level had no effect ([#3718](https://github.com/googleapis/java-spanner/issues/3718)) ([b382999](https://github.com/googleapis/java-spanner/commit/b382999f42d1b643472cf3f605f8c6dc839dec19))
+
+
+### Performance Improvements
+
+* Cache the key used for OTEL traces and metrics ([#3814](https://github.com/googleapis/java-spanner/issues/3814)) ([c5a2045](https://github.com/googleapis/java-spanner/commit/c5a20452ad2ed5a8f1ac12cca4072a86f4457b93))
+* Optimize parsing in Connection API ([#3800](https://github.com/googleapis/java-spanner/issues/3800)) ([a2780ed](https://github.com/googleapis/java-spanner/commit/a2780edb3d9d4972c78befd097692f626a6a4bea))
+* Qualify statements without removing comments ([#3810](https://github.com/googleapis/java-spanner/issues/3810)) ([d358cb9](https://github.com/googleapis/java-spanner/commit/d358cb96e33bdf6de6528d03c884aa702b40b802))
+* Remove all calls to getSqlWithoutComments ([#3822](https://github.com/googleapis/java-spanner/issues/3822)) ([0e1e14c](https://github.com/googleapis/java-spanner/commit/0e1e14c0e8c1f3726c4d3cfd836c580b3b4122d0))
+
+## [6.90.0](https://github.com/googleapis/java-spanner/compare/v6.89.0...v6.90.0) (2025-03-31)
+
+
+### Features
+
+* Add default_isolation_level connection property ([#3702](https://github.com/googleapis/java-spanner/issues/3702)) ([9472d23](https://github.com/googleapis/java-spanner/commit/9472d23c2b233275e779815f89040323e073a7d1))
+* Adds support for Interval datatype in Java client ([#3416](https://github.com/googleapis/java-spanner/issues/3416)) ([8be8f5e](https://github.com/googleapis/java-spanner/commit/8be8f5e6b08c8cf3e5f062e4b985b3ec9c725064))
+* Integration test for End to End tracing ([#3691](https://github.com/googleapis/java-spanner/issues/3691)) ([bf1a07a](https://github.com/googleapis/java-spanner/commit/bf1a07a153b1eb899757260b8ac2bc12384e45af))
+* Specify isolation level per transaction ([#3704](https://github.com/googleapis/java-spanner/issues/3704)) ([868f30f](https://github.com/googleapis/java-spanner/commit/868f30fde95d07c3fc18feaca64b4d1c3ba6a27d))
+* Support PostgreSQL isolation level statements ([#3706](https://github.com/googleapis/java-spanner/issues/3706)) ([dda2e1d](https://github.com/googleapis/java-spanner/commit/dda2e1dec38febdad54b61f588590c7572017ba9))
+
+## [6.89.0](https://github.com/googleapis/java-spanner/compare/v6.88.0...v6.89.0) (2025-03-20)
+
+
+### Features
+
+* Enable ALTS hard bound token in DirectPath ([#3645](https://github.com/googleapis/java-spanner/issues/3645)) ([42cc961](https://github.com/googleapis/java-spanner/commit/42cc9616fa74c765d5716fd948dc0823df0a07a6))
+* Next release from main branch is 6.89.0 ([#3669](https://github.com/googleapis/java-spanner/issues/3669)) ([7a8a29b](https://github.com/googleapis/java-spanner/commit/7a8a29be40258294cafd13b1df7df5ea349a675d))
+* Support isolation level REPEATABLE_READ for R/W transactions ([#3670](https://github.com/googleapis/java-spanner/issues/3670)) ([e62f5ab](https://github.com/googleapis/java-spanner/commit/e62f5ab46da8696a8ff0d213f924588612bb4025))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.55.1 ([b959f4c](https://github.com/googleapis/java-spanner/commit/b959f4c8ebb3551796a894b659aa42ba16fb1c39))
+* Revert the ALTS bound token enablement ([#3679](https://github.com/googleapis/java-spanner/issues/3679)) ([183c1f0](https://github.com/googleapis/java-spanner/commit/183c1f0e228a927a575596a38a01d63bb8eb6943))
+
+
+### Performance Improvements
+
+* Get database dialect using multiplexed session ([#3684](https://github.com/googleapis/java-spanner/issues/3684)) ([f641a40](https://github.com/googleapis/java-spanner/commit/f641a40ed515a6559718c2fe2757c322f037d83b))
+* Skip gRPC trailers for StreamingRead & ExecuteStreamingSql ([#3661](https://github.com/googleapis/java-spanner/issues/3661)) ([bd4b1f5](https://github.com/googleapis/java-spanner/commit/bd4b1f5b9612f6a4dfd748d735c887f8e46ae106))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.45.1 ([#3689](https://github.com/googleapis/java-spanner/issues/3689)) ([67188df](https://github.com/googleapis/java-spanner/commit/67188df2be23eef88de8f4febc3ac7208ebdd937))
+
+## [6.88.0](https://github.com/googleapis/java-spanner/compare/v6.87.0...v6.88.0) (2025-02-27)
+
+
+### Features
+
+* Add a last field in the PartialResultSet ([7c714be](https://github.com/googleapis/java-spanner/commit/7c714be10eb345f2d8f566d752f6de615061c4da))
+* Automatically set default sequence kind in JDBC and PGAdapter ([#3658](https://github.com/googleapis/java-spanner/issues/3658)) ([e8abf33](https://github.com/googleapis/java-spanner/commit/e8abf338b85e95f185ab2875a804134523f84de3))
+* Default authentication support for external hosts ([#3656](https://github.com/googleapis/java-spanner/issues/3656)) ([ace11d5](https://github.com/googleapis/java-spanner/commit/ace11d5d928fb567b16560263ae95aa9cd916e22))
+* **spanner:** A new enum `IsolationLevel` is added ([3fd33ba](https://github.com/googleapis/java-spanner/commit/3fd33ba9c5fab43ed475ed3cff9d60c008843981))
+* **spanner:** Add instance partitions field in backup proto ([3fd33ba](https://github.com/googleapis/java-spanner/commit/3fd33ba9c5fab43ed475ed3cff9d60c008843981))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.54.0 ([57497ad](https://github.com/googleapis/java-spanner/commit/57497ad00c62f152f493645f382530cf0eedf19e))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.44.0 ([#3665](https://github.com/googleapis/java-spanner/issues/3665)) ([3543548](https://github.com/googleapis/java-spanner/commit/35435488f87ebd59179698e8f74578b41eb219da))
+
+## [6.87.0](https://github.com/googleapis/java-spanner/compare/v6.86.0...v6.87.0) (2025-02-20)
+
+
+### Features
+
+* Add AddSplitPoints API ([a5ebcd3](https://github.com/googleapis/java-spanner/commit/a5ebcd343a67c57d61362cfb0ccb4888f5503681))
+* Add option for multiplexed sessions with partitioned operations ([#3635](https://github.com/googleapis/java-spanner/issues/3635)) ([dc89b4d](https://github.com/googleapis/java-spanner/commit/dc89b4d7663f0e40a9169b21243f2d94f2fc5749))
+* Add option to indicate that a statement is the last in a transaction ([#3647](https://github.com/googleapis/java-spanner/issues/3647)) ([b04ea80](https://github.com/googleapis/java-spanner/commit/b04ea804cfa9551b4d7c49cd83f0ef1120942423))
+* Adding gfe_latencies metric to built-in metrics ([#3490](https://github.com/googleapis/java-spanner/issues/3490)) ([314dadc](https://github.com/googleapis/java-spanner/commit/314dadc31f4a5aa798d45886db7231c1bd8b7a91))
+* **spanner:** Support multiplexed session for read-write transactions ([#3608](https://github.com/googleapis/java-spanner/issues/3608)) ([bda78ed](https://github.com/googleapis/java-spanner/commit/bda78edaba827acf974c87c335868a6f8caa38f2))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.53.0 ([20a3d0d](https://github.com/googleapis/java-spanner/commit/20a3d0da41509ffca66c77de6771fc8080930613))
+* **spanner:** End spans for read-write methods ([#3629](https://github.com/googleapis/java-spanner/issues/3629)) ([4a1f99c](https://github.com/googleapis/java-spanner/commit/4a1f99c6bb872ffc08e60d3843e4cdfc4efa2690))
+* **spanner:** Release resources in TransactionManager ([#3638](https://github.com/googleapis/java-spanner/issues/3638)) ([e0a3e5b](https://github.com/googleapis/java-spanner/commit/e0a3e5bd169e28e349a2dc92f86a2a9b5510f8f6))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.43.0 ([#3642](https://github.com/googleapis/java-spanner/issues/3642)) ([c12968a](https://github.com/googleapis/java-spanner/commit/c12968a5f6dad95017d9867d96d4f19a26643a07))
+
+## [6.86.0](https://github.com/googleapis/java-spanner/compare/v6.85.0...v6.86.0) (2025-01-31)
+
+
+### Features
+
+* Add sample for asymmetric autoscaling instances ([#3562](https://github.com/googleapis/java-spanner/issues/3562)) ([3584b81](https://github.com/googleapis/java-spanner/commit/3584b81a27bfcdd071fbf7e0d40dfa840ea88151))
+* Support graph and pipe queries in Connection API ([#3586](https://github.com/googleapis/java-spanner/issues/3586)) ([71c3063](https://github.com/googleapis/java-spanner/commit/71c306346d5b3805f55d5698cf8867d5f4ae519e))
+
+
+### Bug Fixes
+
+* Always add instance-id for built-in metrics ([#3612](https://github.com/googleapis/java-spanner/issues/3612)) ([705b627](https://github.com/googleapis/java-spanner/commit/705b627646f1679b7d1c4c1f86a853872cf8bfd5))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.51.1 ([3e27251](https://github.com/googleapis/java-spanner/commit/3e272510970d1951b74c4ec9425f1a890790ddb3))
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.52.0 ([bf69673](https://github.com/googleapis/java-spanner/commit/bf69673886dbe040292214ed6e64997a230441f6))
+* **spanner:** Moved mTLSContext configurator from builder to construtor ([#3605](https://github.com/googleapis/java-spanner/issues/3605)) ([ac7c30b](https://github.com/googleapis/java-spanner/commit/ac7c30bfb14bdafc11675c2a120effde4a71c922))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.42.0 ([#3616](https://github.com/googleapis/java-spanner/issues/3616)) ([2ea59f0](https://github.com/googleapis/java-spanner/commit/2ea59f05225f2dba2effb503e6abddcfdb6fe6ee))
+* Update dependency io.opentelemetry:opentelemetry-bom to v1.46.0 ([#3530](https://github.com/googleapis/java-spanner/issues/3530)) ([d505850](https://github.com/googleapis/java-spanner/commit/d5058504b94501cabd75ad5e7030404b63c3f8b4))
+
+
+### Documentation
+
+* Clarify how async updates can overtake each other ([#3581](https://github.com/googleapis/java-spanner/issues/3581)) ([1be250f](https://github.com/googleapis/java-spanner/commit/1be250fea686f3a41739c9c8aa474ed956b130e4))
+* Fix typo timzeone -> timezone ([bf69673](https://github.com/googleapis/java-spanner/commit/bf69673886dbe040292214ed6e64997a230441f6))
+* Fixed parameter arguments for AbstractResultSet's Listener's on TransactionMetadata doc ([#3602](https://github.com/googleapis/java-spanner/issues/3602)) ([1f143a4](https://github.com/googleapis/java-spanner/commit/1f143a4b7b899aec8cf58546f7540a41d1c73731))
+* **samples:** Add samples and tests for change streams transaction exclusion ([#3098](https://github.com/googleapis/java-spanner/issues/3098)) ([1f81600](https://github.com/googleapis/java-spanner/commit/1f816009abdbfb32bb26686d8fdb2a771216004e))
+
+## [6.85.0](https://github.com/googleapis/java-spanner/compare/v6.84.0...v6.85.0) (2025-01-10)
+
+
+### Features
+
+* Add gcp client attributes in OpenTelemetry traces ([#3595](https://github.com/googleapis/java-spanner/issues/3595)) ([7893f24](https://github.com/googleapis/java-spanner/commit/7893f2499f6a43e4e80ec78a9f0da5beedb6967a))
+* Add LockHint feature ([#3588](https://github.com/googleapis/java-spanner/issues/3588)) ([326442b](https://github.com/googleapis/java-spanner/commit/326442bca41700debcbeb67b6bd11fc36bd4f26d))
+* **spanner:** MTLS setup for spanner external host clients ([#3574](https://github.com/googleapis/java-spanner/issues/3574)) ([f8dd152](https://github.com/googleapis/java-spanner/commit/f8dd15272f2a250c5b57c9f2527d03dbd557d717))
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-monitoring-v3 to v3.56.0 ([#3563](https://github.com/googleapis/java-spanner/issues/3563)) ([e4d0b0f](https://github.com/googleapis/java-spanner/commit/e4d0b0ffa2308c8d949630b52c67e3b79c4491fb))
+* Update dependency com.google.api.grpc:proto-google-cloud-monitoring-v3 to v3.57.0 ([#3592](https://github.com/googleapis/java-spanner/issues/3592)) ([a7542da](https://github.com/googleapis/java-spanner/commit/a7542daff466226221eeb9a885a2e67a99adb678))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.41.1 ([#3589](https://github.com/googleapis/java-spanner/issues/3589)) ([2cd4238](https://github.com/googleapis/java-spanner/commit/2cd42388370dac004bfd807f6aede3ba45456706))
+* Update dependency com.google.cloud.opentelemetry:exporter-trace to v0.33.0 ([#3455](https://github.com/googleapis/java-spanner/issues/3455)) ([70649dc](https://github.com/googleapis/java-spanner/commit/70649dc2f64aa06404893cc6a36716fc366c83e7))
+* Update dependency com.google.re2j:re2j to v1.8 ([#3594](https://github.com/googleapis/java-spanner/issues/3594)) ([0f2013d](https://github.com/googleapis/java-spanner/commit/0f2013d66d3fd14e6be019cda6745ddc32032091))
+* Update googleapis/sdk-platform-java action to v2.51.1 ([#3591](https://github.com/googleapis/java-spanner/issues/3591)) ([3daa1a0](https://github.com/googleapis/java-spanner/commit/3daa1a0c735000845558a1d3612257a7d0524350))
+
+## [6.84.0](https://github.com/googleapis/java-spanner/compare/v6.83.0...v6.84.0) (2025-01-06)
+
+
+### Features
+
+* Add support for ARRAY<STRUCT> to CloudCilentExecutor ([#3544](https://github.com/googleapis/java-spanner/issues/3544)) ([6cbaf7e](https://github.com/googleapis/java-spanner/commit/6cbaf7ec6502d04fc0a0c09720e2054bd10bead9))
+* Add transaction runner for connections ([#3559](https://github.com/googleapis/java-spanner/issues/3559)) ([5a1be3d](https://github.com/googleapis/java-spanner/commit/5a1be3dedeafa6858502eadc7918820b9cd90f68))
+* Exposing InstanceType in Instance configuration (to define PROVISIONED or FREE spanner instance) ([8d295c4](https://github.com/googleapis/java-spanner/commit/8d295c4a4030b4e97b1d653cc3baf412864f3042))
+* Improve tracing by adding attributes ([#3576](https://github.com/googleapis/java-spanner/issues/3576)) ([eee333b](https://github.com/googleapis/java-spanner/commit/eee333b51fa69123e011dfbd2a0896fd31ac10dc))
+* **spanner:** Add jdbc support for external hosts ([#3536](https://github.com/googleapis/java-spanner/issues/3536)) ([801346a](https://github.com/googleapis/java-spanner/commit/801346a1b2efe7d0144f7442e1568eb5b02ddcbc))
+
+
+### Bug Fixes
+
+* AsyncTransactionManager did not always close the session ([#3580](https://github.com/googleapis/java-spanner/issues/3580)) ([d9813a0](https://github.com/googleapis/java-spanner/commit/d9813a05240b966f444168d3b8c30da9d27a8cc4))
+* Retry specific internal errors ([#3565](https://github.com/googleapis/java-spanner/issues/3565)) ([b9ce1a6](https://github.com/googleapis/java-spanner/commit/b9ce1a6fcbd11373a5cc82807af15c1cca0dd48e))
+* Update max_in_use_session at 10 mins interval ([#3570](https://github.com/googleapis/java-spanner/issues/3570)) ([cc1753d](https://github.com/googleapis/java-spanner/commit/cc1753da72b3e508f8fea8a6d19e1ed3f34e3602))
+
+
+### Dependencies
+
+* Update opentelemetry.version to v1.45.0 ([#3531](https://github.com/googleapis/java-spanner/issues/3531)) ([78c82ed](https://github.com/googleapis/java-spanner/commit/78c82edb4fcc4a5a9a372225ca429038c3b34955))
+
+## [6.83.0](https://github.com/googleapis/java-spanner/compare/v6.82.0...v6.83.0) (2024-12-13)
+
+
+### Features
+
+* Add Metrics host for built in metrics ([#3519](https://github.com/googleapis/java-spanner/issues/3519)) ([4ed455a](https://github.com/googleapis/java-spanner/commit/4ed455a43edf7ff8d138ce4d40a52d3224383b14))
+* Add opt-in for using multiplexed sessions for blind writes ([#3540](https://github.com/googleapis/java-spanner/issues/3540)) ([216f53e](https://github.com/googleapis/java-spanner/commit/216f53e4cbc0150078ece7785da33b342a6ab082))
+* Add UUID in Spanner TypeCode enum ([41f83dc](https://github.com/googleapis/java-spanner/commit/41f83dcf046f955ec289d4e976f40a03922054cb))
+* Introduce java.time variables and methods ([#3495](https://github.com/googleapis/java-spanner/issues/3495)) ([8a7d533](https://github.com/googleapis/java-spanner/commit/8a7d533ded21b9b94992b68c702c08bb84474e1b))
+* **spanner:** Support multiplexed session for Partitioned operations ([#3231](https://github.com/googleapis/java-spanner/issues/3231)) ([4501a3e](https://github.com/googleapis/java-spanner/commit/4501a3ea69a9346e8b95edf6f94ff839b509ec73))
+* Support 'set local' for retry_aborts_internally ([#3532](https://github.com/googleapis/java-spanner/issues/3532)) ([331942f](https://github.com/googleapis/java-spanner/commit/331942f51b11660b9de9c8fe8aacd6f60ac254b5))
+
+
+### Bug Fixes
+
+* **deps:** Update the Java code generator (gapic-generator-java) to 2.51.0 ([41f83dc](https://github.com/googleapis/java-spanner/commit/41f83dcf046f955ec289d4e976f40a03922054cb))
+
+
+### Dependencies
+
+* Update sdk platform java dependencies ([#3549](https://github.com/googleapis/java-spanner/issues/3549)) ([6235f0f](https://github.com/googleapis/java-spanner/commit/6235f0f2c223718c537addc450fa5910d1500271))
+
## [6.82.0](https://github.com/googleapis/java-spanner/compare/v6.81.2...v6.82.0) (2024-12-04)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b65dd279c94..ff092b68e3f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -84,7 +84,7 @@ Code in this repo is formatted with
[google-java-format](https://github.com/google/google-java-format).
To run formatting on your project, you can run:
```
-mvn com.coveo:fmt-maven-plugin:format
+mvn com.spotify.fmt:fmt-maven-plugin:format
```
[1]: https://cloud.google.com/docs/authentication/getting-started#creating_a_service_account
diff --git a/README.md b/README.md
index 29f1bb0322d..d34cbd74130 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+**_THIS REPOSITORY IS DEPRECATED. ALL OF ITS CONTENT AND HISTORY HAS BEEN MOVED TO [GOOGLE-CLOUD-JAVA](https://github.com/googleapis/google-cloud-java/tree/main/java-spanner)_**
+
# Google Cloud Spanner Client for Java
Java idiomatic client for [Cloud Spanner][product-docs].
@@ -19,7 +21,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloudlibraries-bom
- 26.50.0
+ 26.78.0pomimport
@@ -41,7 +43,7 @@ If you are using Maven without the BOM, add this to your dependencies:
com.google.cloudgoogle-cloud-spanner
- 6.81.1
+ 6.112.0
```
@@ -49,20 +51,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.50.0')
+implementation platform('com.google.cloud:libraries-bom:26.78.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.82.0'
+implementation 'com.google.cloud:google-cloud-spanner:6.113.0'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.82.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.113.0"
```
## Authentication
@@ -150,217 +152,30 @@ the Cloud Spanner Java client.
## Metrics
-### Available client-side metrics:
-
-* `spanner/max_in_use_sessions`: This returns the maximum
- number of sessions that have been in use during the last maintenance window
- interval, so as to provide an indication of the amount of activity currently
- in the database.
-
-* `spanner/max_allowed_sessions`: This shows the maximum
- number of sessions allowed.
-
-* `spanner/num_sessions_in_pool`: This metric allows users to
- see instance-level and database-level data for the total number of sessions in
- the pool at this very moment.
-
-* `spanner/num_acquired_sessions`: This metric allows
- users to see the total number of acquired sessions.
-
-* `spanner/num_released_sessions`: This metric allows
- users to see the total number of released (destroyed) sessions.
-
-* `spanner/get_session_timeouts`: This gives you an
- indication of the total number of get session timed-out instead of being
- granted (the thread that requested the session is placed in a wait queue where
- it waits until a session is released into the pool by another thread) due to
- pool exhaustion since the server process started.
-
-* `spanner/gfe_latency`: This metric shows latency between
- Google's network receiving an RPC and reading back the first byte of the response.
+Cloud Spanner client supports [client-side metrics](https://cloud.google.com/spanner/docs/view-manage-client-side-metrics) that you can use along with server-side metrics to optimize performance and troubleshoot performance issues if they occur.
-* `spanner/gfe_header_missing_count`: This metric shows the
- number of RPC responses received without the server-timing header, most likely
- indicating that the RPC never reached Google's network.
+Client-side metrics are measured from the time a request leaves your application to the time your application receives the response.
+In contrast, server-side metrics are measured from the time Spanner receives a request until the last byte of data is sent to the client.
-### Instrument with OpenTelemetry
+These metrics are enabled by default. You can opt out of using client-side metrics with the following code:
-Cloud Spanner client supports [OpenTelemetry Metrics](https://opentelemetry.io/),
-which gives insight into the client internals and aids in debugging/troubleshooting
-production issues. OpenTelemetry metrics will provide you with enough data to enable you to
-spot, and investigate the cause of any unusual deviations from normal behavior.
-
-All Cloud Spanner Metrics are prefixed with `spanner/` and uses `cloud.google.com/java` as [Instrumentation Scope](https://opentelemetry.io/docs/concepts/instrumentation-scope/). The
-metrics will be tagged with:
-* `database`: the target database name.
-* `instance_id`: the instance id of the target Spanner instance.
-* `client_id`: the user defined database client id.
-
-By default, the functionality is disabled. You need to add OpenTelemetry dependencies, enable OpenTelemetry metrics and must configure the OpenTelemetry with appropriate exporters at the startup of your application:
-
-#### OpenTelemetry Dependencies
-If you are using Maven, add this to your pom.xml file
-```xml
-
- io.opentelemetry
- opentelemetry-sdk
- {opentelemetry.version}
-
-
- io.opentelemetry
- opentelemetry-sdk-metrics
- {opentelemetry.version}
-
-
- io.opentelemetry
- opentelemetry-exporter-otlp
- {opentelemetry.version}
-
-```
-If you are using Gradle, add this to your dependencies
-```Groovy
-compile 'io.opentelemetry:opentelemetry-sdk:{opentelemetry.version}'
-compile 'io.opentelemetry:opentelemetry-sdk-metrics:{opentelemetry.version}'
-compile 'io.opentelemetry:opentelemetry-exporter-oltp:{opentelemetry.version}'
```
-
-#### OpenTelemetry Configuration
-By default, all metrics are disabled. To enable metrics and configure the OpenTelemetry follow below:
-
-```java
-// Enable OpenTelemetry metrics before injecting OpenTelemetry object.
-SpannerOptions.enableOpenTelemetryMetrics();
-
-SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
-// Use Otlp exporter or any other exporter of your choice.
- .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build())
- .build())
- .build();
-
-OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
- .setMeterProvider(sdkMeterProvider)
- .build()
-
SpannerOptions options = SpannerOptions.newBuilder()
-// Inject OpenTelemetry object via Spanner Options or register OpenTelemetry object as Global
- .setOpenTelemetry(openTelemetry)
+ .setBuiltInMetricsEnabled(false)
.build();
-
-Spanner spanner = options.getService();
```
-#### OpenTelemetry SQL Statement Tracing
-The OpenTelemetry traces that are generated by the Java client include any request and transaction
-tags that have been set. The traces can also include the SQL statements that are executed and the
-name of the thread that executes the statement. Enable this with the `enableExtendedTracing`
-option:
-
-```
-SpannerOptions options = SpannerOptions.newBuilder()
- .setOpenTelemetry(openTelemetry)
- .setEnableExtendedTracing(true)
- .build();
-```
+You can also disable these metrics by setting `SPANNER_DISABLE_BUILTIN_METRICS` to `true`.
-This option can also be enabled by setting the environment variable
-`SPANNER_ENABLE_EXTENDED_TRACING=true`.
-
-#### OpenTelemetry API Tracing
-You can enable tracing of each API call that the Spanner client executes with the `enableApiTracing`
-option. These traces also include any retry attempts for an API call:
-
-```
-SpannerOptions options = SpannerOptions.newBuilder()
-.setOpenTelemetry(openTelemetry)
-.setEnableApiTracing(true)
-.build();
-```
-
-This option can also be enabled by setting the environment variable
-`SPANNER_ENABLE_API_TRACING=true`.
-
-> Note: The attribute keys that are used for additional information about retry attempts and the number of requests might change in a future release.
-
-
-### Instrument with OpenCensus
-
-> Note: OpenCensus project is deprecated. See [Sunsetting OpenCensus](https://opentelemetry.io/blog/2023/sunsetting-opencensus/).
-We recommend migrating to OpenTelemetry, the successor project.
-
-Cloud Spanner client supports [Opencensus Metrics](https://opencensus.io/stats/),
-which gives insight into the client internals and aids in debugging/troubleshooting
-production issues. OpenCensus metrics will provide you with enough data to enable you to
-spot, and investigate the cause of any unusual deviations from normal behavior.
-
-All Cloud Spanner Metrics are prefixed with `cloud.google.com/java/spanner`
-
-The metrics are tagged with:
-* `database`: the target database name.
-* `instance_id`: the instance id of the target Spanner instance.
-* `client_id`: the user defined database client id.
-* `library_version`: the version of the library that you're using.
-
-
-By default, the functionality is disabled. You need to include opencensus-impl
-dependency to collect the data and exporter dependency to export to backend.
-
-[Click here](https://medium.com/google-cloud/troubleshooting-cloud-spanner-applications-with-opencensus-2cf424c4c590) for more information.
-
-#### OpenCensus Dependencies
-
-If you are using Maven, add this to your pom.xml file
-```xml
-
- io.opencensus
- opencensus-impl
- 0.30.0
- runtime
-
-
- io.opencensus
- opencensus-exporter-stats-stackdriver
- 0.30.0
-
-```
-If you are using Gradle, add this to your dependencies
-```Groovy
-compile 'io.opencensus:opencensus-impl:0.30.0'
-compile 'io.opencensus:opencensus-exporter-stats-stackdriver:0.30.0'
-```
-
-#### Configure the OpenCensus Exporter
-
-At the start of your application configure the exporter:
-
-```java
-import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
-// Enable OpenCensus exporters to export metrics to Stackdriver Monitoring.
-// Exporters use Application Default Credentials to authenticate.
-// See https://developers.google.com/identity/protocols/application-default-credentials
-// for more details.
-// The minimum reporting period for Stackdriver is 1 minute.
-StackdriverStatsExporter.createAndRegister();
-```
-#### Enable RPC Views
-
-By default, all session metrics are enabled. To enable RPC views, use either of the following method:
-
-```java
-// Register views for GFE metrics, including gfe_latency and gfe_header_missing_count.
-SpannerRpcViews.registerGfeLatencyAndHeaderMissingCountViews();
-
-// Register GFE Latency view.
-SpannerRpcViews.registerGfeLatencyView();
-
-// Register GFE Header Missing Count view.
-SpannerRpcViews.registerGfeHeaderMissingCountView();
-```
+> Note: Client-side metrics needs `monitoring.timeSeries.create` IAM permission to export metrics data. Ask your administrator to grant your service account the [Monitoring Metric Writer](https://cloud.google.com/iam/docs/roles-permissions/monitoring#monitoring.metricWriter) (roles/monitoring.metricWriter) IAM role on the project.
## Traces
Cloud Spanner client supports OpenTelemetry Traces, which gives insight into the client internals and aids in debugging/troubleshooting production issues.
By default, the functionality is disabled. You need to add OpenTelemetry dependencies, enable OpenTelemetry traces and must configure the OpenTelemetry with appropriate exporters at the startup of your application.
+See [Configure client-side tracing](https://cloud.google.com/spanner/docs/set-up-tracing#configure-client-side-tracing) for more details on configuring traces.
+
#### OpenTelemetry Dependencies
If you are using Maven, add this to your pom.xml file
@@ -447,9 +262,32 @@ This option can also be enabled by setting the environment variable
> Note: The attribute keys that are used for additional information about retry attempts and the number of requests might change in a future release.
+#### End-to-end Tracing
+
+In addition to client-side tracing, you can opt in for [end-to-end tracing](https://cloud.google.com/spanner/docs/tracing-overview#end-to-end-side-tracing). End-to-end tracing helps you understand and debug latency issues that are specific to Spanner such as the following:
+* Identify whether the latency is due to network latency between your application and Spanner, or if the latency is occurring within Spanner.
+* Identify the Google Cloud regions that your application requests are being routed through and if there is a cross-region request. A cross-region request usually means higher latencies between your application and Spanner.
+
+```
+SpannerOptions options = SpannerOptions.newBuilder()
+.setOpenTelemetry(openTelemetry)
+.setEnableEndToEndTracing(true)
+.build();
+```
+
+Refer to [Configure end-to-end tracing](https://cloud.google.com/spanner/docs/set-up-tracing#configure-end-to-end-tracing) to configure end-to-end tracing and to understand its attributes.
+
+> Note: End-to-end traces can only be exported to [Cloud Trace](https://cloud.google.com/trace/docs).
+
+
+## Instrument with OpenCensus
+
+> Note: OpenCensus project is deprecated. See [Sunsetting OpenCensus](https://opentelemetry.io/blog/2023/sunsetting-opencensus/).
+We recommend migrating to OpenTelemetry, the successor project.
+
## Migrate from OpenCensus to OpenTelemetry
-> Using the [OpenTelemetry OpenCensus Bridge](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-opencensus-shim), you can immediately begin exporting your metrics and traces with OpenTelemetry
+> Using the [OpenTelemetry OpenCensus Bridge](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-opencensus-shim), you can immediately begin exporting your metrics and traces with OpenTelemetry.
#### Disable OpenCensus metrics
Disable OpenCensus metrics for Spanner by including the following code if you still possess OpenCensus dependencies and exporter.
@@ -504,6 +342,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| Async Transaction Manager Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AsyncTransactionManagerExample.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/AsyncTransactionManagerExample.java) |
| Batch Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/BatchSample.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/BatchSample.java) |
| Batch Write At Least Once Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/BatchWriteAtLeastOnceSample.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/BatchWriteAtLeastOnceSample.java) |
+| Change Streams Txn Exclusion Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ChangeStreamsTxnExclusionSample.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/ChangeStreamsTxnExclusionSample.java) |
| Copy Backup Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.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/CopyBackupSample.java) |
| Copy Backup With Multi Region Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CopyBackupWithMultiRegionEncryptionKey.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/CopyBackupWithMultiRegionEncryptionKey.java) |
| Create Backup With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.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/CreateBackupWithEncryptionKey.java) |
@@ -517,12 +356,14 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| Create Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.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/CreateInstanceConfigSample.java) |
| Create Instance Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.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/CreateInstanceExample.java) |
| Create Instance Partition Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstancePartitionSample.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/CreateInstancePartitionSample.java) |
+| Create Instance With Asymmetric Autoscaling Config Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAsymmetricAutoscalingConfigExample.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/CreateInstanceWithAsymmetricAutoscalingConfigExample.java) |
| Create Instance With Autoscaling Config Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAutoscalingConfigExample.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/CreateInstanceWithAutoscalingConfigExample.java) |
| Create Instance With Processing Units Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithProcessingUnitsExample.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/CreateInstanceWithProcessingUnitsExample.java) |
| Create Instance Without Default Backup Schedules Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithoutDefaultBackupSchedulesExample.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/CreateInstanceWithoutDefaultBackupSchedulesExample.java) |
| Create Sequence Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateSequenceSample.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/CreateSequenceSample.java) |
| Create Table With Foreign Key Delete Cascade Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateTableWithForeignKeyDeleteCascadeSample.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/CreateTableWithForeignKeyDeleteCascadeSample.java) |
| Custom Timeout And Retry Settings Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CustomTimeoutAndRetrySettingsExample.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/CustomTimeoutAndRetrySettingsExample.java) |
+| Database Add Split Points Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DatabaseAddSplitPointsSample.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/DatabaseAddSplitPointsSample.java) |
| Delete Backup Schedule Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DeleteBackupScheduleSample.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/DeleteBackupScheduleSample.java) |
| Delete Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.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/DeleteInstanceConfigSample.java) |
| Delete Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/DeleteUsingDmlReturningSample.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/DeleteUsingDmlReturningSample.java) |
@@ -535,6 +376,8 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| Get Database Ddl Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.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/GetDatabaseDdlSample.java) |
| Get Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.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/GetInstanceConfigSample.java) |
| Insert Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/InsertUsingDmlReturningSample.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/InsertUsingDmlReturningSample.java) |
+| Isolation Level And Read Lock Mode Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/IsolationLevelAndReadLockModeSample.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/IsolationLevelAndReadLockModeSample.java) |
+| Last Statement Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/LastStatementSample.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/LastStatementSample.java) |
| List Backup Schedules Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListBackupSchedulesSample.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/ListBackupSchedulesSample.java) |
| List Database Roles | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.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/ListDatabaseRoles.java) |
| List Databases Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.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/ListDatabasesSample.java) |
@@ -551,6 +394,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| Pg Drop Sequence Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgDropSequenceSample.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/PgDropSequenceSample.java) |
| Pg Insert Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgInsertUsingDmlReturningSample.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/PgInsertUsingDmlReturningSample.java) |
| Pg Interleaved Table Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgInterleavedTableSample.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/PgInterleavedTableSample.java) |
+| Pg Last Statement Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgLastStatementSample.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/PgLastStatementSample.java) |
| Pg Partitioned Dml Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgPartitionedDmlSample.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/PgPartitionedDmlSample.java) |
| Pg Query With Numeric Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgQueryWithNumericParameterSample.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/PgQueryWithNumericParameterSample.java) |
| Pg Spanner Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.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/PgSpannerSample.java) |
@@ -572,6 +416,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) |
@@ -700,32 +545,13 @@ information.
Apache 2.0 - See [LICENSE][license] for more information.
-## CI Status
-
-Java Version | Status
------------- | ------
-Java 8 | [![Kokoro CI][kokoro-badge-image-2]][kokoro-badge-link-2]
-Java 8 OSX | [![Kokoro CI][kokoro-badge-image-3]][kokoro-badge-link-3]
-Java 8 Windows | [![Kokoro CI][kokoro-badge-image-4]][kokoro-badge-link-4]
-Java 11 | [![Kokoro CI][kokoro-badge-image-5]][kokoro-badge-link-5]
-
Java is a registered trademark of Oracle and/or its affiliates.
[product-docs]: https://cloud.google.com/spanner/docs/
[javadocs]: https://cloud.google.com/java/docs/reference/google-cloud-spanner/latest/history
-[kokoro-badge-image-1]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java7.svg
-[kokoro-badge-link-1]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java7.html
-[kokoro-badge-image-2]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8.svg
-[kokoro-badge-link-2]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8.html
-[kokoro-badge-image-3]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8-osx.svg
-[kokoro-badge-link-3]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8-osx.html
-[kokoro-badge-image-4]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8-win.svg
-[kokoro-badge-link-4]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java8-win.html
-[kokoro-badge-image-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-spanner/java11.svg
-[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.82.0
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-spanner/6.113.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 22c13635ce8..c72767328de 100644
--- a/benchmarks/pom.xml
+++ b/benchmarks/pom.xml
@@ -24,7 +24,7 @@
com.google.cloudgoogle-cloud-spanner-parent
- 6.82.0
+ 6.113.1-SNAPSHOT
@@ -34,7 +34,8 @@
UTF-8UTF-82.10.1
- 1.44.1
+ 1.59.0
+ 3.85.0
@@ -49,12 +50,17 @@
com.google.cloud.opentelemetryexporter-trace
- 0.33.0
+ 0.36.0com.google.cloud.opentelemetryexporter-metrics
- 0.33.0
+ 0.36.0
+
+
+ com.google.cloud
+ google-cloud-monitoring
+ ${google.cloud.monitoring.version}
@@ -80,29 +86,17 @@
com.google.re2jre2j
- 1.7
-
-
- io.opentelemetry
- opentelemetry-bom
- 1.44.1
- pom
- import
+ 1.8com.google.cloudgoogle-cloud-spanner
- 6.81.1
-
-
- commons-cli
- commons-cli
- 1.9.0
+ 6.112.0com.google.auto.valueauto-value-annotations
- 1.11.0
+ 1.11.1com.kohlschutter.junixsocket
@@ -118,7 +112,7 @@
commons-clicommons-cli
- 1.9.0
+ 1.11.0
@@ -133,15 +127,16 @@
org.codehaus.mojoexec-maven-plugin
- 3.5.0
+ 3.6.3com.google.cloud.spanner.benchmark.LatencyBenchmarkfalse
- com.coveo
+ com.spotify.fmtfmt-maven-plugin
+ 2.29
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 73683932def..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;
@@ -48,7 +49,11 @@ public static void main(String[] args) throws ParseException {
String.format("projects/%s/instances/%s/databases/%s", project, instance, database);
} else {
throw new IllegalArgumentException(
- "You must either set all the environment variables SPANNER_CLIENT_BENCHMARK_GOOGLE_CLOUD_PROJECT, SPANNER_CLIENT_BENCHMARK_SPANNER_INSTANCE and SPANNER_CLIENT_BENCHMARK_SPANNER_DATABASE, or specify a value for the command line argument --database");
+ "You must either set all the environment variables"
+ + " SPANNER_CLIENT_BENCHMARK_GOOGLE_CLOUD_PROJECT,"
+ + " SPANNER_CLIENT_BENCHMARK_SPANNER_INSTANCE and"
+ + " SPANNER_CLIENT_BENCHMARK_SPANNER_DATABASE, or specify a value for the command"
+ + " line argument --database");
}
LatencyBenchmark benchmark = new LatencyBenchmark(DatabaseId.of(fullyQualifiedDatabase));
@@ -61,23 +66,36 @@ 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",
true,
- "The wait time in milliseconds between each query that is executed by each client. Defaults to 0. "
- + "Set this to for example 1000 to have each client execute 1 query per second.");
+ "The wait time in milliseconds between each query that is executed by each client. Defaults"
+ + " to 0. Set this to for example 1000 to have each client execute 1 query per"
+ + " 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.");
+ "The type of transaction to execute. Must be either READ_ONLY or READ_WRITE. Defaults to"
+ + " READ_ONLY.");
+ 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);
@@ -91,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 ef44b5b9dea..5975d727df5 100644
--- a/generation_config.yaml
+++ b/generation_config.yaml
@@ -1,6 +1,6 @@
-gapic_generator_version: 2.50.0
-googleapis_commitish: 349841abac6c3e580ccce6e3d6fcc182ed2512c2
-libraries_bom_version: 26.50.0
+gapic_generator_version: 2.68.0
+googleapis_commitish: 59d5f2b46924714af627ac29ea6de78641a00835
+libraries_bom_version: 26.78.0
libraries:
- api_shortname: spanner
name_pretty: Cloud Spanner
@@ -17,7 +17,7 @@ libraries:
api_id: spanner.googleapis.com
transport: grpc
requires_billing: true
- codeowner_team: '@googleapis/api-spanner-java'
+ codeowner_team: '@googleapis/spanner-team'
library_type: GAPIC_COMBO
excluded_poms: google-cloud-spanner-bom
recommended_package: com.google.cloud.spanner
diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml
index 1db01f10946..1341af5fc1f 100644
--- a/google-cloud-spanner-bom/pom.xml
+++ b/google-cloud-spanner-bom/pom.xml
@@ -3,12 +3,12 @@
4.0.0com.google.cloudgoogle-cloud-spanner-bom
- 6.82.0
+ 6.113.1-SNAPSHOTpomcom.google.cloudsdk-platform-java-config
- 3.40.0
+ 3.58.0Google Cloud Spanner BOM
@@ -53,43 +53,43 @@
com.google.cloudgoogle-cloud-spanner
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.cloudgoogle-cloud-spannertest-jar
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcgrpc-google-cloud-spanner-v1
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcgrpc-google-cloud-spanner-admin-instance-v1
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcgrpc-google-cloud-spanner-admin-database-v1
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcproto-google-cloud-spanner-admin-instance-v1
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcproto-google-cloud-spanner-v1
- 6.82.0
+ 6.113.1-SNAPSHOTcom.google.api.grpcproto-google-cloud-spanner-admin-database-v1
- 6.82.0
+ 6.113.1-SNAPSHOT
@@ -100,7 +100,7 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.13.0
+ 3.15.01.81.8
diff --git a/google-cloud-spanner-executor/clirr-ignored-differences.xml b/google-cloud-spanner-executor/clirr-ignored-differences.xml
index 9d3c127bcc9..11e9890f1d9 100644
--- a/google-cloud-spanner-executor/clirr-ignored-differences.xml
+++ b/google-cloud-spanner-executor/clirr-ignored-differences.xml
@@ -7,4 +7,9 @@
CloudExecutorImpl(boolean)CloudExecutorImpl(boolean, double)
+
+ 7002
+ com/google/cloud/spanner/SessionPoolOptionsHelper
+ com.google.cloud.spanner.SessionPoolOptions$Builder setUseMultiplexedSessionBlindWrite(com.google.cloud.spanner.SessionPoolOptions$Builder, boolean)
+
diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml
index ccb631bb1a2..e3817e02302 100644
--- a/google-cloud-spanner-executor/pom.xml
+++ b/google-cloud-spanner-executor/pom.xml
@@ -5,20 +5,21 @@
4.0.0com.google.cloudgoogle-cloud-spanner-executor
- 6.82.0
+ 6.113.1-SNAPSHOTjarGoogle Cloud Spanner Executorcom.google.cloudgoogle-cloud-spanner-parent
- 6.82.0
+ 6.113.1-SNAPSHOT1.81.8UTF-8
+ 0.36.0
@@ -41,11 +42,30 @@
io.opentelemetryopentelemetry-sdk-trace
-
+
+
+ com.google.cloud.opentelemetry
+ shared-resourcemapping
+ ${google.cloud.opentelemetry.version}
+ com.google.cloud.opentelemetryexporter-trace
- 0.32.0
+ ${google.cloud.opentelemetry.version}
+
+
+ io.opentelemetry.semconv
+ opentelemetry-semconv
+
+
+
+
+ com.google.cloud
+ grpc-gcp
+
+
+ io.opentelemetry.semconv
+ opentelemetry-semconvcom.google.cloud
@@ -54,7 +74,14 @@
com.google.cloudgoogle-cloud-trace
- 2.53.0
+ 2.84.0
+
+
+
+ com.google.guava
+ failureaccess
+
+ io.grpc
@@ -127,7 +154,14 @@
com.google.api.grpcproto-google-cloud-trace-v1
- 2.53.0
+ 2.84.0
+
+
+
+ com.google.guava
+ failureaccess
+
+ com.google.api.grpc
@@ -160,12 +194,12 @@
commons-clicommons-cli
- 1.9.0
+ 1.11.0commons-iocommons-io
- 2.18.0
+ 2.21.0
@@ -192,7 +226,7 @@
org.apache.maven.surefiresurefire-junit4
- 3.5.2
+ 3.5.5test
@@ -257,7 +291,7 @@
org.apache.maven.pluginsmaven-failsafe-plugin
- 3.5.2
+ 3.5.5
@@ -266,7 +300,7 @@
org.apache.maven.pluginsmaven-dependency-plugin
- com.google.api:gax,org.apache.maven.surefire:surefire-junit4
+ com.google.api:gax,org.apache.maven.surefire:surefire-junit4,io.opentelemetry.semconv:opentelemetry-semconv,com.google.cloud.opentelemetry:shared-resourcemapping,com.google.cloud:grpc-gcp
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 c82b6306eb8..a9323fbdc25 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
@@ -26,7 +26,7 @@
import com.google.api.gax.rpc.TransportChannelProvider;
import com.google.api.gax.rpc.UnavailableException;
import com.google.auth.Credentials;
-import com.google.auth.oauth2.GoogleCredentials;
+import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
import com.google.cloud.NoCredentials;
@@ -47,6 +47,7 @@
import com.google.cloud.spanner.InstanceConfigInfo;
import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.InstanceInfo;
+import com.google.cloud.spanner.Interval;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.KeyRange;
import com.google.cloud.spanner.KeySet;
@@ -176,6 +177,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;
@@ -424,6 +426,7 @@ public synchronized boolean finish(Mode finishMode) throws Exception {
}
}
}
+
/**
* All the context in which SpannerActions are executed. It stores the current running transaction
* and table metadata, shared by all the action executor and protected by a lock. There will only
@@ -790,7 +793,7 @@ private synchronized Spanner getClient(boolean useMultiplexedSession) throws IOE
if (client != null) {
return client;
}
- client = getClient(/*timeoutSeconds=*/ 0, useMultiplexedSession);
+ client = getClient(/* timeoutSeconds= */ 0, useMultiplexedSession);
return client;
}
@@ -803,7 +806,7 @@ private synchronized Spanner getClient(long timeoutSeconds, boolean useMultiplex
credentials = NoCredentials.getInstance();
} else {
credentials =
- GoogleCredentials.fromStream(
+ ServiceAccountCredentials.fromStream(
new ByteArrayInputStream(
FileUtils.readFileToByteArray(new File(WorkerProxy.serviceKeyFile))),
HTTP_TRANSPORT_FACTORY);
@@ -830,10 +833,10 @@ private synchronized Spanner getClient(long timeoutSeconds, boolean useMultiplex
com.google.cloud.spanner.SessionPoolOptions.Builder poolOptionsBuilder =
com.google.cloud.spanner.SessionPoolOptions.newBuilder();
SessionPoolOptionsHelper.setUseMultiplexedSession(poolOptionsBuilder, useMultiplexedSession);
- SessionPoolOptionsHelper.setUseMultiplexedSessionBlindWrite(
- poolOptionsBuilder, useMultiplexedSession);
SessionPoolOptionsHelper.setUseMultiplexedSessionForRW(
poolOptionsBuilder, useMultiplexedSession);
+ SessionPoolOptionsHelper.setUseMultiplexedSessionForPartitionedOperations(
+ poolOptionsBuilder, useMultiplexedSession);
LOGGER.log(
Level.INFO,
String.format(
@@ -885,7 +888,7 @@ private synchronized TraceServiceClient getTraceServiceClient() throws IOExcepti
credentials = NoCredentials.getInstance();
} else {
credentials =
- GoogleCredentials.fromStream(
+ ServiceAccountCredentials.fromStream(
new ByteArrayInputStream(
FileUtils.readFileToByteArray(new File(WorkerProxy.serviceKeyFile))),
HTTP_TRANSPORT_FACTORY);
@@ -1021,7 +1024,7 @@ private Status executeAction(
return executeFinishTxn(action.getFinish(), outcomeSender, executionContext);
} else if (action.hasMutation()) {
return executeMutation(
- action.getMutation(), outcomeSender, executionContext, /*isWrite=*/ false);
+ action.getMutation(), outcomeSender, executionContext, /* isWrite= */ false);
} else if (action.hasRead()) {
return executeRead(
useMultiplexedSession, action.getRead(), outcomeSender, executionContext);
@@ -1035,7 +1038,7 @@ private Status executeAction(
return executeCloudBatchDmlUpdates(action.getBatchDml(), outcomeSender, executionContext);
} else if (action.hasWrite()) {
return executeMutation(
- action.getWrite().getMutation(), outcomeSender, executionContext, /*isWrite=*/ true);
+ action.getWrite().getMutation(), outcomeSender, executionContext, /* isWrite= */ true);
} else if (action.hasStartBatchTxn()) {
if (dbPath == null) {
throw SpannerExceptionFactory.newSpannerException(
@@ -2842,61 +2845,81 @@ private Status processResults(
/** Convert a result row to a row proto(value list) for sending back to the client. */
private com.google.spanner.executor.v1.ValueList buildRow(
StructReader result, OutcomeSender sender) throws SpannerException {
- com.google.spanner.executor.v1.ValueList.Builder rowBuilder =
- com.google.spanner.executor.v1.ValueList.newBuilder();
+ sender.setRowType(buildStructType(result));
+ return buildStruct(result);
+ }
+
+ /** Construct a StructType for a given struct. This is used to set the row type. */
+ private com.google.spanner.v1.StructType buildStructType(StructReader struct) {
com.google.spanner.v1.StructType.Builder rowTypeBuilder =
com.google.spanner.v1.StructType.newBuilder();
- for (int i = 0; i < result.getColumnCount(); ++i) {
- com.google.cloud.spanner.Type columnType = result.getColumnType(i);
+ for (int i = 0; i < struct.getColumnCount(); ++i) {
+ com.google.cloud.spanner.Type columnType = struct.getColumnType(i);
rowTypeBuilder.addFields(
com.google.spanner.v1.StructType.Field.newBuilder()
- .setName(result.getType().getStructFields().get(i).getName())
+ .setName(struct.getType().getStructFields().get(i).getName())
.setType(cloudTypeToTypeProto(columnType))
.build());
+ }
+ return rowTypeBuilder.build();
+ }
+
+ /** Convert a struct to a proto(value list) for constructing result rows and struct values. */
+ private com.google.spanner.executor.v1.ValueList buildStruct(StructReader struct) {
+ com.google.spanner.executor.v1.ValueList.Builder structBuilder =
+ com.google.spanner.executor.v1.ValueList.newBuilder();
+ for (int i = 0; i < struct.getColumnCount(); ++i) {
+ com.google.cloud.spanner.Type columnType = struct.getColumnType(i);
com.google.spanner.executor.v1.Value.Builder value =
com.google.spanner.executor.v1.Value.newBuilder();
- if (result.isNull(i)) {
+ if (struct.isNull(i)) {
value.setIsNull(true);
} else {
switch (columnType.getCode()) {
case BOOL:
- value.setBoolValue(result.getBoolean(i));
+ value.setBoolValue(struct.getBoolean(i));
break;
case FLOAT32:
- value.setDoubleValue((double) result.getFloat(i));
+ value.setDoubleValue((double) struct.getFloat(i));
break;
case FLOAT64:
- value.setDoubleValue(result.getDouble(i));
+ value.setDoubleValue(struct.getDouble(i));
break;
case INT64:
- value.setIntValue(result.getLong(i));
+ value.setIntValue(struct.getLong(i));
break;
case STRING:
- value.setStringValue(result.getString(i));
+ value.setStringValue(struct.getString(i));
break;
case BYTES:
- value.setBytesValue(toByteString(result.getBytes(i)));
+ value.setBytesValue(toByteString(struct.getBytes(i)));
break;
case TIMESTAMP:
- value.setTimestampValue(timestampToProto(result.getTimestamp(i)));
+ value.setTimestampValue(timestampToProto(struct.getTimestamp(i)));
break;
case DATE:
- value.setDateDaysValue(daysFromDate(result.getDate(i)));
+ value.setDateDaysValue(daysFromDate(struct.getDate(i)));
+ break;
+ case INTERVAL:
+ value.setStringValue(struct.getInterval(i).toISO8601());
+ break;
+ case UUID:
+ value.setStringValue(struct.getUuid(i).toString());
break;
case NUMERIC:
- String ascii = result.getBigDecimal(i).toPlainString();
+ String ascii = struct.getBigDecimal(i).toPlainString();
value.setStringValue(ascii);
break;
case JSON:
- value.setStringValue(result.getJson(i));
+ value.setStringValue(struct.getJson(i));
break;
case ARRAY:
- switch (result.getColumnType(i).getArrayElementType().getCode()) {
+ switch (struct.getColumnType(i).getArrayElementType().getCode()) {
case BOOL:
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getBooleanList(i);
+ List values = struct.getBooleanList(i);
for (Boolean booleanValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2915,7 +2938,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getFloatList(i);
+ List values = struct.getFloatList(i);
for (Float floatValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2934,7 +2957,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getDoubleList(i);
+ List values = struct.getDoubleList(i);
for (Double doubleValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2953,7 +2976,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getLongList(i);
+ List values = struct.getLongList(i);
for (Long longValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2972,7 +2995,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getStringList(i);
+ List values = struct.getStringList(i);
for (String stringValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2991,7 +3014,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getBytesList(i);
+ List values = struct.getBytesList(i);
for (ByteArray byteArrayValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3013,7 +3036,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getDateList(i);
+ List values = struct.getDateList(i);
for (Date dateValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3033,7 +3056,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getTimestampList(i);
+ List values = struct.getTimestampList(i);
for (Timestamp timestampValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3049,11 +3072,49 @@ private com.google.spanner.executor.v1.ValueList buildRow(
com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.TIMESTAMP).build());
}
break;
+ case INTERVAL:
+ {
+ com.google.spanner.executor.v1.ValueList.Builder builder =
+ com.google.spanner.executor.v1.ValueList.newBuilder();
+ List values = struct.getIntervalList(i);
+ for (Interval interval : values) {
+ com.google.spanner.executor.v1.Value.Builder valueProto =
+ com.google.spanner.executor.v1.Value.newBuilder();
+ if (interval == null) {
+ builder.addValue(valueProto.setIsNull(true).build());
+ } else {
+ builder.addValue(valueProto.setStringValue(interval.toISO8601()).build());
+ }
+ }
+ value.setArrayValue(builder.build());
+ value.setArrayType(
+ com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.INTERVAL).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 NUMERIC:
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getBigDecimalList(i);
+ List values = struct.getBigDecimalList(i);
for (BigDecimal bigDec : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3072,7 +3133,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
{
com.google.spanner.executor.v1.ValueList.Builder builder =
com.google.spanner.executor.v1.ValueList.newBuilder();
- List values = result.getJsonList(i);
+ List values = struct.getJsonList(i);
for (String stringValue : values) {
com.google.spanner.executor.v1.Value.Builder valueProto =
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3087,28 +3148,47 @@ private com.google.spanner.executor.v1.ValueList buildRow(
com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.JSON).build());
}
break;
+ case STRUCT:
+ {
+ com.google.spanner.executor.v1.ValueList.Builder builder =
+ com.google.spanner.executor.v1.ValueList.newBuilder();
+ List values = struct.getStructList(i);
+ for (StructReader structValue : values) {
+ com.google.spanner.executor.v1.Value.Builder valueProto =
+ com.google.spanner.executor.v1.Value.newBuilder();
+ if (structValue == null) {
+ builder.addValue(valueProto.setIsNull(true).build());
+ } else {
+ builder.addValue(valueProto.setStructValue(buildStruct(structValue))).build();
+ }
+ }
+ value.setArrayValue(builder.build());
+ value.setArrayType(
+ com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.STRUCT).build());
+ }
+ break;
default:
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INVALID_ARGUMENT,
"Unsupported row array type: "
- + result.getColumnType(i)
+ + struct.getColumnType(i)
+ " for result type "
- + result.getType().toString());
+ + struct.getType().toString());
}
break;
default:
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INVALID_ARGUMENT,
"Unsupported row type: "
- + result.getColumnType(i)
+ + struct.getColumnType(i)
+ " for result type "
- + result.getType().toString());
+ + struct.getType().toString());
}
}
- rowBuilder.addValue(value.build());
+ structBuilder.addValue(value.build());
}
- sender.setRowType(rowTypeBuilder.build());
- return rowBuilder.build();
+ ;
+ return structBuilder.build();
}
/** Convert a ListValue proto to a list of cloud Value. */
@@ -3164,7 +3244,7 @@ private static com.google.cloud.spanner.KeyRange keyRangeProtoToCloudKeyRange(
return KeyRange.openClosed(start, end);
case OPEN_OPEN:
return KeyRange.openOpen(start, end);
- // Unreachable.
+ // Unreachable.
default:
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INVALID_ARGUMENT, "Unrecognized key range type");
@@ -3193,6 +3273,7 @@ private static com.google.cloud.spanner.Key keyProtoToCloudKey(
case BYTES:
case FLOAT64:
case DATE:
+ case UUID:
case TIMESTAMP:
case NUMERIC:
case JSON:
@@ -3217,7 +3298,7 @@ private static com.google.cloud.spanner.Key keyProtoToCloudKey(
case BYTES:
cloudKey.append(toByteArray(part.getBytesValue()));
break;
- // Unreachable
+ // Unreachable
default:
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.INVALID_ARGUMENT, "Unsupported key part type: " + type.getCode().name());
@@ -3226,6 +3307,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());
}
@@ -3280,6 +3363,12 @@ private static com.google.cloud.spanner.Value valueProtoToCloudValue(
case DATE:
return com.google.cloud.spanner.Value.date(
value.hasIsNull() ? null : dateFromDays(value.getDateDaysValue()));
+ case INTERVAL:
+ return com.google.cloud.spanner.Value.interval(
+ value.hasIsNull() ? null : Interval.parseFromString(value.getStringValue()));
+ case UUID:
+ return com.google.cloud.spanner.Value.uuid(
+ value.hasIsNull() ? null : UUID.fromString(value.getStringValue()));
case NUMERIC:
{
if (value.hasIsNull()) {
@@ -3404,6 +3493,34 @@ private static com.google.cloud.spanner.Value valueProtoToCloudValue(
.collect(Collectors.toList()),
CloudClientExecutor::dateFromDays));
}
+ case INTERVAL:
+ if (value.hasIsNull()) {
+ return com.google.cloud.spanner.Value.intervalArray(null);
+ } else {
+ return com.google.cloud.spanner.Value.intervalArray(
+ 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()),
+ Interval::parseFromString));
+ }
+ 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()) {
@@ -3571,6 +3688,10 @@ private static com.google.cloud.spanner.Type typeProtoToCloudType(
return com.google.cloud.spanner.Type.date();
case TIMESTAMP:
return com.google.cloud.spanner.Type.timestamp();
+ case INTERVAL:
+ return com.google.cloud.spanner.Type.interval();
+ case UUID:
+ return com.google.cloud.spanner.Type.uuid();
case NUMERIC:
if (typeProto.getTypeAnnotation().equals(TypeAnnotationCode.PG_NUMERIC)) {
return com.google.cloud.spanner.Type.pgNumeric();
@@ -3625,6 +3746,10 @@ 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 INTERVAL:
+ return com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.INTERVAL).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-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutor.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutor.java
index 537a6ed4c33..eb6502c461c 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutor.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutor.java
@@ -368,9 +368,9 @@ private Status flush() {
LOGGER.log(
Level.INFO,
String.format(
- "OutcomeSender with action ID %s for change stream %s and partition token %s is "
- + "sending data change records with the following transaction id/record sequence "
- + "combinations: %s and partition tokens: %s",
+ "OutcomeSender with action ID %s for change stream %s and partition token %s is"
+ + " sending data change records with the following transaction id/record"
+ + " sequence combinations: %s and partition tokens: %s",
this.changeStreamForQuery,
this.partitionTokenForQuery,
actionId,
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutorImpl.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutorImpl.java
index 6fee10c95b6..f3de36ac7b4 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutorImpl.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudExecutorImpl.java
@@ -91,21 +91,14 @@ public void onNext(SpannerAsyncActionRequest request) {
SessionPoolOptions.Builder sessionPoolOptionsBuilder;
if (request.getAction().getSpannerOptions().hasSessionPoolOptions()) {
sessionPoolOptionsBuilder =
- request
- .getAction()
- .getSpannerOptions()
- .getSessionPoolOptions()
- .toBuilder()
+ request.getAction().getSpannerOptions().getSessionPoolOptions().toBuilder()
.setUseMultiplexed(true);
} else {
sessionPoolOptionsBuilder = SessionPoolOptions.newBuilder().setUseMultiplexed(true);
}
SpannerOptions.Builder optionsBuilder =
- request
- .getAction()
- .getSpannerOptions()
- .toBuilder()
+ request.getAction().getSpannerOptions().toBuilder()
.setSessionPoolOptions(sessionPoolOptionsBuilder);
SpannerAction.Builder actionBuilder =
request.getAction().toBuilder().setSpannerOptions(optionsBuilder);
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/WorkerProxy.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/WorkerProxy.java
index 2146adb1d47..0da30f82d23 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/WorkerProxy.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/WorkerProxy.java
@@ -19,7 +19,7 @@
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.Credentials;
import com.google.auth.http.HttpTransportFactory;
-import com.google.auth.oauth2.GoogleCredentials;
+import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.opentelemetry.trace.TraceConfiguration;
import com.google.cloud.opentelemetry.trace.TraceExporter;
import com.google.cloud.spanner.ErrorCode;
@@ -87,7 +87,7 @@ public static OpenTelemetrySdk setupOpenTelemetrySdk() throws Exception {
// Read credentials from the serviceKeyFile.
HttpTransportFactory HTTP_TRANSPORT_FACTORY = NetHttpTransport::new;
Credentials credentials =
- GoogleCredentials.fromStream(
+ ServiceAccountCredentials.fromStream(
new ByteArrayInputStream(FileUtils.readFileToByteArray(new File(serviceKeyFile))),
HTTP_TRANSPORT_FACTORY);
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/SessionPoolOptionsHelper.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/SessionPoolOptionsHelper.java
index f19cb8f4a2f..9dd8ac29563 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/SessionPoolOptionsHelper.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/SessionPoolOptionsHelper.java
@@ -31,14 +31,6 @@ public static SessionPoolOptions.Builder setUseMultiplexedSession(
return sessionPoolOptionsBuilder.setUseMultiplexedSession(useMultiplexedSession);
}
- // TODO: Remove when multiplexed session for blind write is released.
- public static SessionPoolOptions.Builder setUseMultiplexedSessionBlindWrite(
- SessionPoolOptions.Builder sessionPoolOptionsBuilder,
- boolean useMultiplexedSessionBlindWrite) {
- return sessionPoolOptionsBuilder.setUseMultiplexedSessionBlindWrite(
- useMultiplexedSessionBlindWrite);
- }
-
// TODO: Remove when multiplexed session for read write is released.
public static SessionPoolOptions.Builder setUseMultiplexedSessionForRW(
SessionPoolOptions.Builder sessionPoolOptionsBuilder, boolean useMultiplexedSessionForRW) {
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClient.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClient.java
index 368b42e07df..fd83e680e9c 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClient.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxySettings.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxySettings.java
index f24a2f2bdc3..ed4b3c70d65 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxySettings.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxySettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,8 +82,8 @@
* }
*
* Please refer to the [Client Side Retry
- * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
- * additional support in setting retries.
+ * Guide](https://docs.cloud.google.com/java/docs/client-retries) for additional support in setting
+ * retries.
*/
@Generated("by gapic-generator-java")
public class SpannerExecutorProxySettings extends ClientSettings {
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/package-info.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/package-info.java
index f76bafaa308..f3f9883a079 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/package-info.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyCallableFactory.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyCallableFactory.java
index 4e69db41a1e..2bdb9765036 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyCallableFactory.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyStub.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyStub.java
index 0950cbc56e5..56a1d3ff55a 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyStub.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/GrpcSpannerExecutorProxyStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ public class GrpcSpannerExecutorProxyStub extends SpannerExecutorProxyStub {
ProtoUtils.marshaller(SpannerAsyncActionRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(SpannerAsyncActionResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private final BidiStreamingCallable
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStub.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStub.java
index c23b1574b5a..8c932e57f95 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStub.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStubSettings.java b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStubSettings.java
index fbcf8bada1f..a71beccbf93 100644
--- a/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStubSettings.java
+++ b/google-cloud-spanner-executor/src/main/java/com/google/cloud/spanner/executor/v1/stub/SpannerExecutorProxyStubSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.rpc.ApiClientHeaderProvider;
import com.google.api.gax.rpc.ClientContext;
+import com.google.api.gax.rpc.LibraryMetadata;
import com.google.api.gax.rpc.StatusCode;
import com.google.api.gax.rpc.StreamingCallSettings;
import com.google.api.gax.rpc.StubSettings;
@@ -91,10 +92,11 @@
* }
*
* Please refer to the [Client Side Retry
- * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
- * additional support in setting retries.
+ * Guide](https://docs.cloud.google.com/java/docs/client-retries) for additional support in setting
+ * retries.
*/
@Generated("by gapic-generator-java")
+@SuppressWarnings("CanonicalDuration")
public class SpannerExecutorProxyStubSettings
extends StubSettings {
/** The default scopes of the service. */
@@ -194,6 +196,14 @@ protected SpannerExecutorProxyStubSettings(Builder settingsBuilder) throws IOExc
executeActionAsyncSettings = settingsBuilder.executeActionAsyncSettings().build();
}
+ @Override
+ protected LibraryMetadata getLibraryMetadata() {
+ return LibraryMetadata.newBuilder()
+ .setArtifactName("com.google.cloud:google-cloud-spanner")
+ .setRepository("googleapis/java-spanner")
+ .build();
+ }
+
/** Builder for SpannerExecutorProxyStubSettings. */
public static class Builder
extends StubSettings.Builder {
diff --git a/google-cloud-spanner-executor/src/main/resources/META-INF/native-image/com.google.cloud.spanner.executor.v1/reflect-config.json b/google-cloud-spanner-executor/src/main/resources/META-INF/native-image/com.google.cloud.spanner.executor.v1/reflect-config.json
index b3291f2748a..02102d0112e 100644
--- a/google-cloud-spanner-executor/src/main/resources/META-INF/native-image/com.google.cloud.spanner.executor.v1/reflect-config.json
+++ b/google-cloud-spanner-executor/src/main/resources/META-INF/native-image/com.google.cloud.spanner.executor.v1/reflect-config.json
@@ -1034,6 +1034,15 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FeatureSet$EnforceNamingStyle",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.protobuf.DescriptorProtos$FeatureSet$EnumType",
"queryAllDeclaredConstructors": true,
@@ -1088,6 +1097,33 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FeatureSet$VisibilityFeature",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FeatureSet$VisibilityFeature$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FeatureSet$VisibilityFeature$DefaultSymbolVisibility",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.protobuf.DescriptorProtos$FeatureSetDefaults",
"queryAllDeclaredConstructors": true,
@@ -1205,6 +1241,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FieldOptions$FeatureSupport",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.protobuf.DescriptorProtos$FieldOptions$FeatureSupport$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.protobuf.DescriptorProtos$FieldOptions$JSType",
"queryAllDeclaredConstructors": true,
@@ -1511,6 +1565,15 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.protobuf.DescriptorProtos$SymbolVisibility",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.protobuf.DescriptorProtos$UninterpretedOption",
"queryAllDeclaredConstructors": true,
@@ -1700,6 +1763,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.database.v1.AddSplitPointsRequest",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.AddSplitPointsRequest$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.AddSplitPointsResponse",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.AddSplitPointsResponse$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.database.v1.Backup",
"queryAllDeclaredConstructors": true,
@@ -1745,6 +1844,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.database.v1.BackupInstancePartition",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.BackupInstancePartition$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.database.v1.BackupSchedule",
"queryAllDeclaredConstructors": true,
@@ -2276,6 +2393,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.database.v1.InternalUpdateGraphOperationRequest",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.InternalUpdateGraphOperationRequest$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.InternalUpdateGraphOperationResponse",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.InternalUpdateGraphOperationResponse$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.database.v1.ListBackupOperationsRequest",
"queryAllDeclaredConstructors": true,
@@ -2618,6 +2771,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.database.v1.SplitPoints",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.SplitPoints$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.SplitPoints$Key",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.database.v1.SplitPoints$Key$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.database.v1.UpdateBackupRequest",
"queryAllDeclaredConstructors": true,
@@ -2978,6 +3167,33 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.instance.v1.FreeInstanceMetadata",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.instance.v1.FreeInstanceMetadata$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.instance.v1.FreeInstanceMetadata$ExpireBehavior",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.instance.v1.FulfillmentPeriod",
"queryAllDeclaredConstructors": true,
@@ -3077,6 +3293,15 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.instance.v1.Instance$InstanceType",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.instance.v1.Instance$State",
"queryAllDeclaredConstructors": true,
@@ -3104,6 +3329,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.admin.instance.v1.InstanceConfig$FreeInstanceAvailability",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.admin.instance.v1.InstanceConfig$QuorumType",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.admin.instance.v1.InstanceConfig$State",
"queryAllDeclaredConstructors": true,
@@ -3572,6 +3815,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.executor.v1.AdaptMessageAction",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.executor.v1.AdaptMessageAction$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.executor.v1.AddSplitPointsAction",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.executor.v1.AddSplitPointsAction$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.executor.v1.AdminAction",
"queryAllDeclaredConstructors": true,
@@ -5138,6 +5417,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.CacheUpdate",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.CacheUpdate$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.CommitRequest",
"queryAllDeclaredConstructors": true,
@@ -5426,6 +5723,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.Group",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Group$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.KeyRange",
"queryAllDeclaredConstructors": true,
@@ -5444,6 +5759,60 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.KeyRecipe",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.KeyRecipe$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.KeyRecipe$Part",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.KeyRecipe$Part$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.KeyRecipe$Part$NullOrder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.KeyRecipe$Part$Order",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.KeySet",
"queryAllDeclaredConstructors": true,
@@ -5525,6 +5894,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.Mutation$Ack",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Mutation$Ack$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.Mutation$Builder",
"queryAllDeclaredConstructors": true,
@@ -5552,6 +5939,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.Mutation$Send",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Mutation$Send$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.Mutation$Write",
"queryAllDeclaredConstructors": true,
@@ -5741,6 +6146,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.QueryAdvisorResult",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.QueryAdvisorResult$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.QueryAdvisorResult$IndexAdvice",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.QueryAdvisorResult$IndexAdvice$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.QueryPlan",
"queryAllDeclaredConstructors": true,
@@ -5759,6 +6200,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.Range",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Range$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.ReadRequest",
"queryAllDeclaredConstructors": true,
@@ -5795,6 +6254,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.RecipeList",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.RecipeList$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.RequestOptions",
"queryAllDeclaredConstructors": true,
@@ -5813,6 +6290,24 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.RequestOptions$ClientContext",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.RequestOptions$ClientContext$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.RequestOptions$Priority",
"queryAllDeclaredConstructors": true,
@@ -5894,6 +6389,42 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.RoutingHint",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.RoutingHint$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.RoutingHint$SkippedTablet",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.RoutingHint$SkippedTablet$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.Session",
"queryAllDeclaredConstructors": true,
@@ -5948,6 +6479,33 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.Tablet",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Tablet$Builder",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
+ {
+ "name": "com.google.spanner.v1.Tablet$Role",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.Transaction",
"queryAllDeclaredConstructors": true,
@@ -5984,6 +6542,15 @@
"allDeclaredClasses": true,
"allPublicClasses": true
},
+ {
+ "name": "com.google.spanner.v1.TransactionOptions$IsolationLevel",
+ "queryAllDeclaredConstructors": true,
+ "queryAllPublicConstructors": true,
+ "queryAllDeclaredMethods": true,
+ "allPublicMethods": true,
+ "allDeclaredClasses": true,
+ "allPublicClasses": true
+ },
{
"name": "com.google.spanner.v1.TransactionOptions$PartitionedDml",
"queryAllDeclaredConstructors": true,
diff --git a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxy.java b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxy.java
index a0c082532ff..95aaa8fea22 100644
--- a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxy.java
+++ b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxyImpl.java b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxyImpl.java
index ac283457321..9e5c02c6ba5 100644
--- a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxyImpl.java
+++ b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/MockSpannerExecutorProxyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -77,7 +77,8 @@ public void onNext(SpannerAsyncActionRequest value) {
responseObserver.onError(
new IllegalArgumentException(
String.format(
- "Unrecognized response type %s for method ExecuteActionAsync, expected %s or %s",
+ "Unrecognized response type %s for method ExecuteActionAsync, expected %s"
+ + " or %s",
response == null ? "null" : response.getClass().getName(),
SpannerAsyncActionResponse.class.getName(),
Exception.class.getName())));
diff --git a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClientTest.java b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClientTest.java
index 97d605fa770..8b74f5ad936 100644
--- a/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClientTest.java
+++ b/google-cloud-spanner-executor/src/test/java/com/google/cloud/spanner/executor/v1/SpannerExecutorProxyClientTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml
index 5b84cb4ebc3..a57bf40d1ba 100644
--- a/google-cloud-spanner/clirr-ignored-differences.xml
+++ b/google-cloud-spanner/clirr-ignored-differences.xml
@@ -566,6 +566,80 @@
java.util.List getFloat32Array()
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.UUID getUuid(int)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.UUID getUuid(java.lang.String)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.List getUuidList(int)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.List getUuidList(java.lang.String)
+
+
+ 7013
+ com/google/cloud/spanner/Value
+ java.util.UUID getUuid()
+
+
+ 7013
+ com/google/cloud/spanner/Value
+ java.util.List getUuidArray()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ com.google.cloud.spanner.Interval getInterval(int)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ com.google.cloud.spanner.Interval getInterval(java.lang.String)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ com.google.cloud.spanner.Interval[] getIntervalArray(int)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ com.google.cloud.spanner.Interval[] getIntervalArray(java.lang.String)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.List getIntervalList(int)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.util.List getIntervalList(java.lang.String)
+
+
+ 7013
+ com/google/cloud/spanner/Value
+ com.google.cloud.spanner.Interval getInterval()
+
+
+ 7013
+ com/google/cloud/spanner/Value
+ java.util.List getIntervalArray()
+
+
7012
@@ -709,6 +783,20 @@
boolean isEnableBuiltInMetrics()
+
+
+ 7012
+ com/google/cloud/spanner/SpannerOptions$SpannerEnvironment
+ boolean isEnableGRPCBuiltInMetrics()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/SpannerOptions$SpannerEnvironment
+ boolean isEnableAFEServerTiming()
+
+
7012
@@ -765,7 +853,7 @@
com/google/cloud/spanner/connection/Connectionboolean isKeepTransactionAlive()
-
+
7012
@@ -797,7 +885,7 @@
com/google/cloud/spanner/connection/Connectionboolean isAutoBatchDmlUpdateCountVerification()
-
+
7012
@@ -814,6 +902,241 @@
com/google/cloud/spanner/connection/TransactionRetryListenervoid retryDmlAsPartitionedDmlFailed(java.util.UUID, com.google.cloud.spanner.Statement, java.lang.Throwable)
-
-
+
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ java.lang.Object runTransaction(com.google.cloud.spanner.connection.Connection$TransactionCallable)
+
+
+
+
+ 7012
+ com/google/cloud/spanner/SpannerOptions$SpannerEnvironment
+ com.google.auth.oauth2.GoogleCredentials getDefaultExperimentalHostCredentials()
+
+
+ 7002
+ com/google/cloud/spanner/SpannerOptions$SpannerEnvironment
+ com.google.auth.oauth2.GoogleCredentials getDefaultExternalHostCredentials()
+
+
+ 7002
+ com/google/cloud/spanner/SpannerOptions
+ com.google.auth.oauth2.GoogleCredentials getDefaultExternalHostCredentialsFromSysEnv()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ void setDefaultSequenceKind(java.lang.String)
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ java.lang.String getDefaultSequenceKind()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ void setDefaultIsolationLevel(com.google.spanner.v1.TransactionOptions$IsolationLevel)
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ com.google.spanner.v1.TransactionOptions$IsolationLevel getDefaultIsolationLevel()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ void beginTransaction(com.google.spanner.v1.TransactionOptions$IsolationLevel)
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ com.google.api.core.ApiFuture beginTransactionAsync(com.google.spanner.v1.TransactionOptions$IsolationLevel)
+
+
+
+
+ 8001
+ com/google/cloud/spanner/connection/ConnectionOptions$ConnectionProperty
+
+
+ 6001
+ com/google/cloud/spanner/connection/ConnectionOptions
+ VALID_PROPERTIES
+
+
+
+
+ 7002
+ com/google/cloud/spanner/connection/AbstractStatementParser
+ boolean supportsExplain()
+
+
+ 7002
+ com/google/cloud/spanner/connection/PostgreSQLStatementParser
+ boolean supportsExplain()
+
+
+ 7002
+ com/google/cloud/spanner/connection/SpannerStatementParser
+ boolean supportsExplain()
+
+
+
+ 7012
+ com/google/cloud/spanner/DatabaseClient
+ com.google.cloud.spanner.Statement$StatementFactory getStatementFactory()
+
+
+
+
+ 7012
+ com/google/cloud/spanner/AsyncTransactionManager
+ com.google.cloud.spanner.AsyncTransactionManager$TransactionContextFuture beginAsync(com.google.cloud.spanner.AbortedException)
+
+
+ 7012
+ com/google/cloud/spanner/TransactionManager
+ com.google.cloud.spanner.TransactionContext begin(com.google.cloud.spanner.AbortedException)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrNull(int, java.util.function.BiFunction)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrNull(java.lang.String, java.util.function.BiFunction)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrDefault(int, java.util.function.BiFunction, java.lang.Object)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrDefault(java.lang.String, java.util.function.BiFunction, java.lang.Object)
+
+
+ 7012
+ com/google/cloud/spanner/SpannerOptions$SpannerEnvironment
+ boolean isEnableDirectAccess()
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ void setReadLockMode(com.google.spanner.v1.TransactionOptions$ReadWrite$ReadLockMode)
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ com.google.spanner.v1.TransactionOptions$ReadWrite$ReadLockMode getReadLockMode()
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ void setTransactionTimeout(java.time.Duration)
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ java.time.Duration getTransactionTimeout()
+
+
+ 8001
+ com/google/cloud/spanner/LatencyTest
+
+
+ 7012
+ com/google/cloud/spanner/connection/Connection
+ java.lang.Object getConnectionPropertyValue(com.google.cloud.spanner.connection.ConnectionProperty)
+
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordAFELatency(java.lang.Long)
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordAFELatency(java.lang.Float)
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordAfeHeaderMissingCount(java.lang.Long)
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordGFELatency(java.lang.Long)
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordGFELatency(java.lang.Float)
+
+
+ 7002
+ com/google/cloud/spanner/CompositeTracer
+ void recordGfeHeaderMissingCount(java.lang.Long)
+
+
+
+ 7002
+ com/google/cloud/spanner/SpannerException
+ void setRequestId(com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerBatchUpdateException newSpannerBatchUpdateException(com.google.cloud.spanner.ErrorCode, java.lang.String, long[], com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerException newSpannerException(com.google.cloud.spanner.ErrorCode, java.lang.String, java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerException newSpannerException(com.google.cloud.spanner.ErrorCode, java.lang.String, com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerException newSpannerException(java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerException newSpannerException(io.grpc.Context, java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 7002
+ com/google/cloud/spanner/SpannerExceptionFactory
+ com.google.cloud.spanner.SpannerException propagateInterrupt(java.lang.InterruptedException, com.google.cloud.spanner.XGoogSpannerRequestId)
+
+
+ 6001
+ com/google/cloud/spanner/XGoogSpannerRequestId
+ REQUEST_HEADER_KEY
+
+
+ 6001
+ com/google/cloud/spanner/XGoogSpannerRequestId
+ REQUEST_ID
+
diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml
index b7589c10203..0d70d6718b2 100644
--- a/google-cloud-spanner/pom.xml
+++ b/google-cloud-spanner/pom.xml
@@ -3,7 +3,7 @@
4.0.0com.google.cloudgoogle-cloud-spanner
- 6.82.0
+ 6.113.1-SNAPSHOTjarGoogle Cloud Spannerhttps://github.com/googleapis/java-spanner
@@ -11,11 +11,12 @@
com.google.cloudgoogle-cloud-spanner-parent
- 6.82.0
+ 6.113.1-SNAPSHOTgoogle-cloud-spanner0.31.1
+ 3.85.0com.google.cloud.spanner.GceTestEnvConfigprojects/gcloud-devel/instances/spanner-testing-east1gcloud-devel
@@ -24,11 +25,18 @@
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.7.1
+
+ org.jacocojacoco-maven-plugin
- 0.8.12
+ 0.8.14
@@ -64,6 +72,7 @@
${spanner.testenv.instance}${spanner.gce.config.project_id}${spanner.testenv.kms_key.name}
+ logging.properties
@@ -88,6 +97,7 @@
${spanner.testenv.instance}${spanner.gce.config.project_id}${spanner.testenv.kms_key.name}
+ logging.properties3000
@@ -124,6 +134,7 @@
-Dspanner.testenv.instance=${spanner.testenv.instance}-Dspanner.gce.config.project_id=${spanner.gce.config.project_id}-Dspanner.testenv.kms_key.name=${spanner.testenv.kms_key.name}
+ -Djava.util.logging.config.file=logging.properties
@@ -143,6 +154,25 @@
com/google/cloud/spanner/spi/v1/**
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.6.1
+
+ com.google.protobuf:protoc:4.33.2:exe:${os.detected.classifier}
+
+ ${project.basedir}/../proto-google-cloud-spanner-v1/src/main/proto
+
+
+
+
+ test-compile
+
+ test-compile
+
+
+
+
@@ -162,6 +192,12 @@
com.google.cloudgrpc-gcp
+
+
+ io.opentelemetry
+ opentelemetry-api
+
+ io.grpc
@@ -191,6 +227,16 @@
io.grpcgrpc-stub
+
+ io.grpc
+ grpc-opentelemetry
+
+
+ io.opentelemetry
+ opentelemetry-api
+
+
+ com.google.apiapi-common
@@ -265,12 +311,39 @@
com.google.cloudgoogle-cloud-monitoring
- 3.54.0
+ ${google.cloud.monitoring.version}
+
+
+
+ com.google.guava
+ failureaccess
+
+ com.google.api.grpcproto-google-cloud-monitoring-v3
- 3.55.0
+ ${google.cloud.monitoring.version}
+
+
+
+ com.google.guava
+ failureaccess
+
+
+
+
+ com.google.api.grpc
+ grpc-google-cloud-monitoring-v3
+ ${google.cloud.monitoring.version}
+ test
+
+
+
+ com.google.guava
+ failureaccess
+
+ com.google.auth
@@ -351,17 +424,10 @@
grpc-rlsruntime
-
-
- org.graalvm.sdk
- graal-sdk
- ${graal-sdk.version}
- provided
- org.graalvm.sdknativeimage
- ${graal-sdk.version}
+ ${graal-sdk-nativeimage.version}provided
@@ -371,7 +437,7 @@
junittest
-
+
com.google.api.grpc
@@ -417,7 +483,7 @@
org.jsonjson
- 20240303
+ 20250517test
@@ -455,6 +521,24 @@
opentelemetry-sdk-testingtest
+
+ com.google.cloud.opentelemetry
+ exporter-trace
+ 0.36.0
+ test
+
+
+ com.google.cloud
+ google-cloud-trace
+ 2.84.0
+ test
+
+
+ com.google.api.grpc
+ proto-google-cloud-trace-v1
+ 2.84.0
+ test
+
@@ -493,12 +577,44 @@
-classpathorg.openjdk.jmh.Main
- ${benchmark.name}
+ ${benchmark.name}
+ -rf
+ JSON
+ -rff
+ jmh-results.json
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ 1.37
+
+
+
+
+
+
+
+
+ validate-benchmark
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+ com.google.cloud.spanner.benchmarking.BenchmarkValidator
+ test
+
+
@@ -557,7 +673,7 @@
com.google.cloud.spanner.GceTestEnvConfigprojects/directpath-prod-manual-testing/instances/spanner-testingdirectpath-prod-manual-testing
- true
+ trueipv43000
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbortedException.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbortedException.java
index 03dff9f7609..28b5f1fa257 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbortedException.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbortedException.java
@@ -17,6 +17,7 @@
package com.google.cloud.spanner;
import com.google.api.gax.rpc.ApiException;
+import com.google.protobuf.ByteString;
import javax.annotation.Nullable;
/**
@@ -32,6 +33,8 @@ public class AbortedException extends SpannerException {
*/
private static final boolean IS_RETRYABLE = false;
+ private ByteString transactionID;
+
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
AbortedException(
DoNotConstructDirectly token, @Nullable String message, @Nullable Throwable cause) {
@@ -45,6 +48,9 @@ public class AbortedException extends SpannerException {
@Nullable Throwable cause,
@Nullable ApiException apiException) {
super(token, ErrorCode.ABORTED, IS_RETRYABLE, message, cause, apiException);
+ if (cause instanceof AbortedException) {
+ this.transactionID = ((AbortedException) cause).getTransactionID();
+ }
}
/**
@@ -54,4 +60,12 @@ public class AbortedException extends SpannerException {
public boolean isEmulatorOnlySupportsOneTransactionException() {
return getMessage().endsWith("The emulator only supports one transaction at a time.");
}
+
+ void setTransactionID(ByteString transactionID) {
+ this.transactionID = transactionID;
+ }
+
+ ByteString getTransactionID() {
+ return this.transactionID;
+ }
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java
index 10ab997d88a..7d083db211a 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractMultiplexedSessionDatabaseClient.java
@@ -16,10 +16,7 @@
package com.google.cloud.spanner;
-import com.google.api.gax.rpc.ServerStream;
import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Options.TransactionOption;
-import com.google.spanner.v1.BatchWriteResponse;
/**
* Base class for the Multiplexed Session {@link DatabaseClient} implementation. Throws {@link
@@ -29,25 +26,8 @@
*/
abstract class AbstractMultiplexedSessionDatabaseClient implements DatabaseClient {
- @Override
- public Dialect getDialect() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getDatabaseRole() {
- throw new UnsupportedOperationException();
- }
-
@Override
public Timestamp writeAtLeastOnce(Iterable mutations) throws SpannerException {
return writeAtLeastOnceWithOptions(mutations).getCommitTimestamp();
}
-
- @Override
- public ServerStream batchWriteAtLeastOnce(
- Iterable mutationGroups, TransactionOption... options)
- throws SpannerException {
- throw new UnsupportedOperationException();
- }
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java
index cecf462bd25..619ea42441a 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java
@@ -58,6 +58,7 @@
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
@@ -67,6 +68,7 @@
*/
abstract class AbstractReadContext
implements ReadContext, AbstractResultSet.Listener, SessionTransaction {
+ private static final Logger logger = Logger.getLogger(AbstractReadContext.class.getName());
abstract static class Builder, T extends AbstractReadContext> {
private SessionImpl session;
@@ -402,6 +404,41 @@ ByteString getTransactionId() {
}
}
+ @Override
+ public void close() {
+ ByteString id = getTransactionId();
+ if (id != null && !id.isEmpty()) {
+ rpc.clearTransactionAffinity(id);
+ }
+ super.close();
+ }
+
+ /**
+ * Initializes the transaction with the timestamp specified within MultiUseReadOnlyTransaction.
+ * This is used only for fallback of PartitionQueryRequest and PartitionReadRequest with
+ * Multiplexed Session.
+ */
+ void initFallbackTransaction() {
+ synchronized (txnLock) {
+ span.addAnnotation("Creating Transaction");
+ TransactionOptions.Builder options = TransactionOptions.newBuilder();
+ if (timestamp != null) {
+ options
+ .getReadOnlyBuilder()
+ .setReadTimestamp(timestamp.toProto())
+ .setReturnReadTimestamp(true);
+ } else {
+ bound.applyToBuilder(options.getReadOnlyBuilder()).setReturnReadTimestamp(true);
+ }
+ final BeginTransactionRequest request =
+ BeginTransactionRequest.newBuilder()
+ .setSession(session.getName())
+ .setOptions(options)
+ .build();
+ initTransactionInternal(request);
+ }
+ }
+
void initTransaction() {
SessionImpl.throwIfTransactionsPending();
@@ -417,40 +454,43 @@ void initTransaction() {
return;
}
span.addAnnotation("Creating Transaction");
+ TransactionOptions.Builder options = TransactionOptions.newBuilder();
+ bound.applyToBuilder(options.getReadOnlyBuilder()).setReturnReadTimestamp(true);
+ final BeginTransactionRequest request =
+ BeginTransactionRequest.newBuilder()
+ .setSession(session.getName())
+ .setOptions(options)
+ .build();
+ initTransactionInternal(request);
+ }
+ }
+
+ private void initTransactionInternal(BeginTransactionRequest request) {
+ try {
+ Transaction transaction =
+ rpc.beginTransaction(request, getTransactionChannelHint(), isRouteToLeader());
+ if (!transaction.hasReadTimestamp()) {
+ throw SpannerExceptionFactory.newSpannerException(
+ ErrorCode.INTERNAL, "Missing expected transaction.read_timestamp metadata field");
+ }
+ if (transaction.getId().isEmpty()) {
+ throw SpannerExceptionFactory.newSpannerException(
+ ErrorCode.INTERNAL, "Missing expected transaction.id metadata field");
+ }
try {
- TransactionOptions.Builder options = TransactionOptions.newBuilder();
- bound.applyToBuilder(options.getReadOnlyBuilder()).setReturnReadTimestamp(true);
- final BeginTransactionRequest request =
- BeginTransactionRequest.newBuilder()
- .setSession(session.getName())
- .setOptions(options)
- .build();
- Transaction transaction =
- rpc.beginTransaction(request, getTransactionChannelHint(), isRouteToLeader());
- if (!transaction.hasReadTimestamp()) {
- throw SpannerExceptionFactory.newSpannerException(
- ErrorCode.INTERNAL, "Missing expected transaction.read_timestamp metadata field");
- }
- if (transaction.getId().isEmpty()) {
- throw SpannerExceptionFactory.newSpannerException(
- ErrorCode.INTERNAL, "Missing expected transaction.id metadata field");
- }
- try {
- timestamp = Timestamp.fromProto(transaction.getReadTimestamp());
- } catch (IllegalArgumentException e) {
- throw SpannerExceptionFactory.newSpannerException(
- ErrorCode.INTERNAL, "Bad value in transaction.read_timestamp metadata field", e);
- }
- transactionId = transaction.getId();
- span.addAnnotation(
- "Transaction Creation Done",
- ImmutableMap.of(
- "Id", transaction.getId().toStringUtf8(), "Timestamp", timestamp.toString()));
-
- } catch (SpannerException e) {
- span.addAnnotation("Transaction Creation Failed", e);
- throw e;
+ timestamp = Timestamp.fromProto(transaction.getReadTimestamp());
+ } catch (IllegalArgumentException e) {
+ throw SpannerExceptionFactory.newSpannerException(
+ ErrorCode.INTERNAL, "Bad value in transaction.read_timestamp metadata field", e);
}
+ transactionId = transaction.getId();
+ span.addAnnotation(
+ "Transaction Creation Done",
+ ImmutableMap.of(
+ "Id", transaction.getId().toStringUtf8(), "Timestamp", timestamp.toString()));
+ } catch (SpannerException e) {
+ span.addAnnotation("Transaction Creation Failed", e);
+ throw e;
}
}
}
@@ -639,8 +679,8 @@ private ResultSet executeQueryInternal(
*
Specific {@link QueryOptions} passed in for this query.
*
Any value specified in a valid environment variable when the {@link SpannerOptions}
* instance was created.
- *
The default {@link SpannerOptions#getDefaultQueryOptions()} specified for the database
- * where the query is executed.
+ *
The default {@link SpannerOptions#getDefaultQueryOptions(DatabaseId)} ()} specified for
+ * the database where the query is executed.
*
*/
@VisibleForTesting
@@ -653,17 +693,15 @@ QueryOptions buildQueryOptions(QueryOptions requestOptions) {
}
RequestOptions buildRequestOptions(Options options) {
- // Shortcut for the most common return value.
- if (!(options.hasPriority() || options.hasTag() || getTransactionTag() != null)) {
- return RequestOptions.getDefaultInstance();
- }
-
- RequestOptions.Builder builder = RequestOptions.newBuilder();
- if (options.hasPriority()) {
- builder.setPriority(options.priority());
- }
- if (options.hasTag()) {
- builder.setRequestTag(options.tag());
+ RequestOptions.Builder builder = options.toRequestOptionsProto(false).toBuilder();
+ RequestOptions.ClientContext defaultClientContext =
+ session.getSpanner().getOptions().getClientContext();
+ if (defaultClientContext != null) {
+ RequestOptions.ClientContext.Builder clientContextBuilder = defaultClientContext.toBuilder();
+ if (builder.hasClientContext()) {
+ clientContextBuilder.mergeFrom(builder.getClientContext());
+ }
+ builder.setClientContext(clientContextBuilder.build());
}
if (getTransactionTag() != null) {
builder.setTransactionTag(getTransactionTag());
@@ -696,6 +734,9 @@ ExecuteSqlRequest.Builder getExecuteSqlRequestBuilder(
if (!isReadOnly()) {
builder.setSeqno(getSeqNo());
}
+ if (options.hasLastStatement()) {
+ builder.setLastStatement(options.isLastStatement());
+ }
builder.setQueryOptions(buildQueryOptions(statement.getQueryOptions()));
builder.setRequestOptions(buildRequestOptions(options));
return builder;
@@ -741,6 +782,9 @@ ExecuteBatchDmlRequest.Builder getExecuteBatchDmlRequestBuilder(
if (selector != null) {
builder.setTransaction(selector);
}
+ if (options.hasLastStatement()) {
+ builder.setLastStatements(options.isLastStatement());
+ }
builder.setSeqno(getSeqNo());
builder.setRequestOptions(buildRequestOptions(options));
return builder;
@@ -756,7 +800,7 @@ ResultSet executeQueryInternalWithOptions(
options.hasPrefetchChunks() ? options.prefetchChunks() : defaultPrefetchChunks;
final ExecuteSqlRequest.Builder request =
getExecuteSqlRequestBuilder(
- statement, queryMode, options, /* withTransactionSelector = */ false);
+ statement, queryMode, options, /* withTransactionSelector= */ false);
ResumableStreamIterator stream =
new ResumableStreamIterator(
MAX_BUFFERED_CHUNKS,
@@ -766,13 +810,19 @@ ResultSet executeQueryInternalWithOptions(
tracer.createStatementAttributes(statement, options),
session.getErrorHandler(),
rpc.getExecuteQueryRetrySettings(),
- rpc.getExecuteQueryRetryableCodes()) {
+ rpc.getExecuteQueryRetryableCodes(),
+ session.getRequestIdCreator()) {
@Override
CloseableIterator startStream(
@Nullable ByteString resumeToken,
- AsyncResultSet.StreamMessageListener streamListener) {
+ AsyncResultSet.StreamMessageListener streamListener,
+ XGoogSpannerRequestId requestId) {
GrpcStreamIterator stream =
- new GrpcStreamIterator(statement, prefetchChunks, cancelQueryWhenClientIsClosed);
+ new GrpcStreamIterator(
+ statement,
+ request.getLastStatement(),
+ prefetchChunks,
+ cancelQueryWhenClientIsClosed);
if (streamListener != null) {
stream.registerListener(streamListener);
}
@@ -794,10 +844,10 @@ CloseableIterator startStream(
request.build(),
stream.consumer(),
getTransactionChannelHint(),
+ requestId,
isRouteToLeader());
session.markUsed(clock.instant());
stream.setCall(call, request.getTransaction().hasBegin());
- call.request(prefetchChunks);
return stream;
}
@@ -810,7 +860,7 @@ boolean prepareIteratorForRetryOnDifferentGrpcChannel() {
stream, this, options.hasDecodeMode() ? options.decodeMode() : defaultDecodeMode);
}
- Map getChannelHintOptions(
+ static Map getChannelHintOptions(
Map channelHintForSession, Long channelHintForTransaction) {
if (channelHintForSession != null) {
return channelHintForSession;
@@ -889,7 +939,8 @@ String getTransactionTag() {
public void onTransactionMetadata(Transaction transaction, boolean shouldIncludeId) {}
@Override
- public SpannerException onError(SpannerException e, boolean withBeginTransaction) {
+ public SpannerException onError(
+ SpannerException e, boolean withBeginTransaction, boolean lastStatement) {
this.session.onError(e);
return e;
}
@@ -952,23 +1003,38 @@ ResultSet readInternalWithOptions(
} else if (defaultDirectedReadOptions != null) {
builder.setDirectedReadOptions(defaultDirectedReadOptions);
}
+ if (readOptions.hasLockHint()) {
+ if (isReadOnly()) {
+ logger.warning(
+ "Lock hint is only supported for ReadWrite transactions. "
+ + "Overriding lock hint to default unspecified.");
+ } else {
+ builder.setLockHint(readOptions.lockHint());
+ }
+ }
final int prefetchChunks =
readOptions.hasPrefetchChunks() ? readOptions.prefetchChunks() : defaultPrefetchChunks;
+ final boolean lastStatement =
+ readOptions.hasLastStatement() ? readOptions.isLastStatement() : false;
ResumableStreamIterator stream =
new ResumableStreamIterator(
MAX_BUFFERED_CHUNKS,
SpannerImpl.READ,
span,
tracer,
+ tracer.createTableAttributes(table, readOptions),
session.getErrorHandler(),
rpc.getReadRetrySettings(),
- rpc.getReadRetryableCodes()) {
+ rpc.getReadRetryableCodes(),
+ session.getRequestIdCreator()) {
@Override
CloseableIterator startStream(
@Nullable ByteString resumeToken,
- AsyncResultSet.StreamMessageListener streamListener) {
+ AsyncResultSet.StreamMessageListener streamListener,
+ XGoogSpannerRequestId requestId) {
GrpcStreamIterator stream =
- new GrpcStreamIterator(prefetchChunks, cancelQueryWhenClientIsClosed);
+ new GrpcStreamIterator(
+ lastStatement, prefetchChunks, cancelQueryWhenClientIsClosed);
if (streamListener != null) {
stream.registerListener(streamListener);
}
@@ -988,10 +1054,10 @@ CloseableIterator startStream(
builder.build(),
stream.consumer(),
getTransactionChannelHint(),
+ requestId,
isRouteToLeader());
session.markUsed(clock.instant());
- stream.setCall(call, /* withBeginTransaction = */ builder.getTransaction().hasBegin());
- call.request(prefetchChunks);
+ stream.setCall(call, /* withBeginTransaction= */ builder.getTransaction().hasBegin());
return stream;
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java
index 3dca970f96e..0717cae74f2 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java
@@ -38,6 +38,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.UUID;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -48,13 +49,15 @@ abstract class AbstractResultSet extends AbstractStructReader implements Resu
interface Listener {
/**
* Called when transaction metadata is seen. This method may be invoked at most once. If the
- * method is invoked, it will precede {@link #onError(SpannerException)} or {@link #onDone()}.
+ * method is invoked, it will precede {@link #onError(SpannerException,boolean)} or {@link
+ * #onDone(boolean)}.
*/
void onTransactionMetadata(Transaction transaction, boolean shouldIncludeId)
throws SpannerException;
/** Called when the read finishes with an error. Returns the error that should be thrown. */
- SpannerException onError(SpannerException e, boolean withBeginTransaction);
+ SpannerException onError(
+ SpannerException e, boolean withBeginTransaction, boolean lastStatement);
/** Called when the read finishes normally. */
void onDone(boolean withBeginTransaction);
@@ -151,6 +154,8 @@ interface CloseableIterator extends Iterator {
boolean isWithBeginTransaction();
+ boolean isLastStatement();
+
/**
* @param streamMessageListener A class object which implements StreamMessageListener
* @return true if streaming is supported by the iterator, otherwise false
@@ -158,6 +163,9 @@ interface CloseableIterator extends Iterator {
default boolean initiateStreaming(AsyncResultSet.StreamMessageListener streamMessageListener) {
return false;
}
+
+ /** it requests the initial prefetch chunks from gRPC stream */
+ default void requestPrefetchChunks() {}
}
static double valueProtoToFloat64(com.google.protobuf.Value proto) {
@@ -430,6 +438,16 @@ protected Date getDateInternal(int columnIndex) {
return currRow().getDateInternal(columnIndex);
}
+ @Override
+ protected UUID getUuidInternal(int columnIndex) {
+ return currRow().getUuidInternal(columnIndex);
+ }
+
+ @Override
+ protected Interval getIntervalInternal(int columnIndex) {
+ return currRow().getIntervalInternal(columnIndex);
+ }
+
@Override
protected Value getValueInternal(int columnIndex) {
return currRow().getValueInternal(columnIndex);
@@ -522,6 +540,16 @@ protected List getDateListInternal(int columnIndex) {
return currRow().getDateListInternal(columnIndex);
}
+ @Override
+ protected List getUuidListInternal(int columnIndex) {
+ return currRow().getUuidListInternal(columnIndex);
+ }
+
+ @Override
+ protected List getIntervalListInternal(int columnIndex) {
+ return currRow().getIntervalListInternal(columnIndex);
+ }
+
@Override
protected List getStructListInternal(int columnIndex) {
return currRow().getStructListInternal(columnIndex);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java
index d13c61aaf01..60ff4fd330e 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java
@@ -28,6 +28,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.UUID;
import java.util.function.Function;
/**
@@ -67,6 +68,14 @@ protected String getPgJsonbInternal(int columnIndex) {
protected abstract Date getDateInternal(int columnIndex);
+ protected UUID getUuidInternal(int columnIndex) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ protected Interval getIntervalInternal(int columnIndex) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
protected T getProtoMessageInternal(int columnIndex, T message) {
throw new UnsupportedOperationException("Not implemented");
}
@@ -128,6 +137,14 @@ protected List getPgJsonbListInternal(int columnIndex) {
protected abstract List getDateListInternal(int columnIndex);
+ protected List getUuidListInternal(int columnIndex) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ protected List getIntervalListInternal(int columnIndex) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
protected abstract List getStructListInternal(int columnIndex);
@Override
@@ -299,6 +316,32 @@ public Date getDate(String columnName) {
return getDateInternal(columnIndex);
}
+ @Override
+ public UUID getUuid(int columnIndex) {
+ checkNonNullOfType(columnIndex, Type.uuid(), columnIndex);
+ return getUuidInternal(columnIndex);
+ }
+
+ @Override
+ public UUID getUuid(String columnName) {
+ final int columnIndex = getColumnIndex(columnName);
+ checkNonNullOfType(columnIndex, Type.uuid(), columnName);
+ return getUuidInternal(columnIndex);
+ }
+
+ @Override
+ public Interval getInterval(int columnIndex) {
+ checkNonNullOfType(columnIndex, Type.interval(), columnIndex);
+ return getIntervalInternal(columnIndex);
+ }
+
+ @Override
+ public Interval getInterval(String columnName) {
+ int columnIndex = getColumnIndex(columnName);
+ checkNonNullOfType(columnIndex, Type.interval(), columnName);
+ return getIntervalInternal(columnIndex);
+ }
+
@Override
public T getProtoEnum(
int columnIndex, Function method) {
@@ -583,6 +626,32 @@ public List getDateList(String columnName) {
return getDateListInternal(columnIndex);
}
+ @Override
+ public List getUuidList(int columnIndex) {
+ checkNonNullOfType(columnIndex, Type.array(Type.uuid()), columnIndex);
+ return getUuidListInternal(columnIndex);
+ }
+
+ @Override
+ public List getUuidList(String columnName) {
+ final int columnIndex = getColumnIndex(columnName);
+ checkNonNullOfType(columnIndex, Type.array(Type.uuid()), columnName);
+ return getUuidListInternal(columnIndex);
+ }
+
+ @Override
+ public List getIntervalList(int columnIndex) {
+ checkNonNullOfType(columnIndex, Type.array(Type.interval()), columnIndex);
+ return getIntervalListInternal(columnIndex);
+ }
+
+ @Override
+ public List getIntervalList(String columnName) {
+ int columnIndex = getColumnIndex(columnName);
+ checkNonNullOfType(columnIndex, Type.array(Type.interval()), columnName);
+ return getIntervalListInternal(columnIndex);
+ }
+
@Override
public List getStructList(int columnIndex) {
checkNonNullArrayOfStruct(columnIndex, columnIndex);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java
index 1161822cd10..e53e4db94b6 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncResultSetImpl.java
@@ -91,6 +91,7 @@ private enum State {
private final BlockingDeque buffer;
private Struct currentRow;
+
/** Supplies the underlying synchronous {@link ResultSet} that will be producing the rows. */
private final Supplier delegateResultSet;
@@ -112,9 +113,9 @@ private enum State {
* Listeners that will be called when the {@link AsyncResultSetImpl} has finished fetching all
* rows and any underlying transaction or session can be closed.
*/
- private Collection listeners = new LinkedList<>();
+ private final Collection listeners = new LinkedList<>();
- private State state = State.INITIALIZED;
+ private volatile State state = State.INITIALIZED;
/** This variable indicates that produce rows thread is initiated */
private volatile boolean produceRowsInitiated;
@@ -137,11 +138,13 @@ private enum State {
* production of rows that are put into the buffer is only paused once the buffer is full.
*/
private volatile CountDownLatch pausedLatch = new CountDownLatch(1);
+
/**
* This variable is used to pause the producer when the buffer is full and the consumer needs some
* time to catch up.
*/
private volatile CountDownLatch bufferConsumptionLatch = new CountDownLatch(0);
+
/**
* This variable is used to pause the producer when all rows have been put into the buffer, but
* the consumer (the callback) has not yet received and processed all rows.
@@ -498,10 +501,12 @@ public ApiFuture setCallback(Executor exec, ReadyCallback cb) {
}
private void initiateProduceRows() {
- if (this.state == State.STREAMING_INITIALIZED) {
- this.state = State.RUNNING;
+ synchronized (monitor) {
+ if (this.state == State.STREAMING_INITIALIZED) {
+ this.state = State.RUNNING;
+ }
+ produceRowsInitiated = true;
}
- produceRowsInitiated = true;
this.service.execute(new ProduceRowsRunnable());
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java
index 1ea58b2bc66..afe2fdb2461 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncRunnerImpl.java
@@ -59,7 +59,7 @@ private R runTransaction(final AsyncWork work) {
try {
return work.doWorkAsync(transaction).get();
} catch (ExecutionException e) {
- throw SpannerExceptionFactory.newSpannerException(e.getCause());
+ throw SpannerExceptionFactory.asSpannerException(e.getCause());
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java
index c6ead432046..502ec9d54f8 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java
@@ -170,6 +170,21 @@ interface AsyncTransactionFunction {
*/
TransactionContextFuture beginAsync();
+ /**
+ * Initializes a new read-write transaction that is a retry of a previously aborted transaction.
+ * This method must be called before performing any operations, and it can only be invoked once
+ * per transaction lifecycle.
+ *
+ *
This method should only be used when multiplexed sessions are enabled to create a retry for
+ * a previously aborted transaction. This method can be used instead of {@link
+ * #resetForRetryAsync()} to create a retry. Using this method or {@link #resetForRetryAsync()}
+ * will have the same effect. You must pass in the {@link AbortedException} from the previous
+ * attempt to preserve the transaction's priority.
+ *
+ *
For regular sessions, this behaves the same as {@link #beginAsync()}.
+ */
+ TransactionContextFuture beginAsync(AbortedException exception);
+
/**
* Rolls back the currently active transaction. In most cases there should be no need to call this
* explicitly since {@link #close()} would automatically roll back any active transaction.
@@ -188,7 +203,10 @@ interface AsyncTransactionFunction {
/** Returns the state of the transaction. */
TransactionState getState();
- /** Returns the {@link CommitResponse} of this transaction. */
+ /**
+ * Returns the {@link CommitResponse} of this transaction. This method may only be called after
+ * committing the transaction.
+ */
ApiFuture getCommitResponse();
/**
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java
index 0057bb15bea..c394ad09fe2 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java
@@ -55,7 +55,7 @@ public void setSpan(ISpan span) {
@Override
public void close() {
- closeAsync();
+ SpannerApiFutures.get(closeAsync());
}
@Override
@@ -76,14 +76,27 @@ public ApiFuture closeAsync() {
@Override
public TransactionContextFutureImpl beginAsync() {
Preconditions.checkState(txn == null, "begin can only be called once");
- return new TransactionContextFutureImpl(this, internalBeginAsync(true));
+ return new TransactionContextFutureImpl(this, internalBeginAsync(true, ByteString.EMPTY));
}
- private ApiFuture internalBeginAsync(boolean firstAttempt) {
+ @Override
+ public TransactionContextFutureImpl beginAsync(AbortedException exception) {
+ Preconditions.checkState(txn == null, "begin can only be called once");
+ Preconditions.checkNotNull(exception, "AbortedException from the previous attempt is required");
+ ByteString abortedTransactionId =
+ exception.getTransactionID() != null ? exception.getTransactionID() : ByteString.EMPTY;
+ return new TransactionContextFutureImpl(this, internalBeginAsync(true, abortedTransactionId));
+ }
+
+ private ApiFuture internalBeginAsync(
+ boolean firstAttempt, ByteString abortedTransactionID) {
txnState = TransactionState.STARTED;
// Determine the latest transactionId when using a multiplexed session.
ByteString multiplexedSessionPreviousTransactionId = ByteString.EMPTY;
+ if (firstAttempt && session.getIsMultiplexed()) {
+ multiplexedSessionPreviousTransactionId = abortedTransactionID;
+ }
if (txn != null && session.getIsMultiplexed() && !firstAttempt) {
// Use the current transactionId if available, otherwise fallback to the previous aborted
// transactionId.
@@ -93,7 +106,7 @@ private ApiFuture internalBeginAsync(boolean firstAttempt) {
txn =
session.newTransaction(
- options, /* previousTransactionId = */ multiplexedSessionPreviousTransactionId);
+ options, /* previousTransactionId= */ multiplexedSessionPreviousTransactionId);
if (firstAttempt) {
session.setActive(this);
}
@@ -110,7 +123,7 @@ private ApiFuture internalBeginAsync(boolean firstAttempt) {
@Override
public void onFailure(Throwable t) {
onError(t);
- res.setException(SpannerExceptionFactory.newSpannerException(t));
+ res.setException(SpannerExceptionFactory.asSpannerException(t));
}
@Override
@@ -152,12 +165,19 @@ public void onFailure(Throwable t) {
txnState = TransactionState.ABORTED;
} else {
txnState = TransactionState.COMMIT_FAILED;
+ if (span != null) {
+ span.setStatus(t);
+ span.end();
+ }
commitResponse.setException(t);
}
}
@Override
public void onSuccess(CommitResponse result) {
+ if (span != null) {
+ span.end();
+ }
commitResponse.set(result);
}
},
@@ -177,13 +197,21 @@ public ApiFuture rollbackAsync() {
ignored -> ApiFutures.immediateFuture(null),
MoreExecutors.directExecutor());
} finally {
+ if (span != null) {
+ span.addAnnotation("Transaction rolled back");
+ span.end();
+ }
txnState = TransactionState.ROLLED_BACK;
}
}
@Override
public TransactionContextFuture resetForRetryAsync() {
- return new TransactionContextFutureImpl(this, internalBeginAsync(false));
+ if (txn == null || !txn.isAborted() && txnState != TransactionState.ABORTED) {
+ throw new IllegalStateException(
+ "resetForRetry can only be called if the previous attempt aborted");
+ }
+ return new TransactionContextFutureImpl(this, internalBeginAsync(false, ByteString.EMPTY));
}
@Override
@@ -193,6 +221,9 @@ public TransactionState getState() {
@Override
public ApiFuture getCommitResponse() {
+ Preconditions.checkState(
+ txnState == TransactionState.COMMITTED,
+ "getCommitResponse can only be invoked if the transaction was successfully committed");
return commitResponse;
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java
index 45e38989be6..2d12179bc91 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClient.java
@@ -67,5 +67,6 @@ public interface BatchClient {
*/
default String getDatabaseRole() {
throw new UnsupportedOperationException("method should be overwritten");
- };
+ }
+ ;
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java
index a250fd5ba39..5cbe01aa711 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchClientImpl.java
@@ -44,8 +44,6 @@
public class BatchClientImpl implements BatchClient {
private final SessionClient sessionClient;
- private final boolean isMultiplexedSessionEnabled;
-
/** Lock to protect the multiplexed session. */
private final ReentrantLock multiplexedSessionLock = new ReentrantLock();
@@ -59,9 +57,8 @@ public class BatchClientImpl implements BatchClient {
@GuardedBy("multiplexedSessionLock")
private final AtomicReference multiplexedSessionReference;
- BatchClientImpl(SessionClient sessionClient, boolean isMultiplexedSessionEnabled) {
+ BatchClientImpl(SessionClient sessionClient) {
this.sessionClient = checkNotNull(sessionClient);
- this.isMultiplexedSessionEnabled = isMultiplexedSessionEnabled;
this.sessionExpirationDuration =
Duration.ofMillis(
sessionClient
@@ -84,12 +81,7 @@ public String getDatabaseRole() {
@Override
public BatchReadOnlyTransaction batchReadOnlyTransaction(TimestampBound bound) {
- SessionImpl session;
- if (isMultiplexedSessionEnabled) {
- session = getMultiplexedSession();
- } else {
- session = sessionClient.createSession();
- }
+ SessionImpl session = getMultiplexedSession();
return new BatchReadOnlyTransactionImpl(
MultiUseReadOnlyTransaction.newBuilder()
.setSession(session)
@@ -231,6 +223,15 @@ public List partitionReadUsingIndex(
public List partitionQuery(
PartitionOptions partitionOptions, Statement statement, QueryOption... option)
throws SpannerException {
+ return partitionQuery(partitionOptions, statement, false, option);
+ }
+
+ private List partitionQuery(
+ PartitionOptions partitionOptions,
+ Statement statement,
+ boolean isFallback,
+ QueryOption... option)
+ throws SpannerException {
Options queryOptions = Options.fromQueryOptions(option);
final PartitionQueryRequest.Builder builder =
PartitionQueryRequest.newBuilder().setSession(sessionName).setSql(statement.getSql());
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchTransactionId.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchTransactionId.java
index a5a02ac1360..0de705c12ea 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchTransactionId.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BatchTransactionId.java
@@ -17,6 +17,7 @@
package com.google.cloud.spanner;
import com.google.cloud.Timestamp;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.protobuf.ByteString;
import java.io.Serializable;
@@ -34,6 +35,7 @@ public class BatchTransactionId implements Serializable {
private final Timestamp timestamp;
private static final long serialVersionUID = 8067099123096783939L;
+ @VisibleForTesting
BatchTransactionId(String sessionId, ByteString transactionId, Timestamp timestamp) {
this.transactionId = Preconditions.checkNotNull(transactionId);
this.sessionId = Preconditions.checkNotNull(sessionId);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java
index 4f8b091d550..dff490832c8 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java
@@ -16,6 +16,8 @@
package com.google.cloud.spanner;
+import static com.google.cloud.spanner.XGoogSpannerRequestId.REQUEST_ID_HEADER_NAME;
+
import com.google.api.core.InternalApi;
import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
import com.google.common.collect.ImmutableList;
@@ -26,6 +28,10 @@
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.View;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -34,26 +40,109 @@
public class BuiltInMetricsConstant {
public static final String METER_NAME = "spanner.googleapis.com/internal/client";
-
public static final String GAX_METER_NAME = OpenTelemetryMetricsRecorder.GAX_METER_NAME;
-
+ public static final String GRPC_GCP_METER_NAME = "grpc-gcp";
+ static final String SPANNER_METER_NAME = "spanner-java";
+ static final String GRPC_METER_NAME = "grpc-java";
+ static final String GFE_LATENCIES_NAME = "gfe_latencies";
+ static final String AFE_LATENCIES_NAME = "afe_latencies";
+ static final String GFE_CONNECTIVITY_ERROR_NAME = "gfe_connectivity_error_count";
+ static final String AFE_CONNECTIVITY_ERROR_NAME = "afe_connectivity_error_count";
static final String OPERATION_LATENCIES_NAME = "operation_latencies";
static final String ATTEMPT_LATENCIES_NAME = "attempt_latencies";
static final String OPERATION_LATENCY_NAME = "operation_latency";
static final String ATTEMPT_LATENCY_NAME = "attempt_latency";
static final String OPERATION_COUNT_NAME = "operation_count";
static final String ATTEMPT_COUNT_NAME = "attempt_count";
+ static final String EEF_FALLBACK_COUNT_NAME = "eef.fallback_count";
+ static final String EEF_CALL_STATUS_NAME = "eef.call_status";
public static final Set SPANNER_METRICS =
ImmutableSet.of(
OPERATION_LATENCIES_NAME,
ATTEMPT_LATENCIES_NAME,
OPERATION_COUNT_NAME,
- ATTEMPT_COUNT_NAME)
+ ATTEMPT_COUNT_NAME,
+ GFE_LATENCIES_NAME,
+ AFE_LATENCIES_NAME,
+ GFE_CONNECTIVITY_ERROR_NAME,
+ AFE_CONNECTIVITY_ERROR_NAME)
.stream()
.map(m -> METER_NAME + '/' + m)
.collect(Collectors.toSet());
+ // The following attributes are optional and need to be enabled explicitly.
+ public static final String GRPC_LB_BACKEND_SERVICE_ATTRIBUTE = "grpc.lb.backend_service";
+ public static final String GRPC_LB_LOCALITY_ATTRIBUTE = "grpc.lb.locality";
+ public static final String GRPC_DISCONNECT_ERROR_ATTRIBUTE = "grpc.disconnect_error";
+
+ static final Set GRPC_LB_RLS_ATTRIBUTES =
+ ImmutableSet.of("grpc.lb.rls.data_plane_target", "grpc.lb.pick_result");
+ static final Set GRPC_CLIENT_ATTEMPT_STARTED_ATTRIBUTES =
+ ImmutableSet.of("grpc.method", "grpc.target");
+ static final Set GRPC_SUBCHANNEL_DEFAULT_ATTRIBUTES =
+ ImmutableSet.of("grpc.target", GRPC_LB_BACKEND_SERVICE_ATTRIBUTE, GRPC_LB_LOCALITY_ATTRIBUTE);
+ static final Set GRPC_SUBCHANNEL_DISCONNECTION_ATTRIBUTES =
+ ImmutableSet.of(
+ "grpc.target",
+ GRPC_LB_BACKEND_SERVICE_ATTRIBUTE,
+ GRPC_LB_LOCALITY_ATTRIBUTE,
+ GRPC_DISCONNECT_ERROR_ATTRIBUTE);
+ static final Set GRPC_XDS_CLIENT_RESOURCE_UPDATE_ATTRIBUTES =
+ ImmutableSet.of("grpc.xds.resource_type");
+
+ // Additional gRPC attributes to enable.
+ static final Map> GRPC_METRIC_ADDITIONAL_ATTRIBUTES =
+ ImmutableMap.>builder()
+ .put("grpc.client.attempt.started", GRPC_CLIENT_ATTEMPT_STARTED_ATTRIBUTES)
+ .put("grpc.subchannel.open_connections", GRPC_SUBCHANNEL_DEFAULT_ATTRIBUTES)
+ .put("grpc.subchannel.disconnections", GRPC_SUBCHANNEL_DISCONNECTION_ATTRIBUTES)
+ .put("grpc.subchannel.connection_attempts_succeeded", GRPC_SUBCHANNEL_DEFAULT_ATTRIBUTES)
+ .put("grpc.subchannel.connection_attempts_failed", GRPC_SUBCHANNEL_DEFAULT_ATTRIBUTES)
+ .put("grpc.lb.rls.default_target_picks", GRPC_LB_RLS_ATTRIBUTES)
+ .put("grpc.lb.rls.target_picks", GRPC_LB_RLS_ATTRIBUTES)
+ .put(
+ "grpc.xds_client.resource_updates_invalid",
+ GRPC_XDS_CLIENT_RESOURCE_UPDATE_ATTRIBUTES)
+ .put("grpc.xds_client.resource_updates_valid", GRPC_XDS_CLIENT_RESOURCE_UPDATE_ATTRIBUTES)
+ .build();
+
+ static final Collection GRPC_METRICS_TO_ENABLE =
+ ImmutableList.of(
+ "grpc.client.attempt.started",
+ "grpc.subchannel.open_connections",
+ "grpc.subchannel.disconnections",
+ "grpc.subchannel.connection_attempts_succeeded",
+ "grpc.subchannel.connection_attempts_failed",
+ "grpc.lb.rls.default_target_picks",
+ "grpc.lb.rls.target_picks",
+ "grpc.xds_client.server_failure",
+ "grpc.xds_client.resource_updates_invalid",
+ "grpc.xds_client.resource_updates_valid");
+
+ public static final AttributeKey CHANNEL_NAME_KEY =
+ AttributeKey.stringKey("channel_name");
+ public static final AttributeKey FROM_CHANNEL_NAME_KEY =
+ AttributeKey.stringKey("from_channel_name");
+ public static final AttributeKey TO_CHANNEL_NAME_KEY =
+ AttributeKey.stringKey("to_channel_name");
+ public static final AttributeKey STATUS_CODE_KEY = AttributeKey.stringKey("status_code");
+
+ static final Set GRPC_GCP_EEF_FALLBACK_COUNT_ATTRIBUTES =
+ ImmutableSet.of(FROM_CHANNEL_NAME_KEY.getKey(), TO_CHANNEL_NAME_KEY.getKey());
+
+ static final Set GRPC_GCP_EEF_CALL_STATUS_ATTRIBUTES =
+ ImmutableSet.of(CHANNEL_NAME_KEY.getKey(), STATUS_CODE_KEY.getKey());
+
+ static final Map> GRPC_GCP_METRIC_ADDITIONAL_ATTRIBUTES =
+ ImmutableMap.>builder()
+ .put(EEF_FALLBACK_COUNT_NAME, GRPC_GCP_EEF_FALLBACK_COUNT_ATTRIBUTES)
+ .put(EEF_CALL_STATUS_NAME, GRPC_GCP_EEF_CALL_STATUS_ATTRIBUTES)
+ .build();
+
+ static final Collection GRPC_GCP_METRICS_TO_ENABLE =
+ ImmutableList.of(EEF_FALLBACK_COUNT_NAME, EEF_CALL_STATUS_NAME);
+
public static final String SPANNER_RESOURCE_TYPE = "spanner_instance_client";
public static final AttributeKey PROJECT_ID_KEY = AttributeKey.stringKey("project_id");
@@ -65,12 +154,7 @@ public class BuiltInMetricsConstant {
// These metric labels will be promoted to the spanner monitored resource fields
public static final Set> SPANNER_PROMOTED_RESOURCE_LABELS =
- ImmutableSet.of(
- PROJECT_ID_KEY,
- INSTANCE_ID_KEY,
- INSTANCE_CONFIG_ID_KEY,
- LOCATION_ID_KEY,
- CLIENT_HASH_KEY);
+ ImmutableSet.of(INSTANCE_ID_KEY);
public static final AttributeKey DATABASE_KEY = AttributeKey.stringKey("database");
public static final AttributeKey CLIENT_UID_KEY = AttributeKey.stringKey("client_uid");
@@ -81,6 +165,10 @@ public class BuiltInMetricsConstant {
AttributeKey.stringKey("directpath_enabled");
public static final AttributeKey DIRECT_PATH_USED_KEY =
AttributeKey.stringKey("directpath_used");
+ public static final AttributeKey REQUEST_ID_KEY =
+ AttributeKey.stringKey(REQUEST_ID_HEADER_NAME);
+ public static Set ALLOWED_EXEMPLARS_ATTRIBUTES =
+ new HashSet<>(Arrays.asList(REQUEST_ID_HEADER_NAME));
// IP address prefixes allocated for DirectPath backends.
public static final String DP_IPV6_PREFIX = "2001:4860:8040";
@@ -101,19 +189,27 @@ public class BuiltInMetricsConstant {
DIRECT_PATH_ENABLED_KEY,
DIRECT_PATH_USED_KEY);
+ static List BUCKET_BOUNDARIES =
+ ImmutableList.of(
+ 0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
+ 16.0, 17.0, 18.0, 19.0, 20.0, 25.0, 30.0, 40.0, 50.0, 65.0, 80.0, 100.0, 130.0, 160.0,
+ 200.0, 250.0, 300.0, 400.0, 500.0, 650.0, 800.0, 1000.0, 2000.0, 5000.0, 10000.0, 20000.0,
+ 50000.0, 100000.0, 200000.0, 400000.0, 800000.0, 1600000.0, 3200000.0);
static Aggregation AGGREGATION_WITH_MILLIS_HISTOGRAM =
- Aggregation.explicitBucketHistogram(
- ImmutableList.of(
- 0.0, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0,
- 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 25.0, 30.0, 40.0, 50.0, 65.0, 80.0, 100.0, 130.0,
- 160.0, 200.0, 250.0, 300.0, 400.0, 500.0, 650.0, 800.0, 1000.0, 2000.0, 5000.0,
- 10000.0, 20000.0, 50000.0, 100000.0, 200000.0, 400000.0, 800000.0, 1600000.0,
- 3200000.0));
+ Aggregation.explicitBucketHistogram(BUCKET_BOUNDARIES);
+
+ static final Collection GRPC_METRICS_ENABLED_BY_DEFAULT =
+ ImmutableList.of(
+ "grpc.client.attempt.sent_total_compressed_message_size",
+ "grpc.client.attempt.rcvd_total_compressed_message_size",
+ "grpc.client.attempt.duration",
+ "grpc.client.call.duration");
static Map getAllViews() {
ImmutableMap.Builder views = ImmutableMap.builder();
defineView(
views,
+ BuiltInMetricsConstant.GAX_METER_NAME,
BuiltInMetricsConstant.OPERATION_LATENCY_NAME,
BuiltInMetricsConstant.OPERATION_LATENCIES_NAME,
BuiltInMetricsConstant.AGGREGATION_WITH_MILLIS_HISTOGRAM,
@@ -121,6 +217,7 @@ static Map getAllViews() {
"ms");
defineView(
views,
+ BuiltInMetricsConstant.GAX_METER_NAME,
BuiltInMetricsConstant.ATTEMPT_LATENCY_NAME,
BuiltInMetricsConstant.ATTEMPT_LATENCIES_NAME,
BuiltInMetricsConstant.AGGREGATION_WITH_MILLIS_HISTOGRAM,
@@ -128,6 +225,7 @@ static Map getAllViews() {
"ms");
defineView(
views,
+ BuiltInMetricsConstant.GAX_METER_NAME,
BuiltInMetricsConstant.OPERATION_COUNT_NAME,
BuiltInMetricsConstant.OPERATION_COUNT_NAME,
Aggregation.sum(),
@@ -135,16 +233,21 @@ static Map getAllViews() {
"1");
defineView(
views,
+ BuiltInMetricsConstant.GAX_METER_NAME,
BuiltInMetricsConstant.ATTEMPT_COUNT_NAME,
BuiltInMetricsConstant.ATTEMPT_COUNT_NAME,
Aggregation.sum(),
InstrumentType.COUNTER,
"1");
+ defineSpannerView(views);
+ defineGRPCView(views);
+ defineGrpcGcpView(views);
return views.build();
}
private static void defineView(
ImmutableMap.Builder viewMap,
+ String meterName,
String metricName,
String metricViewName,
Aggregation aggregation,
@@ -153,7 +256,7 @@ private static void defineView(
InstrumentSelector selector =
InstrumentSelector.builder()
.setName(BuiltInMetricsConstant.METER_NAME + '/' + metricName)
- .setMeterName(BuiltInMetricsConstant.GAX_METER_NAME)
+ .setMeterName(meterName)
.setType(type)
.setUnit(unit)
.build();
@@ -169,4 +272,67 @@ private static void defineView(
.build();
viewMap.put(selector, view);
}
+
+ private static void defineSpannerView(ImmutableMap.Builder viewMap) {
+ InstrumentSelector selector =
+ InstrumentSelector.builder()
+ .setMeterName(BuiltInMetricsConstant.SPANNER_METER_NAME)
+ .build();
+ Set attributesFilter =
+ BuiltInMetricsConstant.COMMON_ATTRIBUTES.stream()
+ .map(AttributeKey::getKey)
+ .collect(Collectors.toSet());
+ View view = View.builder().setAttributeFilter(attributesFilter).build();
+ viewMap.put(selector, view);
+ }
+
+ private static void defineGRPCView(ImmutableMap.Builder viewMap) {
+ for (String metric : BuiltInMetricsConstant.GRPC_METRICS_TO_ENABLE) {
+ InstrumentSelector selector =
+ InstrumentSelector.builder()
+ .setName(metric)
+ .setMeterName(BuiltInMetricsConstant.GRPC_METER_NAME)
+ .build();
+ Set attributesFilter =
+ BuiltInMetricsConstant.COMMON_ATTRIBUTES.stream()
+ .map(AttributeKey::getKey)
+ .collect(Collectors.toSet());
+ attributesFilter.addAll(
+ GRPC_METRIC_ADDITIONAL_ATTRIBUTES.getOrDefault(metric, ImmutableSet.of()));
+
+ View view =
+ View.builder()
+ .setName(BuiltInMetricsConstant.METER_NAME + '/' + metric.replace(".", "/"))
+ .setAttributeFilter(attributesFilter)
+ .build();
+ viewMap.put(selector, view);
+ }
+ }
+
+ private static void defineGrpcGcpView(ImmutableMap.Builder viewMap) {
+ for (String metric : GRPC_GCP_METRICS_TO_ENABLE) {
+ InstrumentSelector selector =
+ InstrumentSelector.builder()
+ .setName(metric)
+ .setMeterName(BuiltInMetricsConstant.GRPC_GCP_METER_NAME)
+ .build();
+
+ Set attributesFilter =
+ BuiltInMetricsConstant.COMMON_ATTRIBUTES.stream()
+ .map(AttributeKey::getKey)
+ .collect(Collectors.toSet());
+
+ attributesFilter.addAll(
+ GRPC_GCP_METRIC_ADDITIONAL_ATTRIBUTES.getOrDefault(metric, ImmutableSet.of()));
+
+ View view =
+ View.builder()
+ .setName(BuiltInMetricsConstant.METER_NAME + '/' + metric.replace(".", "/"))
+ .setAggregation(Aggregation.sum())
+ .setAttributeFilter(attributesFilter)
+ .build();
+
+ viewMap.put(selector, view);
+ }
+ }
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java
similarity index 52%
rename from google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java
rename to google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java
index 4aeb98987d1..0a51ebfae26 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java
@@ -21,24 +21,40 @@
import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_NAME_KEY;
import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_UID_KEY;
import static com.google.cloud.spanner.BuiltInMetricsConstant.INSTANCE_CONFIG_ID_KEY;
+import static com.google.cloud.spanner.BuiltInMetricsConstant.INSTANCE_ID_KEY;
import static com.google.cloud.spanner.BuiltInMetricsConstant.LOCATION_ID_KEY;
import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY;
+import com.google.api.core.ApiFunction;
+import com.google.api.gax.core.GaxProperties;
+import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
import com.google.auth.Credentials;
import com.google.cloud.opentelemetry.detection.AttributeKeys;
import com.google.cloud.opentelemetry.detection.DetectedPlatform;
import com.google.cloud.opentelemetry.detection.GCPPlatformDetector;
+import com.google.common.base.Strings;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.opentelemetry.GrpcOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
+import io.opentelemetry.sdk.resources.Resource;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
import java.net.InetAddress;
+import java.net.URL;
import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -46,27 +62,35 @@
import java.util.logging.Logger;
import javax.annotation.Nullable;
-final class BuiltInOpenTelemetryMetricsProvider {
+final class BuiltInMetricsProvider {
- static BuiltInOpenTelemetryMetricsProvider INSTANCE = new BuiltInOpenTelemetryMetricsProvider();
+ static BuiltInMetricsProvider INSTANCE = new BuiltInMetricsProvider();
- private static final Logger logger =
- Logger.getLogger(BuiltInOpenTelemetryMetricsProvider.class.getName());
+ private static final Logger logger = Logger.getLogger(BuiltInMetricsProvider.class.getName());
private static String taskId;
+ private static String location;
+
+ private static final String default_location = "global";
+
private OpenTelemetry openTelemetry;
- private BuiltInOpenTelemetryMetricsProvider() {}
+ private BuiltInMetricsProvider() {}
OpenTelemetry getOrCreateOpenTelemetry(
- String projectId, @Nullable Credentials credentials, @Nullable String monitoringHost) {
+ String projectId,
+ @Nullable Credentials credentials,
+ @Nullable String monitoringHost,
+ String universeDomain) {
try {
if (this.openTelemetry == null) {
SdkMeterProviderBuilder sdkMeterProviderBuilder = SdkMeterProvider.builder();
- BuiltInOpenTelemetryMetricsView.registerBuiltinMetrics(
- SpannerCloudMonitoringExporter.create(projectId, credentials, monitoringHost),
+ BuiltInMetricsView.registerBuiltinMetrics(
+ SpannerCloudMonitoringExporter.create(
+ projectId, credentials, monitoringHost, universeDomain),
sdkMeterProviderBuilder);
+ sdkMeterProviderBuilder.setResource(Resource.create(createResourceAttributes(projectId)));
SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build();
this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build();
Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close));
@@ -75,21 +99,90 @@ OpenTelemetry getOrCreateOpenTelemetry(
} catch (IOException ex) {
logger.log(
Level.WARNING,
- "Unable to get OpenTelemetry object for client side metrics, will skip exporting client side metrics",
+ "Unable to get OpenTelemetry object for client side metrics, will skip exporting client"
+ + " side metrics",
ex);
return null;
}
}
- Map createClientAttributes(String projectId, String client_name) {
+ // TODO: Remove when
+ // https://github.com/GoogleCloudPlatform/opentelemetry-operations-java/issues/421
+ // has been fixed.
+ static boolean quickCheckIsRunningOnGcp() {
+ int timeout = 5000;
+ try {
+ timeout =
+ Integer.parseInt(System.getProperty("spanner.check_is_running_on_gcp_timeout", "5000"));
+ } catch (NumberFormatException ignore) {
+ // ignore
+ }
+ try {
+ URL url = new URL("http://metadata.google.internal/computeMetadata/v1/project/project-id");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setConnectTimeout(timeout);
+ connection.setRequestProperty("Metadata-Flavor", "Google");
+ if (connection.getResponseCode() == 200
+ && ("Google").equals(connection.getHeaderField("Metadata-Flavor"))) {
+ InputStream input = connection.getInputStream();
+ try (BufferedReader reader =
+ new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
+ return !Strings.isNullOrEmpty(reader.readLine());
+ }
+ }
+ } catch (IOException ignore) {
+ // ignore
+ }
+ return false;
+ }
+
+ void enableGrpcMetrics(
+ InstantiatingGrpcChannelProvider.Builder channelProviderBuilder,
+ String projectId,
+ @Nullable Credentials credentials,
+ @Nullable String monitoringHost,
+ String universeDomain) {
+ GrpcOpenTelemetry grpcOpenTelemetry =
+ GrpcOpenTelemetry.newBuilder()
+ .sdk(
+ this.getOrCreateOpenTelemetry(
+ projectId, credentials, monitoringHost, universeDomain))
+ .enableMetrics(BuiltInMetricsConstant.GRPC_METRICS_TO_ENABLE)
+ // Disable gRPCs default metrics as they are not needed for Spanner.
+ .disableMetrics(BuiltInMetricsConstant.GRPC_METRICS_ENABLED_BY_DEFAULT)
+ .addOptionalLabel(BuiltInMetricsConstant.GRPC_LB_BACKEND_SERVICE_ATTRIBUTE)
+ .addOptionalLabel(BuiltInMetricsConstant.GRPC_LB_LOCALITY_ATTRIBUTE)
+ .addOptionalLabel(BuiltInMetricsConstant.GRPC_DISCONNECT_ERROR_ATTRIBUTE)
+ .build();
+ ApiFunction channelConfigurator =
+ channelProviderBuilder.getChannelConfigurator();
+ channelProviderBuilder.setChannelConfigurator(
+ b -> {
+ grpcOpenTelemetry.configureChannelBuilder(b);
+ if (channelConfigurator != null) {
+ return channelConfigurator.apply(b);
+ }
+ return b;
+ });
+ }
+
+ Attributes createResourceAttributes(String projectId) {
+ AttributesBuilder attributesBuilder =
+ Attributes.builder()
+ .put(PROJECT_ID_KEY.getKey(), projectId)
+ .put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown")
+ .put(CLIENT_HASH_KEY.getKey(), generateClientHash(getDefaultTaskValue()))
+ .put(INSTANCE_ID_KEY.getKey(), "unknown")
+ .put(LOCATION_ID_KEY.getKey(), detectClientLocation());
+
+ return attributesBuilder.build();
+ }
+
+ Map createClientAttributes() {
Map clientAttributes = new HashMap<>();
- clientAttributes.put(LOCATION_ID_KEY.getKey(), detectClientLocation());
- clientAttributes.put(PROJECT_ID_KEY.getKey(), projectId);
- clientAttributes.put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown");
- clientAttributes.put(CLIENT_NAME_KEY.getKey(), client_name);
- String clientUid = getDefaultTaskValue();
- clientAttributes.put(CLIENT_UID_KEY.getKey(), clientUid);
- clientAttributes.put(CLIENT_HASH_KEY.getKey(), generateClientHash(clientUid));
+ clientAttributes.put(
+ CLIENT_NAME_KEY.getKey(), "spanner-java/" + GaxProperties.getLibraryVersion(getClass()));
+ clientAttributes.put(CLIENT_UID_KEY.getKey(), getDefaultTaskValue());
return clientAttributes;
}
@@ -122,14 +215,20 @@ static String generateClientHash(String clientUid) {
}
static String detectClientLocation() {
- GCPPlatformDetector detector = GCPPlatformDetector.DEFAULT_INSTANCE;
- DetectedPlatform detectedPlatform = detector.detectPlatform();
- // All platform except GKE uses "cloud_region" for region attribute.
- String region = detectedPlatform.getAttributes().get("cloud_region");
- if (detectedPlatform.getSupportedPlatform() == GOOGLE_KUBERNETES_ENGINE) {
- region = detectedPlatform.getAttributes().get(AttributeKeys.GKE_CLUSTER_LOCATION);
+ if (location == null) {
+ location = default_location;
+ if (quickCheckIsRunningOnGcp()) {
+ GCPPlatformDetector detector = GCPPlatformDetector.DEFAULT_INSTANCE;
+ DetectedPlatform detectedPlatform = detector.detectPlatform();
+ // All platform except GKE uses "cloud_region" for region attribute.
+ String region = detectedPlatform.getAttributes().get("cloud_region");
+ if (detectedPlatform.getSupportedPlatform() == GOOGLE_KUBERNETES_ENGINE) {
+ region = detectedPlatform.getAttributes().get(AttributeKeys.GKE_CLUSTER_LOCATION);
+ }
+ location = region == null ? location : region;
+ }
}
- return region == null ? "global" : region;
+ return location;
}
/**
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
new file mode 100644
index 00000000000..67e75a1d383
--- /dev/null
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsRecorder.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import com.google.api.gax.core.GaxProperties;
+import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
+import com.google.common.base.Preconditions;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.api.metrics.DoubleHistogram;
+import io.opentelemetry.api.metrics.LongCounter;
+import io.opentelemetry.api.metrics.Meter;
+import java.util.Map;
+
+/**
+ * Implementation for recording built in metrics.
+ *
+ *