Skip to content

Commit 13cb37e

Browse files
authored
fix: Partitioned DML timeout was not always respected (#203)
* fix: Partitioned DML timeout was not always respected Setting a timeout value for Partitioned DML would not be respected if the timeout value was higher than the timeout value set for the ExecuteSql RPC on the SpannerStub. Lower timeout values would be respected. Fixes #199 * fix: add ignored changes + InternalApi * tests: add test for retry on UNAVAILABLE
1 parent 50cb174 commit 13cb37e

File tree

6 files changed

+145
-64
lines changed

6 files changed

+145
-64
lines changed

google-cloud-spanner/clirr-ignored-differences.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,16 @@
159159
<method>com.google.longrunning.Operation getOperation(java.lang.String)</method>
160160
</difference>
161161

162+
<!-- Fix Partitioned DML timeout settings. -->
163+
<difference>
164+
<differenceType>7004</differenceType>
165+
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
166+
<method>com.google.spanner.v1.ResultSet executePartitionedDml(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, org.threeten.bp.Duration)</method>
167+
</difference>
168+
<difference>
169+
<differenceType>7004</differenceType>
170+
<className>com/google/cloud/spanner/spi/v1/GapicSpannerRpc</className>
171+
<method>com.google.spanner.v1.ResultSet executePartitionedDml(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, org.threeten.bp.Duration)</method>
172+
</difference>
173+
162174
</differences>

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import com.google.spanner.v1.TransactionSelector;
3030
import java.util.Map;
3131
import java.util.concurrent.Callable;
32-
import org.threeten.bp.Duration;
3332

3433
/** Partitioned DML transaction for bulk updates and deletes. */
3534
class PartitionedDMLTransaction implements SessionTransaction {
@@ -63,7 +62,7 @@ private ByteString initTransaction() {
6362
* Executes the {@link Statement} using a partitioned dml transaction with automatic retry if the
6463
* transaction was aborted.
6564
*/
66-
long executePartitionedUpdate(final Statement statement, final Duration timeout) {
65+
long executePartitionedUpdate(final Statement statement) {
6766
checkState(isValid, "Partitioned DML has been invalidated by a new operation on the session");
6867
Callable<com.google.spanner.v1.ResultSet> callable =
6968
new Callable<com.google.spanner.v1.ResultSet>() {
@@ -84,7 +83,7 @@ public com.google.spanner.v1.ResultSet call() throws Exception {
8483
builder.putParamTypes(param.getKey(), param.getValue().getType().toProto());
8584
}
8685
}
87-
return rpc.executePartitionedDml(builder.build(), session.getOptions(), timeout);
86+
return rpc.executePartitionedDml(builder.build(), session.getOptions());
8887
}
8988
};
9089
com.google.spanner.v1.ResultSet resultSet =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public String getName() {
105105
public long executePartitionedUpdate(Statement stmt) {
106106
setActive(null);
107107
PartitionedDMLTransaction txn = new PartitionedDMLTransaction(this, spanner.getRpc());
108-
return txn.executePartitionedUpdate(stmt, spanner.getOptions().getPartitionedDmlTimeout());
108+
return txn.executePartitionedUpdate(stmt);
109109
}
110110

111111
@Override

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException;
2020

2121
import com.google.api.core.ApiFuture;
22+
import com.google.api.core.InternalApi;
2223
import com.google.api.core.NanoClock;
2324
import com.google.api.gax.core.CredentialsProvider;
2425
import com.google.api.gax.core.ExecutorProvider;
@@ -54,6 +55,7 @@
5455
import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStub;
5556
import com.google.cloud.spanner.v1.stub.GrpcSpannerStub;
5657
import com.google.cloud.spanner.v1.stub.SpannerStub;
58+
import com.google.cloud.spanner.v1.stub.SpannerStubSettings;
5759
import com.google.common.annotations.VisibleForTesting;
5860
import com.google.common.base.Function;
5961
import com.google.common.base.MoreObjects;
@@ -153,6 +155,7 @@
153155
import org.threeten.bp.Duration;
154156

155157
/** Implementation of Cloud Spanner remote calls using Gapic libraries. */
158+
@InternalApi
156159
public class GapicSpannerRpc implements SpannerRpc {
157160
/**
158161
* {@link ExecutorProvider} that keeps track of the executors that are created and shuts these
@@ -207,6 +210,7 @@ private synchronized void shutdown() {
207210
private final ManagedInstantiatingExecutorProvider executorProvider;
208211
private boolean rpcIsClosed;
209212
private final SpannerStub spannerStub;
213+
private final SpannerStub partitionedDmlStub;
210214
private final InstanceAdminStub instanceAdminStub;
211215
private final DatabaseAdminStubSettings databaseAdminStubSettings;
212216
private final DatabaseAdminStub databaseAdminStub;
@@ -326,6 +330,22 @@ public GapicSpannerRpc(final SpannerOptions options) {
326330
.setCredentialsProvider(credentialsProvider)
327331
.setStreamWatchdogProvider(watchdogProvider)
328332
.build());
333+
SpannerStubSettings.Builder pdmlSettings = options.getSpannerStubSettings().toBuilder();
334+
pdmlSettings
335+
.setTransportChannelProvider(channelProvider)
336+
.setCredentialsProvider(credentialsProvider)
337+
.setStreamWatchdogProvider(watchdogProvider)
338+
.executeSqlSettings()
339+
.setRetrySettings(
340+
options
341+
.getSpannerStubSettings()
342+
.executeSqlSettings()
343+
.getRetrySettings()
344+
.toBuilder()
345+
.setInitialRpcTimeout(options.getPartitionedDmlTimeout())
346+
.setMaxRpcTimeout(options.getPartitionedDmlTimeout())
347+
.build());
348+
this.partitionedDmlStub = GrpcSpannerStub.create(pdmlSettings.build());
329349

330350
this.instanceAdminStub =
331351
GrpcInstanceAdminStub.create(
@@ -1029,9 +1049,9 @@ public ResultSet executeQuery(ExecuteSqlRequest request, @Nullable Map<Option, ?
10291049

10301050
@Override
10311051
public ResultSet executePartitionedDml(
1032-
ExecuteSqlRequest request, @Nullable Map<Option, ?> options, Duration timeout) {
1033-
GrpcCallContext context = newCallContext(options, request.getSession(), timeout);
1034-
return get(spannerStub.executeSqlCallable().futureCall(request, context));
1052+
ExecuteSqlRequest request, @Nullable Map<Option, ?> options) {
1053+
GrpcCallContext context = newCallContext(options, request.getSession());
1054+
return get(partitionedDmlStub.executeSqlCallable().futureCall(request, context));
10351055
}
10361056

10371057
@Override
@@ -1191,19 +1211,11 @@ private static <T> T get(final Future<T> future) throws SpannerException {
11911211

11921212
@VisibleForTesting
11931213
GrpcCallContext newCallContext(@Nullable Map<Option, ?> options, String resource) {
1194-
return newCallContext(options, resource, null);
1195-
}
1196-
1197-
private GrpcCallContext newCallContext(
1198-
@Nullable Map<Option, ?> options, String resource, Duration timeout) {
11991214
GrpcCallContext context = GrpcCallContext.createDefault();
12001215
if (options != null) {
12011216
context = context.withChannelAffinity(Option.CHANNEL_HINT.getLong(options).intValue());
12021217
}
12031218
context = context.withExtraHeaders(metadataProvider.newExtraHeaders(resource, projectName));
1204-
if (timeout != null) {
1205-
context = context.withTimeout(timeout);
1206-
}
12071219
if (callCredentialsProvider != null) {
12081220
CallCredentials callCredentials = callCredentialsProvider.getCallCredentials();
12091221
if (callCredentials != null) {

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
import java.util.List;
5858
import java.util.Map;
5959
import javax.annotation.Nullable;
60-
import org.threeten.bp.Duration;
6160

6261
/**
6362
* Abstracts remote calls to the Cloud Spanner service. Typically end-consumer code will never use
@@ -282,8 +281,7 @@ StreamingCall read(
282281

283282
ResultSet executeQuery(ExecuteSqlRequest request, @Nullable Map<Option, ?> options);
284283

285-
ResultSet executePartitionedDml(
286-
ExecuteSqlRequest request, @Nullable Map<Option, ?> options, Duration timeout);
284+
ResultSet executePartitionedDml(ExecuteSqlRequest request, @Nullable Map<Option, ?> options);
287285

288286
StreamingCall executeQuery(
289287
ExecuteSqlRequest request, ResultStreamConsumer consumer, @Nullable Map<Option, ?> options);

0 commit comments

Comments
 (0)