Skip to content

Commit

Permalink
Significantly improve the performance of _read_attribute on JRuby
Browse files Browse the repository at this point in the history
The `&block` form is more than twice as fast as the manual form of
delegation (and is the code I'd rather write anyway). Unfortunately,
it's still twice as slow on MRI. However, this is enough of a hotspot to
justify giving JRuby special treatment.

I can't currently provide benchmarks in the context of Active Record,
since the JDBC adapters still aren't updated for 4.2, but the actual
work performed (assuming it's been read at least once already) will have
nearly the same performance characteristics as
https://gist.github.com/sgrif/b86832786551aaee74de.
  • Loading branch information
sgrif committed Feb 6, 2015
1 parent f4e8d67 commit ec6c98f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 4 deletions.
13 changes: 11 additions & 2 deletions activerecord/lib/active_record/attribute_methods/read.rb
Expand Up @@ -69,9 +69,18 @@ def read_attribute(attr_name, &block)

# This method exists to avoid the expensive primary_key check internally, without
# breaking compatibility with the read_attribute API
def _read_attribute(attr_name) # :nodoc:
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
if defined?(JRUBY_VERSION)
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
# https://github.com/jruby/jruby/pull/2562
def _read_attribute(attr_name, &block) # :nodoc
@attributes.fetch_value(attr_name.to_s, &block)
end
else
def _read_attribute(attr_name) # :nodoc:
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
end
end

alias :attribute :_read_attribute
private :attribute

Expand Down
12 changes: 10 additions & 2 deletions activerecord/lib/active_record/attribute_set.rb
Expand Up @@ -31,8 +31,16 @@ def keys
attributes.each_key.select { |name| self[name].initialized? }
end

def fetch_value(name)
self[name].value { |n| yield n if block_given? }
if defined?(JRUBY_VERSION)
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
# https://github.com/jruby/jruby/pull/2562
def fetch_value(name, &block)
self[name].value(&block)
end
else
def fetch_value(name)
self[name].value { |n| yield n if block_given? }
end
end

def write_from_database(name, value)
Expand Down

0 comments on commit ec6c98f

Please sign in to comment.