aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErol Fornoles <erol.fornoles@gmail.com>2016-05-22 14:11:06 +0800
committerErol Fornoles <erol.fornoles@gmail.com>2016-05-24 19:04:38 +0800
commitf5c0c7ffa09c3e29a6ba361d927f6c45f49d6425 (patch)
tree268f424de894fb899ab4b428b9757c4fbc0c90d6
parent61483b18bcbfaa054113a67f40515c7bf3e892b2 (diff)
downloadrails-f5c0c7ffa09c3e29a6ba361d927f6c45f49d6425.tar.gz
rails-f5c0c7ffa09c3e29a6ba361d927f6c45f49d6425.tar.bz2
rails-f5c0c7ffa09c3e29a6ba361d927f6c45f49d6425.zip
Introduce new ActiveRecord transaction error classes
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb5
-rw-r--r--activerecord/lib/active_record/errors.rb14
-rw-r--r--activerecord/test/cases/adapters/mysql2/transaction_test.rb33
-rw-r--r--activerecord/test/cases/adapters/postgresql/transaction_test.rb29
5 files changed, 57 insertions, 26 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 44b4b547f3..17aa4000c7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -742,7 +742,7 @@ module ActiveRecord
when ER_DATA_TOO_LONG
ValueTooLong.new(message)
when ER_LOCK_DEADLOCK
- TransactionSerializationError.new(message)
+ DeadlockDetected.new(message)
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index ddfc560747..c9d436e19f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -407,6 +407,7 @@ module ActiveRecord
FOREIGN_KEY_VIOLATION = "23503"
UNIQUE_VIOLATION = "23505"
SERIALIZATION_FAILURE = "40001"
+ DEADLOCK_DETECTED = "40P01"
def translate_exception(exception, message)
return exception unless exception.respond_to?(:result)
@@ -419,7 +420,9 @@ module ActiveRecord
when VALUE_LIMIT_VIOLATION
ValueTooLong.new(message)
when SERIALIZATION_FAILURE
- TransactionSerializationError.new(message)
+ SerializationFailure.new(message)
+ when DEADLOCK_DETECTED
+ DeadlockDetected.new(message)
else
super
end
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index 38e4fbec8b..a317fb4d44 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -285,14 +285,24 @@ module ActiveRecord
class TransactionIsolationError < ActiveRecordError
end
- # TransactionSerializationError will be raised when a transaction is rolled
+ # TransactionRollbackError will be raised when a transaction is rolled
# back by the database due to a serialization failure or a deadlock.
#
# See the following:
#
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
# * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
- class TransactionSerializationError < ActiveRecordError
+ class TransactionRollbackError < ActiveRecordError
+ end
+
+ # SerializationFailure will be raised when a transaction is rolled
+ # back by the database due to a serialization failure.
+ class SerializationFailure < TransactionRollbackError
+ end
+
+ # DeadlockDetected will be raised when a transaction is rolled
+ # back by the database when a deadlock is encountered.
+ class DeadlockDetected < TransactionRollbackError
end
# IrreversibleOrderError is raised when a relation's order is too complex for
diff --git a/activerecord/test/cases/adapters/mysql2/transaction_test.rb b/activerecord/test/cases/adapters/mysql2/transaction_test.rb
index 0e37c70e5c..1a88b9cbca 100644
--- a/activerecord/test/cases/adapters/mysql2/transaction_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/transaction_test.rb
@@ -27,32 +27,25 @@ module ActiveRecord
@connection.drop_table 'samples', if_exists: true
end
- test "raises error when a serialization failure occurs" do
- assert_raises(ActiveRecord::TransactionSerializationError) do
- thread = Thread.new do
- Sample.transaction isolation: :serializable do
- Sample.delete_all
-
- 10.times do |i|
- sleep 0.1
+ test "raises DeadlockDetected when a deadlock is encountered" do
+ assert_raises(ActiveRecord::DeadlockDetected) do
+ s1 = Sample.create value: 1
+ s2 = Sample.create value: 2
- Sample.create value: i
- end
+ thread = Thread.new do
+ Sample.transaction do
+ s1.lock!
+ sleep 1
+ s2.update_attributes value: 1
end
end
- sleep 0.1
-
- Sample.transaction isolation: :serializable do
- Sample.delete_all
-
- 10.times do |i|
- sleep 0.1
-
- Sample.create value: i
- end
+ sleep 0.5
+ Sample.transaction do
+ s2.lock!
sleep 1
+ s1.update_attributes value: 2
end
thread.join
diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
index e76705a802..87d1fffe19 100644
--- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
@@ -26,9 +26,9 @@ module ActiveRecord
@connection.drop_table 'samples', if_exists: true
end
- test "raises error when a serialization failure occurs" do
+ test "raises SerializationFailure when a serialization failure occurs" do
with_warning_suppression do
- assert_raises(ActiveRecord::TransactionSerializationError) do
+ assert_raises(ActiveRecord::SerializationFailure) do
thread = Thread.new do
Sample.transaction isolation: :serializable do
Sample.delete_all
@@ -51,8 +51,33 @@ module ActiveRecord
Sample.create value: i
end
+ end
+
+ thread.join
+ end
+ end
+ end
+
+ test "raises DeadlockDetected when a deadlock is encountered" do
+ with_warning_suppression do
+ assert_raises(ActiveRecord::DeadlockDetected) do
+ s1 = Sample.create value: 1
+ s2 = Sample.create value: 2
+
+ thread = Thread.new do
+ Sample.transaction do
+ s1.lock!
+ sleep 1
+ s2.update_attributes value: 1
+ end
+ end
+
+ sleep 0.5
+ Sample.transaction do
+ s2.lock!
sleep 1
+ s1.update_attributes value: 2
end
thread.join