Skip to content

Commit c9864e5

Browse files
skuruppuolavloite
authored andcommitted
perf: close sessions async revert revert (#46)
* Revert "Revert "perf: close sessions async (#24)" (#43)" This reverts commit 809ed88. * Ignore compatibility check failure in internal interfaces. asyncClose() was added to com.google.cloud.spanner.Session and asyncDeleteSession() was added to com.google.cloud.spanner.spi.v1.SpannerRpc in #24 which resulted in binary compatibility test failures. This config allows us to ignore the failure. * Annotate SpannerRpc and Session classes as @internalapi. Users shouldn't be implementing these interfaces as they're internal to the client library implementation.
1 parent b619fed commit c9864e5

18 files changed

+129
-49
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
3+
<differences>
4+
<difference>
5+
<differenceType>7012</differenceType>
6+
<className>com/google/cloud/spanner/Session</className>
7+
<method>* asyncClose()</method>
8+
</difference>
9+
<difference>
10+
<differenceType>7012</differenceType>
11+
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
12+
<method>* asyncDeleteSession(*)</method>
13+
</difference>
14+
</differences>

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package com.google.cloud.spanner;
1818

19+
import com.google.api.core.ApiFuture;
20+
import com.google.api.core.InternalApi;
21+
import com.google.protobuf.Empty;
22+
1923
/**
2024
* A {@code Session} can be used to perform transactions that read and/or modify data in a Cloud
2125
* Spanner database.
@@ -39,6 +43,7 @@
3943
* require external synchronization; {@code Session} implementations are not required to be
4044
* thread-safe.
4145
*/
46+
@InternalApi
4247
public interface Session extends DatabaseClient, AutoCloseable {
4348
/** Returns the resource name associated with this session. */
4449
String getName();
@@ -54,4 +59,10 @@ public interface Session extends DatabaseClient, AutoCloseable {
5459

5560
@Override
5661
void close();
62+
63+
/**
64+
* Closes the session asynchronously and returns the {@link ApiFuture} that can be used to monitor
65+
* the operation progress.
66+
*/
67+
ApiFuture<Empty> asyncClose();
5768
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
2020
import static com.google.common.base.Preconditions.checkNotNull;
2121

22+
import com.google.api.core.ApiFuture;
2223
import com.google.cloud.Timestamp;
2324
import com.google.cloud.spanner.AbstractReadContext.MultiUseReadOnlyTransaction;
2425
import com.google.cloud.spanner.AbstractReadContext.SingleReadContext;
@@ -27,6 +28,7 @@
2728
import com.google.cloud.spanner.spi.v1.SpannerRpc;
2829
import com.google.common.collect.Lists;
2930
import com.google.protobuf.ByteString;
31+
import com.google.protobuf.Empty;
3032
import com.google.spanner.v1.BeginTransactionRequest;
3133
import com.google.spanner.v1.CommitRequest;
3234
import com.google.spanner.v1.CommitResponse;
@@ -196,6 +198,11 @@ public void prepareReadWriteTransaction() {
196198
readyTransactionId = beginTransaction();
197199
}
198200

201+
@Override
202+
public ApiFuture<Empty> asyncClose() {
203+
return spanner.getRpc().asyncDeleteSession(name, options);
204+
}
205+
199206
@Override
200207
public void close() {
201208
Span span = tracer.spanBuilder(SpannerImpl.DELETE_SESSION).startSpan();

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

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
2020

21+
import com.google.api.core.ApiFuture;
22+
import com.google.api.core.ApiFutures;
2123
import com.google.cloud.Timestamp;
2224
import com.google.cloud.grpc.GrpcTransportOptions;
2325
import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory;
@@ -35,6 +37,7 @@
3537
import com.google.common.util.concurrent.MoreExecutors;
3638
import com.google.common.util.concurrent.SettableFuture;
3739
import com.google.common.util.concurrent.Uninterruptibles;
40+
import com.google.protobuf.Empty;
3841
import io.opencensus.common.Scope;
3942
import io.opencensus.trace.Annotation;
4043
import io.opencensus.trace.AttributeValue;
@@ -763,6 +766,12 @@ public TransactionRunner readWriteTransaction() {
763766
return new SessionPoolTransactionRunner(SessionPool.this, this);
764767
}
765768

769+
@Override
770+
public ApiFuture<Empty> asyncClose() {
771+
close();
772+
return ApiFutures.immediateFuture(Empty.getDefaultInstance());
773+
}
774+
766775
@Override
767776
public void close() {
768777
synchronized (lock) {
@@ -998,7 +1007,7 @@ private void closeIdleSessions(Instant currTime) {
9981007
}
9991008
for (PooledSession sess : sessionsToClose) {
10001009
logger.log(Level.FINE, "Closing session {0}", sess.getName());
1001-
closeSession(sess);
1010+
closeSessionAsync(sess);
10021011
}
10031012
}
10041013

@@ -1611,37 +1620,27 @@ int totalSessions() {
16111620
}
16121621
}
16131622

1614-
private void closeSessionAsync(final PooledSession sess) {
1615-
executor.submit(
1623+
private ApiFuture<Empty> closeSessionAsync(final PooledSession sess) {
1624+
ApiFuture<Empty> res = sess.delegate.asyncClose();
1625+
res.addListener(
16161626
new Runnable() {
16171627
@Override
16181628
public void run() {
1619-
closeSession(sess);
1629+
synchronized (lock) {
1630+
allSessions.remove(sess);
1631+
if (isClosed()) {
1632+
decrementPendingClosures(1);
1633+
return;
1634+
}
1635+
// Create a new session if needed to unblock some waiter.
1636+
if (numWaiters() > numSessionsBeingCreated) {
1637+
createSessions(getAllowedCreateSessions(numWaiters() - numSessionsBeingCreated));
1638+
}
1639+
}
16201640
}
1621-
});
1622-
}
1623-
1624-
private void closeSession(PooledSession sess) {
1625-
try {
1626-
sess.delegate.close();
1627-
} catch (SpannerException e) {
1628-
// Backend will delete these sessions after a while even if we fail to close them.
1629-
if (logger.isLoggable(Level.FINE)) {
1630-
logger.log(Level.FINE, "Failed to close session: " + sess.getName(), e);
1631-
}
1632-
} finally {
1633-
synchronized (lock) {
1634-
allSessions.remove(sess);
1635-
if (isClosed()) {
1636-
decrementPendingClosures(1);
1637-
return;
1638-
}
1639-
// Create a new session if needed to unblock some waiter.
1640-
if (numWaiters() > numSessionsBeingCreated) {
1641-
createSessions(getAllowedCreateSessions(numWaiters() - numSessionsBeingCreated));
1642-
}
1643-
}
1644-
}
1641+
},
1642+
executor);
1643+
return res;
16451644
}
16461645

16471646
private void prepareSession(final PooledSession sess) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
2020

21+
import com.google.api.core.ApiFuture;
2122
import com.google.api.core.NanoClock;
2223
import com.google.api.gax.core.CredentialsProvider;
2324
import com.google.api.gax.core.ExecutorProvider;
@@ -523,9 +524,14 @@ public Session createSession(
523524
@Override
524525
public void deleteSession(String sessionName, @Nullable Map<Option, ?> options)
525526
throws SpannerException {
527+
get(asyncDeleteSession(sessionName, options));
528+
}
529+
530+
@Override
531+
public ApiFuture<Empty> asyncDeleteSession(String sessionName, @Nullable Map<Option, ?> options) {
526532
DeleteSessionRequest request = DeleteSessionRequest.newBuilder().setName(sessionName).build();
527533
GrpcCallContext context = newCallContext(options, sessionName);
528-
get(spannerStub.deleteSessionCallable().futureCall(request, context));
534+
return spannerStub.deleteSessionCallable().futureCall(request, context);
529535
}
530536

531537
@Override

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.cloud.spanner.spi.v1;
1818

19+
import com.google.api.core.ApiFuture;
20+
import com.google.api.core.InternalApi;
1921
import com.google.api.gax.longrunning.OperationFuture;
2022
import com.google.cloud.ServiceRpc;
2123
import com.google.cloud.spanner.SpannerException;
@@ -66,6 +68,7 @@
6668
* is purely for expedience; a future version of this interface is likely to be independent of
6769
* transport to allow switching between gRPC and HTTP.
6870
*/
71+
@InternalApi
6972
public interface SpannerRpc extends ServiceRpc {
7073
/** Options passed in {@link SpannerRpc} methods to control how an RPC is issued. */
7174
enum Option {
@@ -219,6 +222,9 @@ Session createSession(
219222

220223
void deleteSession(String sessionName, @Nullable Map<Option, ?> options) throws SpannerException;
221224

225+
ApiFuture<Empty> asyncDeleteSession(String sessionName, @Nullable Map<Option, ?> options)
226+
throws SpannerException;
227+
222228
StreamingCall read(
223229
ReadRequest request, ResultStreamConsumer consumer, @Nullable Map<Option, ?> options);
224230

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
import static org.mockito.Mockito.spy;
2424
import static org.mockito.Mockito.when;
2525

26+
import com.google.api.core.ApiFutures;
2627
import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory;
2728
import com.google.cloud.spanner.SessionPool.Clock;
29+
import com.google.protobuf.Empty;
2830
import java.util.concurrent.ScheduledExecutorService;
2931
import java.util.concurrent.ScheduledFuture;
3032
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -61,6 +63,7 @@ SessionImpl mockSession() {
6163
when(session.getName())
6264
.thenReturn(
6365
"projects/dummy/instances/dummy/database/dummy/sessions/session" + sessionIndex);
66+
when(session.asyncClose()).thenReturn(ApiFutures.immediateFuture(Empty.getDefaultInstance()));
6467
sessionIndex++;
6568
return session;
6669
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,9 @@ public static void startStaticServer() throws IOException {
216216
}
217217

218218
@AfterClass
219-
public static void stopServer() {
219+
public static void stopServer() throws InterruptedException {
220220
server.shutdown();
221+
server.awaitTermination();
221222
}
222223

223224
@Before

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,9 @@ public static void startStaticServer() throws IOException {
219219
}
220220

221221
@AfterClass
222-
public static void stopServer() {
222+
public static void stopServer() throws InterruptedException {
223223
server.shutdown();
224+
server.awaitTermination();
224225
}
225226

226227
@Before

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,10 @@ public static void startStaticServer() throws IOException {
172172
}
173173

174174
@AfterClass
175-
public static void stopServer() {
175+
public static void stopServer() throws InterruptedException {
176176
spannerClient.close();
177177
server.shutdown();
178+
server.awaitTermination();
178179
}
179180

180181
@Before

0 commit comments

Comments
 (0)