Skip to content

Commit 06ddbcd

Browse files
authored
chore(Spanner): TransactionOptions refactor (#8681)
1 parent 4f8b308 commit 06ddbcd

15 files changed

Lines changed: 327 additions & 411 deletions

Spanner/src/Batch/BatchClient.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717

1818
namespace Google\Cloud\Spanner\Batch;
1919

20+
use Google\Cloud\Core\ArrayTrait;
2021
use Google\Cloud\Core\TimeTrait;
2122
use Google\Cloud\Spanner\Operation;
2223
use Google\Cloud\Spanner\Session\SessionCache;
2324
use Google\Cloud\Spanner\Timestamp;
24-
use Google\Cloud\Spanner\TransactionConfigurationTrait;
25-
use Google\Protobuf\Duration;
25+
use Google\Cloud\Spanner\TransactionOptionsBuilder;
2626

2727
/**
2828
* Provides Batch APIs used to read data from a Cloud Spanner database.
@@ -102,7 +102,7 @@
102102
class BatchClient
103103
{
104104
use TimeTrait;
105-
use TransactionConfigurationTrait;
105+
use ArrayTrait;
106106

107107
const PARTITION_TYPE_KEY = '__partitionTypeName';
108108
private const ALLOWED_PARTITION_TYPES = [
@@ -145,22 +145,17 @@ public function __construct(
145145
*/
146146
public function snapshot(array $options = [])
147147
{
148-
$options += [
149-
'transactionOptions' => [],
150-
];
151-
152148
// Single Use transactions are not supported in batch mode.
153149
$options['transactionOptions']['singleUse'] = false;
150+
$options['transactionOptions']['returnReadTimestamp'] = true;
154151

155-
$transactionOptions = $this->pluck('transactionOptions', $options);
156-
$transactionOptions['returnReadTimestamp'] = true;
157-
158-
$transactionOptions = $this->configureReadOnlyTransactionOptions($transactionOptions);
152+
$txnOptions = (new TransactionOptionsBuilder())
153+
->configureReadOnlyTransactionOptions($options['transactionOptions']);
159154

160155
/** @var BatchSnapshot */
161156
return $this->operation->snapshot($this->session, [
162157
'className' => BatchSnapshot::class,
163-
'transactionOptions' => $transactionOptions
158+
'transactionOptions' => $txnOptions
164159
] + $options);
165160
}
166161

Spanner/src/Database.php

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@
8888
class Database
8989
{
9090
use ApiHelperTrait;
91-
use TransactionConfigurationTrait;
9291
use RequestTrait;
9392

9493
public const CONTEXT_READ = 'r';
@@ -128,6 +127,7 @@ class Database
128127
private CacheItemPoolInterface $cacheItemPool;
129128
private array $info;
130129
private int $isolationLevel;
130+
private TransactionOptionsBuilder $transactionOptionsBuilder;
131131

132132
/**
133133
* Create an object representing a Database.
@@ -185,6 +185,7 @@ public function __construct(
185185
);
186186

187187
$this->optionsValidator = new OptionsValidator($serializer);
188+
$this->transactionOptionsBuilder = new TransactionOptionsBuilder();
188189
$this->directedReadOptions = $instance->directedReadOptions();
189190
}
190191

@@ -747,25 +748,13 @@ public function snapshot(array $options = []): TransactionalReadInterface
747748
throw new BadMethodCallException('Nested transactions are not supported by this client.');
748749
}
749750

750-
$options += [
751-
'singleUse' => false
751+
$snapshotOptions = [
752+
'singleUse' => $options['singleUse'] ?? false,
753+
'transactionOptions' => $this->transactionOptionsBuilder
754+
->configureReadOnlyTransactionOptions($options),
752755
];
753756

754-
$options['transactionOptions'] = $this->configureReadOnlyTransactionOptions($options);
755-
756-
// For backwards compatibility - remove all PBReadOnly fields
757-
// This was previously being done in configureReadOnlyTransactionOptions
758-
// @TODO: clean this up
759-
unset(
760-
$options['returnReadTimestamp'],
761-
$options['strong'],
762-
$options['readTimestamp'],
763-
$options['exactStaleness'],
764-
$options['minReadTimestamp'],
765-
$options['maxStaleness'],
766-
);
767-
768-
return $this->operation->snapshot($this->session, $options);
757+
return $this->operation->snapshot($this->session, $snapshotOptions);
769758
}
770759

771760
/**
@@ -814,9 +803,11 @@ public function transaction(array $options = []): Transaction
814803
}
815804

816805
// Configure readWrite options here. Any nested options for readWrite should be added to this call
817-
$options['transactionOptions'] = $this->configureReadWriteTransactionOptions(
818-
($options['transactionOptions'] ?? []) + ['isolationLevel' => $this->isolationLevel]
819-
);
806+
$txnOptions = $options['transactionOptions'] ?? [];
807+
$options['transactionOptions'] = $this->transactionOptionsBuilder
808+
->configureReadWriteTransactionOptions($txnOptions + [
809+
'isolationLevel' => $this->isolationLevel
810+
]);
820811

821812
return $this->operation->transaction($this->session, $options);
822813
}
@@ -920,10 +911,11 @@ public function runTransaction(callable $operation, array $options = []): mixed
920911
: $retrySettings['maxRetries'];
921912

922913
// Configure necessary readWrite nested and base options
923-
$transactionOptions = $options['transactionOptions'] ?? [];
924-
$options['transactionOptions'] = $this->configureReadWriteTransactionOptions(
925-
$transactionOptions + ['isolationLevel' => $this->isolationLevel]
926-
);
914+
$txnOptions = $options['transactionOptions'] ?? [];
915+
$options['transactionOptions'] = $this->transactionOptionsBuilder
916+
->configureReadWriteTransactionOptions($txnOptions + [
917+
'isolationLevel' => $this->isolationLevel
918+
]);
927919

928920
$attempt = 0;
929921
$startTransactionFn = function ($options) use (&$attempt) {
@@ -1666,28 +1658,23 @@ public function delete(string $table, KeySet $keySet, array $options = []): Time
16661658
*/
16671659
public function execute($sql, array $options = []): Result
16681660
{
1669-
unset($options['requestOptions']['transactionTag']);
1670-
$session = $this->pluck('session', $options, false)
1671-
?: $this->session;
1672-
1673-
list(
1674-
$options['transaction'],
1675-
$options['transactionContext']
1676-
) = $this->transactionSelector($options);
1677-
16781661
if (isset($options['transaction']['readWrite'])) {
16791662
$options['transaction']['begin']['isolationLevel'] ??= $this->isolationLevel;
16801663
}
16811664

1682-
$options['directedReadOptions'] = $this->configureDirectedReadOptions(
1683-
$options,
1684-
$this->directedReadOptions
1665+
[$txnOptions, $txnContext] = $this->transactionOptionsBuilder->transactionSelector($options);
1666+
$directedReadOptions = $this->transactionOptionsBuilder->configureDirectedReadOptions(
1667+
['transaction' => $txnOptions] + $options,
1668+
$this->directedReadOptions,
16851669
);
16861670

1687-
// Unset the internal flag.
1688-
unset($options['singleUse']);
1689-
return $this->operation->execute($session, $sql, $options + [
1690-
'route-to-leader' => $options['transactionContext'] === Database::CONTEXT_READWRITE
1671+
$session = $options['session'] ?? $this->session;
1672+
$executeOptions = $this->pluckArray(['parameters', 'types'], $options);
1673+
return $this->operation->execute($session, $sql, $executeOptions + [
1674+
'transaction' => $txnOptions,
1675+
'transactionContext' => $txnContext,
1676+
'directedReadOptions' => $directedReadOptions,
1677+
'route-to-leader' => $txnContext === Database::CONTEXT_READWRITE
16911678
]);
16921679
}
16931680

@@ -1903,8 +1890,6 @@ public function batchWrite(array $mutationGroups, array $options = []): Generato
19031890
*/
19041891
public function executePartitionedUpdate($statement, array $options = []): int
19051892
{
1906-
unset($options['requestOptions']['transactionTag']);
1907-
19081893
if (isset($options['transactionOptions']['isolationLevel'])) {
19091894
throw new ValidationException('Partitioned DML cannot be configured with an isolation level');
19101895
}
@@ -1915,11 +1900,13 @@ public function executePartitionedUpdate($statement, array $options = []): int
19151900
]
19161901
];
19171902

1903+
unset($options['requestOptions']['transactionTag']);
19181904
if (isset($options['transactionOptions']['excludeTxnFromChangeStreams'])) {
19191905
$beginTransactionOptions['transactionOptions']['excludeTxnFromChangeStreams'] =
19201906
$options['transactionOptions']['excludeTxnFromChangeStreams'];
19211907
unset($options['transactionOptions']);
19221908
}
1909+
19231910
$transaction = $this->operation->transaction($this->session, $beginTransactionOptions);
19241911

19251912
return $this->operation->executeUpdate($this->session, $transaction, $statement, [
@@ -2053,21 +2040,23 @@ public function executePartitionedUpdate($statement, array $options = []): int
20532040
*/
20542041
public function read($table, KeySet $keySet, array $columns, array $options = []): Result
20552042
{
2056-
unset($options['requestOptions']['transactionTag']);
2057-
2058-
list($transactionOptions, $context) = $this->transactionSelector($options);
2059-
$options['transaction'] = $transactionOptions;
2060-
$options['transactionContext'] = $context;
2043+
[$txnOptions, $txnContext] = $this->transactionOptionsBuilder->transactionSelector($options);
20612044

2062-
$options['directedReadOptions'] = $this->configureDirectedReadOptions(
2063-
$options,
2064-
$this->directedReadOptions
2045+
$readOptions = $this->pluckArray(
2046+
['index', 'limit', 'orderBy', 'lockHint', 'directedReadOptions'],
2047+
$options
20652048
);
2049+
$readOptions += [
2050+
'transactionContext' => $txnContext,
2051+
'directedReadOptions' => $this->transactionOptionsBuilder->configureDirectedReadOptions(
2052+
['transaction' => $txnOptions] + $readOptions,
2053+
$this->directedReadOptions
2054+
),
2055+
'transaction' => $txnOptions,
2056+
];
20662057

2067-
// Unset the internal flag.
2068-
unset($options['singleUse']);
2069-
return $this->operation->read($this->session, $table, $keySet, $columns, $options + [
2070-
'route-to-leader' => $context === Database::CONTEXT_READ
2058+
return $this->operation->read($this->session, $table, $keySet, $columns, $readOptions + [
2059+
'route-to-leader' => $txnContext === Database::CONTEXT_READ
20712060
]);
20722061
}
20732062

@@ -2146,7 +2135,7 @@ public function createDatabaseFromBackup($name, $backup, array $options = []): L
21462135
{
21472136
$options += [
21482137
'parent' => $this->instance->name(),
2149-
'databaseId' => $this->databaseIdOnly($name),
2138+
'databaseId' => $this->databaseId($name),
21502139
'backup' => $backup instanceof Backup ? $backup->name() : $backup
21512140
];
21522141
/**
@@ -2368,7 +2357,7 @@ private function getCreateDbStatement(int $dialect): string
23682357
* @param string $name The database name or id.
23692358
* @return string
23702359
*/
2371-
private function databaseIdOnly(string $name): string
2360+
private function databaseId(string $name): string
23722361
{
23732362
try {
23742363
return DatabaseAdminClient::parseName($name)['database'];

Spanner/src/Instance.php

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public function __construct(
119119
private string $name,
120120
array $options = [],
121121
) {
122-
$this->name = $this->fullyQualifiedInstanceName($name, $projectId);
122+
$this->name = $this->fullyQualifiedInstanceName($name);
123123
$this->directedReadOptions = $options['directedReadOptions'] ?? [];
124124
$this->isolationLevel = $options['isolationLevel'] ?? IsolationLevel::ISOLATION_LEVEL_UNSPECIFIED;
125125
$this->routeToLeader = $options['routeToLeader'] ?? true;
@@ -545,21 +545,10 @@ public function database(string $name, array $options = []): Database
545545
'isolationLevel',
546546
]);
547547

548-
try {
549-
$instance = DatabaseAdminClient::parseName($this->name())['instance'];
550-
$databaseName = GapicSpannerClient::databaseName(
551-
$this->projectId,
552-
$instance,
553-
$name
554-
);
555-
} catch (ValidationException $e) {
556-
$databaseName = $name;
557-
}
558-
559548
if (!$session = $options['session'] ?? null) {
560549
$session = new SessionCache(
561550
$this->spannerClient,
562-
$databaseName,
551+
$this->fullyQualifiedDatabaseName($name),
563552
[
564553
'databaseRole' => $options['databaseRole'] ?? '',
565554
'lock' => $options['lock'] ?? null,
@@ -837,17 +826,36 @@ public function iam(): IamManager
837826
* Convert the simple instance name to a fully qualified name.
838827
*
839828
* @param string $name The instance name.
840-
* @param string $project The project ID.
841829
* @return string
842830
*/
843-
private function fullyQualifiedInstanceName(string $name, string $project): string
831+
private function fullyQualifiedInstanceName(string $name): string
844832
{
845833
return InstanceAdminClient::instanceName(
846-
$project,
834+
$this->projectId,
847835
$name
848836
);
849837
}
850838

839+
/**
840+
* Convert the simple database name to a fully qualified name.
841+
*
842+
* @param string $databaseName The database name.
843+
* @return string
844+
*/
845+
private function fullyQualifiedDatabaseName(string $databaseName): string
846+
{
847+
try {
848+
$instance = DatabaseAdminClient::parseName($this->name())['instance'];
849+
return GapicSpannerClient::databaseName(
850+
$this->projectId,
851+
$instance,
852+
$databaseName
853+
);
854+
} catch (ValidationException $e) {
855+
return $databaseName;
856+
}
857+
}
858+
851859
/**
852860
* Return the directed read options.
853861
*

0 commit comments

Comments
 (0)