diff options
author | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2016-08-03 07:05:22 -0300 |
---|---|---|
committer | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2016-08-03 07:05:22 -0300 |
commit | fac9938b917f3417a19775d1c6905123fc402256 (patch) | |
tree | d8efc9958372769cde477dc70f613c044cdb11fc /activerecord | |
parent | 8ada07b2b8d63c3379facb5d81485b5fdeafaceb (diff) | |
parent | f5c0c7ffa09c3e29a6ba361d927f6c45f49d6425 (diff) | |
download | rails-fac9938b917f3417a19775d1c6905123fc402256.tar.gz rails-fac9938b917f3417a19775d1c6905123fc402256.tar.bz2 rails-fac9938b917f3417a19775d1c6905123fc402256.zip |
Merge pull request #25107 from Erol/introduce-new-ar-transaction-error-classes
Introduce new ActiveRecord transaction error classes
Closes #26018
Diffstat (limited to 'activerecord')
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 610d78245f..acc21866f1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -753,7 +753,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 61a980fda9..e213c991c8 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 26146dbce7..3f75ce4099 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 < StatementInvalid + class TransactionRollbackError < StatementInvalid + 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 |