From f9326e567ca0d9fe957e70de821a0a644b0b441d Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 21 Apr 2019 21:54:32 +0900 Subject: Avoid method call if `@transaction_state` is not finalized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Method call in Ruby is a bit slow. This makes attribute access 10% faster by avoiding method call (`sync_with_transaction_state`). Before (96cf7e0e): ``` Warming up -------------------------------------- user.id 131.291k i/100ms user['id'] 91.786k i/100ms user.name 151.605k i/100ms user['name'] 92.664k i/100ms user.changed? 17.772k i/100ms user.saved_changes? 23.909k i/100ms Calculating ------------------------------------- user.id 1.988M (± 7.0%) i/s - 9.978M in 5.051474s user['id'] 1.155M (± 5.8%) i/s - 5.783M in 5.022672s user.name 2.450M (± 4.3%) i/s - 12.280M in 5.021234s user['name'] 1.263M (± 2.1%) i/s - 6.394M in 5.066638s user.changed? 175.070k (±13.3%) i/s - 853.056k in 5.011555s user.saved_changes? 259.114k (±11.8%) i/s - 1.267M in 5.001260s ``` After (this change): ``` Warming up -------------------------------------- user.id 137.625k i/100ms user['id'] 96.054k i/100ms user.name 156.379k i/100ms user['name'] 94.795k i/100ms user.changed? 18.172k i/100ms user.saved_changes? 24.337k i/100ms Calculating ------------------------------------- user.id 2.201M (± 0.5%) i/s - 11.010M in 5.002955s user['id'] 1.320M (± 1.0%) i/s - 6.628M in 5.021293s user.name 2.677M (± 1.6%) i/s - 13.449M in 5.024399s user['name'] 1.314M (± 1.8%) i/s - 6.636M in 5.051444s user.changed? 190.588k (±11.1%) i/s - 944.944k in 5.065848s user.saved_changes? 262.782k (±12.1%) i/s - 1.290M in 5.028080s ``` --- .../lib/active_record/attribute_methods/before_type_cast.rb | 6 +++--- activerecord/lib/active_record/attribute_methods/dirty.rb | 4 ++-- activerecord/lib/active_record/attribute_methods/read.rb | 2 +- activerecord/lib/active_record/attribute_methods/write.rb | 4 ++-- activerecord/lib/active_record/core.rb | 2 +- activerecord/lib/active_record/persistence.rb | 6 +++--- activerecord/lib/active_record/transactions.rb | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index affcf2a4db..3d917ec9b1 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -46,7 +46,7 @@ module ActiveRecord # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21" # task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21" def read_attribute_before_type_cast(attr_name) - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes[attr_name.to_s].value_before_type_cast end @@ -61,7 +61,7 @@ module ActiveRecord # task.attributes_before_type_cast # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil} def attributes_before_type_cast - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes.values_before_type_cast end @@ -73,7 +73,7 @@ module ActiveRecord end def attribute_came_from_user?(attribute_name) - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes[attribute_name].came_from_user? end end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 942fe48635..444568562b 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -157,12 +157,12 @@ module ActiveRecord private def mutations_from_database - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? super end def mutations_before_last_save - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? super end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 84b1ec2fea..409a150e56 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -39,7 +39,7 @@ module ActiveRecord # This method exists to avoid the expensive primary_key check internally, without # breaking compatibility with the read_attribute API def _read_attribute(attr_name, &block) # :nodoc - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes.fetch_value(attr_name.to_s, &block) end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index d1cfe43bb2..6a21643884 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -43,14 +43,14 @@ module ActiveRecord # This method exists to avoid the expensive primary_key check internally, without # breaking compatibility with the write_attribute API def _write_attribute(attr_name, value) # :nodoc: - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes.write_from_user(attr_name.to_s, value) value end private def write_attribute_without_type_cast(attr_name, value) - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes.write_cast_value(attr_name.to_s, value) value end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 04b21b4d00..3d4457f39f 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -466,7 +466,7 @@ module ActiveRecord # Returns +true+ if the attributes hash has been frozen. def frozen? - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @attributes.frozen? end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 8bade8cd28..bd572486c8 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -423,20 +423,20 @@ module ActiveRecord # Returns true if this object hasn't been saved yet -- that is, a record # for the object doesn't exist in the database yet; otherwise, returns false. def new_record? - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @new_record end # Returns true if this object has been destroyed, otherwise returns false. def destroyed? - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @destroyed end # Returns true if the record is persisted, i.e. it's not a new record and it was # not destroyed, otherwise returns false. def persisted? - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? !(@new_record || @destroyed) end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index ea288456b9..9f52734e00 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -365,7 +365,7 @@ module ActiveRecord status = nil self.class.transaction do unless has_transactional_callbacks? - sync_with_transaction_state + sync_with_transaction_state if @transaction_state&.finalized? @transaction_state = self.class.connection.transaction_state end remember_transaction_record_state @@ -479,7 +479,7 @@ module ActiveRecord # the TransactionState, and rolls back or commits the Active Record object # as appropriate. def sync_with_transaction_state - if (transaction_state = @transaction_state)&.finalized? + if transaction_state = @transaction_state if transaction_state.fully_committed? force_clear_transaction_record_state elsif transaction_state.committed? -- cgit v1.2.3