Class: ActiveRecord::ConnectionAdapters::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/connection_adapters/abstract/transaction.rb

Overview

:nodoc:

Defined Under Namespace

Classes: Callback

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false) ⇒ Transaction

Returns a new instance of Transaction.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 153

def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false)
  super()
  @connection = connection
  @state = TransactionState.new
  @callbacks = nil
  @records = nil
  @isolation_level = isolation
  @materialized = false
  @joinable = joinable
  @run_commit_callbacks = run_commit_callbacks
  @lazy_enrollment_records = nil
  @dirty = false
  @user_transaction = joinable ? ActiveRecord::Transaction.new(self) : ActiveRecord::Transaction::NULL_TRANSACTION
  @instrumenter = TransactionInstrumenter.new(connection: connection, transaction: @user_transaction)
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



148
149
150
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 148

def connection
  @connection
end

#isolation_levelObject (readonly)

Returns the value of attribute isolation_level.



148
149
150
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 148

def isolation_level
  @isolation_level
end

#savepoint_nameObject (readonly)

Returns the value of attribute savepoint_name.



148
149
150
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 148

def savepoint_name
  @savepoint_name
end

#stateObject (readonly)

Returns the value of attribute state.



148
149
150
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 148

def state
  @state
end

#user_transactionObject (readonly)

Returns the value of attribute user_transaction.



148
149
150
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 148

def user_transaction
  @user_transaction
end

#writtenObject

Returns the value of attribute written.



149
150
151
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 149

def written
  @written
end

Instance Method Details

#add_record(record, ensure_finalize = true) ⇒ Object



185
186
187
188
189
190
191
192
193
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 185

def add_record(record, ensure_finalize = true)
  @records ||= []
  if ensure_finalize
    @records << record
  else
    @lazy_enrollment_records ||= ObjectSpace::WeakMap.new
    @lazy_enrollment_records[record] = record
  end
end

#after_commit(&block) ⇒ Object



203
204
205
206
207
208
209
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 203

def after_commit(&block)
  if @state.finalized?
    raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
  end

  (@callbacks ||= []) << Callback.new(:after_commit, block)
end

#after_rollback(&block) ⇒ Object



211
212
213
214
215
216
217
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 211

def after_rollback(&block)
  if @state.finalized?
    raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
  end

  (@callbacks ||= []) << Callback.new(:after_rollback, block)
end

#before_commit(&block) ⇒ Object



195
196
197
198
199
200
201
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 195

def before_commit(&block)
  if @state.finalized?
    raise ActiveRecordError, "Cannot register callbacks on a finalized transaction"
  end

  (@callbacks ||= []) << Callback.new(:before_commit, block)
end

#before_commit_recordsObject



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 274

def before_commit_records
  if @run_commit_callbacks
    if records
      if ActiveRecord.before_committed_on_all_records
        ite = unique_records

        instances_to_run_callbacks_on = records.each_with_object({}) do |record, candidates|
          candidates[record] = record
        end

        run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
          record.before_committed! if should_run_callbacks
        end
      else
        records.uniq.each(&:before_committed!)
      end
    end

    @callbacks&.each(&:before_commit)
  end
  # Note: When @run_commit_callbacks is false #commit_records takes care of appending
  # remaining callbacks to the parent transaction
end

#closed?Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 181

def closed?
  false
end

#commit_recordsObject



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 298

def commit_records
  if records
    begin
      ite = unique_records

      if @run_commit_callbacks
        instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)

        run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
          record.committed!(should_run_callbacks: should_run_callbacks)
        end
      else
        while record = ite.shift
          # if not running callbacks, only adds the record to the parent transaction
          connection.add_transaction_record(record)
        end
      end
    ensure
      ite&.each { |i| i.committed!(should_run_callbacks: false) }
    end
  end

  if @run_commit_callbacks
    @callbacks&.each(&:after_commit)
  elsif @callbacks
    connection.current_transaction.append_callbacks(@callbacks)
  end
end

#dirty!Object



169
170
171
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 169

def dirty!
  @dirty = true
end

#dirty?Boolean

Returns:

  • (Boolean)


173
174
175
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 173

def dirty?
  @dirty
end

#full_rollback?Boolean

Returns:

  • (Boolean)


327
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 327

def full_rollback?; true; end

#incomplete!Object



233
234
235
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 233

def incomplete!
  @instrumenter.finish(:incomplete) if materialized?
end

#joinable?Boolean

Returns:

  • (Boolean)


328
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 328

def joinable?; @joinable; end

#materialize!Object



237
238
239
240
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 237

def materialize!
  @materialized = true
  @instrumenter.start
end

#materialized?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 242

def materialized?
  @materialized
end

#open?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 177

def open?
  true
end

#recordsObject



219
220
221
222
223
224
225
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 219

def records
  if @lazy_enrollment_records
    @records.concat @lazy_enrollment_records.values
    @lazy_enrollment_records = nil
  end
  @records
end

#restartable?Boolean

Can this transaction’s current state be recreated by rollback+begin ?

Returns:

  • (Boolean)


229
230
231
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 229

def restartable?
  joinable? && !dirty?
end

#restore!Object



246
247
248
249
250
251
252
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 246

def restore!
  if materialized?
    incomplete!
    @materialized = false
    materialize!
  end
end

#rollback_recordsObject



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 254

def rollback_records
  if records
    begin
      ite = unique_records

      instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite)

      run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks|
        record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
      end
    ensure
      ite&.each do |i|
        i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
      end
    end
  end

  @callbacks&.each(&:after_rollback)
end