ebisu_connection 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3bea33e80ff8e417162f05398ebb64531751825b
4
+ data.tar.gz: a908cbe78a57d95209b8660de521a1371f0e5b05
5
+ SHA512:
6
+ metadata.gz: c407ba2f24d9466e390eae96ff9931630b4f5ddd0361135d1e07c3d491e7d01e297c1f501ef0004130c5a49c6d0e9fd934877e2ff1ec8d244fd0ffd515851d2e
7
+ data.tar.gz: 871ee55618b50ffc9e833f9933d1706f1127a081d2d1c644d634cf26906d9c90e5f440fb3a537edb4b2735ab7f8cf069606003e74281b0b9bd8b1428aa143309
data/.gitignore CHANGED
@@ -1,17 +1,8 @@
1
1
  *.gem
2
- *.rbc
3
2
  .bundle
4
- .config
5
- .yardoc
3
+ .ruby-version
6
4
  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
5
+ gemfiles/*.lock
6
+ bundle
7
+ log/*
8
+ .*.sw[a-z]
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
@@ -1,13 +1,11 @@
1
1
  # EbisuConnection
2
2
 
3
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.
4
+ You can assign a performance weight to each slave server. And slave config is reflected dynamic.
5
5
  EbisuConnection uses FreshConnection (https://github.com/tsukasaoishi/fresh_connection).
6
6
 
7
7
  ## Installation
8
8
 
9
- EbisuConnection has tested Rails3.2.16 and Rails4.0.2.
10
-
11
9
  Add this line to your application's Gemfile:
12
10
 
13
11
  gem 'ebisu_connection'
@@ -40,7 +38,7 @@ config/database.yml
40
38
  password: slave
41
39
  host: slave
42
40
 
43
- slave is base config to connect to slave servers.
41
+ ```slave``` is base config to connect to slave servers.
44
42
  Others will use the master setting. If you want to change, write in the slave.
45
43
 
46
44
  Config of each slave server fill out config/slave.yaml
@@ -58,13 +56,73 @@ config/slave.yaml is checked by end of action. If config changed, it's reflected
58
56
 
59
57
  String format is it. You can write config with hash.
60
58
 
61
- ### Only master models
59
+ ### use multiple slave servers group
60
+ If you may want to user multiple slave group, write multiple slave group to config/database.yml.
62
61
 
63
- config/initializers/ebisu_connection.rb
62
+ production:
63
+ adapter: mysql2
64
+ encoding: utf8
65
+ reconnect: true
66
+ database: kaeru
67
+ pool: 5
68
+ username: master
69
+ password: master
70
+ host: localhost
71
+ socket: /var/run/mysqld/mysqld.sock
64
72
 
65
- EbisuConnection::ConnectionManager.ignore_models = %w|Model1 Model2|
73
+ slave:
74
+ username: slave
75
+ password: slave
76
+ host: slave
77
+
78
+ admin_slave:
79
+ username: slave
80
+ password: slave
81
+ host: admin_slaves
82
+
83
+ Config of each slave server fill out config/slave.yaml
84
+
85
+ production:
86
+ slave:
87
+ - "slave1, 10"
88
+ - "slave2, 20"
89
+ -
90
+ host: "slave3"
91
+ weight: 30
92
+ admin_slave:
93
+ - "slave3, 10"
94
+ - "slave4, 20"
66
95
 
67
- If models that ignore access to slave servers is exist, You can write model name at EbisuConnection::ConnectionManager.ignore models.
96
+
97
+ And call establish_fresh_connection method in model that access to ```admin_slave``` slave group.
98
+
99
+ class AdminUser < ActiveRecord::Base
100
+ establish_fresh_connection :admin_slave
101
+ end
102
+
103
+ The children is access to same slave group of parent.
104
+
105
+ class Parent < ActiveRecord::Base
106
+ establish_fresh_connection :admin_slave
107
+ end
108
+
109
+ class AdminUser < Parent
110
+ end
111
+
112
+ class Benefit < Parent
113
+ end
114
+
115
+ AdminUser and Benefit access to ```admin_slave``` slave group.
116
+
117
+
118
+ ### Declare model that doesn't use slave db
119
+
120
+ class SomethingModel < ActiveRecord::Base
121
+ master_db_only!
122
+ end
123
+
124
+ If model that always access to master servers is exist, You may want to write ```master_db_only!``` in model.
125
+ The model that master_db_only model's child is always access to master db.
68
126
 
69
127
  ## Usage
70
128
 
@@ -91,3 +149,22 @@ In transaction, Always will be access to master server.
91
149
  3. Commit your changes (`git commit -am 'Add some feature'`)
92
150
  4. Push to the branch (`git push origin my-new-feature`)
93
151
  5. Create new Pull Request
152
+
153
+ ## Test
154
+
155
+ I'm glad that you would do test!
156
+ To run the test suite, you need mysql installed.
157
+ How to setup your test environment.
158
+
159
+ ```bash
160
+ bundle install --path bundle
161
+ GEM_HOME=bundle/ruby/(your ruby version) gem install bundler --pre
162
+ bundle exec appraisal install
163
+ ```
164
+
165
+ This command run the spec suite for all rails versions supported.
166
+
167
+ ```base
168
+ bundle exec appraisal rake spec
169
+ ```
170
+
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -18,9 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'activerecord', '>= 3.2.0'
22
- spec.add_dependency 'fresh_connection', '>= 0.1.8'
21
+ spec.add_dependency 'fresh_connection', '~> 0.2.0'
23
22
 
24
23
  spec.add_development_dependency "bundler", "~> 1.3"
25
- spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rake", '>= 10.0.0'
25
+ spec.add_development_dependency "rspec", '>= 2.14.1'
26
+ spec.add_development_dependency 'mysql2', '>= 0.3.15'
27
+ spec.add_development_dependency 'appraisal', '>= 1.0.0'
26
28
  end
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.0"
6
+ gem "activesupport", "~> 3.2.0"
7
+ gem "railties", "~> 3.2.0"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.0"
6
+ gem "activesupport", "~> 4.0.0"
7
+ gem "railties", "~> 4.0.0"
8
+
9
+ gemspec :path => "../"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.0"
6
+ gem "activesupport", "~> 4.1.0"
7
+ gem "railties", "~> 4.1.0"
8
+
9
+ gemspec :path => "../"
@@ -2,7 +2,6 @@ module EbisuConnection
2
2
  class ConfFile
3
3
  class << self
4
4
  attr_writer :slaves_file, :check_interval
5
- attr_accessor :slave_type
6
5
 
7
6
  def if_modify
8
7
  if time_to_check? && modify?
@@ -15,12 +14,18 @@ module EbisuConnection
15
14
  @spec = nil
16
15
  end
17
16
 
18
- def slaves_conf
17
+ def slaves_conf(slave_group)
19
18
  @slaves_conf ||= get_slaves_conf
19
+ if @slaves_conf.is_a?(Hash)
20
+ @slaves_conf[slave_group] || @slaves_conf
21
+ else
22
+ @slaves_conf
23
+ end
20
24
  end
21
25
 
22
- def spec
26
+ def spec(slave_group)
23
27
  @spec ||= get_spec
28
+ @spec.merge(@spec[slave_group] || {})
24
29
  end
25
30
 
26
31
  def slaves_file
@@ -50,13 +55,11 @@ module EbisuConnection
50
55
  def get_slaves_conf
51
56
  @file_mtime = File.mtime(slaves_file)
52
57
  conf = YAML.load_file(slaves_file)
53
- conf = conf[Rails.env.to_s] if conf.is_a?(Hash)
54
- slave_type ? conf[slave_type.to_s] : conf
58
+ conf[Rails.env.to_s] || {}
55
59
  end
56
60
 
57
61
  def get_spec
58
- ret = ActiveRecord::Base.configurations[Rails.env]
59
- ret.merge(ret["slave"] || {})
62
+ ActiveRecord::Base.configurations[Rails.env]
60
63
  end
61
64
  end
62
65
  end
@@ -3,17 +3,9 @@ require 'fresh_connection/abstract_connection_manager'
3
3
 
4
4
  module EbisuConnection
5
5
  class ConnectionManager < FreshConnection::AbstractConnectionManager
6
- class << self
7
- delegate :slaves_file, :slaves_file=, :check_interval, :check_interval=,
8
- :slave_type, :slave_type=, :to => EbisuConnection::ConfFile
6
+ delegate :if_modify, :conf_clear!, :to => ConfFile
9
7
 
10
- delegate :ignore_models=, :to => FreshConnection::SlaveConnection
11
- end
12
-
13
- delegate :if_modify, :conf_clear!, :slaves_conf, :spec,
14
- :to => EbisuConnection::ConfFile
15
-
16
- def initialize
8
+ def initialize(slave_group = "slave")
17
9
  super
18
10
  @slaves = {}
19
11
  end
@@ -87,7 +79,15 @@ module EbisuConnection
87
79
  end
88
80
 
89
81
  def get_slaves
90
- EbisuConnection::Slaves.new(slaves_conf, spec)
82
+ SlaveGroup.new(slaves_conf, spec)
83
+ end
84
+
85
+ def slaves_conf
86
+ ConfFile.slaves_conf(@slave_group)
87
+ end
88
+
89
+ def spec
90
+ ConfFile.spec(@slave_group)
91
91
  end
92
92
  end
93
93
  end
@@ -0,0 +1,34 @@
1
+ module EbisuConnection
2
+ class GreatestCommonDivisor
3
+ class << self
4
+ def calc(set)
5
+ self.new(set).calc
6
+ end
7
+ end
8
+
9
+ def initialize(set)
10
+ @set = set.sort.uniq
11
+ end
12
+
13
+ def calc
14
+ n = @set.shift
15
+ return n if n == 1 || @set.empty?
16
+
17
+ while !@set.empty?
18
+ m = @set.shift
19
+ n = gcd_euclid(m, n)
20
+ end
21
+ n
22
+ end
23
+
24
+ def gcd_euclid(m, n)
25
+ m, n = n, m if m < n
26
+ while n != 0
27
+ work = m % n
28
+ m = n
29
+ n = work
30
+ end
31
+ m
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+ require 'active_support/core_ext/object/blank'
3
+
4
+ module EbisuConnection
5
+ class Slave
6
+ attr_reader :hostname, :weight
7
+
8
+ def initialize(conf, spec)
9
+ case conf
10
+ when String
11
+ host, weight = conf.split(/\s*,\s*/)
12
+ @hostname, port = host.split(/\s*:\s*/)
13
+ when Hash
14
+ conf.stringify_keys!
15
+ @hostname = conf["host"]
16
+ weight = conf["weight"]
17
+ port = conf["port"]
18
+ else
19
+ raise ArgumentError, "slaves config is invalid"
20
+ end
21
+
22
+ modify_spec = {"host" => @hostname}
23
+ modify_spec["port"] = port.to_i if port.present?
24
+
25
+ @spec = spec.merge(modify_spec)
26
+ @weight = (weight || 1).to_i
27
+ end
28
+
29
+ def connection
30
+ @connection ||= ActiveRecord::Base.send("mysql2_connection", @spec)
31
+ end
32
+
33
+ def disconnect!
34
+ if @connection
35
+ @connection.disconnect!
36
+ @connection = nil
37
+ end
38
+ rescue
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ module EbisuConnection
2
+ class SlaveGroup
3
+ class AllSlavesHasGoneError < StandardError; end
4
+
5
+ def initialize(slaves_conf, spec)
6
+ @slaves = slaves_conf.map do |conf|
7
+ Slave.new(conf, spec)
8
+ end
9
+
10
+ recalc_roulette
11
+ end
12
+
13
+ def sample
14
+ raise AllSlavesHasGoneError if @slaves.blank?
15
+ @slaves[@roulette.sample]
16
+ end
17
+
18
+ def remove_connection(connection)
19
+ return unless s = @slaves.detect{|s| s.connection == connection}
20
+ s.disconnect! rescue nil
21
+ @slaves.delete(s)
22
+ raise AllSlavesHasGoneError if @slaves.blank?
23
+ recalc_roulette
24
+ nil
25
+ end
26
+
27
+ def all_disconnect!
28
+ @reserve_release = nil
29
+ @slaves.each {|s| s.disconnect!}
30
+ end
31
+
32
+ def reserve_release_connection!
33
+ @reserve_release = true
34
+ end
35
+
36
+ def reserved_release?
37
+ !!@reserve_release
38
+ end
39
+
40
+ private
41
+
42
+ def recalc_roulette
43
+ weight_list = @slaves.map {|s| s.weight }
44
+
45
+ @roulette = []
46
+ gcd = GreatestCommonDivisor.calc(weight_list)
47
+ weight_list.each_with_index do |w, index|
48
+ weight = w / gcd
49
+ @roulette.concat([index] * weight)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,3 +1,3 @@
1
1
  module EbisuConnection
