diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml
new file mode 100644
index 0000000000..bdef45796c
--- /dev/null
+++ b/google-cloud-spanner/clirr-ignored-differences.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ 7012
+ com/google/cloud/spanner/Session
+ * asyncClose()
+
+
+ 7012
+ com/google/cloud/spanner/spi/v1/SpannerRpc
+ * asyncDeleteSession(*)
+
+
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Session.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Session.java
index 4eefefd1c5..697521554e 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Session.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Session.java
@@ -16,6 +16,10 @@
package com.google.cloud.spanner;
+import com.google.api.core.ApiFuture;
+import com.google.api.core.InternalApi;
+import com.google.protobuf.Empty;
+
/**
* A {@code Session} can be used to perform transactions that read and/or modify data in a Cloud
* Spanner database.
@@ -39,6 +43,7 @@
* require external synchronization; {@code Session} implementations are not required to be
* thread-safe.
*/
+@InternalApi
public interface Session extends DatabaseClient, AutoCloseable {
/** Returns the resource name associated with this session. */
String getName();
@@ -54,4 +59,10 @@ public interface Session extends DatabaseClient, AutoCloseable {
@Override
void close();
+
+ /**
+ * Closes the session asynchronously and returns the {@link ApiFuture} that can be used to monitor
+ * the operation progress.
+ */
+ ApiFuture asyncClose();
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java
index c383c4c336..ed11aaf548 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java
@@ -19,6 +19,7 @@
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.api.core.ApiFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.AbstractReadContext.MultiUseReadOnlyTransaction;
import com.google.cloud.spanner.AbstractReadContext.SingleReadContext;
@@ -27,6 +28,7 @@
import com.google.cloud.spanner.spi.v1.SpannerRpc;
import com.google.common.collect.Lists;
import com.google.protobuf.ByteString;
+import com.google.protobuf.Empty;
import com.google.spanner.v1.BeginTransactionRequest;
import com.google.spanner.v1.CommitRequest;
import com.google.spanner.v1.CommitResponse;
@@ -196,6 +198,11 @@ public void prepareReadWriteTransaction() {
readyTransactionId = beginTransaction();
}
+ @Override
+ public ApiFuture asyncClose() {
+ return spanner.getRpc().asyncDeleteSession(name, options);
+ }
+
@Override
public void close() {
Span span = tracer.spanBuilder(SpannerImpl.DELETE_SESSION).startSpan();
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java
index 1ca0ef1aa7..f19333f4e3 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java
@@ -18,6 +18,8 @@
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
+import com.google.api.core.ApiFuture;
+import com.google.api.core.ApiFutures;
import com.google.cloud.Timestamp;
import com.google.cloud.grpc.GrpcTransportOptions;
import com.google.cloud.grpc.GrpcTransportOptions.ExecutorFactory;
@@ -35,6 +37,7 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.protobuf.Empty;
import io.opencensus.common.Scope;
import io.opencensus.trace.Annotation;
import io.opencensus.trace.AttributeValue;
@@ -763,6 +766,12 @@ public TransactionRunner readWriteTransaction() {
return new SessionPoolTransactionRunner(SessionPool.this, this);
}
+ @Override
+ public ApiFuture asyncClose() {
+ close();
+ return ApiFutures.immediateFuture(Empty.getDefaultInstance());
+ }
+
@Override
public void close() {
synchronized (lock) {
@@ -998,7 +1007,7 @@ private void closeIdleSessions(Instant currTime) {
}
for (PooledSession sess : sessionsToClose) {
logger.log(Level.FINE, "Closing session {0}", sess.getName());
- closeSession(sess);
+ closeSessionAsync(sess);
}
}
@@ -1611,37 +1620,27 @@ int totalSessions() {
}
}
- private void closeSessionAsync(final PooledSession sess) {
- executor.submit(
+ private ApiFuture closeSessionAsync(final PooledSession sess) {
+ ApiFuture res = sess.delegate.asyncClose();
+ res.addListener(
new Runnable() {
@Override
public void run() {
- closeSession(sess);
+ synchronized (lock) {
+ allSessions.remove(sess);
+ if (isClosed()) {
+ decrementPendingClosures(1);
+ return;
+ }
+ // Create a new session if needed to unblock some waiter.
+ if (numWaiters() > numSessionsBeingCreated) {
+ createSessions(getAllowedCreateSessions(numWaiters() - numSessionsBeingCreated));
+ }
+ }
}
- });
- }
-
- private void closeSession(PooledSession sess) {
- try {
- sess.delegate.close();
- } catch (SpannerException e) {
- // Backend will delete these sessions after a while even if we fail to close them.
- if (logger.isLoggable(Level.FINE)) {
- logger.log(Level.FINE, "Failed to close session: " + sess.getName(), e);
- }
- } finally {
- synchronized (lock) {
- allSessions.remove(sess);
- if (isClosed()) {
- decrementPendingClosures(1);
- return;
- }
- // Create a new session if needed to unblock some waiter.
- if (numWaiters() > numSessionsBeingCreated) {
- createSessions(getAllowedCreateSessions(numWaiters() - numSessionsBeingCreated));
- }
- }
- }
+ },
+ executor);
+ return res;
}
private void prepareSession(final PooledSession sess) {
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
index 19f41618fe..b3a6c9b92b 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java
@@ -18,6 +18,7 @@
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
+import com.google.api.core.ApiFuture;
import com.google.api.core.NanoClock;
import com.google.api.gax.core.CredentialsProvider;
import com.google.api.gax.core.ExecutorProvider;
@@ -523,9 +524,14 @@ public Session createSession(
@Override
public void deleteSession(String sessionName, @Nullable Map