Skip to content

Commit 68a7f91

Browse files
committed
Initial test case for deferred preloading; Log per query Socket and Thread identifier
1 parent 755718b commit 68a7f91

8 files changed

Lines changed: 71 additions & 21 deletions

File tree

lib/active_record/connection_adapters/mysqlplus_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def execute(sql, name = nil, skip_logging = false) #:nodoc:
3636
if skip_logging
3737
@connection.c_async_query( sql )
3838
else
39-
log("(Socket #{socket.to_s}) #{sql}",name) do
39+
log("(Socket #{socket.to_s}, Thread #{Thread.current.object_id.to_s}) #{sql}",name) do
4040
@connection.c_async_query( sql )
4141
end
4242
end

lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class << self
77
def install!
88
ActiveRecord::Base.send :extend, SingletonMethods
99
ar_eigenclass::VALID_FIND_OPTIONS << :defer
10-
alias_deferred :find, :find_by_sql, :preload_associations
10+
alias_deferred :find, :find_by_sql, :preload_associations, :find_every
1111
end
1212

1313
private
@@ -35,13 +35,26 @@ module SingletonMethods
3535
# connection.
3636
#
3737
# ....
38-
# Record.find(:first, :include => [:other. :another], :defer => true)
38+
# Record.find(:first, :include => [:other, :another], :defer => true)
3939
# ....
4040
#
4141
def preload_associations_with_defer(records, associations, preload_options={})
4242
if preload_options.key?(:defer)
43-
ActiveRecord::Deferrable::Result.new do
44-
preload_associations_without_defer(records, associations, preload_options)
43+
records = [records].flatten.compact.uniq
44+
return if records.empty?
45+
case associations
46+
when Array then associations.each {|association| ActiveRecord::Deferrable::Result.new{ preload_associations(records, association, preload_options) } }
47+
when Symbol, String then ActiveRecord::Deferrable::Result.new{ preload_one_association(records, associations.to_sym, preload_options) }
48+
when Hash then
49+
associations.each do |parent, child|
50+
raise "parent must be an association name" unless parent.is_a?(String) || parent.is_a?(Symbol)
51+
preload_associations(records, parent, preload_options)
52+
reflection = reflections[parent]
53+
parents = records.map {|record| record.send(reflection.name)}.flatten.compact
54+
unless parents.empty?
55+
parents.first.class.preload_associations(parents, child)
56+
end
57+
end
4558
end
4659
else
4760
preload_associations_without_defer(records, associations, preload_options)
@@ -91,6 +104,22 @@ def with_deferred_scope( &block ) #:nodoc:
91104
with_scope( { :find => { :defer => true } }, :merge, &block )
92105
end
93106

107+
def find_every_with_defer(options) #:nodoc:
108+
include_associations = merge_includes(scope(:find, :include), options[:include])
109+
if include_associations.any? && references_eager_loaded_tables?(options)
110+
records = find_with_associations(options)
111+
else
112+
records = find_by_sql(construct_finder_sql(options))
113+
if include_associations.any?
114+
preload_associations(records, include_associations, options)
115+
end
116+
end
117+
118+
records.each { |record| record.readonly! } if options[:readonly]
119+
120+
records
121+
end
122+
94123
end
95124

96125
end

lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def initialize( &deferrable )
1616
#
1717
def defer!( deferrable )
1818
@result = Thread.new( deferrable ) do |deferrable|
19+
puts '*'
1920
begin
2021
deferrable.call
2122
rescue => exception

test/deferrable/macro_test.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
require "#{File.dirname(__FILE__)}/../helper"
2+
Mysqlplus::Test.prepare!
3+
4+
class MacroTest < ActiveSupport::TestCase
5+
6+
def test_should_be_able_to_find_records_in_a_background_thread
7+
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
8+
assert_equal MysqlUser.find(:first, :defer => true), MysqlUser.find(:first)
9+
assert_instance_of MysqlUser, MysqlUser.find(:first, :defer => true)
10+
end
11+
12+
def test_should_be_able_to_find_records_by_sql_background_thread
13+
ActiveRecord::Base.connection_pool.expects(:release_connection).once
14+
assert_equal MysqlUser.find_by_sql("SELECT * FROM mysql.user WHERE User = 'root'", true), MysqlUser.find(:all, :conditions => ['user.User = ?', 'root'])
15+
end
16+
17+
def test_should_be_able_to_preload_related_records_on_multiple_connections
18+
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
19+
assert_instance_of MysqlUser, MysqlUser.find( :first, :defer => true, :include => [:mysql_user_info])
20+
end
21+
22+
end
23+
24+
Thread.list.each{|t| t.join unless t == Thread.main }

test/deferrable_test.rb

Lines changed: 0 additions & 15 deletions
This file was deleted.

test/helper.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
require 'rubygems'
22
require 'active_support'
3+
require 'active_support/test_case'
34
require 'activerecord'
5+
46
ActiveRecord.load_all!
57

68
module Mysqlplus
@@ -32,7 +34,7 @@ def active_record_test_files
3234
end
3335

3436
def test_files
35-
glob( "#{File.dirname(__FILE__)}/*_test.rb" )
37+
glob( "#{File.dirname(__FILE__)}/**/*_test.rb" )
3638
end
3739

3840
private

test/models/mysql_user.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
class MysqlUser < ActiveRecord::Base
22
set_table_name 'user'
3+
set_primary_key :User
4+
5+
has_one :mysql_user_info, :class_name => 'MysqlUserInfo', :foreign_key => :User
36
end

test/models/mysql_user_info.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class MysqlUserInfo < ActiveRecord::Base
2+
set_table_name 'user_info'
3+
set_primary_key :User
4+
5+
belongs_to :mysql_user, :class_name => 'MysqlUser', :foreign_key => :User
6+
end

0 commit comments

Comments
 (0)