2
- VERSION = "0.0.8"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,7 +1,17 @@
1
1
  require "fresh_connection"
2
- require "ebisu_connection/version"
3
- require "ebisu_connection/conf_file"
4
- require "ebisu_connection/slaves"
5
- require "ebisu_connection/connection_manager"
6
2
 
7
- FreshConnection::SlaveConnection.connection_manager = EbisuConnection::ConnectionManager
3
+ module EbisuConnection
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :ConfFile
7
+ autoload :ConnectionManager
8
+ autoload :SlaveGroup
9
+ autoload :Slave
10
+ autoload :GreatestCommonDivisor
11
+
12
+ class << self
13
+ delegate :slaves_file=, :check_interval=, :to => ConfFile
14
+ end
15
+ end
16
+
17
+ FreshConnection.connection_manager = EbisuConnection::ConnectionManager
@@ -0,0 +1,5 @@
1
+ ENV["RAILS_ENV"]="test"
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'ebisu_connection'
4
+
5
+ FreshConnection::Initializer.extend_active_record
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe EbisuConnection::GreatestCommonDivisor do
4
+ before(:all) do
5
+ @g = EbisuConnection::GreatestCommonDivisor
6
+ end
7
+
8
+ context ".calc" do
9
+ it "return nil if set is empty" do
10
+ expect(@g.calc([])).to be_nil
11
+ end
12
+
13
+ it "return first element if set has one element" do
14
+ expect(@g.calc([1])).to eq(1)
15
+ end
16
+
17
+ it "return first element if set has elements that is all same" do
18
+ set = [1] * 100
19
+ expect(@g.calc(set)).to eq(1)
20
+ end
21
+
22
+ it "return 1 if set includes 1 in elements" do
23
+ set = (1..100).to_a
24
+ expect(@g.calc(set)).to eq(1)
25
+ end
26
+
27
+ it "return gcd" do
28
+ expect(@g.calc([2,4])).to eq(2)
29
+ expect(@g.calc([2,4,6])).to eq(2)
30
+ expect(@g.calc([4,6])).to eq(2)
31
+ expect(@g.calc([3,4,6])).to eq(1)
32
+ expect(@g.calc([3,6])).to eq(3)
33
+ expect(@g.calc([10,10,2])).to eq(2)
34
+ expect(@g.calc([10,10,2,10,5])).to eq(1)
35
+ expect(@g.calc([10,10,10,5])).to eq(5)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe EbisuConnection::SlaveGroup do
4
+ before(:all) do
5
+ @sg = EbisuConnection::SlaveGroup
6
+ @spec = {
7
+ "adapter" => "mysql2",
8
+ "database" => "ebisu_connection_test",
9
+ "username" => "root"
10
+ }
11
+ end
12
+
13
+ context "#sample" do
14
+ it "raise exception if slaves empty" do
15
+ inst = @sg.new([], {})
16
+ expect{
17
+ inst.sample
18
+ }.to raise_error(EbisuConnection::SlaveGroup::AllSlavesHasGoneError)
19
+ end
20
+
21
+ it "return slve instance object" do
22
+ inst = @sg.new(["h"], {})
23
+ expect(inst.sample).to be_a(EbisuConnection::Slave)
24
+ end
25
+ end
26
+
27
+ context "#remove_connection" do
28
+ it "raise exception AllSlavesHasGoneError when slaves size is one" do
29
+ inst = @sg.new(["localhost"], @spec)
30
+ c = inst.sample.connection
31
+ expect {
32
+ inst.remove_connection(c)
33
+ }.to raise_error(EbisuConnection::SlaveGroup::AllSlavesHasGoneError)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe EbisuConnection::Slave do
4
+ before(:all) do
5
+ @spec = {
6
+ "adapter" => "mysql2",
7
+ "database" => "ebisu_connection_test",
8
+ "username" => "root"
9
+ }
10
+ end
11
+
12
+ context "initialize(conf is String)" do
13
+ it "hostname only" do
14
+ s = EbisuConnection::Slave.new("host_1", {})
15
+ expect(s.hostname).to eq("host_1")
16
+ expect(s.weight).to eq(1)
17
+ end
18
+
19
+ it "hostname and weight" do
20
+ s = EbisuConnection::Slave.new("host_1, 10", {})
21
+ expect(s.hostname).to eq("host_1")
22
+ expect(s.weight).to eq(10)
23
+ end
24
+
25
+ it "hostname, weight and port" do
26
+ s = EbisuConnection::Slave.new("host_1:1975, 10", {})
27
+ expect(s.hostname).to eq("host_1")
28
+ expect(s.weight).to eq(10)
29
+ end
30
+ end
31
+
32
+ context "initialize(conf is Hash)" do
33
+ it "hostname only" do
34
+ s = EbisuConnection::Slave.new({:host => "host_1"}, {})
35
+ expect(s.hostname).to eq("host_1")
36
+ expect(s.weight).to eq(1)
37
+ end
38
+
39
+ it "hostname and weight" do
40
+ s = EbisuConnection::Slave.new({:host => "host_1", :weight => 10}, {})
41
+ expect(s.hostname).to eq("host_1")
42
+ expect(s.weight).to eq(10)
43
+ end
44
+
45
+ it "hostname, weight and port" do
46
+ s = EbisuConnection::Slave.new({:host => "host_1", :weight => 10, :port => 1975}, {})
47
+ expect(s.hostname).to eq("host_1")
48
+ expect(s.weight).to eq(10)
49
+ end
50
+ end
51
+
52
+ context "#connection" do
53
+ it "return Mysql2Adapter object" do
54
+ s = EbisuConnection::Slave.new("localhost", @spec)
55
+ expect(s.connection).to be_a(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
56
+ end
57
+ end
58
+ end
metadata CHANGED
@@ -1,138 +1,154 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ebisu_connection
3
- version: !ruby/object:Gem::Version
4
- hash: 15
5
- prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 8
10
- version: 0.0.8
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - tsukasaoishi
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2014-03-12 00:00:00 +09:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: activerecord
11
+ date: 2014-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fresh_connection
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.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: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
23
35
  prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
27
45
  - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 15
30
- segments:
31
- - 3
32
- - 2
33
- - 0
34
- version: 3.2.0
35
- type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: fresh_connection
46
+ - !ruby/object:Gem::Version
47
+ version: 10.0.0
48
+ type: :development
39
49
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
43
52
  - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 11
46
- segments:
47
- - 0
48
- - 1
49
- - 8
50
- version: 0.1.8
51
- type: :runtime
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: bundler
53
+ - !ruby/object:Gem::Version
54
+ version: 10.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 2.14.1
62
+ type: :development
55
63
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- hash: 9
62
- segments:
63
- - 1
64
- - 3
65
- version: "1.3"
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 2.14.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: mysql2
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.15
66
76
  type: :development
67
- version_requirements: *id003
68
- - !ruby/object:Gem::Dependency
69
- name: rake
70
77
  prerelease: false
71
- requirement: &id004 !ruby/object:Gem::Requirement
72
- none: false
73
- requirements:
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.3.15
83
+ - !ruby/object:Gem::Dependency
84
+ name: appraisal
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
74
87
  - - ">="
75
- - !ruby/object:Gem::Version
76
- hash: 3
77
- segments:
78
- - 0
79
- version: "0"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.0.0
80
90
  type: :development
81
- version_requirements: *id004
82
- description: EbisuConnection supports to connect with Mysql slave servers. It doesn't need Load Balancer.
83
- email:
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.0.0
97
+ description: EbisuConnection supports to connect with Mysql slave servers. It doesn't
98
+ need Load Balancer.
99
+ email:
84
100
  - tsukasa.oishi@gmail.com
85
101
  executables: []
86
-
87
102
  extensions: []
88
-
89
103
  extra_rdoc_files: []
90
-
91
- files:
92
- - .gitignore
104
+ files:
105
+ - ".gitignore"
106
+ - Appraisals
93
107
  - Gemfile
94
108
  - LICENSE.txt
95
109
  - README.md
96
110
  - Rakefile
97
111
  - ebisu_connection.gemspec
112
+ - gemfiles/rails3.gemfile
113
+ - gemfiles/rails40.gemfile
114
+ - gemfiles/rails41.gemfile
98
115
  - lib/ebisu_connection.rb
99
116
  - lib/ebisu_connection/conf_file.rb
100
117
  - lib/ebisu_connection/connection_manager.rb
101
- - lib/ebisu_connection/slaves.rb
118
+ - lib/ebisu_connection/greatest_common_divisor.rb
119
+ - lib/ebisu_connection/slave.rb
120
+ - lib/ebisu_connection/slave_group.rb
102
121
  - lib/ebisu_connection/version.rb
103
- has_rdoc: true
104
- homepage: ""
105
- licenses:
122
+ - spec/spec_helper.rb
123
+ - spec/unit/greatest_common_divisor_spec.rb
124
+ - spec/unit/slave_group_spec.rb
125
+ - spec/unit/slave_spec.rb
126
+ homepage: ''
127
+ licenses:
106
128
  - MIT
129
+ metadata: {}
107
130
  post_install_message:
108
131
  rdoc_options: []
109
-
110
- require_paths:
132
+ require_paths:
111
133
  - lib
112
- required_ruby_version: !ruby/object:Gem::Requirement
113
- none: false
114
- requirements:
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
115
136
  - - ">="
116
- - !ruby/object:Gem::Version
117
- hash: 3
118
- segments:
119
- - 0
120
- version: "0"
121
- required_rubygems_version: !ruby/object:Gem::Requirement
122
- none: false
123
- requirements:
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
124
141
  - - ">="
125
- - !ruby/object:Gem::Version
126
- hash: 3
127
- segments:
128
- - 0
129
- version: "0"
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
130
144
  requirements: []
131
-
132
145
  rubyforge_project:
133
- rubygems_version: 1.6.2
146
+ rubygems_version: 2.2.0
134
147
  signing_key:
135
- specification_version: 3
148
+ specification_version: 4
136
149
  summary: EbisuConnection supports to connect with Mysql slave servers.
137
- test_files: []
138
-
150
+ test_files:
151
+ - spec/spec_helper.rb
152
+ - spec/unit/greatest_common_divisor_spec.rb
153
+ - spec/unit/slave_group_spec.rb
154
+ - spec/unit/slave_spec.rb
@@ -1,119 +0,0 @@
1
- module EbisuConnection
2
- class Slaves
3
- class AllSlavesHasGoneError < StandardError; end
4
-
5
- class Slave
6
- attr_reader :hostname, :weight
7
-
8
- def initialize(conf, spec)
9
- case conf
10
- when String
11
- @hostname, weight = conf.split(/\s*,\s*/)
12
- edit_spec = {"host" => @hostname}
13
- when Hash
14
- conf = stringify_keys(conf)
15
- weight = conf.delete("weight")
16
- edit_spec = conf
17
- @hostname = conf["host"]
18
- else
19
- raise ArgumentError, "slaves config is invalid"
20
- end
21
-
22
- @spec = spec.merge(edit_spec)
23
- @weight = (weight || 1).to_i
24
- end
25
-
26
- def connection
27
- @connection ||= ActiveRecord::Base.send("#{@spec["adapter"]}_connection", @spec)
28
- end
29
-
30
- def disconnect!
31
- if @connection
32
- @connection.disconnect!
33
- @connection = nil
34
- end
35
- rescue
36
- end
37
-
38
- private
39
-
40
- def stringify_keys(hash)
41
- stringify_hash = {}
42
- hash.each do |k,v|
43
- stringify_hash[k.to_s] = v
44
- end
45
- stringify_hash
46
- end
47
- end
48
-
49
- def initialize(slaves_conf, spec)
50
- @slaves = slaves_conf.map do |conf|
51
- Slave.new(conf, spec)
52
- end
53
-
54
- recalc_roulette
55
- end
56
-
57
- def sample
58
- raise AllSlavesHasGoneError if @slaves.blank?
59
- @slaves[@roulette.sample]
60
- end
61
-
62
- def remove_connection(connection)
63
- return unless s = @slaves.detect{|s| s.connection == connection}
64
- s.disconnect! rescue nil
65
- @slaves.delete(s)
66
- raise AllSlavesHasGoneError if @slaves.blank?
67
- recalc_roulette
68
- nil
69
- end
70
-
71
- def all_disconnect!
72
- @reserve_release = nil
73
- @slaves.each {|s| s.disconnect!}
74
- end
75
-
76
- def reserve_release_connection!
77
- @reserve_release = true
78
- end
79
-
80
- def reserved_release?
81
- !!@reserve_release
82
- end
83
-
84
- private
85
-
86
- def recalc_roulette
87
- weight_list = @slaves.map {|s| s.weight }
88
-
89
- @roulette = []
90
- gcd = get_gcd(weight_list)
91
- weight_list.each_with_index do |w, index|
92
- weight = w / gcd
93
- @roulette.concat([index] * weight)
94
- end
95
- end
96
-
97
- def get_gcd(list)
98
- list = list.sort.uniq
99
- n = list.shift
100
- return n if n == 1 || list.empty?
101
-
102
- while !list.empty?
103
- m = list.shift
104
- n = gcd_euclid(m, n)
105
- end
106
- n
107
- end
108
-
109
- def gcd_euclid(m, n)
110
- m, n = n, m if m < n
111
- while n != 0
112
- work = m % n
113
- m = n
114
- n = work
115
- end
116
- m
117
- end
118
- end
119
- end