Skip to content

Commit 869a364

Browse files
chore: support RESET ALL in the Connection API (#3142)
* chore: support RESET ALL in the Connection API Adds support for the RESET ALL statement to the Connection API. This allows users to easily reset a connection to its original state, for example before returning a connection to a pool, or after retrieving a connection from a pool. Fixes googleapis/java-spanner-jdbc#1116 * 🦉 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 a0a4bc5 commit 869a364

File tree

13 files changed

+855
-238
lines changed

13 files changed

+855
-238
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -725,4 +725,11 @@
725725
<className>com/google/cloud/spanner/SessionPoolOptions$Builder</className>
726726
<method>com.google.cloud.spanner.SessionPoolOptions$Builder setUseMultiplexedSession(boolean)</method>
727727
</difference>
728+
729+
<!-- Added reset() method -->
730+
<difference>
731+
<differenceType>7012</differenceType>
732+
<className>com/google/cloud/spanner/connection/Connection</className>
733+
<method>void reset()</method>
734+
</difference>
728735
</differences>

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

+13
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ public interface Connection extends AutoCloseable {
172172
/** @return <code>true</code> if this connection has been closed. */
173173
boolean isClosed();
174174

175+
/**
176+
* Resets the state of this connection to the default state that it had when it was first created.
177+
* Calling this method after a transaction has started (that is; after a statement has been
178+
* executed in the transaction), does not change the active transaction. If for example a
179+
* transaction has been started with a transaction tag, the transaction tag for the active
180+
* transaction is not reset.
181+
*
182+
* <p>You can use this method to reset the state of the connection before returning a connection
183+
* to a connection pool, and/or before using a connection that was retrieved from a connection
184+
* pool.
185+
*/
186+
void reset();
187+
175188
/**
176189
* Sets autocommit on/off for this {@link Connection}. Connections in autocommit mode will apply
177190
* any changes to the database directly without waiting for an explicit commit. DDL- and DML

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

+39-14
Original file line numberDiff line numberDiff line change
@@ -306,21 +306,10 @@ static UnitOfWorkType of(TransactionMode transactionMode) {
306306
}
307307
this.dbClient = spanner.getDatabaseClient(options.getDatabaseId());
308308
this.batchClient = spanner.getBatchClient(options.getDatabaseId());
309-
this.retryAbortsInternally = options.isRetryAbortsInternally();
310-
this.readOnly = options.isReadOnly();
311-
this.autocommit = options.isAutocommit();
312-
this.queryOptions = this.queryOptions.toBuilder().mergeFrom(options.getQueryOptions()).build();
313-
this.rpcPriority = options.getRPCPriority();
314-
this.ddlInTransactionMode = options.getDdlInTransactionMode();
315-
this.returnCommitStats = options.isReturnCommitStats();
316-
this.delayTransactionStartUntilFirstWrite = options.isDelayTransactionStartUntilFirstWrite();
317-
this.dataBoostEnabled = options.isDataBoostEnabled();
318-
this.autoPartitionMode = options.isAutoPartitionMode();
319-
this.maxPartitions = options.getMaxPartitions();
320-
this.maxPartitionedParallelism = options.getMaxPartitionedParallelism();
321-
this.maxCommitDelay = options.getMaxCommitDelay();
322309
this.ddlClient = createDdlClient();
323-
setDefaultTransactionOptions();
310+
311+
// (Re)set the state of the connection to the default.
312+
reset();
324313
}
325314

326315
/** Constructor only for test purposes. */
@@ -434,6 +423,42 @@ public ApiFuture<Void> closeAsync() {
434423
return ApiFutures.immediateFuture(null);
435424
}
436425

426+
/**
427+
* Resets the state of this connection to the default state in the {@link ConnectionOptions} of
428+
* this connection.
429+
*/
430+
public void reset() {
431+
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
432+
433+
this.retryAbortsInternally = options.isRetryAbortsInternally();
434+
this.readOnly = options.isReadOnly();
435+
this.autocommit = options.isAutocommit();
436+
this.queryOptions =
437+
QueryOptions.getDefaultInstance().toBuilder().mergeFrom(options.getQueryOptions()).build();
438+
this.rpcPriority = options.getRPCPriority();
439+
this.ddlInTransactionMode = options.getDdlInTransactionMode();
440+
this.returnCommitStats = options.isReturnCommitStats();
441+
this.delayTransactionStartUntilFirstWrite = options.isDelayTransactionStartUntilFirstWrite();
442+
this.dataBoostEnabled = options.isDataBoostEnabled();
443+
this.autoPartitionMode = options.isAutoPartitionMode();
444+
this.maxPartitions = options.getMaxPartitions();
445+
this.maxPartitionedParallelism = options.getMaxPartitionedParallelism();
446+
this.maxCommitDelay = options.getMaxCommitDelay();
447+
448+
this.autocommitDmlMode = AutocommitDmlMode.TRANSACTIONAL;
449+
this.readOnlyStaleness = TimestampBound.strong();
450+
this.statementTag = null;
451+
this.statementTimeout = new StatementExecutor.StatementTimeout();
452+
this.directedReadOptions = null;
453+
this.savepointSupport = SavepointSupport.FAIL_AFTER_ROLLBACK;
454+
this.protoDescriptors = null;
455+
this.protoDescriptorsFilePath = null;
456+
457+
if (!isTransactionStarted()) {
458+
setDefaultTransactionOptions();
459+
}
460+
}
461+
437462
/** Get the current unit-of-work type of this connection. */
438463
UnitOfWorkType getUnitOfWorkType() {
439464
return unitOfWorkType;

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

+2
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ StatementResult statementSetPgSessionCharacteristicsTransactionMode(
128128

129129
StatementResult statementAbortBatch();
130130

131+
StatementResult statementResetAll();
132+
131133
StatementResult statementSetRPCPriority(Priority priority);
132134

133135
StatementResult statementShowRPCPriority();

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

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.ABORT_BATCH;
2121
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.BEGIN;
2222
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.COMMIT;
23+
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.RESET_ALL;
2324
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.ROLLBACK;
2425
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.RUN_BATCH;
2526
import static com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType.SET_AUTOCOMMIT;
@@ -528,6 +529,12 @@ public StatementResult statementAbortBatch() {
528529
return noResult(ABORT_BATCH);
529530
}
530531

532+
@Override
533+
public StatementResult statementResetAll() {
534+
getConnection().reset();
535+
return noResult(RESET_ALL);
536+
}
537+
531538
@Override
532539
public StatementResult statementSetRPCPriority(Priority priority) {
533540
RpcPriority value = validRPCPriorityValues.get(priority);

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

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ enum ClientSideStatementType {
9090
START_BATCH_DML,
9191
RUN_BATCH,
9292
ABORT_BATCH,
93+
RESET_ALL,
9394
SET_RPC_PRIORITY,
9495
SHOW_RPC_PRIORITY,
9596
SHOW_TRANSACTION_ISOLATION_LEVEL,

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

+9
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,15 @@
279279
"exampleStatements": ["abort batch"],
280280
"examplePrerequisiteStatements": ["start batch ddl"]
281281
},
282+
{
283+
"name": "RESET ALL",
284+
"executorName": "ClientSideStatementNoParamExecutor",
285+
"resultType": "NO_RESULT",
286+
"statementType": "RESET_ALL",
287+
"regex": "(?is)\\A\\s*(?:reset)(?:\\s+all)\\s*\\z",
288+
"method": "statementResetAll",
289+
"exampleStatements": ["reset all"]
290+
},
282291
{
283292
"name": "SET AUTOCOMMIT = TRUE|FALSE",
284293
"executorName": "ClientSideStatementSetExecutor",

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

+9
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,15 @@
328328
"exampleStatements": ["abort batch"],
329329
"examplePrerequisiteStatements": ["start batch ddl"]
330330
},
331+
{
332+
"name": "RESET ALL",
333+
"executorName": "ClientSideStatementNoParamExecutor",
334+
"resultType": "NO_RESULT",
335+
"statementType": "RESET_ALL",
336+
"regex": "(?is)\\A\\s*(?:reset)(?:\\s+all)\\s*\\z",
337+
"method": "statementResetAll",
338+
"exampleStatements": ["reset all"]
339+
},
331340
{
332341
"name": "SET AUTOCOMMIT =|TO TRUE|FALSE",
333342
"executorName": "ClientSideStatementSetExecutor",

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionTest.java

+148
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,31 @@
3030
import com.google.cloud.spanner.ErrorCode;
3131
import com.google.cloud.spanner.MockSpannerServiceImpl;
3232
import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime;
33+
import com.google.cloud.spanner.Options.RpcPriority;
3334
import com.google.cloud.spanner.ResultSet;
3435
import com.google.cloud.spanner.SpannerException;
3536
import com.google.cloud.spanner.SpannerOptions;
3637
import com.google.cloud.spanner.Statement;
38+
import com.google.cloud.spanner.TimestampBound;
3739
import com.google.common.collect.ImmutableList;
3840
import com.google.spanner.v1.BatchCreateSessionsRequest;
3941
import com.google.spanner.v1.CommitRequest;
42+
import com.google.spanner.v1.DirectedReadOptions;
43+
import com.google.spanner.v1.DirectedReadOptions.ExcludeReplicas;
44+
import com.google.spanner.v1.DirectedReadOptions.ReplicaSelection;
4045
import com.google.spanner.v1.ExecuteBatchDmlRequest;
4146
import com.google.spanner.v1.ExecuteSqlRequest;
4247
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
4348
import com.google.spanner.v1.RequestOptions;
49+
import java.nio.charset.StandardCharsets;
50+
import java.time.Duration;
4451
import java.util.Arrays;
4552
import java.util.Collections;
4653
import java.util.concurrent.ExecutionException;
4754
import java.util.concurrent.TimeUnit;
4855
import java.util.concurrent.TimeoutException;
56+
import java.util.function.Consumer;
57+
import java.util.function.Supplier;
4958
import javax.annotation.Nonnull;
5059
import org.junit.After;
5160
import org.junit.AfterClass;
@@ -228,6 +237,145 @@ public void testBatchUpdateAborted() {
228237
}
229238
}
230239
}
240+
241+
@Test
242+
public void testReset() {
243+
try (ConnectionImpl connection = (ConnectionImpl) createConnection()) {
244+
assertResetBooleanProperty(
245+
connection,
246+
true,
247+
connection::setRetryAbortsInternally,
248+
connection::isRetryAbortsInternally);
249+
assertResetBooleanProperty(
250+
connection, false, connection::setReadOnly, connection::isReadOnly);
251+
assertResetBooleanProperty(
252+
connection, false, connection::setAutocommit, connection::isAutocommit);
253+
assertResetBooleanProperty(
254+
connection, false, connection::setReturnCommitStats, connection::isReturnCommitStats);
255+
assertResetBooleanProperty(
256+
connection,
257+
false,
258+
connection::setDelayTransactionStartUntilFirstWrite,
259+
connection::isDelayTransactionStartUntilFirstWrite);
260+
assertResetBooleanProperty(
261+
connection, false, connection::setDataBoostEnabled, connection::isDataBoostEnabled);
262+
assertResetBooleanProperty(
263+
connection, false, connection::setAutoPartitionMode, connection::isAutoPartitionMode);
264+
assertResetBooleanProperty(
265+
connection,
266+
false,
267+
connection::setExcludeTxnFromChangeStreams,
268+
connection::isExcludeTxnFromChangeStreams);
269+
270+
assertResetProperty(
271+
connection, "", "1", connection::setOptimizerVersion, connection::getOptimizerVersion);
272+
assertResetProperty(
273+
connection,
274+
null,
275+
RpcPriority.LOW,
276+
connection::setRPCPriority,
277+
connection::getRPCPriority);
278+
assertResetProperty(
279+
connection,
280+
DdlInTransactionMode.ALLOW_IN_EMPTY_TRANSACTION,
281+
DdlInTransactionMode.AUTO_COMMIT_TRANSACTION,
282+
connection::setDdlInTransactionMode,
283+
connection::getDdlInTransactionMode);
284+
assertResetProperty(
285+
connection, 0, 4, connection::setMaxPartitions, connection::getMaxPartitions);
286+
assertResetProperty(
287+
connection,
288+
1,
289+
8,
290+
connection::setMaxPartitionedParallelism,
291+
connection::getMaxPartitionedParallelism);
292+
assertResetProperty(
293+
connection,
294+
null,
295+
Duration.ofMillis(20),
296+
connection::setMaxCommitDelay,
297+
connection::getMaxCommitDelay);
298+
assertResetProperty(
299+
connection,
300+
TimestampBound.strong(),
301+
TimestampBound.ofExactStaleness(10L, TimeUnit.SECONDS),
302+
connection::setReadOnlyStaleness,
303+
connection::getReadOnlyStaleness);
304+
assertResetProperty(
305+
connection, null, "tag", connection::setStatementTag, connection::getStatementTag);
306+
assertResetProperty(
307+
connection, null, "tag", connection::setTransactionTag, connection::getTransactionTag);
308+
assertResetProperty(
309+
connection,
310+
null,
311+
DirectedReadOptions.newBuilder()
312+
.setExcludeReplicas(
313+
ExcludeReplicas.newBuilder()
314+
.addReplicaSelections(
315+
ReplicaSelection.newBuilder().setLocation("foo").build())
316+
.build())
317+
.build(),
318+
connection::setDirectedRead,
319+
connection::getDirectedRead);
320+
assertResetProperty(
321+
connection,
322+
SavepointSupport.FAIL_AFTER_ROLLBACK,
323+
SavepointSupport.ENABLED,
324+
connection::setSavepointSupport,
325+
connection::getSavepointSupport);
326+
assertResetProperty(
327+
connection,
328+
null,
329+
"descriptor".getBytes(StandardCharsets.UTF_8),
330+
connection::setProtoDescriptors,
331+
connection::getProtoDescriptors);
332+
assertResetProperty(
333+
connection,
334+
null,
335+
"filename",
336+
connection::setProtoDescriptorsFilePath,
337+
connection::getProtoDescriptorsFilePath);
338+
339+
// Test the AutocommitDmlMode property that is only supported in auto-commit mode.
340+
connection.rollback();
341+
connection.setAutocommit(true);
342+
assertResetProperty(
343+
connection,
344+
AutocommitDmlMode.TRANSACTIONAL,
345+
AutocommitDmlMode.PARTITIONED_NON_ATOMIC,
346+
connection::setAutocommitDmlMode,
347+
connection::getAutocommitDmlMode);
348+
connection.setAutocommit(false);
349+
350+
// Statement timeouts use a customer getter/setter, so we need to manually test that.
351+
assertEquals(0L, connection.getStatementTimeout(TimeUnit.MILLISECONDS));
352+
connection.setStatementTimeout(10L, TimeUnit.SECONDS);
353+
assertEquals(10L, connection.getStatementTimeout(TimeUnit.SECONDS));
354+
connection.reset();
355+
assertEquals(0L, connection.getStatementTimeout(TimeUnit.MILLISECONDS));
356+
}
357+
}
358+
359+
private void assertResetBooleanProperty(
360+
ConnectionImpl connection,
361+
boolean defaultValue,
362+
Consumer<Boolean> setter,
363+
Supplier<Boolean> getter) {
364+
assertResetProperty(connection, defaultValue, !defaultValue, setter, getter);
365+
}
366+
367+
private <T> void assertResetProperty(
368+
ConnectionImpl connection,
369+
T defaultValue,
370+
T alternativeValue,
371+
Consumer<T> setter,
372+
Supplier<T> getter) {
373+
assertEquals(defaultValue, getter.get());
374+
setter.accept(alternativeValue);
375+
assertEquals(alternativeValue, getter.get());
376+
connection.reset();
377+
assertEquals(defaultValue, getter.get());
378+
}
231379
}
232380

233381
public static class ConnectionMinSessionsTest extends AbstractMockServerTest {

0 commit comments

Comments
 (0)