activerecord-turntable 1.0.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.
- data/.document +5 -0
- data/.gitignore +25 -0
- data/.rspec +3 -0
- data/Gemfile +25 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +290 -0
- data/Rakefile +101 -0
- data/activerecord-turntable.gemspec +47 -0
- data/lib/active_record/turntable.rb +58 -0
- data/lib/active_record/turntable/active_record_ext.rb +26 -0
- data/lib/active_record/turntable/active_record_ext/.gitkeep +0 -0
- data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +50 -0
- data/lib/active_record/turntable/active_record_ext/clever_load.rb +90 -0
- data/lib/active_record/turntable/active_record_ext/fixtures.rb +131 -0
- data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +64 -0
- data/lib/active_record/turntable/active_record_ext/persistence.rb +95 -0
- data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +107 -0
- data/lib/active_record/turntable/active_record_ext/sequencer.rb +28 -0
- data/lib/active_record/turntable/active_record_ext/transactions.rb +33 -0
- data/lib/active_record/turntable/algorithm.rb +7 -0
- data/lib/active_record/turntable/algorithm/.gitkeep +0 -0
- data/lib/active_record/turntable/algorithm/base.rb +11 -0
- data/lib/active_record/turntable/algorithm/range_algorithm.rb +37 -0
- data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +41 -0
- data/lib/active_record/turntable/base.rb +130 -0
- data/lib/active_record/turntable/cluster.rb +70 -0
- data/lib/active_record/turntable/compatible.rb +19 -0
- data/lib/active_record/turntable/config.rb +24 -0
- data/lib/active_record/turntable/connection_proxy.rb +218 -0
- data/lib/active_record/turntable/connection_proxy/mixable.rb +39 -0
- data/lib/active_record/turntable/error.rb +8 -0
- data/lib/active_record/turntable/helpers.rb +5 -0
- data/lib/active_record/turntable/helpers/test_helper.rb +25 -0
- data/lib/active_record/turntable/master_shard.rb +28 -0
- data/lib/active_record/turntable/migration.rb +132 -0
- data/lib/active_record/turntable/mixer.rb +203 -0
- data/lib/active_record/turntable/mixer/fader.rb +34 -0
- data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +15 -0
- data/lib/active_record/turntable/mixer/fader/insert_shards_merge_result.rb +24 -0
- data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +22 -0
- data/lib/active_record/turntable/mixer/fader/specified_shard.rb +12 -0
- data/lib/active_record/turntable/mixer/fader/update_shards_merge_result.rb +17 -0
- data/lib/active_record/turntable/pool_proxy.rb +56 -0
- data/lib/active_record/turntable/rack.rb +5 -0
- data/lib/active_record/turntable/rack/connection_management.rb +18 -0
- data/lib/active_record/turntable/railtie.rb +14 -0
- data/lib/active_record/turntable/railties/databases.rake +205 -0
- data/lib/active_record/turntable/seq_shard.rb +14 -0
- data/lib/active_record/turntable/sequencer.rb +46 -0
- data/lib/active_record/turntable/sequencer/api.rb +36 -0
- data/lib/active_record/turntable/sequencer/mysql.rb +32 -0
- data/lib/active_record/turntable/shard.rb +48 -0
- data/lib/active_record/turntable/sql_tree_patch.rb +199 -0
- data/lib/active_record/turntable/version.rb +5 -0
- data/lib/activerecord-turntable.rb +2 -0
- data/lib/generators/active_record/turntable/install_generator.rb +14 -0
- data/lib/generators/templates/turntable.yml +40 -0
- data/sample_app/.gitignore +16 -0
- data/sample_app/Gemfile +41 -0
- data/sample_app/README.rdoc +261 -0
- data/sample_app/Rakefile +7 -0
- data/sample_app/app/assets/images/rails.png +0 -0
- data/sample_app/app/assets/javascripts/application.js +15 -0
- data/sample_app/app/assets/stylesheets/application.css +13 -0
- data/sample_app/app/controllers/application_controller.rb +3 -0
- data/sample_app/app/helpers/application_helper.rb +2 -0
- data/sample_app/app/mailers/.gitkeep +0 -0
- data/sample_app/app/models/.gitkeep +0 -0
- data/sample_app/app/models/user.rb +4 -0
- data/sample_app/app/views/layouts/application.html.erb +14 -0
- data/sample_app/config.ru +4 -0
- data/sample_app/config/application.rb +65 -0
- data/sample_app/config/boot.rb +6 -0
- data/sample_app/config/database.yml +70 -0
- data/sample_app/config/environment.rb +5 -0
- data/sample_app/config/environments/development.rb +37 -0
- data/sample_app/config/environments/production.rb +67 -0
- data/sample_app/config/environments/test.rb +37 -0
- data/sample_app/config/initializers/backtrace_silencers.rb +7 -0
- data/sample_app/config/initializers/inflections.rb +15 -0
- data/sample_app/config/initializers/mime_types.rb +5 -0
- data/sample_app/config/initializers/secret_token.rb +7 -0
- data/sample_app/config/initializers/session_store.rb +8 -0
- data/sample_app/config/initializers/wrap_parameters.rb +14 -0
- data/sample_app/config/locales/en.yml +5 -0
- data/sample_app/config/routes.rb +58 -0
- data/sample_app/config/turntable.yml +64 -0
- data/sample_app/db/migrate/20120316073058_create_users.rb +11 -0
- data/sample_app/db/seeds.rb +7 -0
- data/sample_app/lib/assets/.gitkeep +0 -0
- data/sample_app/lib/tasks/.gitkeep +0 -0
- data/sample_app/log/.gitkeep +0 -0
- data/sample_app/public/404.html +26 -0
- data/sample_app/public/422.html +26 -0
- data/sample_app/public/500.html +25 -0
- data/sample_app/public/favicon.ico +0 -0
- data/sample_app/public/index.html +241 -0
- data/sample_app/public/robots.txt +5 -0
- data/sample_app/script/rails +6 -0
- data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
- data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/sample_app/vendor/plugins/.gitkeep +0 -0
- data/script/performance/algorithm +32 -0
- data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +81 -0
- data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +151 -0
- data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +35 -0
- data/spec/active_record/turntable/algorithm_spec.rb +69 -0
- data/spec/active_record/turntable/base_spec.rb +13 -0
- data/spec/active_record/turntable/cluster_spec.rb +18 -0
- data/spec/active_record/turntable/config_spec.rb +17 -0
- data/spec/active_record/turntable/connection_proxy_spec.rb +186 -0
- data/spec/active_record/turntable/finder_spec.rb +27 -0
- data/spec/active_record/turntable/mixer/fader_spec.rb +4 -0
- data/spec/active_record/turntable/mixer_spec.rb +114 -0
- data/spec/active_record/turntable/shard_spec.rb +21 -0
- data/spec/active_record/turntable_spec.rb +30 -0
- data/spec/config/database.yml +45 -0
- data/spec/config/turntable.yml +17 -0
- data/spec/fabricators/.gitkeep +0 -0
- data/spec/fabricators/turntable_fabricator.rb +14 -0
- data/spec/migrations/.gitkeep +0 -0
- data/spec/migrations/001_create_users.rb +16 -0
- data/spec/migrations/002_create_user_statuses.rb +16 -0
- data/spec/migrations/003_create_cards.rb +14 -0
- data/spec/migrations/004_create_cards_users.rb +15 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/test_models.rb +27 -0
- data/spec/turntable_helper.rb +29 -0
- metadata +367 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
|
3
|
+
|
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
|
6
|
+
require 'rails/commands'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'rspec'
|
|
3
|
+
require File.join(File.dirname(__FILE__), '../../../spec/spec_helper')
|
|
4
|
+
require 'benchmark'
|
|
5
|
+
|
|
6
|
+
def setup_algorithm(n, alg = "Range")
|
|
7
|
+
config = {
|
|
8
|
+
"shards" => n.times.map do |i|
|
|
9
|
+
{"connection" => "connection_#{i}", "less_than" => (i+1) * 100}
|
|
10
|
+
end
|
|
11
|
+
}
|
|
12
|
+
"ActiveRecord::Turntable::Algorithm::#{alg}Algorithm".constantize.new(config)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Benchmark.bm(40) do |x|
|
|
16
|
+
%w(Range RangeBsearch).each do |alg|
|
|
17
|
+
[2, 4, 8, 16, 32, 64, 128, 256, 512].map do |n|
|
|
18
|
+
algorithm = setup_algorithm(n, alg)
|
|
19
|
+
x.report("#{alg}: selrand(#{n}) * 1000") {
|
|
20
|
+
1000.times do
|
|
21
|
+
algorithm.calculate(rand(n*100))
|
|
22
|
+
end
|
|
23
|
+
}
|
|
24
|
+
x.report("#{alg}: sellast(#{n}) * 1000") {
|
|
25
|
+
1000.times do
|
|
26
|
+
algorithm.calculate(n*100-1)
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'logger'
|
|
3
|
+
|
|
4
|
+
describe ActiveRecord::Turntable::ActiveRecordExt::CleverLoad do
|
|
5
|
+
before(:all) do
|
|
6
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
before(:each) do
|
|
10
|
+
establish_connection_to("test")
|
|
11
|
+
truncate_shard
|
|
12
|
+
|
|
13
|
+
@user1 = User.new({:nickname => 'user1'})
|
|
14
|
+
@user1.id = 1
|
|
15
|
+
@user1.save
|
|
16
|
+
@user1_status = @user1.create_user_status(:hp => 10, :mp => 10)
|
|
17
|
+
@user2 = User.new({:nickname => 'user2'})
|
|
18
|
+
@user2.id = 2
|
|
19
|
+
@user2.save
|
|
20
|
+
@user2_status = @user2.create_user_status(:hp => 20, :mp => 10)
|
|
21
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "When a model has has_one relation" do
|
|
25
|
+
context "When call clever_load!" do
|
|
26
|
+
before(:each) do
|
|
27
|
+
@strio = StringIO.new
|
|
28
|
+
ActiveRecord::Base.logger = Logger.new(@strio)
|
|
29
|
+
@users = User.clever_load!(:user_status)
|
|
30
|
+
puts @strio.string
|
|
31
|
+
end
|
|
32
|
+
it "should send merged user_status select query" do
|
|
33
|
+
@strio.string.should =~ //
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should target loaded" do
|
|
37
|
+
@users.each do |user|
|
|
38
|
+
user.association(:user_status).loaded?.should be_true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should assigned reverse relation" do
|
|
43
|
+
pending "should be implemented"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "When a model has belongs_to relation" do
|
|
49
|
+
context "When call clever_load!" do
|
|
50
|
+
before(:each) do
|
|
51
|
+
@strio = StringIO.new
|
|
52
|
+
@strio = StringIO.new
|
|
53
|
+
ActiveRecord::Base.logger = Logger.new(@strio)
|
|
54
|
+
@user_statuses = UserStatus.clever_load!(:user)
|
|
55
|
+
puts @strio.string
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should send merged user_status select query" do
|
|
59
|
+
@strio.string.should =~ //
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should target loaded" do
|
|
63
|
+
@user_statuses.each do |user_status|
|
|
64
|
+
user_status.association(:user).loaded?.should be_true
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should assigned reverse relation" do
|
|
69
|
+
pending "should be implemented"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context "When a model has has_many relation" do
|
|
75
|
+
it "should send query only 2 times." do
|
|
76
|
+
pending "not implemented yet"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'logger'
|
|
3
|
+
|
|
4
|
+
describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
|
|
5
|
+
before(:all) do
|
|
6
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
before(:each) do
|
|
10
|
+
establish_connection_to("test")
|
|
11
|
+
truncate_shard
|
|
12
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:user) {
|
|
16
|
+
u = User.new({:nickname => 'foobar'})
|
|
17
|
+
u.id = 1
|
|
18
|
+
u.updated_at = Time.current - 1.day
|
|
19
|
+
u.save
|
|
20
|
+
u
|
|
21
|
+
}
|
|
22
|
+
let(:user_status){
|
|
23
|
+
stat = user.create_user_status(:hp => 10, :mp => 10)
|
|
24
|
+
stat.updated_at = Time.current - 1.day
|
|
25
|
+
stat.save
|
|
26
|
+
stat
|
|
27
|
+
}
|
|
28
|
+
let(:card){
|
|
29
|
+
Card.create!(:name => 'foobar')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
context "When the model is sharded by surrogate key" do
|
|
33
|
+
it "should not changed from normal operation when updating" do
|
|
34
|
+
user.nickname = "fizzbuzz"
|
|
35
|
+
strio = StringIO.new
|
|
36
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
37
|
+
expect {
|
|
38
|
+
user.save!
|
|
39
|
+
}.to_not raise_error
|
|
40
|
+
strio.string.should =~ /WHERE `users`\.`id` = #{user.id}[^\s]*$/
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should change updated_at when updating" do
|
|
44
|
+
user.nickname = "fizzbuzz"
|
|
45
|
+
|
|
46
|
+
lambda {
|
|
47
|
+
user.save!
|
|
48
|
+
}.should change(user, :updated_at)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should not changed from normal operation when destroying" do
|
|
52
|
+
strio = StringIO.new
|
|
53
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
54
|
+
expect {
|
|
55
|
+
user.destroy
|
|
56
|
+
}.to_not raise_error
|
|
57
|
+
strio.string.should =~ /WHERE `users`\.`id` = #{user.id}[^\s]*$/
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "When called Callbacks" do
|
|
62
|
+
before do
|
|
63
|
+
class ::User
|
|
64
|
+
after_destroy :on_destroy
|
|
65
|
+
after_save :on_update
|
|
66
|
+
|
|
67
|
+
def on_destroy
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def on_update
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context "on update once" do
|
|
76
|
+
it "callback should be called once" do
|
|
77
|
+
mock(user).on_update.times(1)
|
|
78
|
+
user.save
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
context "on destroy once" do
|
|
82
|
+
it "callback should be called once" do
|
|
83
|
+
mock(user).on_destroy.times(1)
|
|
84
|
+
user.destroy
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context "When the model is sharded by other key" do
|
|
90
|
+
it "should send shard_key condition when updating" do
|
|
91
|
+
user_status.hp = 20
|
|
92
|
+
|
|
93
|
+
strio = StringIO.new
|
|
94
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
95
|
+
expect {
|
|
96
|
+
user_status.save!
|
|
97
|
+
}.to_not raise_error
|
|
98
|
+
strio.string.should =~ /WHERE `user_statuses`\.`id` = #{user_status.id} AND `user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*$/
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should change updated_at when updating" do
|
|
102
|
+
user_status.hp = 20
|
|
103
|
+
|
|
104
|
+
lambda {
|
|
105
|
+
user_status.save!
|
|
106
|
+
}.should change(user_status, :updated_at)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should send shard_key condition when destroying" do
|
|
110
|
+
strio = StringIO.new
|
|
111
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
112
|
+
expect {
|
|
113
|
+
user_status.destroy
|
|
114
|
+
}.to_not raise_error
|
|
115
|
+
puts strio.string
|
|
116
|
+
strio.string.should =~ /WHERE `user_statuses`\.`id` = #{user_status.id} AND `user_statuses`\.`user_id` = #{user_status.user_id}[^\s]*$/
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should warn when creating without shard_key" do
|
|
120
|
+
pending "doesn't need to implemented soon"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "When the model is not sharded" do
|
|
125
|
+
it "should not send shard_key condition when updating" do
|
|
126
|
+
card.name = "barbaz"
|
|
127
|
+
strio = StringIO.new
|
|
128
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
129
|
+
expect {
|
|
130
|
+
card.save!
|
|
131
|
+
}.to_not raise_error
|
|
132
|
+
strio.string.should =~ /WHERE `cards`\.`id` = #{card.id}[^\s]*$/
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "should not send shard_key condition when destroying" do
|
|
136
|
+
strio = StringIO.new
|
|
137
|
+
ActiveRecord::Base.logger = Logger.new(strio)
|
|
138
|
+
expect {
|
|
139
|
+
card.destroy
|
|
140
|
+
}.to_not raise_error
|
|
141
|
+
strio.string.should =~ /WHERE `cards`\.`id` = #{card.id}[^\s]*$/
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
context "When call reload" do
|
|
146
|
+
subject { user_status.reload }
|
|
147
|
+
it { should be_instance_of(UserStatus)}
|
|
148
|
+
it { should == user_status }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveRecord::Turntable::Algorithm::RangeAlgorithm do
|
|
4
|
+
before(:all) do
|
|
5
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../../config/turntable.yml"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context "When initialized" do
|
|
9
|
+
before do
|
|
10
|
+
@alg = ActiveRecord::Turntable::Algorithm::RangeAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster])
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "#calculate with 1" do
|
|
14
|
+
subject { @alg.calculate(1) }
|
|
15
|
+
it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "#calculate with 19999" do
|
|
19
|
+
subject { @alg.calculate(19999) }
|
|
20
|
+
it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][0][:connection] }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "#calculate with 20000" do
|
|
24
|
+
subject { @alg.calculate(20000) }
|
|
25
|
+
it { should == ActiveRecord::Base.turntable_config[:clusters][:user_cluster][:shards][1][:connection] }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "#calculate with 10000000" do
|
|
29
|
+
it "raises ActiveRecord::Turntable::CannotSpecifyShardError" do
|
|
30
|
+
lambda { @alg.calculate(10000000) }.should raise_error(ActiveRecord::Turntable::CannotSpecifyShardError)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveRecord::Turntable::Algorithm do
|
|
4
|
+
before(:all) do
|
|
5
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../config/turntable.yml"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe ActiveRecord::Turntable::Algorithm::RangeBsearchAlgorithm do
|
|
9
|
+
let(:algorithm) { ActiveRecord::Turntable::Algorithm::RangeBsearchAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
|
|
10
|
+
context "#calculate" do
|
|
11
|
+
it "called with 1 returns user_shard_1" do
|
|
12
|
+
algorithm.calculate(1).should == "user_shard_1"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "called with 100000 returns user_shard_3" do
|
|
16
|
+
algorithm.calculate(100000).should == "user_shard_3"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "#calculate_used_shards_with_weight" do
|
|
21
|
+
it "called with 10 returns 1 item" do
|
|
22
|
+
algorithm.calculate_used_shards_with_weight(10).should have(1).items
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "called with 10 returns {\"user_shard_1\" => 10}" do
|
|
26
|
+
algorithm.calculate_used_shards_with_weight(10).should == {"user_shard_1" => 10}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "called with 65000 returns 2 items" do
|
|
30
|
+
algorithm.calculate_used_shards_with_weight(65000).should have(2).items
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "called with 65000 returns {\"user_shard_1\" => 39999, \"user_shard_2\" => 25001}" do
|
|
34
|
+
algorithm.calculate_used_shards_with_weight(65000).should == {"user_shard_1" => 39999, "user_shard_2" => 25001}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe ActiveRecord::Turntable::Algorithm::RangeAlgorithm do
|
|
40
|
+
let(:algorithm) { ActiveRecord::Turntable::Algorithm::RangeAlgorithm.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
|
|
41
|
+
context "#calculate" do
|
|
42
|
+
it "called with 1 returns user_shard_1" do
|
|
43
|
+
algorithm.calculate(1).should == "user_shard_1"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "called with 100000 returns user_shard_3" do
|
|
47
|
+
algorithm.calculate(100000).should == "user_shard_3"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "#calculate_used_shards_with_weight" do
|
|
52
|
+
it "called with 10 returns 1 item" do
|
|
53
|
+
algorithm.calculate_used_shards_with_weight(10).should have(1).items
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "called with 10 returns {\"user_shard_1\" => 10}" do
|
|
57
|
+
algorithm.calculate_used_shards_with_weight(10).should == {"user_shard_1" => 10}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "called with 65000 returns 2 items" do
|
|
61
|
+
algorithm.calculate_used_shards_with_weight(65000).should have(2).items
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "called with 65000 returns {\"user_shard_1\" => 39999, \"user_shard_2\" => 25001}" do
|
|
65
|
+
algorithm.calculate_used_shards_with_weight(65000).should == {"user_shard_1" => 39999, "user_shard_2" => 25001}
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveRecord::Turntable::Base do
|
|
4
|
+
before(:all) do
|
|
5
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../config/turntable.yml"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context "When installed to ActiveRecord::Base" do
|
|
9
|
+
it "ActiveRecord::Base respond_to 'turntable'" do
|
|
10
|
+
ActiveRecord::Base.should respond_to(:turntable)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveRecord::Turntable::Cluster do
|
|
4
|
+
before(:all) do
|
|
5
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../config/turntable.yml"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context "When initialized" do
|
|
9
|
+
before do
|
|
10
|
+
establish_connection_to("test")
|
|
11
|
+
truncate_shard
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
subject { ActiveRecord::Turntable::Cluster.new(User, ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
|
|
15
|
+
its(:klass) { should == User }
|
|
16
|
+
its(:shards) { should have(3).items }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActiveRecord::Turntable::Config do
|
|
4
|
+
before(:all) do
|
|
5
|
+
reload_turntable!(File.join(File.dirname(__FILE__), "../../config/turntable.yml"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
subject { ActiveRecord::Turntable::Config }
|
|
9
|
+
|
|
10
|
+
it "has config hash" do
|
|
11
|
+
subject.instance.instance_variable_get(:@config).should be_an_kind_of(Hash)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "has cluster setting" do
|
|
15
|
+
subject[:clusters][:user_cluster].should be_instance_of(ActiveSupport::HashWithIndifferentAccess)
|
|
16
|
+
end
|
|
17
|
+
end
|