Skip to content

Commit

Permalink
feat: allow setting min/max sessions (#335)
Browse files Browse the repository at this point in the history
* feat: allow setting min/max sessions

* chore: run code formatter
  • Loading branch information
olavloite committed Feb 18, 2021
1 parent eff34a0 commit a5862a5
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 16 deletions.
4 changes: 4 additions & 0 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcDriver.java
Expand Up @@ -88,6 +88,10 @@
* connection. Default is true. @see {@link
* com.google.cloud.spanner.jdbc.CloudSpannerJdbcConnection#setRetryAbortsInternally(boolean)}
* for more information.
* <li>minSessions (int): Sets the minimum number of sessions in the backing session pool.
* Defaults to 100.
* <li>maxSessions (int): Sets the maximum number of sessions in the backing session pool.
* Defaults to 400.
* <li>numChannels (int): Sets the number of gRPC channels to use. Defaults to 4.
* <li>usePlainText (boolean): Sets whether the JDBC connection should establish an unencrypted
* connection to the server. This option can only be used when connecting to a local emulator
Expand Down
121 changes: 121 additions & 0 deletions src/test/java/com/google/cloud/spanner/jdbc/JdbcConnectionUrlTest.java
@@ -0,0 +1,121 @@
/*
* Copyright 2021 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.jdbc;

import static com.google.common.truth.Truth.assertThat;

import com.google.cloud.spanner.connection.AbstractMockServerTest;
import com.google.common.base.Predicate;
import com.google.protobuf.AbstractMessage;
import com.google.spanner.v1.BatchCreateSessionsRequest;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;

@RunWith(Enclosed.class)
public class JdbcConnectionUrlTest {

public static class ConnectionMinSessionsTest extends AbstractMockServerTest {
@AfterClass
public static void reset() {
mockSpanner.reset();
}

protected String getBaseUrl() {
return super.getBaseUrl() + ";minSessions=1";
}

@Test
public void testMinSessions() throws InterruptedException, TimeoutException, SQLException {
try (Connection connection = createJdbcConnection()) {
mockSpanner.waitForRequestsToContain(
new Predicate<AbstractMessage>() {
@Override
public boolean apply(AbstractMessage input) {
return input instanceof BatchCreateSessionsRequest
&& ((BatchCreateSessionsRequest) input).getSessionCount() == 1;
}
},
5000L);
}
}
}

public static class ConnectionMaxSessionsTest extends AbstractMockServerTest {

@AfterClass
public static void reset() {
mockSpanner.reset();
}

protected String getBaseUrl() {
return super.getBaseUrl() + ";maxSessions=1";
}

@Test
public void testMaxSessions()
throws InterruptedException, TimeoutException, ExecutionException, SQLException {
ExecutorService executor1 = Executors.newSingleThreadExecutor();
ExecutorService executor2 = Executors.newSingleThreadExecutor();

try (Connection connection1 = createJdbcConnection();
Connection connection2 = createJdbcConnection()) {
final CountDownLatch latch = new CountDownLatch(1);
Future<Void> fut1 =
executor1.submit(
new Callable<Void>() {
@Override
public Void call() throws SQLException, InterruptedException {
latch.await(5L, TimeUnit.SECONDS);
connection1.createStatement().executeUpdate(INSERT_STATEMENT.getSql());
connection1.commit();
return null;
}
});
Future<Void> fut2 =
executor2.submit(
new Callable<Void>() {
@Override
public Void call() throws SQLException {
latch.countDown();
connection2.createStatement().executeUpdate(INSERT_STATEMENT.getSql());
connection2.commit();
return null;
}
});
// Wait until both finishes.
fut1.get(5L, TimeUnit.SECONDS);
fut2.get(5L, TimeUnit.SECONDS);
} finally {
executor1.shutdown();
executor2.shutdown();
}
assertThat(mockSpanner.numSessionsCreated()).isEqualTo(1);
}
}
}
21 changes: 5 additions & 16 deletions src/test/java/com/google/cloud/spanner/jdbc/JdbcGrpcErrorTest.java
Expand Up @@ -46,7 +46,6 @@
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand Down Expand Up @@ -133,30 +132,28 @@ public void reset() {

private String createUrl() {
return String.format(
"jdbc:cloudspanner://localhost:%d/projects/%s/instances/%s/databases/%s?usePlainText=true",
"jdbc:cloudspanner://localhost:%d/projects/%s/instances/%s/databases/%s?usePlainText=true;minSessions=0",
server.getPort(), "proj", "inst", "db");
}

private Connection createConnection() throws SQLException {
return DriverManager.getConnection(createUrl());
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void autocommitBeginTransaction() {
mockSpanner.setBeginTransactionExecutionTime(
SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
// This triggers a retry with an explicit BeginTransaction RPC.
mockSpanner.abortNextStatement();
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
fail("missing expected exception");
} catch (SQLException e) {
assertThat(testExceptionMatcher.matches(e)).isTrue();
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void autocommitBeginPDMLTransaction() {
mockSpanner.setBeginTransactionExecutionTime(
Expand All @@ -170,23 +167,21 @@ public void autocommitBeginPDMLTransaction() {
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void transactionalBeginTransaction() {
mockSpanner.setBeginTransactionExecutionTime(
SimulatedExecutionTime.ofException(serverException));
try (java.sql.Connection connection = createConnection()) {
connection.setAutoCommit(false);
// This triggers a retry with an explicit BeginTransaction RPC.
mockSpanner.abortNextStatement();
connection.createStatement().executeUpdate(UPDATE_STATEMENT.getSql());
fail("missing expected exception");
} catch (SQLException e) {
assertThat(testExceptionMatcher.matches(e)).isTrue();
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void readOnlyBeginTransaction() {
mockSpanner.setBeginTransactionExecutionTime(
Expand Down Expand Up @@ -368,8 +363,6 @@ public void readOnlyExecuteStreamingSql() {
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void autocommitCreateSession() {
mockSpanner.setBatchCreateSessionsExecutionTime(
Expand All @@ -382,8 +375,6 @@ public void autocommitCreateSession() {
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void transactionalCreateSession() {
mockSpanner.setBatchCreateSessionsExecutionTime(
Expand All @@ -397,8 +388,6 @@ public void transactionalCreateSession() {
}
}

@Ignore(
"This can only be guaranteed with MinSessions=0. Re-enable when MinSessions is configurable for JDBC.")
@Test
public void readOnlyCreateSession() {
mockSpanner.setBatchCreateSessionsExecutionTime(
Expand Down

0 comments on commit a5862a5

Please sign in to comment.