google-cloud-php icon indicating copy to clipboard operation
google-cloud-php copied to clipboard

feat: Add support for the Isolation Level value

Open Hectorhammett opened this issue 8 months ago • 1 comments

b/388238239

Hectorhammett avatar Apr 15 '25 21:04 Hectorhammett

Here are the ways this option can currently be used:

  • SpannerClient constructor
  • Database::execute
  • Database::runTransaction
  • Database::transaction
  • Operation::transaction
  • Transaction::commit

Supplying Isolation Level here will throw an exception:

  • Database::executePartitionedUpdate
  • Transaction::executeUpdate (when "type" is single-use)

Potential Issues identified

  • Database::runTransaction does not get the client option value of isolationLevel passed into Database
  • Transaction::commit does some strangeness with passing the options back and forth - track down what this means

SpannerClient constructor

Supplying the isolationLevel to the SpannerClient constructor will ensure the Isolation Level is passed down to the Instance and Database, and will be present in the following calls:

$spanner = new SpannerClient(['isolationLevel' => $isolationLevel]);

// TransactionOptions.begin.isolationLevel will be set to $isolationLevel
$spanner->instance->database->execute($sql);
// TransactionOptions.begin.isolationLevel will be set to $newIsolationLevel
$spanner->instance->database->execute($sql, ['isolationLevel' => $newIsolationLevel]);

Database::execute

$database->execute($sql, ['isolationLevel' => $isolationLevel]);

Database::runTransaction

// NOTE: This does NOT get the operation from the client option. This seems like a bug
$database->runTransaction($operation);
// This will create a 
$database->runTransaction($operation, ['isolationLevel' => $isolationLevel]);

Database::transaction

$database->transaction(['isolationLevel' => $isolationLevel]);

Operation::transaction

Operations now take a isolationlevel option when creating a transaction. This is either passed to a BeginTransaction request, or passed to a Transaction object.

Transaction::commit

When the Transaction object receives an isolationlevel in the constructor, it's passed back to Operation::transaction. This requires more investigation

// calls `Operation::transaction` under the hood, which can potentially create a new Transaction
// Also calls `TransactionConfigurationTrait::transactionOptions`, which adds the `isolationLevel`
// @TODO: figure out why/how this works. 
$transaction->commit($session, ['isolationLevel' => $isolationLevel]);

Database::executePartitionedUpdate

The following will throw an InvalidArgumentException:

$database->executePartitionedUpdate($sql, ['transactionOptions' => ['isolationLevel' => $isolationLevel]])
// Throws InvalidArgumentException with "Partitioned DML cannot be configured with an isolation level"

Transaction::executeUpdate

The following will throw an ValidationException:

$database->executePartitionedUpdate($sql, ['transactionOptions' => ['isolationLevel' => $isolationLevel]])
// Throws ValidationException with "Partitioned DML cannot be configured with an isolation level"

bshaffer avatar May 21 '25 18:05 bshaffer