Skip to content

Commit a8f1852

Browse files
feat: support max_commit_delay in Connection API (#2954)
* feat: support max_commit_delay in Connection API Adds support for max_commit_delay to the Connection API: 1. Adds a setMaxCommitDelay(Duration) method to Connection 2. Adds a maxCommitDelay connection URL property 3. Adds a SET MAX_COMMIT_DELAY=<duration> SQL statement * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent c9be29c commit a8f1852

File tree

15 files changed

+582
-224
lines changed

15 files changed

+582
-224
lines changed

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

+12
Original file line numberDiff line numberDiff line change
@@ -631,4 +631,16 @@
631631
<className>com/google/cloud/spanner/connection/Connection</className>
632632
<method>void setDirectedRead(com.google.spanner.v1.DirectedReadOptions)</method>
633633
</difference>
634+
635+
<!-- Added MaxCommitDelay -->
636+
<difference>
637+
<differenceType>7012</differenceType>
638+
<className>com/google/cloud/spanner/connection/Connection</className>
639+
<method>java.time.Duration getMaxCommitDelay()</method>
640+
</difference>
641+
<difference>
642+
<differenceType>7012</differenceType>
643+
<className>com/google/cloud/spanner/connection/Connection</className>
644+
<method>void setMaxCommitDelay(java.time.Duration)</method>
645+
</difference>
634646
</differences>

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/Connection.java

+11
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.google.spanner.v1.DirectedReadOptions;
4242
import com.google.spanner.v1.ExecuteBatchDmlRequest;
4343
import com.google.spanner.v1.ResultSetStats;
44+
import java.time.Duration;
4445
import java.util.Iterator;
4546
import java.util.Set;
4647
import java.util.concurrent.ExecutionException;
@@ -556,6 +557,16 @@ default String getOptimizerStatisticsPackage() {
556557
/** @return true if this connection requests commit statistics from Cloud Spanner */
557558
boolean isReturnCommitStats();
558559

560+
/** Sets the max_commit_delay that will be applied to commit requests from this connection. */
561+
default void setMaxCommitDelay(Duration maxCommitDelay) {
562+
throw new UnsupportedOperationException("Unimplemented");
563+
}
564+
565+
/** Returns the max_commit_delay that will be applied to commit requests from this connection. */
566+
default Duration getMaxCommitDelay() {
567+
throw new UnsupportedOperationException("Unimplemented");
568+
}
569+
559570
/**
560571
* Sets the priority to use for RPCs executed by this connection..
561572
*

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java

+18
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.google.spanner.v1.DirectedReadOptions;
5757
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
5858
import com.google.spanner.v1.ResultSetStats;
59+
import java.time.Duration;
5960
import java.util.ArrayList;
6061
import java.util.Arrays;
6162
import java.util.Collections;
@@ -245,6 +246,8 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
245246
private String transactionTag;
246247
private String statementTag;
247248

249+
private Duration maxCommitDelay;
250+
248251
/** Create a connection and register it in the SpannerPool. */
249252
ConnectionImpl(ConnectionOptions options) {
250253
Preconditions.checkNotNull(options);
@@ -273,6 +276,7 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
273276
this.autoPartitionMode = options.isAutoPartitionMode();
274277
this.maxPartitions = options.getMaxPartitions();
275278
this.maxPartitionedParallelism = options.getMaxPartitionedParallelism();
279+
this.maxCommitDelay = options.getMaxCommitDelay();
276280
this.ddlClient = createDdlClient();
277281
setDefaultTransactionOptions();
278282
}
@@ -791,6 +795,18 @@ public boolean isReturnCommitStats() {
791795
return this.returnCommitStats;
792796
}
793797

798+
@Override
799+
public void setMaxCommitDelay(Duration maxCommitDelay) {
800+
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
801+
this.maxCommitDelay = maxCommitDelay;
802+
}
803+
804+
@Override
805+
public Duration getMaxCommitDelay() {
806+
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
807+
return this.maxCommitDelay;
808+
}
809+
794810
@Override
795811
public void setDelayTransactionStartUntilFirstWrite(
796812
boolean delayTransactionStartUntilFirstWrite) {
@@ -1614,6 +1630,7 @@ UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery) {
16141630
.setReadOnlyStaleness(readOnlyStaleness)
16151631
.setAutocommitDmlMode(autocommitDmlMode)
16161632
.setReturnCommitStats(returnCommitStats)
1633+
.setMaxCommitDelay(maxCommitDelay)
16171634
.setStatementTimeout(statementTimeout)
16181635
.withStatementExecutor(statementExecutor)
16191636
.build();
@@ -1636,6 +1653,7 @@ UnitOfWork createNewUnitOfWork(boolean isInternalMetadataQuery) {
16361653
.setRetryAbortsInternally(retryAbortsInternally)
16371654
.setSavepointSupport(savepointSupport)
16381655
.setReturnCommitStats(returnCommitStats)
1656+
.setMaxCommitDelay(maxCommitDelay)
16391657
.setTransactionRetryListeners(transactionRetryListeners)
16401658
.setStatementTimeout(statementTimeout)
16411659
.withStatementExecutor(statementExecutor)

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java

+32
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.lang.reflect.Constructor;
4545
import java.lang.reflect.InvocationTargetException;
4646
import java.net.URL;
47+
import java.time.Duration;
4748
import java.util.ArrayList;
4849
import java.util.Arrays;
4950
import java.util.Collections;
@@ -357,6 +358,9 @@ private static String generateGuardedConnectionPropertyError(
357358
ConnectionProperty.createStringProperty(
358359
OPTIMIZER_STATISTICS_PACKAGE_PROPERTY_NAME, ""),
359360
ConnectionProperty.createBooleanProperty("returnCommitStats", "", false),
361+
ConnectionProperty.createStringProperty(
362+
"maxCommitDelay",
363+
"The maximum commit delay in milliseconds that should be applied to commit requests from this connection."),
360364
ConnectionProperty.createBooleanProperty(
361365
"autoConfigEmulator",
362366
"Automatically configure the connection to try to connect to the Cloud Spanner emulator (true/false). "
@@ -689,6 +693,7 @@ public static Builder newBuilder() {
689693
private final String userAgent;
690694
private final QueryOptions queryOptions;
691695
private final boolean returnCommitStats;
696+
private final Long maxCommitDelay;
692697
private final boolean autoConfigEmulator;
693698
private final Dialect dialect;
694699
private final RpcPriority rpcPriority;
@@ -744,6 +749,7 @@ private ConnectionOptions(Builder builder) {
744749
queryOptionsBuilder.setOptimizerStatisticsPackage(parseOptimizerStatisticsPackage(this.uri));
745750
this.queryOptions = queryOptionsBuilder.build();
746751
this.returnCommitStats = parseReturnCommitStats(this.uri);
752+
this.maxCommitDelay = parseMaxCommitDelay(this.uri);
747753
this.autoConfigEmulator = parseAutoConfigEmulator(this.uri);
748754
this.dialect = parseDialect(this.uri);
749755
this.usePlainText = this.autoConfigEmulator || parseUsePlainText(this.uri);
@@ -1074,6 +1080,27 @@ static boolean parseReturnCommitStats(String uri) {
10741080
return Boolean.parseBoolean(value);
10751081
}
10761082

1083+
@VisibleForTesting
1084+
static Long parseMaxCommitDelay(String uri) {
1085+
String value = parseUriProperty(uri, "maxCommitDelay");
1086+
try {
1087+
Long millis = value == null ? null : Long.valueOf(value);
1088+
if (millis != null && millis < 0L) {
1089+
throw SpannerExceptionFactory.newSpannerException(
1090+
ErrorCode.INVALID_ARGUMENT, "maxCommitDelay must be >=0");
1091+
}
1092+
return millis;
1093+
} catch (NumberFormatException numberFormatException) {
1094+
throw SpannerExceptionFactory.newSpannerException(
1095+
ErrorCode.INVALID_ARGUMENT,
1096+
"Invalid value for maxCommitDelay: "
1097+
+ value
1098+
+ "\n"
1099+
+ "The value must be a positive integer indicating the number of "
1100+
+ "milliseconds to use as the max delay.");
1101+
}
1102+
}
1103+
10771104
static boolean parseAutoConfigEmulator(String uri) {
10781105
String value = parseUriProperty(uri, "autoConfigEmulator");
10791106
return Boolean.parseBoolean(value);
@@ -1405,6 +1432,11 @@ public boolean isReturnCommitStats() {
14051432
return returnCommitStats;
14061433
}
14071434

1435+
/** The max_commit_delay that should be applied to commit operations on this connection. */
1436+
public Duration getMaxCommitDelay() {
1437+
return maxCommitDelay == null ? null : Duration.ofMillis(maxCommitDelay);
1438+
}
1439+
14081440
/**
14091441
* Whether connections created by this {@link ConnectionOptions} will automatically try to connect
14101442
* to the emulator using the default host/port of the emulator, and automatically create the

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutor.java

+4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ interface ConnectionStatementExecutor {
8282

8383
StatementResult statementShowReturnCommitStats();
8484

85+
StatementResult statementSetMaxCommitDelay(Duration maxCommitDelay);
86+
87+
StatementResult statementShowMaxCommitDelay();
88+
8589
StatementResult statementSetDelayTransactionStartUntilFirstWrite(
8690
Boolean delayTransactionStartUntilFirstWrite);
8791

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionStatementExecutorImpl.java

+22
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DEFAULT_TRANSACTION_ISOLATION;
3030
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE;
3131
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_DIRECTED_READ;
32+
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_COMMIT_DELAY;
3233
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_PARTITIONED_PARALLELISM;
3334
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_MAX_PARTITIONS;
3435
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_OPTIMIZER_STATISTICS_PACKAGE;
@@ -51,6 +52,7 @@
5152
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DATA_BOOST_ENABLED;
5253
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE;
5354
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_DIRECTED_READ;
55+
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_COMMIT_DELAY;
5456
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_PARTITIONED_PARALLELISM;
5557
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_MAX_PARTITIONS;
5658
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SHOW_OPTIMIZER_STATISTICS_PACKAGE;
@@ -343,6 +345,26 @@ public StatementResult statementShowReturnCommitStats() {
343345
SHOW_RETURN_COMMIT_STATS);
344346
}
345347

348+
@Override
349+
public StatementResult statementSetMaxCommitDelay(Duration duration) {
350+
getConnection()
351+
.setMaxCommitDelay(
352+
duration == null || duration.equals(Duration.getDefaultInstance())
353+
? null
354+
: java.time.Duration.ofSeconds(duration.getSeconds(), duration.getNanos()));
355+
return noResult(SET_MAX_COMMIT_DELAY);
356+
}
357+
358+
@Override
359+
public StatementResult statementShowMaxCommitDelay() {
360+
return resultSet(
361+
"MAX_COMMIT_DELAY",
362+
getConnection().getMaxCommitDelay() == null
363+
? null
364+
: getConnection().getMaxCommitDelay().toMillis() + "ms",
365+
SHOW_MAX_COMMIT_DELAY);
366+
}
367+
346368
@Override
347369
public StatementResult statementSetDelayTransactionStartUntilFirstWrite(
348370
Boolean delayTransactionStartUntilFirstWrite) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReadWriteTransaction.java

+13
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.google.common.collect.Iterables;
5858
import com.google.common.util.concurrent.MoreExecutors;
5959
import com.google.spanner.v1.SpannerGrpc;
60+
import java.time.Duration;
6061
import java.util.ArrayList;
6162
import java.util.LinkedList;
6263
import java.util.List;
@@ -111,6 +112,7 @@ static class Builder extends AbstractMultiUseTransaction.Builder<Builder, ReadWr
111112
private Boolean retryAbortsInternally;
112113
private boolean delayTransactionStartUntilFirstWrite;
113114
private boolean returnCommitStats;
115+
private Duration maxCommitDelay;
114116
private SavepointSupport savepointSupport;
115117
private List<TransactionRetryListener> transactionRetryListeners;
116118

@@ -137,6 +139,11 @@ Builder setReturnCommitStats(boolean returnCommitStats) {
137139
return this;
138140
}
139141

142+
Builder setMaxCommitDelay(Duration maxCommitDelay) {
143+
this.maxCommitDelay = maxCommitDelay;
144+
return this;
145+
}
146+
140147
Builder setSavepointSupport(SavepointSupport savepointSupport) {
141148
this.savepointSupport = savepointSupport;
142149
return this;
@@ -180,6 +187,9 @@ private TransactionOption[] extractOptions(Builder builder) {
180187
if (builder.returnCommitStats) {
181188
numOptions++;
182189
}
190+
if (builder.maxCommitDelay != null) {
191+
numOptions++;
192+
}
183193
if (this.transactionTag != null) {
184194
numOptions++;
185195
}
@@ -191,6 +201,9 @@ private TransactionOption[] extractOptions(Builder builder) {
191201
if (builder.returnCommitStats) {
192202
options[index++] = Options.commitStats();
193203
}
204+
if (builder.maxCommitDelay != null) {
205+
options[index++] = Options.maxCommitDelay(builder.maxCommitDelay);
206+
}
194207
if (this.transactionTag != null) {
195208
options[index++] = Options.tag(this.transactionTag);
196209
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java

+16
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@
4646
import com.google.cloud.spanner.Type;
4747
import com.google.cloud.spanner.connection.AbstractStatementParser.ParsedStatement;
4848
import com.google.cloud.spanner.connection.AbstractStatementParser.StatementType;
49+
import com.google.cloud.spanner.connection.ReadWriteTransaction.Builder;
4950
import com.google.common.base.Preconditions;
5051
import com.google.common.collect.ImmutableList;
5152
import com.google.common.collect.Iterables;
5253
import com.google.common.util.concurrent.MoreExecutors;
5354
import com.google.spanner.admin.database.v1.DatabaseAdminGrpc;
5455
import com.google.spanner.v1.SpannerGrpc;
56+
import java.time.Duration;
5557
import java.util.concurrent.Callable;
5658

5759
/**
@@ -78,6 +80,7 @@ class SingleUseTransaction extends AbstractBaseUnitOfWork {
7880
private final TimestampBound readOnlyStaleness;
7981
private final AutocommitDmlMode autocommitDmlMode;
8082
private final boolean returnCommitStats;
83+
private final Duration maxCommitDelay;
8184
private final boolean internalMetdataQuery;
8285
private volatile SettableApiFuture<Timestamp> readTimestamp = null;
8386
private volatile TransactionRunner writeTransaction;
@@ -92,6 +95,7 @@ static class Builder extends AbstractBaseUnitOfWork.Builder<Builder, SingleUseTr
9295
private TimestampBound readOnlyStaleness;
9396
private AutocommitDmlMode autocommitDmlMode;
9497
private boolean returnCommitStats;
98+
private Duration maxCommitDelay;
9599
private boolean internalMetadataQuery;
96100

97101
private Builder() {}
@@ -135,6 +139,11 @@ Builder setReturnCommitStats(boolean returnCommitStats) {
135139
return this;
136140
}
137141

142+
Builder setMaxCommitDelay(Duration maxCommitDelay) {
143+
this.maxCommitDelay = maxCommitDelay;
144+
return this;
145+
}
146+
138147
Builder setInternalMetadataQuery(boolean internalMetadataQuery) {
139148
this.internalMetadataQuery = internalMetadataQuery;
140149
return this;
@@ -164,6 +173,7 @@ private SingleUseTransaction(Builder builder) {
164173
this.readOnlyStaleness = builder.readOnlyStaleness;
165174
this.autocommitDmlMode = builder.autocommitDmlMode;
166175
this.returnCommitStats = builder.returnCommitStats;
176+
this.maxCommitDelay = builder.maxCommitDelay;
167177
this.internalMetdataQuery = builder.internalMetadataQuery;
168178
}
169179

@@ -467,6 +477,9 @@ private TransactionRunner createWriteTransaction() {
467477
if (returnCommitStats) {
468478
numOptions++;
469479
}
480+
if (maxCommitDelay != null) {
481+
numOptions++;
482+
}
470483
if (numOptions == 0) {
471484
return dbClient.readWriteTransaction();
472485
}
@@ -478,6 +491,9 @@ private TransactionRunner createWriteTransaction() {
478491
if (returnCommitStats) {
479492
options[index++] = Options.commitStats();
480493
}
494+
if (maxCommitDelay != null) {
495+
options[index++] = Options.maxCommitDelay(maxCommitDelay);
496+
}
481497
return dbClient.readWriteTransaction(options);
482498
}
483499

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/StatementResult.java

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ enum ClientSideStatementType {
7171
SET_OPTIMIZER_STATISTICS_PACKAGE,
7272
SHOW_RETURN_COMMIT_STATS,
7373
SET_RETURN_COMMIT_STATS,
74+
SHOW_MAX_COMMIT_DELAY,
75+
SET_MAX_COMMIT_DELAY,
7476
SHOW_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE,
7577
SET_DELAY_TRANSACTION_START_UNTIL_FIRST_WRITE,
7678
SHOW_STATEMENT_TAG,

google-cloud-spanner/src/main/resources/com/google/cloud/spanner/connection/ClientSideStatements.json

+24
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@
112112
"method": "statementShowReturnCommitStats",
113113
"exampleStatements": ["show variable return_commit_stats"]
114114
},
115+
{
116+
"name": "SHOW VARIABLE MAX_COMMIT_DELAY",
117+
"executorName": "ClientSideStatementNoParamExecutor",
118+
"resultType": "RESULT_SET",
119+
"statementType": "SHOW_MAX_COMMIT_DELAY",
120+
"regex": "(?is)\\A\\s*show\\s+variable\\s+max_commit_delay\\s*\\z",
121+
"method": "statementShowMaxCommitDelay",
122+
"exampleStatements": ["show variable max_commit_delay"]
123+
},
115124
{
116125
"name": "SHOW VARIABLE COMMIT_RESPONSE",
117126
"executorName": "ClientSideStatementNoParamExecutor",
@@ -442,6 +451,21 @@
442451
"converterName": "ClientSideStatementValueConverters$BooleanConverter"
443452
}
444453
},
454+
{
455+
"name": "SET MAX_COMMIT_DELAY = '<duration>'|NULL",
456+
"executorName": "ClientSideStatementSetExecutor",
457+
"resultType": "NO_RESULT",
458+
"statementType": "SET_MAX_COMMIT_DELAY",
459+
"regex": "(?is)\\A\\s*set\\s+max_commit_delay\\s*(?:=)\\s*(.*)\\z",
460+
"method": "statementSetMaxCommitDelay",
461+
"exampleStatements": ["set max_commit_delay=null", "set max_commit_delay='1s'", "set max_commit_delay='100ms'", "set max_commit_delay='10000us'", "set max_commit_delay='9223372036854775807ns'"],
462+
"setStatement": {
463+
"propertyName": "MAX_COMMIT_DELAY",
464+
"separator": "=",
465+
"allowedValues": "('(\\d{1,19})(s|ms|us|ns)'|NULL)",
466+
"converterName": "ClientSideStatementValueConverters$DurationConverter"
467+
}
468+
},
445469
{
446470
"name": "SET STATEMENT_TAG = '<tag>'",
447471
"executorName": "ClientSideStatementSetExecutor",

0 commit comments

Comments
 (0)