Skip to content

Commit

Permalink
Merge pull request #633 from artk0de/add-call-stacks-for-avoid
Browse files Browse the repository at this point in the history
Added CallStacks support for avoid eager loading
  • Loading branch information
flyerhzm authored Dec 9, 2022
2 parents 8e9671a + f2af761 commit ef33b38
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 10 deletions.
1 change: 1 addition & 0 deletions lib/bullet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def start_request
Thread.current[:bullet_impossible_objects] = Bullet::Registry::Object.new
Thread.current[:bullet_inversed_objects] = Bullet::Registry::Base.new
Thread.current[:bullet_eager_loadings] = Bullet::Registry::Association.new
Thread.current[:bullet_call_stacks] = Bullet::Registry::CallStack.new

Thread.current[:bullet_counter_possible_objects] ||= Bullet::Registry::Object.new
Thread.current[:bullet_counter_impossible_objects] ||= Bullet::Registry::Object.new
Expand Down
8 changes: 8 additions & 0 deletions lib/bullet/detector/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def add_object_associations(object, associations)
'Detector::Association#add_object_associations',
"object: #{object.bullet_key}, associations: #{associations}"
)
call_stacks.add(object.bullet_key)
object_associations.add(object.bullet_key, associations)
end

Expand All @@ -25,6 +26,7 @@ def add_call_object_associations(object, associations)
'Detector::Association#add_call_object_associations',
"object: #{object.bullet_key}, associations: #{associations}"
)
call_stacks.add(object.bullet_key)
call_object_associations.add(object.bullet_key, associations)
end

Expand Down Expand Up @@ -76,6 +78,12 @@ def inversed_objects
def eager_loadings
Thread.current[:bullet_eager_loadings]
end

# cal_stacks keeps stacktraces where querie-objects were called from.
# e.g. { 'Object:111' => [SomeProject/app/controllers/...] }
def call_stacks
Thread.current[:bullet_call_stacks]
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/bullet/detector/n_plus_one_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def call_association(object, associations)
)
if !excluded_stacktrace_path? && conditions_met?(object, associations)
Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
create_notification caller_in_project, object.class.to_s, associations
create_notification caller_in_project(object.bullet_key), object.class.to_s, associations
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/bullet/detector/unused_eager_loading.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def check_unused_preload_associations
next if object_association_diff.empty?

Bullet.debug('detect unused preload', "object: #{bullet_key}, associations: #{object_association_diff}")
create_notification(caller_in_project, bullet_key.bullet_class_name, object_association_diff)
create_notification(caller_in_project(bullet_key), bullet_key.bullet_class_name, object_association_diff)
end
end

Expand Down
1 change: 1 addition & 0 deletions lib/bullet/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ module Registry
autoload :Base, 'bullet/registry/base'
autoload :Object, 'bullet/registry/object'
autoload :Association, 'bullet/registry/association'
autoload :CallStack, 'bullet/registry/call_stack'
end
end
12 changes: 12 additions & 0 deletions lib/bullet/registry/call_stack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module Bullet
module Registry
class CallStack < Base
# remembers found association backtrace
def add(key)
@registry[key] = Thread.current.backtrace
end
end
end
end
18 changes: 10 additions & 8 deletions lib/bullet/stack_trace_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ module StackTraceFilter
VENDOR_PATH = '/vendor'
IS_RUBY_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')

def caller_in_project
# @param bullet_key[String] - use this to get stored call stack from call_stacks object.
def caller_in_project(bullet_key = nil)
vendor_root = Bullet.app_root + VENDOR_PATH
bundler_path = Bundler.bundle_path.to_s
select_caller_locations do |location|
select_caller_locations(bullet_key) do |location|
caller_path = location_as_path(location)
caller_path.include?(Bullet.app_root) && !caller_path.include?(vendor_root) &&
!caller_path.include?(bundler_path) || Bullet.stacktrace_includes.any? { |include_pattern|
Expand Down Expand Up @@ -50,15 +51,16 @@ def pattern_matches?(location, pattern)
end

def location_as_path(location)
return location if location.is_a?(String)

IS_RUBY_19 ? location : location.absolute_path.to_s
end

def select_caller_locations
if IS_RUBY_19
caller.select { |caller_path| yield caller_path }
else
caller_locations.select { |location| yield location }
end
def select_caller_locations(bullet_key = nil)
return caller.select { |caller_path| yield caller_path } if IS_RUBY_19

call_stack = bullet_key ? call_stacks[bullet_key] : caller_locations
call_stack.select { |location| yield location }
end
end
end
5 changes: 5 additions & 0 deletions spec/bullet/detector/unused_eager_loading_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ module Detector
expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
UnusedEagerLoading.check_unused_preload_associations
end

it 'should create call stack for notification' do
UnusedEagerLoading.add_object_associations(@post, :association)
expect(UnusedEagerLoading.send(:call_stacks).registry).not_to be_empty
end
end

context '.add_eager_loadings' do
Expand Down

0 comments on commit ef33b38

Please sign in to comment.