Skip to content

Commit beb07fb

Browse files
committed
Revert "Revert "Reduce allocations when running AR callbacks.""
This reverts commit bdc1d32. Before: Calculating ------------------------------------- 22.000 i/100ms ------------------------------------------------- 229.700 (± 0.4%) i/s - 1.166k Total Allocated Object: 9939 After: Calculating ------------------------------------- 24.000 i/100ms ------------------------------------------------- 246.443 (± 0.8%) i/s - 1.248k Total Allocated Object: 7939 ``` begin require 'bundler/inline' rescue LoadError => e $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' raise e end gemfile(true) do source 'https://rubygems.org' # gem 'rails', github: 'rails/rails', ref: 'bdc1d329d4eea823d07cf010064bd19c07099ff3' gem 'rails', github: 'rails/rails', ref: 'd2876141d08341ec67cf6a11a073d1acfb920de7' gem 'arel', github: 'rails/arel' gem 'sqlite3' gem 'benchmark-ips' end require 'active_record' require 'benchmark/ips' ActiveRecord::Base.establish_connection('sqlite3::memory:') ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name, :email t.boolean :admin t.timestamps null: false end end class User < ActiveRecord::Base default_scope { where(admin: true) } end admin = true 1000.times do attributes = { name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com", admin: admin } User.create!(attributes) admin = !admin end GC.disable Benchmark.ips(5, 3) do |x| x.report { User.all.to_a } end key = if RUBY_VERSION < '2.2' :total_allocated_object else :total_allocated_objects end before = GC.stat[key] User.all.to_a after = GC.stat[key] puts "Total Allocated Object: #{after - before}" ```
1 parent 794252d commit beb07fb

File tree

8 files changed

+32
-23
lines changed

8 files changed

+32
-23
lines changed

activemodel/lib/active_model/validations.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ def validate!(context = nil)
404404
protected
405405

406406
def run_validations! #:nodoc:
407-
run_callbacks :validate
407+
_run_validate_callbacks
408408
errors.empty?
409409
end
410410

activemodel/lib/active_model/validations/callbacks.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def after_validation(*args, &block)
109109

110110
# Overwrite run validations to include callbacks.
111111
def run_validations! #:nodoc:
112-
run_callbacks(:validation) { super }
112+
_run_validation_callbacks { super }
113113
end
114114
end
115115
end

activerecord/lib/active_record/associations/has_many_through_association.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def delete_records(records, method)
133133
if scope.klass.primary_key
134134
count = scope.destroy_all.length
135135
else
136-
scope.each { |record| record.run_callbacks :destroy }
136+
scope.each(&:_run_destroy_callbacks)
137137

138138
arel = scope.arel
139139

activerecord/lib/active_record/callbacks.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,24 +289,25 @@ module ClassMethods
289289
end
290290

291291
def destroy #:nodoc:
292-
run_callbacks(:destroy) { super }
292+
_run_destroy_callbacks { super }
293293
end
294294

295295
def touch(*) #:nodoc:
296-
run_callbacks(:touch) { super }
296+
_run_touch_callbacks { super }
297297
end
298298

299299
private
300+
300301
def create_or_update(*) #:nodoc:
301-
run_callbacks(:save) { super }
302+
_run_save_callbacks { super }
302303
end
303304

304305
def _create_record #:nodoc:
305-
run_callbacks(:create) { super }
306+
_run_create_callbacks { super }
306307
end
307308

308309
def _update_record(*) #:nodoc:
309-
run_callbacks(:update) { super }
310+
_run_update_callbacks { super }
310311
end
311312
end
312313
end

activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ def checkin(conn)
508508
synchronize do
509509
remove_connection_from_thread_cache conn
510510

511-
conn.run_callbacks :checkin do
511+
conn._run_checkin_callbacks do
512512
conn.expire
513513
end
514514

@@ -764,7 +764,7 @@ def checkout_new_connection
764764
end
765765

766766
def checkout_and_verify(c)
767-
c.run_callbacks :checkout do
767+
c._run_checkout_callbacks do
768768
c.verify!
769769
end
770770
c

activerecord/lib/active_record/core.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def initialize(attributes = nil)
303303
assign_attributes(attributes) if attributes
304304

305305
yield self if block_given?
306-
run_callbacks :initialize
306+
_run_initialize_callbacks
307307
end
308308

309309
# Initialize an empty model object from +coder+. +coder+ should be
@@ -330,8 +330,8 @@ def init_with(coder)
330330

331331
self.class.define_attribute_methods
332332

333-
run_callbacks :find
334-
run_callbacks :initialize
333+
_run_find_callbacks
334+
_run_initialize_callbacks
335335

336336
self
337337
end
@@ -367,7 +367,7 @@ def initialize_dup(other) # :nodoc:
367367
@attributes = @attributes.dup
368368
@attributes.reset(self.class.primary_key)
369369

370-
run_callbacks(:initialize)
370+
_run_initialize_callbacks
371371

372372
@new_record = true
373373
@destroyed = false

activerecord/lib/active_record/transactions.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ def rollback_active_record_state!
319319
end
320320

321321
def before_committed! # :nodoc:
322-
run_callbacks :before_commit_without_transaction_enrollment
323-
run_callbacks :before_commit
322+
_run_before_commit_without_transaction_enrollment_callbacks
323+
_run_before_commit_callbacks
324324
end
325325

326326
# Call the +after_commit+ callbacks.
@@ -329,8 +329,8 @@ def before_committed! # :nodoc:
329329
# but call it after the commit of a destroyed object.
330330
def committed!(should_run_callbacks: true) #:nodoc:
331331
if should_run_callbacks && destroyed? || persisted?
332-
run_callbacks :commit_without_transaction_enrollment
333-
run_callbacks :commit
332+
_run_commit_without_transaction_enrollment_callbacks
333+
_run_commit_callbacks
334334
end
335335
ensure
336336
force_clear_transaction_record_state
@@ -340,8 +340,8 @@ def committed!(should_run_callbacks: true) #:nodoc:
340340
# state should be rolled back to the beginning or just to the last savepoint.
341341
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
342342
if should_run_callbacks
343-
run_callbacks :rollback
344-
run_callbacks :rollback_without_transaction_enrollment
343+
_run_rollback_callbacks
344+
_run_rollback_without_transaction_enrollment_callbacks
345345
end
346346
ensure
347347
restore_transaction_record_state(force_restore_state)

activesupport/lib/active_support/callbacks.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ module Callbacks
8080
# save
8181
# end
8282
def run_callbacks(kind, &block)
83-
callbacks = send("_#{kind}_callbacks")
83+
send "_run_#{kind}_callbacks", &block
84+
end
85+
86+
private
8487

88+
def __run_callbacks__(callbacks, &block)
8589
if callbacks.empty?
8690
yield if block_given?
8791
else
@@ -91,8 +95,6 @@ def run_callbacks(kind, &block)
9195
end
9296
end
9397

94-
private
95-
9698
# A hook invoked every time a before callback is halted.
9799
# This can be overridden in AS::Callback implementors in order
98100
# to provide better debugging/logging.
@@ -806,6 +808,12 @@ def define_callbacks(*names)
806808
names.each do |name|
807809
class_attribute "_#{name}_callbacks"
808810
set_callbacks name, CallbackChain.new(name, options)
811+
812+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
813+
def _run_#{name}_callbacks(&block)
814+
__run_callbacks__(_#{name}_callbacks, &block)
815+
end
816+
RUBY
809817
end
810818
end
811819

0 commit comments

Comments
 (0)