ebisu_connection 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b135ecfde83d564cc7dcfbfaa7632f057fdf2fe1
4
+ data.tar.gz: 39f3cdb331514ae4ea8d24d9e463f7287bd60dd9
5
+ SHA512:
6
+ metadata.gz: c59b5f27c126da53ff6a29e8f7604d69be14c0f0d55347ea01d20d0efad05a428765f21dfdfc160265167b26e7ad28135f118c875ae226bd9453c2cd721b0d1d
7
+ data.tar.gz: f6ffaf1813892a30f3750d0a796170b36a0fc8e162644d436dcbc8e3640abd532dadf39786de1bec1206884e5190a08fd4c7317ece15643683110cfec28a447c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ebisu_connection.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 tsukasaoishi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # EbisuConnection
2
+
3
+ EbisuConnection supports to connect with Mysql slave servers. It doesn't need Load Balancer.
4
+ You can assign a performance weight to each slave server. And slave config is reflected dynamic.
5
+ EbisuConnection uses FreshConnection (https://github.com/tsukasaoishi/fresh_connection).
6
+
7
+ ## Installation
8
+
9
+ EbisuConnection has tested Rails3.2.16 and Rails4.0.2.
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'ebisu_connection'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install ebisu_connection
22
+
23
+ ## Config
24
+
25
+ config/database.yml
26
+
27
+ production:
28
+ adapter: mysql2
29
+ encoding: utf8
30
+ reconnect: true
31
+ database: kaeru
32
+ pool: 5
33
+ username: master
34
+ password: master
35
+ host: localhost
36
+ socket: /var/run/mysqld/mysqld.sock
37
+
38
+ slave:
39
+ username: slave
40
+ password: slave
41
+ host: slave
42
+
43
+ slave is base config to connect to slave servers.
44
+ Others will use the master setting. If you want to change, write in the slave.
45
+
46
+ Config of each slave server fill out config/slave.yaml
47
+
48
+ - "slave1, 10"
49
+ - "slave2, 20"
50
+ -
51
+ host: "slave3"
52
+ weight: 30
53
+
54
+ config/slave.yaml is checked by end of action. If config changed, it's reflected dynamic. Application doesn't need restart.
55
+
56
+ "hostname, weight"
57
+
58
+ String format is it. You can write config with hash.
59
+
60
+ ### Only master models
61
+
62
+ config/initializers/fresh_connection.rb
63
+
64
+ FreshConnection::SlaveConnection.ignore_models = %w|Model1 Model2|
65
+
66
+ If models that ignore access to slave servers is exist, You can write model name at FreshConnection::SlaveConnection.ignore models.
67
+
68
+ ## Usage
69
+
70
+ Read query will be access to slave server.
71
+
72
+ Article.where(:id => 1)
73
+
74
+ If you want to access to master saver, use readonly(false).
75
+
76
+ Article.where(:id => 1).readonly(false)
77
+
78
+ In transaction, Always will be access to master server.
79
+
80
+ Article.transaction do
81
+ Article.where(:id => 1)
82
+ end
83
+
84
+
85
+ ## Contributing
86
+
87
+ 1. Fork it
88
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
89
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
90
+ 4. Push to the branch (`git push origin my-new-feature`)
91
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ebisu_connection/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ebisu_connection"
8
+ spec.version = EbisuConnection::VERSION
9
+ spec.authors = ["tsukasaoishi"]
10
+ spec.email = ["tsukasa.oishi@gmail.com"]
11
+ spec.description = %q{EbisuConnection supports to connect with Mysql slave servers. It doesn't need Load Balancer.}
12
+ spec.summary = %q{EbisuConnection supports to connect with Mysql slave servers.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activerecord', '>= 3.2.0'
22
+ spec.add_dependency 'fresh_connection', '>= 0.1.2'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,6 @@
1
+ require "fresh_connection"
2
+ require "ebisu_connection/version"
3
+ require "ebisu_connection/slaves"
4
+ require "ebisu_connection/connection_manager"
5
+
6
+ FreshConnection::SlaveConnection.connection_manager = EbisuConnection::ConnectionManager
@@ -0,0 +1,86 @@
1
+ require 'yaml'
2
+
3
+ module EbisuConnection
4
+ class ConnectionManager
5
+ CHECK_INTERVAL = 1.minute
6
+
7
+ class << self
8
+ attr_writer :slaves_file
9
+ attr_accessor :slave_type
10
+
11
+ def slaves_file
12
+ @slaves_file || File.join(Rails.root, "config/slave.yaml")
13
+ end
14
+ end
15
+
16
+ def initialize
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ def slave_connection
21
+ slaves.sample.connection
22
+ end
23
+
24
+ def put_aside!
25
+ return unless @file_mtime
26
+
27
+ now = Time.now
28
+ @check_time ||= now
29
+ return if now - @check_time < CHECK_INTERVAL
30
+ @check_time = now
31
+
32
+ mtime = File.mtime(self.class.slaves_file)
33
+ return if @file_mtime == mtime
34
+
35
+ clear_all_connection!
36
+ end
37
+
38
+ def clear_all_connection!
39
+ @mutex.synchronize do
40
+ @slaves.values.each do |s|
41
+ s.all_disconnect!
42
+ end
43
+
44
+ @slaves = nil
45
+ @slave_conf = nil
46
+ @spec = nil
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def slaves
53
+ @mutex.synchronize do
54
+ @slaves ||= {}
55
+ @slaves[current_thread_id] ||= get_slaves
56
+ end
57
+ end
58
+
59
+ def get_slaves
60
+ EbisuConnection::Slaves.new(slaves_conf, spec)
61
+ end
62
+
63
+ def slaves_conf
64
+ @slaves_conf ||= get_slaves_conf
65
+ end
66
+
67
+ def spec
68
+ @spec ||= get_spec
69
+ end
70
+
71
+ def get_slaves_conf
72
+ @file_mtime = File.mtime(self.class.slaves_file)
73
+ conf = YAML.load_file(self.class.slaves_file)
74
+ self.class.slave_type ? conf[self.class.slave_type] : conf
75
+ end
76
+
77
+ def get_spec
78
+ ret = ActiveRecord::Base.configurations[Rails.env]
79
+ ret.merge(ret["slave"] || {})
80
+ end
81
+
82
+ def current_thread_id
83
+ Thread.current.object_id
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,95 @@
1
+ module EbisuConnection
2
+ class Slaves
3
+ class Slave
4
+ attr_reader :hostname, :weight
5
+
6
+ def initialize(conf, spec)
7
+ case conf
8
+ when String
9
+ @hostname, weight = conf.split(/\s*,\s*/)
10
+ edit_spec = {:host => @hostname}
11
+ when Hash
12
+ conf = symbolize_keys(conf)
13
+ weight = conf.delete(:weight)
14
+ edit_spec = conf
15
+ @hostname = conf[:host]
16
+ else
17
+ raise ArgumentError, "slaves config is invalid"
18
+ end
19
+
20
+ @spec = spec.merge(edit_spec)
21
+ @weight = (weight || 1).to_i
22
+ end
23
+
24
+ def connection
25
+ @connection ||= ActiveRecord::Base.send("#{@spec["adapter"]}_connection", @spec)
26
+ end
27
+
28
+ def disconnect!
29
+ if @connection
30
+ @connection.disconnect!
31
+ @connection = nil
32
+ end
33
+ rescue
34
+ end
35
+
36
+ private
37
+
38
+ def symbolize_keys(hash)
39
+ symbolize_hash = {}
40
+ hash.each do |k,v|
41
+ symbolize_hash[k.to_sym] = v
42
+ end
43
+ symbolize_hash
44
+ end
45
+ end
46
+
47
+ def initialize(slaves_conf, spec)
48
+ weight_list = []
49
+ @slaves = slaves_conf.map do |conf|
50
+ s = Slave.new(conf, spec)
51
+ weight_list << s.weight
52
+ s
53
+ end
54
+
55
+ @roulette = []
56
+ gcd = get_gcd(weight_list)
57
+ weight_list.each_with_index do |w, index|
58
+ weight = w / gcd
59
+ @roulette.concat([index] * weight)
60
+ end
61
+ end
62
+
63
+ def sample
64
+ @slaves[@roulette.sample]
65
+ end
66
+
67
+ def all_disconnect!
68
+ @slaves.each {|s| s.disconnect!}
69
+ end
70
+
71
+ private
72
+
73
+ def get_gcd(list)
74
+ list = list.sort.uniq
75
+ n = list.shift
76
+ return n if n == 1 || list.empty?
77
+
78
+ while !list.empty?
79
+ m = list.shift
80
+ n = gcd_euclid(m, n)
81
+ end
82
+ n
83
+ end
84
+
85
+ def gcd_euclid(m, n)
86
+ m, n = n, m if m < n
87
+ while n != 0
88
+ work = m % n
89
+ m = n
90
+ n = work
91
+ end
92
+ m
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,3 @@
1
+ module EbisuConnection
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ebisu_connection
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - tsukasaoishi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: fresh_connection
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: EbisuConnection supports to connect with Mysql slave servers. It doesn't
70
+ need Load Balancer.
71
+ email:
72
+ - tsukasa.oishi@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - ebisu_connection.gemspec
83
+ - lib/ebisu_connection.rb
84
+ - lib/ebisu_connection/connection_manager.rb
85
+ - lib/ebisu_connection/slaves.rb
86
+ - lib/ebisu_connection/version.rb
87
+ homepage: ''
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.0.0
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: EbisuConnection supports to connect with Mysql slave servers.
111
+ test_files: []