active_record_host_pool 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/active_record_host_pool.rb +1 -0
- data/lib/active_record_host_pool/connection_adapter_mixin.rb +24 -19
- data/lib/active_record_host_pool/connection_proxy.rb +3 -3
- data/lib/active_record_host_pool/pool_proxy.rb +13 -14
- data/lib/active_record_host_pool/version.rb +2 -1
- data/test/helper.rb +5 -4
- data/test/schema.rb +5 -3
- data/test/test_arhp.rb +49 -31
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 336ed17f3718db418f1f757a17a81fbb0e24da41
|
4
|
+
data.tar.gz: a3902cee8a77566286c728feb6511d397a80e5a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: def4a6ebe3b0069c2de4374c46b33c93d739511b0b8c893cc9e12797dc6fc94e449b9971b2214053c29e9572fc993ffdccec49a440266ee974d7976ec7adbc63
|
7
|
+
data.tar.gz: 520d09bd7360556db30a3a0289acc3b5defca029919998d521d9160cc00ada03029f7b8aab9ab209594cad77e70048e60417a5382b9588609da7964b6e0f42b9
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
['mysql_adapter', 'mysql2_adapter'].each do |adapter|
|
3
4
|
begin
|
4
5
|
require "active_record/connection_adapters/#{adapter}"
|
@@ -31,29 +32,30 @@ module ActiveRecordHostPool
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
def initialize(*)
|
36
|
+
@_cached_current_database = nil
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
34
40
|
def execute_with_switching(*args)
|
35
|
-
if _host_pool_current_database && !
|
41
|
+
if _host_pool_current_database && !_no_switch
|
36
42
|
_switch_connection
|
37
43
|
end
|
38
44
|
execute_without_switching(*args)
|
39
45
|
end
|
40
46
|
|
41
47
|
def drop_database_with_no_switching(*args)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@_no_switch = false
|
47
|
-
end
|
48
|
+
self._no_switch = true
|
49
|
+
drop_database_without_no_switching(*args)
|
50
|
+
ensure
|
51
|
+
self._no_switch = false
|
48
52
|
end
|
49
53
|
|
50
54
|
def create_database_with_no_switching(*args)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@_no_switch = false
|
56
|
-
end
|
55
|
+
self._no_switch = true
|
56
|
+
create_database_without_no_switching(*args)
|
57
|
+
ensure
|
58
|
+
self._no_switch = false
|
57
59
|
end
|
58
60
|
|
59
61
|
def disconnect_with_host_pooling!
|
@@ -64,8 +66,14 @@ module ActiveRecordHostPool
|
|
64
66
|
|
65
67
|
private
|
66
68
|
|
69
|
+
attr_accessor :_no_switch
|
70
|
+
|
67
71
|
def _switch_connection
|
68
|
-
if _host_pool_current_database &&
|
72
|
+
if _host_pool_current_database &&
|
73
|
+
(
|
74
|
+
(_host_pool_current_database != @_cached_current_database) ||
|
75
|
+
@connection.object_id != @_cached_connection_object_id
|
76
|
+
)
|
69
77
|
log("select_db #{_host_pool_current_database}", "SQL") do
|
70
78
|
clear_cache! if respond_to?(:clear_cache!)
|
71
79
|
raw_connection.select_db(_host_pool_current_database)
|
@@ -85,7 +93,6 @@ end
|
|
85
93
|
module ActiveRecord
|
86
94
|
module ConnectionAdapters
|
87
95
|
class ConnectionHandler
|
88
|
-
|
89
96
|
if ActiveRecord::VERSION::MAJOR == 5
|
90
97
|
if ActiveRecord::VERSION::MINOR == 0
|
91
98
|
def establish_connection(spec)
|
@@ -104,11 +111,11 @@ module ActiveRecord
|
|
104
111
|
|
105
112
|
def establish_connection(owner, spec)
|
106
113
|
@class_to_pool.clear
|
107
|
-
raise
|
114
|
+
raise "Anonymous class is not allowed." unless owner.name
|
108
115
|
owner_to_pool[owner.name] = ActiveRecordHostPool::PoolProxy.new(spec)
|
109
116
|
end
|
110
117
|
|
111
|
-
elsif ActiveRecord::VERSION::MAJOR == 3
|
118
|
+
elsif ActiveRecord::VERSION::MAJOR == 3
|
112
119
|
|
113
120
|
def establish_connection(owner, spec)
|
114
121
|
@connection_pools[spec] ||= ActiveRecordHostPool::PoolProxy.new(spec)
|
@@ -120,9 +127,7 @@ module ActiveRecord
|
|
120
127
|
def establish_connection(owner, spec)
|
121
128
|
@connection_pools[owner] = ActiveRecordHostPool::PoolProxy.new(spec)
|
122
129
|
end
|
123
|
-
|
124
130
|
end
|
125
|
-
|
126
131
|
end
|
127
132
|
end
|
128
133
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'delegate'
|
3
4
|
|
4
5
|
# the ConnectionProxy sits between user-code and a real connection and says "I expect to be on this database"
|
@@ -38,7 +39,7 @@ module ActiveRecordHostPool
|
|
38
39
|
__getobj__.respond_to?(m, include_private)
|
39
40
|
end
|
40
41
|
|
41
|
-
def private_methods(all=true)
|
42
|
+
def private_methods(all = true)
|
42
43
|
__getobj__.private_methods(all) | super
|
43
44
|
end
|
44
45
|
|
@@ -51,10 +52,9 @@ module ActiveRecordHostPool
|
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
55
|
+
|
54
56
|
def select(*args)
|
55
57
|
@cx.__send__(:select, *args)
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
59
|
-
|
60
|
-
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'delegate'
|
3
4
|
require 'active_record'
|
4
5
|
require 'active_record_host_pool/connection_adapter_mixin'
|
@@ -34,15 +35,13 @@ module ActiveRecordHostPool
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def connection(*args)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
_connection_pools.delete(_pool_key)
|
43
|
-
end
|
44
|
-
Kernel.raise(e)
|
38
|
+
real_connection = _connection_pool.connection(*args)
|
39
|
+
_connection_proxy_for(real_connection, @config[:database])
|
40
|
+
rescue Exception => e
|
41
|
+
if rescuable_errors.any? { |r| e.is_a?(r) }
|
42
|
+
_connection_pools.delete(_pool_key)
|
45
43
|
end
|
44
|
+
Kernel.raise(e)
|
46
45
|
end
|
47
46
|
|
48
47
|
# by the time we are patched into ActiveRecord, the current thread has already established
|
@@ -59,9 +58,9 @@ module ActiveRecordHostPool
|
|
59
58
|
|
60
59
|
def with_connection
|
61
60
|
cx = checkout
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
yield cx
|
62
|
+
ensure
|
63
|
+
checkin cx
|
65
64
|
end
|
66
65
|
|
67
66
|
def disconnect!
|
@@ -83,7 +82,8 @@ module ActiveRecordHostPool
|
|
83
82
|
_clear_connection_proxy_cache
|
84
83
|
end
|
85
84
|
|
86
|
-
|
85
|
+
private
|
86
|
+
|
87
87
|
def rescuable_errors
|
88
88
|
@rescuable_errors ||= begin
|
89
89
|
e = []
|
@@ -108,7 +108,7 @@ module ActiveRecordHostPool
|
|
108
108
|
@_pool_key ||= "#{@config[:host]}/#{@config[:port]}/#{@config[:socket]}/#{@config[:username]}/#{@config[:slave] && 'slave'}"
|
109
109
|
end
|
110
110
|
|
111
|
-
def _connection_pool(auto_create=true)
|
111
|
+
def _connection_pool(auto_create = true)
|
112
112
|
pool = _connection_pools[_pool_key]
|
113
113
|
if pool.nil? && auto_create
|
114
114
|
pool = _connection_pools[_pool_key] = ActiveRecord::ConnectionAdapters::ConnectionPool.new(@spec)
|
@@ -132,4 +132,3 @@ module ActiveRecordHostPool
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
135
|
-
|
data/test/helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'bundler/setup'
|
3
4
|
require 'minitest/autorun'
|
4
5
|
|
@@ -7,11 +8,11 @@ require 'logger'
|
|
7
8
|
require 'mocha/setup'
|
8
9
|
require 'phenix'
|
9
10
|
|
10
|
-
RAILS_ENV =
|
11
|
+
RAILS_ENV = 'test'
|
11
12
|
|
12
13
|
Minitest::Test = MiniTest::Unit::TestCase unless defined?(::Minitest::Test)
|
13
14
|
|
14
|
-
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) +
|
15
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/test.log')
|
15
16
|
|
16
17
|
Phenix.configure do |config|
|
17
18
|
config.skip_database = ->(name, conf) { name =~ /not_there/ || conf['username'] == 'travis' }
|
@@ -21,7 +22,7 @@ module ARHPTestSetup
|
|
21
22
|
private
|
22
23
|
|
23
24
|
def arhp_create_models
|
24
|
-
return if Object.const_defined?(
|
25
|
+
return if Object.const_defined?('Test1')
|
25
26
|
eval <<-EOL
|
26
27
|
class Test1 < ActiveRecord::Base
|
27
28
|
self.table_name = "tests"
|
@@ -56,6 +57,6 @@ module ARHPTestSetup
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def current_database(klass)
|
59
|
-
klass.connection.select_value(
|
60
|
+
klass.connection.select_value('select DATABASE()')
|
60
61
|
end
|
61
62
|
end
|
data/test/schema.rb
CHANGED
data/test/test_arhp.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require_relative 'helper'
|
3
4
|
|
4
5
|
class ActiveRecordHostPoolTest < Minitest::Test
|
@@ -13,32 +14,32 @@ class ActiveRecordHostPoolTest < Minitest::Test
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def test_models_with_matching_hosts_should_share_a_connection
|
16
|
-
|
17
|
-
|
17
|
+
assert_equal(Test1.connection.raw_connection, Test2.connection.raw_connection)
|
18
|
+
assert_equal(Test3.connection.raw_connection, Test4.connection.raw_connection)
|
18
19
|
end
|
19
20
|
|
20
21
|
def test_models_without_matching_hosts_should_not_share_a_connection
|
21
|
-
|
22
|
+
refute_equal(Test1.connection.raw_connection, Test4.connection.raw_connection)
|
22
23
|
end
|
23
24
|
|
24
25
|
def test_models_without_matching_usernames_should_not_share_a_connection
|
25
|
-
|
26
|
+
refute_equal(Test4.connection.raw_connection, Test5.connection.raw_connection)
|
26
27
|
end
|
27
28
|
|
28
29
|
def test_models_without_match_slave_status_should_not_share_a_connection
|
29
|
-
|
30
|
+
refute_equal(Test1.connection.raw_connection, Test1Slave.connection.raw_connection)
|
30
31
|
end
|
31
32
|
|
32
33
|
def test_should_select_on_correct_database
|
33
|
-
|
34
|
+
assert_action_uses_correct_database(:select_all, 'select 1')
|
34
35
|
end
|
35
36
|
|
36
37
|
def test_should_insert_on_correct_database
|
37
|
-
|
38
|
+
assert_action_uses_correct_database(:insert, "insert into tests values(NULL, 'foo')")
|
38
39
|
end
|
39
40
|
|
40
41
|
def test_connection_returns_a_proxy
|
41
|
-
|
42
|
+
assert_kind_of ActiveRecordHostPool::ConnectionProxy, Test1.connection
|
42
43
|
end
|
43
44
|
|
44
45
|
def test_connection_proxy_handles_private_methods
|
@@ -52,47 +53,62 @@ class ActiveRecordHostPoolTest < Minitest::Test
|
|
52
53
|
assert Test1.connection.respond_to?(:test_private_method, true)
|
53
54
|
refute Test1.connection.respond_to?(:test_private_method)
|
54
55
|
assert_includes(Test1.connection.private_methods, :test_private_method)
|
55
|
-
|
56
|
+
assert_equal true, Test1.connection.send(:test_private_method)
|
56
57
|
end
|
57
58
|
|
58
59
|
def test_should_not_share_a_query_cache
|
59
|
-
Test1.create(:
|
60
|
-
Test2.create(:
|
60
|
+
Test1.create(val: 'foo')
|
61
|
+
Test2.create(val: 'foobar')
|
61
62
|
Test1.connection.cache do
|
62
|
-
|
63
|
+
refute_equal Test1.first.val, Test2.first.val
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
def test_object_creation
|
67
|
-
Test1.create(:
|
68
|
-
assert_equal(
|
68
|
+
Test1.create(val: 'foo')
|
69
|
+
assert_equal('arhp_test_1', current_database(Test1))
|
69
70
|
|
70
|
-
Test3.create(:
|
71
|
-
assert_equal(
|
72
|
-
assert_equal(
|
71
|
+
Test3.create(val: 'bar')
|
72
|
+
assert_equal('arhp_test_1', current_database(Test1))
|
73
|
+
assert_equal('arhp_test_3', current_database(Test3))
|
73
74
|
|
74
|
-
Test2.create!(:
|
75
|
-
assert_equal(
|
75
|
+
Test2.create!(val: 'bar_distinct')
|
76
|
+
assert_equal('arhp_test_2', current_database(Test2))
|
76
77
|
assert Test2.find_by_val('bar_distinct')
|
77
|
-
|
78
|
+
refute Test1.find_by_val('bar_distinct')
|
78
79
|
end
|
79
80
|
|
80
81
|
def test_disconnect
|
81
|
-
Test1.create(:
|
82
|
+
Test1.create(val: 'foo')
|
82
83
|
unproxied = Test1.connection.unproxied
|
83
84
|
Test1.connection_handler.clear_all_connections!
|
84
|
-
Test1.create(:
|
85
|
+
Test1.create(val: 'foo')
|
85
86
|
assert(unproxied != Test1.connection.unproxied)
|
86
87
|
end
|
87
88
|
|
88
89
|
def test_checkout
|
89
90
|
connection = ActiveRecord::Base.connection_pool.checkout
|
90
|
-
|
91
|
+
assert_kind_of(ActiveRecordHostPool::ConnectionProxy, connection)
|
91
92
|
ActiveRecord::Base.connection_pool.checkin(connection)
|
92
93
|
c2 = ActiveRecord::Base.connection_pool.checkout
|
93
94
|
assert(c2 == connection)
|
94
95
|
end
|
95
96
|
|
97
|
+
def test_no_switch_when_creating_db
|
98
|
+
conn = Test1.connection
|
99
|
+
conn.expects(:execute_without_switching)
|
100
|
+
conn.expects(:_switch_connection).never
|
101
|
+
assert conn._host_pool_current_database
|
102
|
+
conn.create_database(:some_args)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_no_switch_when_dropping_db
|
106
|
+
conn = Test1.connection
|
107
|
+
conn.expects(:execute_without_switching)
|
108
|
+
conn.expects(:_switch_connection).never
|
109
|
+
assert conn._host_pool_current_database
|
110
|
+
conn.drop_database(:some_args)
|
111
|
+
end
|
96
112
|
|
97
113
|
def test_underlying_assumption_about_test_db
|
98
114
|
debug_me = false
|
@@ -104,10 +120,12 @@ class ActiveRecordHostPoolTest < Minitest::Test
|
|
104
120
|
puts "\nOk, we started on #{first_db}" if debug_me
|
105
121
|
|
106
122
|
switch_to_klass = case first_db
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
123
|
+
when 'arhp_test_2'
|
124
|
+
Test1
|
125
|
+
when 'arhp_test_1'
|
126
|
+
Test2
|
127
|
+
else
|
128
|
+
raise "Expected a database name, got #{first_db.inspect}"
|
111
129
|
end
|
112
130
|
expected_database = switch_to_klass.connection.instance_variable_get(:@database)
|
113
131
|
|
@@ -116,7 +134,7 @@ class ActiveRecordHostPoolTest < Minitest::Test
|
|
116
134
|
puts "\nAnd now we're on #{current_database(switch_to_klass)}" if debug_me
|
117
135
|
|
118
136
|
# get the current thread id so we can shoot ourselves in the head
|
119
|
-
thread_id = switch_to_klass.connection.select_value(
|
137
|
+
thread_id = switch_to_klass.connection.select_value('select @@pseudo_thread_id')
|
120
138
|
|
121
139
|
# now, disable our auto-switching and trigger a mysql reconnect
|
122
140
|
switch_to_klass.connection.unproxied.stubs(:_switch_connection).returns(true)
|
@@ -129,12 +147,12 @@ class ActiveRecordHostPoolTest < Minitest::Test
|
|
129
147
|
|
130
148
|
private
|
131
149
|
|
132
|
-
def
|
133
|
-
(1..4).each
|
150
|
+
def assert_action_uses_correct_database(action, sql)
|
151
|
+
(1..4).each do |i|
|
134
152
|
klass = eval "Test#{i}"
|
135
153
|
desired_db = "arhp_test_#{i}"
|
136
154
|
klass.connection.send(action, sql)
|
137
155
|
assert_equal desired_db, current_database(klass)
|
138
|
-
|
156
|
+
end
|
139
157
|
end
|
140
158
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_host_pool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Osheroff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 12.0.0
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 12.0.0
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: shoulda
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,6 +128,20 @@ dependencies:
|
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rubocop
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 0.48.0
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 0.48.0
|
131
145
|
description: ''
|
132
146
|
email:
|
133
147
|
- ben@gimbo.net
|
@@ -168,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
182
|
version: '0'
|
169
183
|
requirements: []
|
170
184
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.
|
185
|
+
rubygems_version: 2.6.11
|
172
186
|
signing_key:
|
173
187
|
specification_version: 4
|
174
188
|
summary: Allow ActiveRecord to share a connection to multiple databases on the same
|