Skip to content

Commit a434730

Browse files
authored
fix(5.2.x): sessions were not always removed from checkedOutSessions (#1447)
* fix: sessions were not always removed from checkedOutSessions Sessions were added to a set of checked out sessions when one was checked out from the session pool. When the session was released back to the pool, the session would normally be removed from the set of checked out sessions. The latter would not always happen if the application that checked out the session did not use the session for any reads or writes. chore: fix maven version to 3.8.1 chore: fix maven version for windows * test: skip slow tests on stable branch
1 parent b7a911a commit a434730

File tree

6 files changed

+122
-18
lines changed

6 files changed

+122
-18
lines changed

.github/workflows/ci.yaml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jobs:
1212
java: [7, 8, 11]
1313
steps:
1414
- uses: actions/checkout@v2
15+
- uses: stCarolas/setup-maven@v4
16+
with:
17+
maven-version: 3.8.1
1518
- uses: actions/setup-java@v1
1619
with:
1720
java-version: ${{matrix.java}}
@@ -27,6 +30,9 @@ jobs:
2730
runs-on: windows-latest
2831
steps:
2932
- uses: actions/checkout@v2
33+
- uses: stCarolas/setup-maven@v4
34+
with:
35+
maven-version: 3.8.1
3036
- uses: actions/setup-java@v1
3137
with:
3238
java-version: 8
@@ -41,6 +47,9 @@ jobs:
4147
java: [8, 11]
4248
steps:
4349
- uses: actions/checkout@v2
50+
- uses: stCarolas/setup-maven@v4
51+
with:
52+
maven-version: 3.8.1
4453
- uses: actions/setup-java@v1
4554
with:
4655
java-version: ${{matrix.java}}
@@ -50,6 +59,9 @@ jobs:
5059
runs-on: ubuntu-latest
5160
steps:
5261
- uses: actions/checkout@v2
62+
- uses: stCarolas/setup-maven@v4
63+
with:
64+
maven-version: 3.8.1
5365
- uses: actions/setup-java@v1
5466
with:
5567
java-version: 8
@@ -63,6 +75,9 @@ jobs:
6375
runs-on: ubuntu-latest
6476
steps:
6577
- uses: actions/checkout@v2
78+
- uses: stCarolas/setup-maven@v4
79+
with:
80+
maven-version: 3.8.1
6681
- uses: actions/setup-java@v1
6782
with:
6883
java-version: 8
@@ -74,10 +89,13 @@ jobs:
7489
runs-on: ubuntu-latest
7590
steps:
7691
- uses: actions/checkout@v2
92+
- uses: stCarolas/setup-maven@v4
93+
with:
94+
maven-version: 3.8.1
7795
- uses: actions/setup-java@v1
7896
with:
7997
java-version: 8
8098
- run: java -version
8199
- run: .kokoro/build.sh
82100
env:
83-
JOB_TYPE: clirr
101+
JOB_TYPE: clirr

.github/workflows/integration-tests-against-emulator.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ jobs:
1717

1818
steps:
1919
- uses: actions/checkout@v2
20+
- uses: stCarolas/setup-maven@v4
21+
with:
22+
maven-version: 3.8.1
2023
- uses: actions/setup-java@v1
2124
with:
2225
java-version: 8

.github/workflows/samples.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ jobs:
66
runs-on: ubuntu-latest
77
steps:
88
- uses: actions/checkout@v2
9+
- uses: stCarolas/setup-maven@v4
10+
with:
11+
maven-version: 3.8.1
912
- uses: actions/setup-java@v1
1013
with:
1114
java-version: 8

google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,25 +1288,27 @@ public void prepareReadWriteTransaction() {
12881288

12891289
@Override
12901290
public void close() {
1291-
synchronized (lock) {
1292-
leakedException = null;
1293-
checkedOutSessions.remove(this);
1294-
}
1295-
PooledSession delegate = getOrNull();
1296-
if (delegate != null) {
1297-
delegate.close();
1291+
try {
1292+
asyncClose().get();
1293+
} catch (InterruptedException e) {
1294+
throw SpannerExceptionFactory.propagateInterrupt(e);
1295+
} catch (ExecutionException e) {
1296+
throw SpannerExceptionFactory.asSpannerException(e.getCause());
12981297
}
12991298
}
13001299

13011300
@Override
13021301
public ApiFuture<Empty> asyncClose() {
1303-
synchronized (lock) {
1304-
leakedException = null;
1305-
checkedOutSessions.remove(this);
1306-
}
1307-
PooledSession delegate = getOrNull();
1308-
if (delegate != null) {
1309-
return delegate.asyncClose();
1302+
try {
1303+
PooledSession delegate = getOrNull();
1304+
if (delegate != null) {
1305+
return delegate.asyncClose();
1306+
}
1307+
} finally {
1308+
synchronized (lock) {
1309+
leakedException = null;
1310+
checkedOutSessions.remove(this);
1311+
}
13101312
}
13111313
return ApiFutures.immediateFuture(Empty.getDefaultInstance());
13121314
}
@@ -1823,7 +1825,8 @@ private static enum Position {
18231825
private final Set<PooledSession> allSessions = new HashSet<>();
18241826

18251827
@GuardedBy("lock")
1826-
private final Set<PooledSessionFuture> checkedOutSessions = new HashSet<>();
1828+
@VisibleForTesting
1829+
final Set<PooledSessionFuture> checkedOutSessions = new HashSet<>();
18271830

18281831
private final SessionConsumer sessionConsumer = new SessionConsumerImpl();
18291832

google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import java.util.ArrayList;
6161
import java.util.Arrays;
6262
import java.util.List;
63+
import java.util.Set;
6364
import java.util.concurrent.ExecutionException;
6465
import java.util.concurrent.ExecutorService;
6566
import java.util.concurrent.Executors;
@@ -211,13 +212,18 @@ public void testWriteAtLeastOnceWithCommitStats() {
211212

212213
@Test
213214
public void singleUse() {
214-
DatabaseClient client =
215-
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
215+
DatabaseClientImpl client =
216+
(DatabaseClientImpl)
217+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
218+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
219+
assertThat(checkedOut).isEmpty();
216220
try (ResultSet rs = client.singleUse().executeQuery(SELECT1)) {
217221
assertThat(rs.next()).isTrue();
222+
assertThat(checkedOut).hasSize(1);
218223
assertThat(rs.getLong(0)).isEqualTo(1L);
219224
assertThat(rs.next()).isFalse();
220225
}
226+
assertThat(checkedOut).isEmpty();
221227
}
222228

223229
@Test
@@ -1642,4 +1648,71 @@ public void testTransactionManagerAsync_usesOptions() {
16421648

16431649
verify(session).transactionManagerAsync(option);
16441650
}
1651+
1652+
@Test
1653+
public void singleUseNoAction_ClearsCheckedOutSession() {
1654+
DatabaseClientImpl client =
1655+
(DatabaseClientImpl)
1656+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
1657+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
1658+
assertThat(checkedOut).isEmpty();
1659+
1660+
// Getting a single use read-only transaction and not using it should not cause any sessions
1661+
// to be stuck in the map of checked out sessions.
1662+
client.singleUse().close();
1663+
1664+
assertThat(checkedOut).isEmpty();
1665+
}
1666+
1667+
@Test
1668+
public void singleUseReadOnlyTransactionNoAction_ClearsCheckedOutSession() {
1669+
DatabaseClientImpl client =
1670+
(DatabaseClientImpl)
1671+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
1672+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
1673+
assertThat(checkedOut).isEmpty();
1674+
1675+
client.singleUseReadOnlyTransaction().close();
1676+
1677+
assertThat(checkedOut).isEmpty();
1678+
}
1679+
1680+
@Test
1681+
public void readWriteTransactionNoAction_ClearsCheckedOutSession() {
1682+
DatabaseClientImpl client =
1683+
(DatabaseClientImpl)
1684+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
1685+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
1686+
assertThat(checkedOut).isEmpty();
1687+
1688+
client.readWriteTransaction();
1689+
1690+
assertThat(checkedOut).isEmpty();
1691+
}
1692+
1693+
@Test
1694+
public void readOnlyTransactionNoAction_ClearsCheckedOutSession() {
1695+
DatabaseClientImpl client =
1696+
(DatabaseClientImpl)
1697+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
1698+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
1699+
assertThat(checkedOut).isEmpty();
1700+
1701+
client.readOnlyTransaction().close();
1702+
1703+
assertThat(checkedOut).isEmpty();
1704+
}
1705+
1706+
@Test
1707+
public void transactionManagerNoAction_ClearsCheckedOutSession() {
1708+
DatabaseClientImpl client =
1709+
(DatabaseClientImpl)
1710+
spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE));
1711+
Set<PooledSessionFuture> checkedOut = client.pool.checkedOutSessions;
1712+
assertThat(checkedOut).isEmpty();
1713+
1714+
client.transactionManager().close();
1715+
1716+
assertThat(checkedOut).isEmpty();
1717+
}
16451718
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.junit.Before;
7373
import org.junit.BeforeClass;
7474
import org.junit.ClassRule;
75+
import org.junit.Ignore;
7576
import org.junit.Test;
7677
import org.junit.experimental.categories.Category;
7778
import org.junit.runner.RunWith;
@@ -197,6 +198,7 @@ private void waitForDbOperations(String backupId) throws InterruptedException {
197198
}
198199

199200
@Test
201+
@Ignore("Do not run slow test in stable branch")
200202
public void testBackups() throws InterruptedException, ExecutionException {
201203
// Create two test databases in parallel.
202204
String db1Id = testHelper.getUniqueDatabaseId() + "_db1";
@@ -361,6 +363,7 @@ public void testBackups() throws InterruptedException, ExecutionException {
361363
}
362364

363365
@Test(expected = SpannerException.class)
366+
@Ignore("Do not run slow test in stable branch")
364367
public void backupCreationWithVersionTimeTooFarInThePastFails() throws Exception {
365368
final Database testDatabase = testHelper.createTestDatabase();
366369
final DatabaseId databaseId = testDatabase.getId();
@@ -380,6 +383,7 @@ public void backupCreationWithVersionTimeTooFarInThePastFails() throws Exception
380383
}
381384

382385
@Test(expected = SpannerException.class)
386+
@Ignore("Do not run slow test in stable branch")
383387
public void backupCreationWithVersionTimeInTheFutureFails() throws Exception {
384388
final Database testDatabase = testHelper.createTestDatabase();
385389
final DatabaseId databaseId = testDatabase.getId();

0 commit comments

Comments
 (0)