Skip to content

Commit

Permalink
Merge pull request #729 from vprigent/reduce-mem-allocations
Browse files Browse the repository at this point in the history
Reduce mem allocations
  • Loading branch information
flyerhzm authored Jan 25, 2025
2 parents a769a08 + aa2158f commit f475e37
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:
ruby-version: 2.7
bundler: 1
bundler-cache: true
- name: Breakpoint if tests failed
if: failure()
uses: namespacelabs/breakpoint-action@v0
with:
duration: 30m
- name: Run tests
run: bundle exec rake
test_rails_5:
Expand Down
2 changes: 1 addition & 1 deletion lib/bullet/detector/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def eager_loadings
Thread.current.thread_variable_get(:bullet_eager_loadings)
end

# cal_stacks keeps stacktraces where querie-objects were called from.
# call_stacks keeps stacktraces where querie-objects were called from.
# e.g. { 'Object:111' => [SomeProject/app/controllers/...] }
def call_stacks
Thread.current.thread_variable_get(:bullet_call_stacks)
Expand Down
11 changes: 6 additions & 5 deletions lib/bullet/detector/n_plus_one_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,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.bullet_key), object.class.to_s, associations
create_notification(caller_in_project(object.bullet_key), object.class.to_s, associations)
end
end

Expand All @@ -38,16 +38,17 @@ def add_possible_objects(object_or_objects)
objects = Array.wrap(object_or_objects)
class_names_match_regex = true
primary_key_values_are_empty = true
keys_joined = ""
objects.each do |obj|

keys_joined = objects.map do |obj|
unless obj.class.name =~ /^HABTM_/
class_names_match_regex = false
end
unless obj.bullet_primary_key_value.nil?
primary_key_values_are_empty = false
end
keys_joined += "#{(keys_joined.empty? ? '' : ', ')}#{obj.bullet_key}"
end
obj.bullet_key
end.join(", ")

unless class_names_match_regex || primary_key_values_are_empty
Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{keys_joined}")
objects.each { |object| possible_objects.add object.bullet_key }
Expand Down
20 changes: 9 additions & 11 deletions lib/bullet/ext/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ module Bullet
module Ext
module Object
refine ::Object do
attr_writer :bullet_key, :bullet_primary_key_value

def bullet_key
"#{self.class}:#{bullet_primary_key_value}"
@bullet_key ||= "#{self.class}:#{bullet_primary_key_value}"
end

def bullet_primary_key_value
return if respond_to?(:persisted?) && !persisted?

if self.class.respond_to?(:primary_keys) && self.class.primary_keys
primary_key = self.class.primary_keys
elsif self.class.respond_to?(:primary_key) && self.class.primary_key
primary_key = self.class.primary_key
else
primary_key = :id
end
@bullet_primary_key_value ||= begin
return if respond_to?(:persisted?) && !persisted?

bullet_join_potential_composite_primary_key(primary_key)
primary_key = self.class.try(:primary_keys) || self.class.try(:primary_key) || :id

bullet_join_potential_composite_primary_key(primary_key)
end
end

private
Expand Down
3 changes: 2 additions & 1 deletion lib/bullet/ext/string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module Ext
module String
refine ::String do
def bullet_class_name
sub(/:[^:]*?$/, '')
last_colon = self.rindex(':')
last_colon ? self[0...last_colon].dup : self.dup
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions lib/bullet/stack_trace_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
module Bullet
module StackTraceFilter
VENDOR_PATH = '/vendor'
IS_RUBY_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')

# @param bullet_key[String] - use this to get stored call stack from call_stacks object.
def caller_in_project(bullet_key = nil)
Expand Down Expand Up @@ -56,13 +55,12 @@ def pattern_matches?(location, pattern)
def location_as_path(location)
return location if location.is_a?(String)

IS_RUBY_19 ? location : location.absolute_path.to_s
location.absolute_path.to_s
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
Expand Down
8 changes: 3 additions & 5 deletions perf/benchmark.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ class User < ActiveRecord::Base

# create database bullet_benchmark;
ActiveRecord::Base.establish_connection(
adapter: 'mysql2',
database: 'bullet_benchmark',
server: '/tmp/mysql.socket',
username: 'root'
adapter: 'sqlite3',
database: 'bullet_benchmark'
)

ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
Expand Down Expand Up @@ -81,7 +79,7 @@ class User < ActiveRecord::Base
bm.report("Querying & Iterating #{posts_size} Posts with #{comments_size} Comments and #{users_size} Users") do
10.times do
Bullet.start_request
Post.select('SQL_NO_CACHE *').includes(:user, comments: :user).each do |p|
Post.includes(:user, comments: :user).each do |p|
p.title
p.user.name
p.comments.each do |c|
Expand Down
1 change: 1 addition & 0 deletions spec/bullet/detector/n_plus_one_query_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'spec_helper'
require 'ostruct'

using Bullet::Ext::Object

Expand Down
6 changes: 3 additions & 3 deletions spec/bullet/ext/object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@
end

it 'should return primary key value' do
post = Post.first
Post.primary_key = 'name'
post = Post.first
expect(post.bullet_primary_key_value).to eq(post.name)
Post.primary_key = 'id'
end

it 'should return value for multiple primary keys from the composite_primary_key gem' do
post = Post.first
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
post = Post.first
expect(post.bullet_primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
end

it 'should return value for multiple primary keys from ActiveRecord 7.1' do
post = Post.first
allow(Post).to receive(:primary_key).and_return(%i[category_id writer_id])
post = Post.first
expect(post.bullet_primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
end

Expand Down

0 comments on commit f475e37

Please sign in to comment.