Skip to content

feat: Use multiplexed sessions for read-only transactions #3917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 23, 2025
Merged
38 changes: 37 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,26 @@
- run: .kokoro/build.sh
env:
JOB_TYPE: test
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS: true
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW: true
units-with-regular-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: false
units-java8:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
# Building using Java 17 and run the tests with Java 8 runtime
name: "units (8)"
runs-on: ubuntu-latest
Expand Down Expand Up @@ -96,7 +112,27 @@
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS: true
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW: true
units-with-regular-session8:
# Building using Java 17 and run the tests with Java 8 runtime
name: "units-with-regular-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: false
windows:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
env:
JOB_TYPE: test
SPANNER_EMULATOR_HOST: localhost:9010
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: true
GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS: false
38 changes: 38 additions & 0 deletions .kokoro/presubmit/integration-regular-sessions-enabled.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
value: "gcr.io/cloud-devrel-kokoro-resources/java8"
}

env_vars: {
key: "JOB_TYPE"
value: "integration"
}

# 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: "false"
}
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ public static class Builder {

// This field controls the default behavior of session management in Java client.
// Set useMultiplexedSession to true to make multiplexed session the default.
private boolean useMultiplexedSession = false;
private boolean useMultiplexedSession = true;

// This field controls the default behavior of session management for RW operations in Java
// client.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;

import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class MultiplexedSessionDatabaseClientMockServerTest extends AbstractMock

@BeforeClass
public static void setupResults() {
assumeFalse(TestHelper.isMultiplexSessionDisabled());
mockSpanner.putStatementResults(
StatementResult.query(STATEMENT, new RandomResultSetGenerator(1).generate()));
mockSpanner.putStatementResult(StatementResult.update(UPDATE_STATEMENT, UPDATE_COUNT));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;

import com.google.api.gax.longrunning.OperationTimedPollAlgorithm;
import com.google.api.gax.retrying.RetrySettings;
Expand Down Expand Up @@ -255,6 +256,7 @@ public void testMetricsWithGaxRetryUnaryRpc() {

@Test
public void testNoNetworkConnection() {
assumeFalse(TestHelper.isMultiplexSessionDisabled());
// Create a Spanner instance that tries to connect to a server that does not exist.
// This simulates a bad network connection.
SpannerOptions.Builder builder = SpannerOptions.newBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ public void testDenyListedChannelIsCleared() {

@Test
public void testSingleUseQuery_retriesOnNewChannel() {
assumeFalse(TestHelper.isMultiplexSessionDisabled());
SpannerOptions.Builder builder = createSpannerOptionsBuilder();
builder.setSessionPoolOption(
SessionPoolOptions.newBuilder().setUseMultiplexedSession(true).build());
Expand Down Expand Up @@ -312,6 +313,7 @@ public void testSingleUseQuery_retriesOnNewChannel() {

@Test
public void testSingleUseQuery_stopsRetrying() {
assumeFalse(TestHelper.isMultiplexSessionDisabled());
SpannerOptions.Builder builder = createSpannerOptionsBuilder();
builder.setSessionPoolOption(
SessionPoolOptions.newBuilder().setUseMultiplexedSession(true).build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ public void testRandomizePositionQPSThreshold() {

@Test
public void testUseMultiplexedSession() {
assumeFalse(TestHelper.isMultiplexSessionDisabled());
// skip these tests since this configuration can have dual behaviour in different test-runners
assumeFalse(SessionPoolOptions.newBuilder().build().getUseMultiplexedSession());
assertEquals(false, SessionPoolOptions.newBuilder().build().getUseMultiplexedSession());
Expand All @@ -304,6 +305,7 @@ public void testUseMultiplexedSession() {
@Test
public void testUseMultiplexedSessionForRW() {
// skip these tests since this configuration can have dual behaviour in different test-runners
assumeFalse(TestHelper.isMultiplexSessionDisabled());
assumeFalse(
Boolean.parseBoolean(System.getenv("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_FOR_RW")));
assumeFalse(SessionPoolOptions.newBuilder().build().getUseMultiplexedSession());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.cloud.spanner;

class TestHelper {

static boolean isMultiplexSessionDisabled() {
return System.getenv()
.getOrDefault("GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS", "")
.equalsIgnoreCase("false");
}
}