Skip to content

Commit

Permalink
Merge pull request #711 from ildarkayumov/use-thread-local-vars
Browse files Browse the repository at this point in the history
Store global objects into thread-local variables
  • Loading branch information
flyerhzm authored Aug 11, 2024
2 parents c86dbb2 + 6e8325c commit dddf7ab
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 33 deletions.
53 changes: 29 additions & 24 deletions lib/bullet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,42 +148,47 @@ def debug(title, message)
end

def start_request
Thread.current[:bullet_start] = true
Thread.current[:bullet_notification_collector] = Bullet::NotificationCollector.new

Thread.current[:bullet_object_associations] = Bullet::Registry::Base.new
Thread.current[:bullet_call_object_associations] = Bullet::Registry::Base.new
Thread.current[:bullet_possible_objects] = Bullet::Registry::Object.new
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.thread_variable_set(:bullet_start, true)
Thread.current.thread_variable_set(:bullet_notification_collector, Bullet::NotificationCollector.new)

Thread.current.thread_variable_set(:bullet_object_associations, Bullet::Registry::Base.new)
Thread.current.thread_variable_set(:bullet_call_object_associations, Bullet::Registry::Base.new)
Thread.current.thread_variable_set(:bullet_possible_objects, Bullet::Registry::Object.new)
Thread.current.thread_variable_set(:bullet_impossible_objects, Bullet::Registry::Object.new)
Thread.current.thread_variable_set(:bullet_inversed_objects, Bullet::Registry::Base.new)
Thread.current.thread_variable_set(:bullet_eager_loadings, Bullet::Registry::Association.new)
Thread.current.thread_variable_set(:bullet_call_stacks, Bullet::Registry::CallStack.new)

unless Thread.current.thread_variable_get(:bullet_counter_possible_objects)
Thread.current.thread_variable_set(:bullet_counter_possible_objects, Bullet::Registry::Object.new)
end

Thread.current[:bullet_counter_possible_objects] ||= Bullet::Registry::Object.new
Thread.current[:bullet_counter_impossible_objects] ||= Bullet::Registry::Object.new
unless Thread.current.thread_variable_get(:bullet_counter_impossible_objects)
Thread.current.thread_variable_set(:bullet_counter_impossible_objects, Bullet::Registry::Object.new)
end
end

def end_request
Thread.current[:bullet_start] = nil
Thread.current[:bullet_notification_collector] = nil
Thread.current.thread_variable_set(:bullet_start, nil)
Thread.current.thread_variable_set(:bullet_notification_collector, nil)

Thread.current[:bullet_object_associations] = nil
Thread.current[:bullet_call_object_associations] = nil
Thread.current[:bullet_possible_objects] = nil
Thread.current[:bullet_impossible_objects] = nil
Thread.current[:bullet_inversed_objects] = nil
Thread.current[:bullet_eager_loadings] = nil
Thread.current.thread_variable_set(:bullet_object_associations, nil)
Thread.current.thread_variable_set(:bullet_call_object_associations, nil)
Thread.current.thread_variable_set(:bullet_possible_objects, nil)
Thread.current.thread_variable_set(:bullet_impossible_objects, nil)
Thread.current.thread_variable_set(:bullet_inversed_objects, nil)
Thread.current.thread_variable_set(:bullet_eager_loadings, nil)

Thread.current[:bullet_counter_possible_objects] = nil
Thread.current[:bullet_counter_impossible_objects] = nil
Thread.current.thread_variable_set(:bullet_counter_possible_objects, nil)
Thread.current.thread_variable_set(:bullet_counter_impossible_objects, nil)
end

def start?
enable? && Thread.current[:bullet_start]
enable? && Thread.current.thread_variable_get(:bullet_start)
end

def notification_collector
Thread.current[:bullet_notification_collector]
Thread.current.thread_variable_get(:bullet_notification_collector)
end

def notification?
Expand Down
14 changes: 7 additions & 7 deletions lib/bullet/detector/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def add_call_object_associations(object, associations)
# that the objects may cause N+1 query.
# e.g. { Post => ["Post:1", "Post:2"] }
def possible_objects
Thread.current[:bullet_possible_objects]
Thread.current.thread_variable_get(:bullet_possible_objects)
end

# impossible_objects keep the class to objects relationships
Expand All @@ -43,7 +43,7 @@ def possible_objects
# if find collection returns only one object, then the object is impossible object,
# impossible_objects are used to avoid treating 1+1 query to N+1 query.
def impossible_objects
Thread.current[:bullet_impossible_objects]
Thread.current.thread_variable_get(:bullet_impossible_objects)
end

private
Expand All @@ -54,35 +54,35 @@ def impossible_objects
# the object_associations keep all associations that may be or may no be
# unpreload associations or unused preload associations.
def object_associations
Thread.current[:bullet_object_associations]
Thread.current.thread_variable_get(:bullet_object_associations)
end

# call_object_associations keep the object relationships
# that object.associations is called.
# e.g. { "Post:1" => [:comments] }
# they are used to detect unused preload associations.
def call_object_associations
Thread.current[:bullet_call_object_associations]
Thread.current.thread_variable_get(:bullet_call_object_associations)
end

# inversed_objects keeps object relationships
# that association is inversed.
# e.g. { "Comment:1" => ["post"] }
def inversed_objects
Thread.current[:bullet_inversed_objects]
Thread.current.thread_variable_get(:bullet_inversed_objects)
end

# eager_loadings keep the object relationships
# that the associations are preloaded by find :include.
# e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
def eager_loadings
Thread.current[:bullet_eager_loadings]
Thread.current.thread_variable_get(: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]
Thread.current.thread_variable_get(:bullet_call_stacks)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/bullet/detector/counter_cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ def conditions_met?(object, _associations)
end

def possible_objects
Thread.current[:bullet_counter_possible_objects]
Thread.current.thread_variable_get(:bullet_counter_possible_objects)
end

def impossible_objects
Thread.current[:bullet_counter_impossible_objects]
Thread.current.thread_variable_get(:bullet_counter_impossible_objects)
end

private
Expand Down
14 changes: 14 additions & 0 deletions spec/integration/active_record/association_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@

expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
end

context 'inside Fiber' do
it 'should detect non preload post => comments' do
fiber = Fiber.new do
Post.all.each { |post| post.comments.map(&:name) }
end
fiber.resume

Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations

expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
end
end
end

context 'category => posts => comments' do
Expand Down

0 comments on commit dddf7ab

Please sign in to comment.