aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2012-08-28 11:59:45 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2012-09-07 10:22:38 -0700
commitc24c885209ac2334dc6f798c394a821ee270bec6 (patch)
tree4caeaaf4d1a21790faacda262aa09f9958c83b92
parentf24a5517e93feaf4a7400471021764c99623d3e2 (diff)
downloadrails-c24c885209ac2334dc6f798c394a821ee270bec6.tar.gz
rails-c24c885209ac2334dc6f798c394a821ee270bec6.tar.bz2
rails-c24c885209ac2334dc6f798c394a821ee270bec6.zip
create a transaction object and point AR objects at that object during a
transaction.
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb23
-rw-r--r--activerecord/lib/active_record/core.rb1
-rw-r--r--activerecord/lib/active_record/transactions.rb35
4 files changed, 55 insertions, 12 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 4e1f0e1d62..11e4d34de2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -193,7 +193,8 @@ module ActiveRecord
rescue Exception => database_transaction_rollback
if transaction_open && !outside_transaction?
transaction_open = false
- decrement_open_transactions
+ txn = decrement_open_transactions
+ txn.aborted!
if open_transactions == 0
rollback_db_transaction
rollback_transaction_records(true)
@@ -208,9 +209,10 @@ module ActiveRecord
@transaction_joinable = last_transaction_joinable
if outside_transaction?
- @open_transactions = 0
+ @current_transaction = nil
elsif transaction_open
- decrement_open_transactions
+ txn = decrement_open_transactions
+ txn.committed!
begin
if open_transactions == 0
commit_db_transaction
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index b3f9187429..27700e4fd2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -69,6 +69,7 @@ module ActiveRecord
@last_use = false
@logger = logger
@open_transactions = 0
+ @current_transaction = nil
@pool = pool
@query_cache = Hash.new { |h,sql| h[sql] = {} }
@query_cache_enabled = false
@@ -236,14 +237,30 @@ module ActiveRecord
@connection
end
- attr_reader :open_transactions
+ def open_transactions
+ count = 0
+ txn = current_transaction
+
+ while txn
+ count += 1
+ txn = txn.next
+ end
+
+ count
+ end
+
+ attr_reader :current_transaction
def increment_open_transactions
- @open_transactions += 1
+ @current_transaction = Transaction.new(current_transaction)
end
def decrement_open_transactions
- @open_transactions -= 1
+ return unless current_transaction
+
+ txn = current_transaction
+ @current_transaction = txn.next
+ txn
end
def transaction_joinable=(joinable)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index aad21b8e37..791ff4eaec 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -393,6 +393,7 @@ module ActiveRecord
@marked_for_destruction = false
@new_record = true
@mass_assignment_options = nil
+ @txn = nil
@_start_transaction_state = {}
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 09318879d5..e008b32170 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -1,6 +1,32 @@
require 'thread'
module ActiveRecord
+ class Transaction
+ attr_reader :next
+
+ def initialize(txn = nil)
+ @next = txn
+ @committed = false
+ @aborted = false
+ end
+
+ def committed!
+ @committed = true
+ end
+
+ def aborted!
+ @aborted = true
+ end
+
+ def committed?
+ @committed
+ end
+
+ def aborted?
+ @aborted
+ end
+ end
+
# See ActiveRecord::Transactions::ClassMethods for documentation.
module Transactions
extend ActiveSupport::Concern
@@ -307,11 +333,11 @@ module ActiveRecord
def with_transaction_returning_status
status = nil
self.class.transaction do
+ @txn = self.class.connection.current_transaction
add_to_transaction
begin
status = yield
rescue ActiveRecord::Rollback
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
status = nil
end
@@ -327,20 +353,17 @@ module ActiveRecord
@_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
@_start_transaction_state[:new_record] = @new_record
@_start_transaction_state[:destroyed] = @destroyed
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
end
# Clear the new record state and id of a record.
def clear_transaction_record_state #:nodoc:
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
- @_start_transaction_state.clear if @_start_transaction_state[:level] < 1
+ @_start_transaction_state.clear if @txn.committed?
end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
def restore_transaction_record_state(force = false) #:nodoc:
unless @_start_transaction_state.empty?
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
- if @_start_transaction_state[:level] < 1 || force
+ if @txn.aborted? || force
restore_state = @_start_transaction_state
was_frozen = @attributes.frozen?
@attributes = @attributes.dup if was_frozen