Class: ActiveRecordSpannerAdapter::Transaction
- Inherits:
-
Object
- Object
- ActiveRecordSpannerAdapter::Transaction
- Defined in:
- lib/activerecord_spanner_adapter/transaction.rb
Instance Attribute Summary collapse
-
#state ⇒ Object
readonly
Returns the value of attribute state.
Instance Method Summary collapse
- #active? ⇒ Boolean
-
#begin ⇒ Object
Begins the transaction.
- #buffer(mutation) ⇒ Object
- #commit ⇒ Object
-
#force_begin_read_write ⇒ Object
Forces a BeginTransaction RPC for a read/write transaction.
-
#grpc_transaction=(grpc) ⇒ Object
Sets the underlying gRPC transaction to use for this Transaction.
-
#initialize(connection, isolation) ⇒ Transaction
constructor
A new instance of Transaction.
- #isolation ⇒ Object
- #mark_aborted ⇒ Object
- #next_sequence_number ⇒ Object
- #rollback ⇒ Object
- #shoot_and_forget_rollback ⇒ Object
- #transaction_selector ⇒ Object
Constructor Details
#initialize(connection, isolation) ⇒ Transaction
Returns a new instance of Transaction.
11 12 13 14 15 16 17 18 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 11 def initialize connection, isolation @connection = connection @isolation = isolation @committable = ![:read_only, :pdml].include?(isolation) && !isolation.is_a?(Hash) @state = :INITIALIZED @sequence_number = 0 @mutations = [] end |
Instance Attribute Details
#state ⇒ Object (readonly)
Returns the value of attribute state.
9 10 11 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 9 def state @state end |
Instance Method Details
#active? ⇒ Boolean
20 21 22 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 20 def active? @state == :STARTED end |
#begin ⇒ Object
Begins the transaction.
Read-only and PDML transactions are started by executing a BeginTransaction RPC. Read/write transactions are not really started by this method, and instead a transaction selector is prepared that will be included with the first statement on the transaction.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 39 def begin raise "Nested transactions are not allowed" if @state != :INITIALIZED begin case @isolation when Hash if @isolation[:timestamp] @grpc_transaction = @connection.session.create_snapshot timestamp: @isolation[:timestamp] elsif @isolation[:staleness] @grpc_transaction = @connection.session.create_snapshot staleness: @isolation[:staleness] elsif @isolation[:strong] @grpc_transaction = @connection.session.create_snapshot strong: true else raise "Invalid snapshot argument: #{@isolation}" end when :read_only @grpc_transaction = @connection.session.create_snapshot strong: true when :pdml @grpc_transaction = @connection.session.create_pdml else @begin_transaction_selector = Google::Cloud::Spanner::V1::TransactionSelector.new \ begin: Google::Cloud::Spanner::V1::TransactionOptions.new( read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new ) end @state = :STARTED rescue Google::Cloud::NotFoundError => e if @connection.session_not_found? e @connection.reset! retry end @state = :FAILED raise rescue StandardError @state = :FAILED raise end end |
#buffer(mutation) ⇒ Object
29 30 31 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 29 def buffer mutation @mutations << mutation end |
#commit ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 88 def commit raise "This transaction is not active" unless active? begin # Start a transaction with an explicit BeginTransaction RPC if the transaction only contains mutations. force_begin_read_write if @committable && !@mutations.empty? && !@grpc_transaction @connection.session.commit_transaction @grpc_transaction, @mutations if @committable && @grpc_transaction @state = :COMMITTED rescue Google::Cloud::NotFoundError => e if @connection.session_not_found? e shoot_and_forget_rollback @connection.reset! @connection.raise_aborted_err end @state = :FAILED raise rescue StandardError @state = :FAILED raise end end |
#force_begin_read_write ⇒ Object
Forces a BeginTransaction RPC for a read/write transaction. This is used by a connection if the first statement of a transaction failed.
80 81 82 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 80 def force_begin_read_write @grpc_transaction = @connection.session.create_transaction end |
#grpc_transaction=(grpc) ⇒ Object
Sets the underlying gRPC transaction to use for this Transaction. This is used for queries/DML statements that inlined the BeginTransaction option and returned a transaction in the metadata.
137 138 139 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 137 def grpc_transaction= grpc @grpc_transaction = Google::Cloud::Spanner::Transaction.from_grpc grpc, @connection.session end |
#isolation ⇒ Object
24 25 26 27 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 24 def isolation return nil unless active? @isolation end |
#mark_aborted ⇒ Object
130 131 132 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 130 def mark_aborted @state = :ABORTED end |
#next_sequence_number ⇒ Object
84 85 86 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 84 def next_sequence_number @sequence_number += 1 if @committable end |
#rollback ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 111 def rollback # Allow rollback after abort and/or a failed commit. raise "This transaction is not active" unless active? || @state == :FAILED || @state == :ABORTED if active? && @grpc_transaction # We do a shoot-and-forget rollback here, as the error that caused the transaction to be rolled back could # also have invalidated the transaction (e.g. `Session not found`). If the rollback fails for any other # reason, we also do not need to retry it or propagate the error to the application, as the transaction will # automatically be aborted by Cloud Spanner after 10 seconds anyways. shoot_and_forget_rollback end @state = :ROLLED_BACK end |
#shoot_and_forget_rollback ⇒ Object
124 125 126 127 128 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 124 def shoot_and_forget_rollback @connection.session.rollback @grpc_transaction.transaction_id if @committable rescue StandardError # rubocop:disable Lint/HandleExceptions # Ignored end |
#transaction_selector ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/activerecord_spanner_adapter/transaction.rb', line 141 def transaction_selector return unless active? # Use the transaction that has been started by a BeginTransaction RPC or returned by a # statement, if present. return Google::Cloud::Spanner::V1::TransactionSelector.new id: @grpc_transaction.transaction_id \ if @grpc_transaction # Return a transaction selector that will instruct the statement to also start a transaction # and return its id as a side effect. @begin_transaction_selector end |