methodmissing-mysqlplus_adapter 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +43 -3
- data/VERSION.yml +1 -1
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb +1 -0
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb +1 -1
- data/test/connection_pool_test.rb +20 -0
- data/test/deferrable/macro_test.rb +4 -4
- data/test/deferrable/result_test.rb +35 -0
- metadata +4 -2
data/README.textile
CHANGED
@@ -14,6 +14,8 @@ Grab mysqlplus ....
|
|
14
14
|
|
15
15
|
... then update config/database.yml
|
16
16
|
|
17
|
+
<pre>
|
18
|
+
<code>
|
17
19
|
production:
|
18
20
|
adapter: mysqlplus
|
19
21
|
database: myapp_production
|
@@ -21,6 +23,8 @@ Grab mysqlplus ....
|
|
21
23
|
password:
|
22
24
|
host: localhost
|
23
25
|
pool: 10
|
26
|
+
</code>
|
27
|
+
</pre>
|
24
28
|
|
25
29
|
h2. Why Bother ?
|
26
30
|
|
@@ -30,7 +34,11 @@ The ever popular "mysql ruby":http://www.tmtm.org/en/mysql/ruby/ do *not* schedu
|
|
30
34
|
|
31
35
|
Rails since release 2.2 support connection pooling and Thread safety ( at the framework level mind you, plugins, gems and user code aside ) through :
|
32
36
|
|
37
|
+
<pre>
|
38
|
+
<code>
|
33
39
|
config.threadsafe!
|
40
|
+
</code>
|
41
|
+
</pre>
|
34
42
|
|
35
43
|
This configuration hook removes the global Dispatcher lock and yields one connection from the pool per request / response cycle.
|
36
44
|
|
@@ -40,6 +48,8 @@ h2. Configuration Options
|
|
40
48
|
|
41
49
|
An additional connection specification element, *warmup* is available that attempts to establish the pooled connections in advance.This may be useful for high traffic environments where it makes sense to setup connections when bouncing the App and not let initial incoming requests be hogged with Mysql connection overheads.
|
42
50
|
|
51
|
+
<pre>
|
52
|
+
<code>
|
43
53
|
production:
|
44
54
|
adapter: mysqlplus
|
45
55
|
database: myapp_production
|
@@ -48,22 +58,34 @@ An additional connection specification element, *warmup* is available that attem
|
|
48
58
|
host: localhost
|
49
59
|
pool: 10
|
50
60
|
warmup: true
|
61
|
+
</code>
|
62
|
+
</pre>
|
51
63
|
|
52
64
|
h3. Deferrable Results
|
53
65
|
|
54
66
|
Deferred results simulate lazy loading in a background Thread, through another Mysql connection, other than the one the current Thread has acquired.This type of workflow assumes a decent Connection Pool size of 5 to 10 connections.
|
55
67
|
|
68
|
+
<pre>
|
69
|
+
<code>
|
56
70
|
# Immediate yield control back to the current Thread as the query is pushed to the background.
|
57
71
|
# Yields an instance of ActiveRecord::Deferrable::Result
|
58
72
|
#
|
59
73
|
Post.find( :first, :defer => true )
|
74
|
+
</code>
|
75
|
+
</pre>
|
60
76
|
|
61
77
|
A deferred result blocks when any method's invoked on the result set right away.
|
62
78
|
|
79
|
+
<pre>
|
80
|
+
<code>
|
63
81
|
Post.find( :first, :defer => true ).title
|
82
|
+
</code>
|
83
|
+
</pre>
|
64
84
|
|
65
85
|
This concept is quite useful in an MVC context, allowing the controller to fetch results, defer fetching them to the background and reference them in the view, allowing an undefined period / time slice during which rendering, template setup etc. may occur.
|
66
86
|
|
87
|
+
<pre>
|
88
|
+
<code>
|
67
89
|
class PostsController
|
68
90
|
|
69
91
|
def index
|
@@ -73,17 +95,37 @@ This concept is quite useful in an MVC context, allowing the controller to fetch
|
|
73
95
|
end
|
74
96
|
|
75
97
|
end
|
98
|
+
</code>
|
99
|
+
</pre>
|
76
100
|
|
77
101
|
Since ActiveRecord 2.1 preloading favors multiple efficient queries to cumbersome and mostly slow JOINs.Those secondary queries can easily be pushed down different connections.
|
78
102
|
|
103
|
+
<pre>
|
104
|
+
<code>
|
79
105
|
# Use 3 connections from the pool : 1 x Post, 1 x Comment and 1 x Vote
|
80
106
|
#
|
81
107
|
Post.find(:all, :limit => 10, :include => [:comments, :votes], :defer => true )
|
108
|
+
</code>
|
109
|
+
</pre>
|
82
110
|
|
83
111
|
h2. Garbage Collection
|
84
112
|
|
85
113
|
There's some experimental GC patches "available":http://github.com/oldmoe/mysqlplus/tree/with_async_validation - the mysql ruby gem forces GC every 20 queries, that's a guaranteed GC cycle every 5th request for a request with a 4 query overhead.This adapter will automatically detect the presence of those patches and disable the forced GC runs.
|
86
114
|
|
115
|
+
<pre>
|
116
|
+
<code>
|
117
|
+
methodmissing:mysqlplus lourens$ ruby test/gc_benchmark.rb
|
118
|
+
Rehearsal ----------------------------------------------
|
119
|
+
With GC 0.440000 0.020000 0.460000 ( 0.741424)
|
120
|
+
Without GC 0.040000 0.030000 0.070000 ( 0.327787)
|
121
|
+
------------------------------------- total: 0.530000sec
|
122
|
+
|
123
|
+
user system total real
|
124
|
+
With GC 0.430000 0.030000 0.460000 ( 0.725934)
|
125
|
+
Without GC 0.040000 0.010000 0.050000 ( 0.311233)
|
126
|
+
</code>
|
127
|
+
</pre>
|
128
|
+
|
87
129
|
h2. Stability
|
88
130
|
|
89
131
|
In (pre)-production use at a handful of sites and the test suite is designed to run against the existing ActiveRecord suite.
|
@@ -92,6 +134,4 @@ h2. TODO
|
|
92
134
|
|
93
135
|
* Experiment with turning off query_with_result for certain queries.
|
94
136
|
|
95
|
-
* Deferred inserts / updates - *dangerous* INSERT DELAYED for Innodb
|
96
|
-
|
97
|
-
* 1.9 compatibility testing
|
137
|
+
* Deferred inserts / updates - *dangerous* INSERT DELAYED for Innodb
|
data/VERSION.yml
CHANGED
@@ -7,6 +7,7 @@ module ActiveRecord
|
|
7
7
|
def install!
|
8
8
|
ActiveRecord::Base.send :extend, SingletonMethods
|
9
9
|
ar_eigenclass::VALID_FIND_OPTIONS << :defer
|
10
|
+
ActiveRecord::Calculations::CALCULATIONS_OPTIONS << :defer
|
10
11
|
alias_deferred :find, :find_by_sql, :preload_associations, :find_every
|
11
12
|
end
|
12
13
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/helper"
|
2
|
+
|
3
|
+
Mysqlplus::Test.prepare!
|
4
|
+
|
5
|
+
class ConnectionPoolTest < ActiveSupport::TestCase
|
6
|
+
|
7
|
+
def teardown
|
8
|
+
ActiveRecord::Base.clear_all_connections!
|
9
|
+
ActiveRecord::Base.establish_connection( Mysqlplus::Test::CONNECTION_SPEC )
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should not establish connections in a lazy manner when warmed up" do
|
14
|
+
ActiveRecord::Base.connection_pool.expects(:checkout_new_connection).never
|
15
|
+
5.times do
|
16
|
+
ActiveRecord::Base.connection_pool.checkout
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -10,18 +10,18 @@ class MacroTest < ActiveSupport::TestCase
|
|
10
10
|
super
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
test "should be able to find records in a background thread" do
|
14
14
|
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
|
15
15
|
assert_equal MysqlUser.find(:first, :defer => true), MysqlUser.find(:first)
|
16
16
|
assert_instance_of MysqlUser, MysqlUser.find(:first, :defer => true)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
test "should be able to find records by sql background thread" do
|
20
20
|
ActiveRecord::Base.connection_pool.expects(:release_connection).once
|
21
21
|
assert_equal MysqlUser.find_by_sql("SELECT * FROM mysql.user WHERE User = 'root'", true), MysqlUser.find(:all, :conditions => ['user.User = ?', 'root'])
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
test "should be able to preload related records on multiple connections" do
|
25
25
|
ActiveRecord::Base.connection_pool.expects(:release_connection).twice
|
26
26
|
assert_instance_of MysqlUser, MysqlUser.find( :first, :defer => true, :include => :mysql_user_info)
|
27
27
|
sleep(0.5)
|
@@ -29,4 +29,4 @@ class MacroTest < ActiveSupport::TestCase
|
|
29
29
|
|
30
30
|
end
|
31
31
|
|
32
|
-
Thread.list.each{|t| t.join unless t == Thread.main }
|
32
|
+
Thread.list.each{|t| t.join unless t == Thread.main }
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../helper"
|
2
|
+
|
3
|
+
Mysqlplus::Test.prepare!
|
4
|
+
|
5
|
+
class ResultTest < ActiveSupport::TestCase
|
6
|
+
|
7
|
+
def teardown
|
8
|
+
ActiveRecord::Base.clear_all_connections!
|
9
|
+
ActiveRecord::Base.establish_connection( Mysqlplus::Test::CONNECTION_SPEC )
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
test "should be able to raise exceptions from the background Thread" do
|
14
|
+
assert_raises( StandardError ) do
|
15
|
+
ActiveRecord::Deferrable::Result.new do
|
16
|
+
raise StandardError
|
17
|
+
end.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should release the checked out connection for the background Thread at all times" do
|
22
|
+
ActiveRecord::Base.connection_pool.expects(:release_connection).once
|
23
|
+
ActiveRecord::Deferrable::Result.new do
|
24
|
+
raise StandardError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
test "should only block when an immediate result is required" do
|
29
|
+
ActiveRecord::Deferrable::Result.any_instance.expects(:validate!).never
|
30
|
+
ActiveRecord::Deferrable::Result.new do
|
31
|
+
sleep(5)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: methodmissing-mysqlplus_adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Lourens Naud\xC3\xA9"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -32,11 +32,13 @@ files:
|
|
32
32
|
- lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb
|
33
33
|
- lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb
|
34
34
|
- lib/active_record/connection_adapters/mysqlplus_adapter.rb
|
35
|
+
- test/connection_pool_test.rb
|
35
36
|
- test/connections
|
36
37
|
- test/connections/mysqlplus
|
37
38
|
- test/connections/mysqlplus/connection.rb
|
38
39
|
- test/deferrable
|
39
40
|
- test/deferrable/macro_test.rb
|
41
|
+
- test/deferrable/result_test.rb
|
40
42
|
- test/helper.rb
|
41
43
|
- test/models
|
42
44
|
- test/models/mysql_user.rb
|