fresh_connection 0.1.8 → 0.2.0
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/Appraisals +17 -0
- data/README.md +72 -8
- data/Rakefile +5 -0
- data/fresh_connection.gemspec +6 -1
- data/gemfiles/rails3.gemfile +9 -0
- data/gemfiles/rails40.gemfile +9 -0
- data/gemfiles/rails41.gemfile +9 -0
- data/lib/fresh_connection.rb +39 -9
- data/lib/fresh_connection/abstract_connection_manager.rb +4 -1
- data/lib/fresh_connection/access_control.rb +56 -0
- data/lib/fresh_connection/connection_manager.rb +2 -2
- data/lib/fresh_connection/extend/ar_base.rb +47 -0
- data/lib/fresh_connection/extend/ar_relation.rb +44 -0
- data/lib/fresh_connection/extend/connection_handler.rb +16 -0
- data/lib/fresh_connection/extend/mysql2_adapter.rb +46 -0
- data/lib/fresh_connection/initializer.rb +35 -0
- data/lib/fresh_connection/rack/connection_management.rb +1 -1
- data/lib/fresh_connection/railtie.rb +7 -4
- data/lib/fresh_connection/slave_connection.rb +29 -65
- data/lib/fresh_connection/slave_connection_handler.rb +43 -0
- data/lib/fresh_connection/version.rb +1 -1
- data/log/.gitkeep +0 -0
- data/spec/database.yml +14 -0
- data/spec/db_schema.sql +291 -0
- data/spec/prepare.rb +33 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/active_record_logger.rb +3 -0
- data/spec/unit/access_control_spec.rb +63 -0
- data/spec/unit/ar_base_spec.rb +42 -0
- data/spec/unit/fresh_connection_spec.rb +106 -0
- data/spec/unit/recovery_spec.rb +39 -0
- metadata +154 -81
- data/lib/fresh_connection/active_record/abstract_adapter.rb +0 -35
- data/lib/fresh_connection/active_record/mysql2_adapter.rb +0 -14
- data/lib/fresh_connection/active_record/relation.rb +0 -33
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 145cd233562347272db93ca9a321d741c2d20228
|
4
|
+
data.tar.gz: 47b006e8bb8ac186726d6b71decbb337bd9ebd93
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: faf4ef73727580b787ee41e7b2d7ceea4181687fb6ac9a4343272e32341ab7c36a6d431a471b87172748a48595af33bd00b6e33eed30ebeb4620e43bca0c63ba
|
7
|
+
data.tar.gz: 09e031f971560f1a235bb83adf3b679621671f9c308de92d8bfc98ea100222f3ea9477b51b8ff4726abb76be0b313bc1e1c0a51da474922c8d832caf12521c0e
|
data/.gitignore
ADDED
data/Appraisals
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
appraise "rails3" do
|
2
|
+
gem "activerecord", "~> 3.2.0"
|
3
|
+
gem "activesupport", "~> 3.2.0"
|
4
|
+
gem "railties", "~> 3.2.0"
|
5
|
+
end
|
6
|
+
|
7
|
+
appraise "rails40" do
|
8
|
+
gem "activerecord", "~> 4.0.0"
|
9
|
+
gem "activesupport", "~> 4.0.0"
|
10
|
+
gem "railties", "~> 4.0.0"
|
11
|
+
end
|
12
|
+
|
13
|
+
appraise "rails41" do
|
14
|
+
gem "activerecord", "~> 4.1.0"
|
15
|
+
gem "activesupport", "~> 4.1.0"
|
16
|
+
gem "railties", "~> 4.1.0"
|
17
|
+
end
|
data/README.md
CHANGED
@@ -18,9 +18,6 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
$ gem install fresh_connection
|
20
20
|
|
21
|
-
### For Rails2.3
|
22
|
-
|
23
|
-
$ gem install fresh_connection -v 0.0.7
|
24
21
|
|
25
22
|
## Config
|
26
23
|
### config/database.yml
|
@@ -41,14 +38,62 @@ Or install it yourself as:
|
|
41
38
|
password: slave
|
42
39
|
host: slave
|
43
40
|
|
44
|
-
slave is config to connect to slave servers.
|
41
|
+
```slave``` is config to connect to slave servers.
|
45
42
|
Others will use the master setting. If you want to change, write in the slave.
|
46
43
|
|
47
|
-
###
|
44
|
+
### use multiple slave servers group
|
45
|
+
If you may want to user multiple slave group, write multiple slave group to config/database.yml.
|
46
|
+
|
47
|
+
production:
|
48
|
+
adapter: mysql2
|
49
|
+
encoding: utf8
|
50
|
+
reconnect: true
|
51
|
+
database: kaeru
|
52
|
+
pool: 5
|
53
|
+
username: master
|
54
|
+
password: master
|
55
|
+
host: localhost
|
56
|
+
socket: /var/run/mysqld/mysqld.sock
|
57
|
+
|
58
|
+
slave:
|
59
|
+
username: slave
|
60
|
+
password: slave
|
61
|
+
host: slave
|
62
|
+
|
63
|
+
admin_slave:
|
64
|
+
username: slave
|
65
|
+
password: slave
|
66
|
+
host: admin_slaves
|
67
|
+
|
68
|
+
And call establish_fresh_connection method in model that access to ```admin_slave``` slave group.
|
69
|
+
|
70
|
+
class AdminUser < ActiveRecord::Base
|
71
|
+
establish_fresh_connection :admin_slave
|
72
|
+
end
|
73
|
+
|
74
|
+
The children is access to same slave group of parent.
|
75
|
+
|
76
|
+
class Parent < ActiveRecord::Base
|
77
|
+
establish_fresh_connection :admin_slave
|
78
|
+
end
|
79
|
+
|
80
|
+
class AdminUser < Parent
|
81
|
+
end
|
82
|
+
|
83
|
+
class Benefit < Parent
|
84
|
+
end
|
85
|
+
|
86
|
+
AdminUser and Benefit access to ```admin_slave``` slave group.
|
87
|
+
|
48
88
|
|
49
|
-
|
89
|
+
### Declare model that doesn't use slave db
|
50
90
|
|
51
|
-
|
91
|
+
class SomethingModel < ActiveRecord::Base
|
92
|
+
master_db_only!
|
93
|
+
end
|
94
|
+
|
95
|
+
If model that always access to master servers is exist, You may want to write ```master_db_only!``` in model.
|
96
|
+
The model that master_db_only model's child is always access to master db.
|
52
97
|
|
53
98
|
### Slave Connection Manager
|
54
99
|
Default slave connection manager is FreshConnection::ConnectionManager.
|
@@ -56,7 +101,7 @@ If you would like to change slave connection manager, assign yourself slave conn
|
|
56
101
|
|
57
102
|
#### config/initializers/fresh_connection.rb
|
58
103
|
|
59
|
-
FreshConnection
|
104
|
+
FreshConnection.connection_manager = MySlaveConnection
|
60
105
|
|
61
106
|
|
62
107
|
Yourself Slave Connection Manager should be inherited FreshConnection::AbstractConnectionManager
|
@@ -99,3 +144,22 @@ In transaction, Always will be access to master server.
|
|
99
144
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
100
145
|
4. Push to the branch (`git push origin my-new-feature`)
|
101
146
|
5. Create new Pull Request
|
147
|
+
|
148
|
+
## Test
|
149
|
+
|
150
|
+
I'm glad that you would do test!
|
151
|
+
To run the test suite, you need mysql installed.
|
152
|
+
How to setup your test environment.
|
153
|
+
|
154
|
+
```bash
|
155
|
+
bundle install --path bundle
|
156
|
+
GEM_HOME=bundle/ruby/(your ruby version) gem install bundler --pre
|
157
|
+
bundle exec appraisal install
|
158
|
+
```
|
159
|
+
|
160
|
+
This command run the spec suite for all rails versions supported.
|
161
|
+
|
162
|
+
```base
|
163
|
+
bundle exec appraisal rake spec
|
164
|
+
```
|
165
|
+
|
data/Rakefile
CHANGED
data/fresh_connection.gemspec
CHANGED
@@ -19,7 +19,12 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency 'activerecord', '>= 3.2.0'
|
22
|
+
spec.add_dependency 'activesupport', '>= 3.2.0'
|
23
|
+
spec.add_dependency 'railties', '>= 3.2.0'
|
22
24
|
|
23
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
-
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rake", '>= 10.0.0'
|
27
|
+
spec.add_development_dependency "rspec", '>= 2.14.1'
|
28
|
+
spec.add_development_dependency 'mysql2', '>= 0.3.15'
|
29
|
+
spec.add_development_dependency 'appraisal', '>= 1.0.0'
|
25
30
|
end
|
data/lib/fresh_connection.rb
CHANGED
@@ -1,9 +1,39 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'active_support/dependencies/autoload'
|
4
|
+
|
5
|
+
module FreshConnection
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :AccessControl
|
9
|
+
autoload :ConnectionManager
|
10
|
+
autoload :SlaveConnectionHandler
|
11
|
+
autoload :Initializer
|
12
|
+
autoload :SlaveConnection
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_writer :connection_manager, :ignore_configure_connection, :retry_limit
|
16
|
+
|
17
|
+
def connection_manager
|
18
|
+
@connection_manager || ConnectionManager
|
19
|
+
end
|
20
|
+
|
21
|
+
def ignore_configure_connection?
|
22
|
+
!!@ignore_configure_connection
|
23
|
+
end
|
24
|
+
|
25
|
+
def retry_limit
|
26
|
+
@retry_limit || 3
|
27
|
+
end
|
28
|
+
|
29
|
+
def rails_3?
|
30
|
+
ActiveRecord::VERSION::MAJOR == 3
|
31
|
+
end
|
32
|
+
|
33
|
+
def rails_4?
|
34
|
+
ActiveRecord::VERSION::MAJOR == 4
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require "fresh_connection/railtie.rb"
|
@@ -6,8 +6,11 @@ module FreshConnection
|
|
6
6
|
"Can't connect to local MySQL server"
|
7
7
|
].map{|msg| Regexp.escape(msg)}.join("|")
|
8
8
|
|
9
|
-
|
9
|
+
attr_reader :slave_group
|
10
|
+
|
11
|
+
def initialize(slave_group = "slave")
|
10
12
|
@mutex = Mutex.new
|
13
|
+
@slave_group = (slave_group.presence || "slave").to_s
|
11
14
|
end
|
12
15
|
|
13
16
|
def slave_connection
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module FreshConnection
|
2
|
+
class AccessControl
|
3
|
+
class << self
|
4
|
+
def force_master_access
|
5
|
+
db = access_db
|
6
|
+
access_to(:master)
|
7
|
+
yield
|
8
|
+
ensure
|
9
|
+
access_to(db)
|
10
|
+
end
|
11
|
+
|
12
|
+
def access(enable_slave_access)
|
13
|
+
access_in(enable_slave_access ? :slave : :master)
|
14
|
+
yield
|
15
|
+
ensure
|
16
|
+
access_out
|
17
|
+
end
|
18
|
+
|
19
|
+
def slave_access?
|
20
|
+
access_db == :slave
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def access_in(db)
|
26
|
+
increment_access_count
|
27
|
+
access_to(db) unless access_db
|
28
|
+
end
|
29
|
+
|
30
|
+
def access_out
|
31
|
+
decrement_access_count
|
32
|
+
access_to(nil) if access_count == 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def access_db
|
36
|
+
Thread.current[:fresh_connection_access_target]
|
37
|
+
end
|
38
|
+
|
39
|
+
def access_to(db)
|
40
|
+
Thread.current[:fresh_connection_access_target] = db
|
41
|
+
end
|
42
|
+
|
43
|
+
def access_count
|
44
|
+
Thread.current['fresh_connection_access_count'] || 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def increment_access_count
|
48
|
+
Thread.current['fresh_connection_access_count'] = access_count + 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def decrement_access_count
|
52
|
+
Thread.current['fresh_connection_access_count'] = access_count - 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -36,7 +36,7 @@ module FreshConnection
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def new_connection
|
39
|
-
ActiveRecord::Base.send("
|
39
|
+
ActiveRecord::Base.send("mysql2_connection", spec)
|
40
40
|
end
|
41
41
|
|
42
42
|
def spec
|
@@ -45,7 +45,7 @@ module FreshConnection
|
|
45
45
|
|
46
46
|
def get_spec
|
47
47
|
ret = ActiveRecord::Base.configurations[Rails.env]
|
48
|
-
ret.merge(ret[
|
48
|
+
ret.merge(ret[@slave_group] || {})
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module FreshConnection
|
2
|
+
module Extend
|
3
|
+
module ArBase
|
4
|
+
def self.extended(base)
|
5
|
+
base.class_attribute :slave_connection_handler, :instance_writer => false
|
6
|
+
base.slave_connection_handler = FreshConnection::SlaveConnectionHandler.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def manage_access(slave_access, &block)
|
10
|
+
if master_db_only?
|
11
|
+
FreshConnection::AccessControl.force_master_access(&block)
|
12
|
+
else
|
13
|
+
FreshConnection::AccessControl.access(slave_access, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def establish_fresh_connection(slave_group = nil)
|
18
|
+
slave_connection_handler.establish_connection(name, slave_group)
|
19
|
+
end
|
20
|
+
|
21
|
+
def slave_connection
|
22
|
+
slave_connection_handler.connection(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def master_db_only!
|
26
|
+
@_fresh_connection_master_only = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def master_db_only?
|
30
|
+
@_fresh_connection_master_only ||
|
31
|
+
(self != ActiveRecord::Base && superclass.master_db_only?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def put_aside!
|
35
|
+
slave_connection_handler.put_aside!
|
36
|
+
end
|
37
|
+
|
38
|
+
def recovery(failure_connection, exception)
|
39
|
+
slave_connection_handler.recovery(self, failure_connection, exception)
|
40
|
+
end
|
41
|
+
|
42
|
+
def slave_group
|
43
|
+
slave_connection_handler.slave_group(self)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module FreshConnection
|
2
|
+
module Extend
|
3
|
+
module ArRelation
|
4
|
+
def self.included(base)
|
5
|
+
base.alias_method_chain :exec_queries, :fresh_connection
|
6
|
+
|
7
|
+
if FreshConnection.rails_4?
|
8
|
+
base.__send__(:include, ForRails4)
|
9
|
+
elsif FreshConnection.rails_3?
|
10
|
+
base.__send__(:include, ForRails3)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def calculate(operation, column_name, options = {})
|
15
|
+
slave_access = enable_slave_access && options[:readonly] != false
|
16
|
+
@klass.manage_access(slave_access) { super }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def exec_queries_with_fresh_connection
|
22
|
+
return @records if loaded?
|
23
|
+
|
24
|
+
@klass.manage_access(enable_slave_access) do
|
25
|
+
exec_queries_without_fresh_connection
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module ForRails4
|
30
|
+
private
|
31
|
+
def enable_slave_access
|
32
|
+
connection.open_transactions == 0 && (readonly_value.nil? || readonly_value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module ForRails3
|
37
|
+
private
|
38
|
+
def enable_slave_access
|
39
|
+
connection.open_transactions == 0 && (@readonly_value.nil? || @readonly_value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module FreshConnection
|
2
|
+
module Extend
|
3
|
+
module ConnectionHandler
|
4
|
+
def self.included(base)
|
5
|
+
base.alias_method_chain :retrieve_connection, :fresh_connection
|
6
|
+
end
|
7
|
+
|
8
|
+
def retrieve_connection_with_fresh_connection(klass)
|
9
|
+
c = retrieve_connection_without_fresh_connection(klass)
|
10
|
+
c.model_class = klass
|
11
|
+
c
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|