switchman 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +30 -0
- data/app/models/switchman/shard.rb +502 -0
- data/db/migrate/20130328212039_create_switchman_shards.rb +9 -0
- data/db/migrate/20130328224244_create_default_shard.rb +9 -0
- data/lib/switchman.rb +9 -0
- data/lib/switchman/active_record/abstract_adapter.rb +11 -0
- data/lib/switchman/active_record/association.rb +108 -0
- data/lib/switchman/active_record/attribute_methods.rb +104 -0
- data/lib/switchman/active_record/base.rb +95 -0
- data/lib/switchman/active_record/calculations.rb +63 -0
- data/lib/switchman/active_record/connection_handler.rb +147 -0
- data/lib/switchman/active_record/connection_pool.rb +117 -0
- data/lib/switchman/active_record/finder_methods.rb +25 -0
- data/lib/switchman/active_record/log_subscriber.rb +43 -0
- data/lib/switchman/active_record/postgresql_adapter.rb +13 -0
- data/lib/switchman/active_record/query_cache.rb +12 -0
- data/lib/switchman/active_record/query_methods.rb +184 -0
- data/lib/switchman/active_record/relation.rb +69 -0
- data/lib/switchman/cache_extensions.rb +12 -0
- data/lib/switchman/connection_pool_proxy.rb +62 -0
- data/lib/switchman/database_server.rb +197 -0
- data/lib/switchman/default_shard.rb +28 -0
- data/lib/switchman/engine.rb +91 -0
- data/lib/switchman/r_spec_helper.rb +124 -0
- data/lib/switchman/shackles.rb +34 -0
- data/lib/switchman/test_helper.rb +65 -0
- data/lib/switchman/version.rb +3 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/models/appendage.rb +24 -0
- data/spec/dummy/app/models/digit.rb +9 -0
- data/spec/dummy/app/models/feature.rb +5 -0
- data/spec/dummy/app/models/mirror_user.rb +5 -0
- data/spec/dummy/app/models/user.rb +23 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/database.yml.example +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/db/migrate/20130403132607_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20130411202442_create_appendages.rb +10 -0
- data/spec/dummy/db/migrate/20130411202551_create_mirror_users.rb +9 -0
- data/spec/dummy/db/migrate/20131022202028_create_digits.rb +10 -0
- data/spec/dummy/db/migrate/20131206172923_create_features.rb +12 -0
- data/spec/dummy/db/schema.rb +57 -0
- data/spec/dummy/log/development.log +504 -0
- data/spec/dummy/log/test.log +29907 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/tmp/cache/2E2/830/shard%2F2 +0 -0
- data/spec/dummy/tmp/cache/2E3/840/shard%2F3 +0 -0
- data/spec/dummy/tmp/cache/313/970/shard%2F30 +0 -0
- data/spec/dummy/tmp/cache/314/980/shard%2F31 +0 -0
- data/spec/dummy/tmp/cache/316/980/shard%2F15 +1 -0
- data/spec/dummy/tmp/cache/316/9D0/shard%2F60 +0 -0
- data/spec/dummy/tmp/cache/317/990/shard%2F16 +0 -0
- data/spec/dummy/tmp/cache/317/9C0/shard%2F43 +1 -0
- data/spec/dummy/tmp/cache/317/9E0/shard%2F61 +0 -0
- data/spec/dummy/tmp/cache/318/9A0/shard%2F17 +0 -0
- data/spec/dummy/tmp/cache/318/9D0/shard%2F44 +0 -0
- data/spec/dummy/tmp/cache/318/9F0/shard%2F62 +1 -0
- data/spec/dummy/tmp/cache/319/9E0/shard%2F45 +0 -0
- data/spec/dummy/tmp/cache/319/9F0/shard%2F54 +1 -0
- data/spec/dummy/tmp/cache/319/A10/shard%2F72 +1 -0
- data/spec/dummy/tmp/cache/319/A30/shard%2F90 +0 -0
- data/spec/dummy/tmp/cache/31B/9E0/shard%2F29 +1 -0
- data/spec/dummy/tmp/cache/321/AA0/shard%2F89 +0 -0
- data/spec/dummy/tmp/cache/322/AC0/shard%2F99 +1 -0
- data/spec/dummy/tmp/cache/344/D70/shard%2F103 +1 -0
- data/spec/dummy/tmp/cache/345/D80/shard%2F104 +0 -0
- data/spec/dummy/tmp/cache/345/DB0/shard%2F131 +1 -0
- data/spec/dummy/tmp/cache/345/DC0/shard%2F140 +0 -0
- data/spec/dummy/tmp/cache/346/D90/shard%2F105 +0 -0
- data/spec/dummy/tmp/cache/346/DB0/shard%2F123 +0 -0
- data/spec/dummy/tmp/cache/346/DD0/shard%2F222 +1 -0
- data/spec/dummy/tmp/cache/346/DE0/shard%2F150 +0 -0
- data/spec/dummy/tmp/cache/346/DF0/shard%2F240 +1 -0
- data/spec/dummy/tmp/cache/347/DA0/shard%2F106 +1 -0
- data/spec/dummy/tmp/cache/347/DC0/shard%2F124 +0 -0
- data/spec/dummy/tmp/cache/347/DC0/shard%2F205 +1 -0
- data/spec/dummy/tmp/cache/347/E10/shard%2F250 +1 -0
- data/spec/dummy/tmp/cache/348/DF0/shard%2F143 +1 -0
- data/spec/dummy/tmp/cache/348/DF0/shard%2F224 +1 -0
- data/spec/dummy/tmp/cache/348/E10/shard%2F161 +1 -0
- data/spec/dummy/tmp/cache/349/DD0/shard%2F117 +1 -0
- data/spec/dummy/tmp/cache/349/E40/shard%2F180 +1 -0
- data/spec/dummy/tmp/cache/34A/DF0/shard%2F127 +1 -0
- data/spec/dummy/tmp/cache/34A/DF0/shard%2F208 +1 -0
- data/spec/dummy/tmp/cache/34A/E10/shard%2F145 +1 -0
- data/spec/dummy/tmp/cache/34A/E60/shard%2F190 +1 -0
- data/spec/dummy/tmp/cache/34B/E30/shard%2F155 +1 -0
- data/spec/dummy/tmp/cache/34D/E30/shard%2F139 +0 -0
- data/spec/dummy/tmp/cache/34E/E50/shard%2F149 +0 -0
- data/spec/dummy/tmp/cache/353/EF0/shard%2F199 +1 -0
- data/spec/dummy/tmp/cache/3A4/E90/shard%2F10003 +1 -0
- data/spec/dummy/tmp/cache/3A5/ED0/shard%2F10031 +1 -0
- data/spec/dummy/tmp/cache/3A9/EF0/shard%2F10017 +1 -0
- data/spec/lib/active_record/association_spec.rb +305 -0
- data/spec/lib/active_record/attribute_methods_spec.rb +108 -0
- data/spec/lib/active_record/base_spec.rb +66 -0
- data/spec/lib/active_record/calculations_spec.rb +119 -0
- data/spec/lib/active_record/connection_handler_spec.rb +45 -0
- data/spec/lib/active_record/connection_pool_spec.rb +23 -0
- data/spec/lib/active_record/finder_methods_spec.rb +29 -0
- data/spec/lib/active_record/query_cache_spec.rb +20 -0
- data/spec/lib/active_record/query_methods_spec.rb +130 -0
- data/spec/lib/active_record/relation_spec.rb +38 -0
- data/spec/lib/cache_extensions_spec.rb +27 -0
- data/spec/lib/connection_pool_proxy_spec.rb +13 -0
- data/spec/lib/database_server_spec.rb +154 -0
- data/spec/lib/shackles_spec.rb +147 -0
- data/spec/models/shard_spec.rb +382 -0
- data/spec/spec_helper.rb +32 -0
- metadata +344 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe AttributeMethods do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
describe "ids" do
|
9
|
+
it "should return id relative to the current shard" do
|
10
|
+
user = User.create!
|
11
|
+
user.id.should < Shard::IDS_PER_SHARD
|
12
|
+
user.local_id.should < Shard::IDS_PER_SHARD
|
13
|
+
user.global_id.should > Shard::IDS_PER_SHARD
|
14
|
+
|
15
|
+
@shard1.activate do
|
16
|
+
user.id.should > Shard::IDS_PER_SHARD
|
17
|
+
user.local_id.should < Shard::IDS_PER_SHARD
|
18
|
+
user.global_id.should > Shard::IDS_PER_SHARD
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return foreign keys relative to the current shard" do
|
23
|
+
appendage = Appendage.create!
|
24
|
+
|
25
|
+
# bypass the setter; we're going to test it in just a minute
|
26
|
+
|
27
|
+
# local id, should stay local
|
28
|
+
appendage.original_user_id = 6
|
29
|
+
appendage.user_id.should == 6
|
30
|
+
|
31
|
+
# (incorrect) self referencing global id; should come out as local
|
32
|
+
appendage.original_user_id = Shard.current.global_id_for(6)
|
33
|
+
appendage.user_id.should == 6
|
34
|
+
|
35
|
+
# global id referencing another shard; should come out unscathed
|
36
|
+
appendage.original_user_id = @shard1.global_id_for(6)
|
37
|
+
appendage.user_id.should == @shard1.global_id_for(6)
|
38
|
+
|
39
|
+
@shard1.activate do
|
40
|
+
# local id in another shard, should be global in this shard
|
41
|
+
appendage.original_user_id = 6
|
42
|
+
appendage.user_id.should == Shard.default.global_id_for(6)
|
43
|
+
|
44
|
+
# (incorrect) self referencing global id; should come out as global in this shard
|
45
|
+
appendage.original_user_id = Shard.default.global_id_for(6)
|
46
|
+
appendage.user_id.should == Shard.default.global_id_for(6)
|
47
|
+
|
48
|
+
# global id referencing this shard; should come out as a local id in this shard
|
49
|
+
appendage.original_user_id = @shard1.global_id_for(6)
|
50
|
+
appendage.user_id.should == 6
|
51
|
+
|
52
|
+
# global id from an unrelated shard; should stay global
|
53
|
+
appendage.original_user_id = @shard2.global_id_for(6)
|
54
|
+
appendage.user_id.should == @shard2.global_id_for(6)
|
55
|
+
end
|
56
|
+
|
57
|
+
# now that we trust the getters, try the setters
|
58
|
+
|
59
|
+
# local stays local
|
60
|
+
appendage.user_id = 6
|
61
|
+
appendage.original_user_id.should == 6
|
62
|
+
appendage.user_id = '6'
|
63
|
+
appendage.original_user_id.should == 6
|
64
|
+
|
65
|
+
# (incorrect) global id to this shard, should become local
|
66
|
+
appendage.user_id = Shard.current.global_id_for(6)
|
67
|
+
appendage.original_user_id.should == 6
|
68
|
+
appendage.user_id = Shard.current.global_id_for(6).to_s
|
69
|
+
appendage.original_user_id.should == 6
|
70
|
+
|
71
|
+
# global id from another shard, should stay global
|
72
|
+
appendage.user_id = @shard1.global_id_for(6)
|
73
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
74
|
+
appendage.local_user_id.should == 6
|
75
|
+
appendage.user_id = @shard1.global_id_for(6).to_s
|
76
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
77
|
+
appendage.local_user_id.should == 6
|
78
|
+
|
79
|
+
@shard1.activate do
|
80
|
+
# local to this shard becomes global
|
81
|
+
appendage.user_id = 6
|
82
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
83
|
+
appendage.user_id = '6'
|
84
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
85
|
+
|
86
|
+
# global id from original shard, should become local
|
87
|
+
appendage.user_id = Shard.default.global_id_for(6)
|
88
|
+
appendage.original_user_id.should == 6
|
89
|
+
appendage.user_id = Shard.default.global_id_for(6).to_s
|
90
|
+
appendage.original_user_id.should == 6
|
91
|
+
|
92
|
+
# global id from this shard, should stay global
|
93
|
+
appendage.user_id = Shard.current.global_id_for(6)
|
94
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
95
|
+
appendage.user_id = Shard.current.global_id_for(6).to_s
|
96
|
+
appendage.original_user_id.should == @shard1.global_id_for(6)
|
97
|
+
|
98
|
+
# global id from unrelated shard, should stay global
|
99
|
+
appendage.user_id = @shard2.global_id_for(6)
|
100
|
+
appendage.original_user_id.should == @shard2.global_id_for(6)
|
101
|
+
appendage.user_id = @shard2.global_id_for(6).to_s
|
102
|
+
appendage.original_user_id.should == @shard2.global_id_for(6)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe Base do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
describe "to_param" do
|
9
|
+
it "should return nil if not persisted" do
|
10
|
+
user = User.new
|
11
|
+
user.to_param.should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return local id if in the current shard" do
|
15
|
+
user = User.create!
|
16
|
+
user.to_param.should == user.local_id
|
17
|
+
@shard1.activate do
|
18
|
+
user2 = User.create!
|
19
|
+
user2.to_param.should == user2.local_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a short form global id if not in the current shard" do
|
24
|
+
user = nil
|
25
|
+
@shard1.activate do
|
26
|
+
user = User.create!
|
27
|
+
end
|
28
|
+
@shard2.activate do
|
29
|
+
user.to_param.should == "#{@shard1.id}~#{user.local_id}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should use to_param in url helpers" do
|
34
|
+
helpers = Rails.application.routes.url_helpers
|
35
|
+
user = nil
|
36
|
+
appendage = nil
|
37
|
+
|
38
|
+
@shard1.activate do
|
39
|
+
user = User.create!
|
40
|
+
appendage = Appendage.create!
|
41
|
+
|
42
|
+
helpers.user_path(user).should == "/users/#{user.local_id}"
|
43
|
+
helpers.user_appendages_path(user).should == "/users/#{user.local_id}/appendages"
|
44
|
+
helpers.user_appendage_path(user, appendage).should == "/users/#{user.local_id}/appendages/#{appendage.local_id}"
|
45
|
+
helpers.user_test1_path(user).should == "/users/#{user.local_id}"
|
46
|
+
helpers.user_test2_path(user).should == "/users/#{user.local_id}/test2"
|
47
|
+
end
|
48
|
+
|
49
|
+
@shard2.activate do
|
50
|
+
user_short_id = "#{@shard1.id}~#{user.local_id}"
|
51
|
+
appendage_short_id = "#{@shard1.id}~#{appendage.local_id}"
|
52
|
+
|
53
|
+
helpers.user_path(user).should == "/users/#{user_short_id}"
|
54
|
+
helpers.user_appendages_path(user).should == "/users/#{user_short_id}/appendages"
|
55
|
+
helpers.user_appendage_path(user, appendage).should == "/users/#{user_short_id}/appendages/#{appendage_short_id}"
|
56
|
+
helpers.user_test1_path(user).should == "/users/#{user_short_id}"
|
57
|
+
helpers.user_test2_path(user).should == "/users/#{user_short_id}/test2"
|
58
|
+
|
59
|
+
appendage2 = Appendage.create!
|
60
|
+
helpers.user_appendage_path(user, appendage2).should == "/users/#{user_short_id}/appendages/#{appendage2.local_id}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe Calculations do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
describe "#pluck" do
|
9
|
+
before do
|
10
|
+
@shard1.activate do
|
11
|
+
@user1 = User.create!(:name => "user1")
|
12
|
+
@appendage1 = @user1.appendages.create!
|
13
|
+
end
|
14
|
+
@shard2.activate do
|
15
|
+
@user2 = User.create!(:name => "user2")
|
16
|
+
@appendage2 = @user2.appendages.create!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return non-id columns" do
|
21
|
+
User.where(:id => [@user1.id, @user2.id]).pluck(:name).sort.should == ["user1", "user2"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return primary ids relative to current shard" do
|
25
|
+
Appendage.where(:id => @appendage1).pluck(:id).should == [@appendage1.global_id]
|
26
|
+
Appendage.where(:id => @appendage2).pluck(:id).should == [@appendage2.global_id]
|
27
|
+
@shard1.activate do
|
28
|
+
Appendage.where(:id => @appendage1).pluck(:id).should == [@appendage1.local_id]
|
29
|
+
Appendage.where(:id => @appendage2).pluck(:id).should == [@appendage2.global_id]
|
30
|
+
end
|
31
|
+
@shard2.activate do
|
32
|
+
Appendage.where(:id => @appendage1).pluck(:id).should == [@appendage1.global_id]
|
33
|
+
Appendage.where(:id => @appendage2).pluck(:id).should == [@appendage2.local_id]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return foreign ids relative to current shard" do
|
38
|
+
Appendage.where(:id => @appendage1).pluck(:user_id).should == [@user1.global_id]
|
39
|
+
Appendage.where(:id => @appendage2).pluck(:user_id).should == [@user2.global_id]
|
40
|
+
@shard1.activate do
|
41
|
+
Appendage.where(:id => @appendage1).pluck(:user_id).should == [@user1.local_id]
|
42
|
+
Appendage.where(:id => @appendage2).pluck(:user_id).should == [@user2.global_id]
|
43
|
+
end
|
44
|
+
@shard2.activate do
|
45
|
+
Appendage.where(:id => @appendage1).pluck(:user_id).should == [@user1.global_id]
|
46
|
+
Appendage.where(:id => @appendage2).pluck(:user_id).should == [@user2.local_id]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#execute_simple_calculation" do
|
52
|
+
before do
|
53
|
+
@appendages = []
|
54
|
+
@shard1.activate do
|
55
|
+
@user1 = User.create!(:name => "user1")
|
56
|
+
@appendages << @user1.appendages.create!(:value => 1)
|
57
|
+
@appendages << @user1.appendages.create!(:value => 2)
|
58
|
+
end
|
59
|
+
@shard2.activate do
|
60
|
+
@user2 = User.create!(:name => "user2")
|
61
|
+
@appendages << @user2.appendages.create!(:value => 3)
|
62
|
+
@appendages << @user2.appendages.create!(:value => 4)
|
63
|
+
@appendages << @user2.appendages.create!(:value => 5)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should calculate average across shards" do
|
68
|
+
@user1.appendages.average(:value).should == 1.5
|
69
|
+
@shard1.activate {Appendage.average(:value)}.should == 1.5
|
70
|
+
|
71
|
+
@user2.appendages.average(:value).should == 4
|
72
|
+
@shard2.activate {Appendage.average(:value)}.should == 4
|
73
|
+
|
74
|
+
Appendage.where(:id => @appendages).average(:value).should == 3
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should count across shards" do
|
78
|
+
@user1.appendages.count.should == 2
|
79
|
+
@shard1.activate {Appendage.count}.should == 2
|
80
|
+
|
81
|
+
@user2.appendages.count.should == 3
|
82
|
+
@shard2.activate {Appendage.count}.should == 3
|
83
|
+
|
84
|
+
Appendage.where(:id => @appendages).count.should == 5
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should calculate minimum across shards" do
|
88
|
+
@user1.appendages.minimum(:value).should == 1
|
89
|
+
@shard1.activate {Appendage.minimum(:value)}.should == 1
|
90
|
+
|
91
|
+
@user2.appendages.minimum(:value).should == 3
|
92
|
+
@shard2.activate {Appendage.minimum(:value)}.should == 3
|
93
|
+
|
94
|
+
Appendage.where(:id => @appendages).minimum(:value).should == 1
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should calculate maximum across shards" do
|
98
|
+
@user1.appendages.maximum(:value).should == 2
|
99
|
+
@shard1.activate {Appendage.maximum(:value)}.should == 2
|
100
|
+
|
101
|
+
@user2.appendages.maximum(:value).should == 5
|
102
|
+
@shard2.activate {Appendage.maximum(:value)}.should == 5
|
103
|
+
|
104
|
+
Appendage.where(:id => @appendages).maximum(:value).should == 5
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should calculate sum across shards" do
|
108
|
+
@user1.appendages.sum(:value).should == 3
|
109
|
+
@shard1.activate {Appendage.sum(:value)}.should == 3
|
110
|
+
|
111
|
+
@user2.appendages.sum(:value).should == 12
|
112
|
+
@shard2.activate {Appendage.sum(:value)}.should == 12
|
113
|
+
|
114
|
+
Appendage.where(:id => @appendages).sum(:value).should == 15
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe ConnectionHandler do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
it "should use different proxies for different categories" do
|
9
|
+
Shard.connection_pool.should_not == User.connection_pool
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should share underlying pools for different categories on the same shard" do
|
13
|
+
Shard.connection_pool.current_pool.should == User.connection_pool.current_pool
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should insert sharding for connections established after initialization" do
|
17
|
+
User.connection_pool.should == ::ActiveRecord::Base.connection_pool
|
18
|
+
begin
|
19
|
+
config = { :adapter => 'sqlite3', :database => ':memory:', :something_unique_in_the_spec => true }
|
20
|
+
User.establish_connection(config)
|
21
|
+
User.connection_pool.should_not == ::ActiveRecord::Base.connection_pool
|
22
|
+
User.connection_pool.spec.config.should == config
|
23
|
+
User.connection_pool.should be_is_a(ConnectionPoolProxy)
|
24
|
+
@shard2.activate do
|
25
|
+
User.connection_pool.spec.config.should == ::ActiveRecord::Base.connection_pool.spec.config
|
26
|
+
User.connection_pool.spec.config.should_not == config
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
User.remove_connection
|
30
|
+
User.connection_pool.should == ::ActiveRecord::Base.connection_pool
|
31
|
+
User.connection_pool.should be_is_a(ConnectionPoolProxy)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set up separate pools for different categories" do
|
36
|
+
User.connection_pool.should_not == MirrorUser.connection_pool
|
37
|
+
mu = MirrorUser.create!
|
38
|
+
MirrorUser.find(mu.local_id).should == mu
|
39
|
+
# didn't activate the :mirror_universe category
|
40
|
+
@shard1.activate { MirrorUser.find(mu.local_id).should == mu }
|
41
|
+
@shard1.activate(:mirror_universe) { MirrorUser.find_by_id(mu.local_id).should == nil }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe ConnectionPool do
|
6
|
+
it "should be able to access another shard on a db server after the 'primary' shard is gone" do
|
7
|
+
pending 'A "real" database"' unless Shard.default.database_server.shareable?
|
8
|
+
# separate connections
|
9
|
+
server = DatabaseServer.create(:config => Shard.default.database_server.config.dup)
|
10
|
+
s1 = server.shards.create!(:name => 'non_existent_shard') # don't actually create any schema
|
11
|
+
s2 = server.shards.create! # inherit's the default shard's config, which is functional
|
12
|
+
s1.activate do
|
13
|
+
lambda { User.count }.should raise_exception
|
14
|
+
end
|
15
|
+
# the config for s1 should not be the permanent default for all new
|
16
|
+
# connections now
|
17
|
+
s2.activate do
|
18
|
+
lambda { User.count }.should_not raise_exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe FinderMethods do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@user = @shard1.activate { User.create! }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#find_one" do
|
13
|
+
it "should find with a global id" do
|
14
|
+
User.find(@user.global_id).should == @user
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#find_by_attributes" do
|
19
|
+
it "should find with a global id" do
|
20
|
+
User.find_by_id(@user.global_id).should == @user
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should find with an array of global ids" do
|
24
|
+
User.find_by_id([@user.global_id]).should == @user
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe QueryCache do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
it "should isolate queries to multiple shards on the same server" do
|
9
|
+
@shard1.activate do
|
10
|
+
User.create!
|
11
|
+
User.create!
|
12
|
+
end
|
13
|
+
@shard3.activate do
|
14
|
+
User.create!
|
15
|
+
end
|
16
|
+
@shard1.activate { User.all }.should_not == @shard3.activate { User.all }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe QueryMethods do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@user1 = User.create!
|
10
|
+
@appendage1 = @user1.appendages.create!
|
11
|
+
@user2 = @shard1.activate { User.create! }
|
12
|
+
@appendage2 = @user2.appendages.create!
|
13
|
+
@user3 = @shard2.activate { User.create! }
|
14
|
+
@appendage3 = @user3.appendages.create!
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#primary_shard" do
|
18
|
+
it "should be the shard if it's a shard" do
|
19
|
+
User.shard(Shard.default).primary_shard.should == Shard.default
|
20
|
+
User.shard(@shard1).primary_shard.should == @shard1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be the first shard of an array of shards" do
|
24
|
+
User.shard([Shard.default, @shard1]).primary_shard.should == Shard.default
|
25
|
+
User.shard([@shard1, Shard.default]).primary_shard.should == @shard1
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be the object's shard if it's a model" do
|
29
|
+
User.shard(@user1).primary_shard.should == Shard.default
|
30
|
+
User.shard(@user2).primary_shard.should == @shard1
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be the default shard if it's a scope of Shard" do
|
34
|
+
User.shard(Shard.scoped).primary_shard.should == Shard.default
|
35
|
+
@shard1.activate do
|
36
|
+
User.shard(Shard.scoped).primary_shard.should == Shard.default
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should default to the current shard" do
|
42
|
+
relation = User.scoped
|
43
|
+
relation.shard_value.should == Shard.default
|
44
|
+
relation.shard_source_value.should == :implicit
|
45
|
+
|
46
|
+
@shard1.activate do
|
47
|
+
relation.shard_value.should == Shard.default
|
48
|
+
|
49
|
+
relation = User.scoped
|
50
|
+
relation.shard_value.should == @shard1
|
51
|
+
relation.shard_source_value.should == :implicit
|
52
|
+
end
|
53
|
+
relation.shard_value.should == @shard1
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "with primary key conditions" do
|
57
|
+
it "should be changeable, and change conditions when it is changed" do
|
58
|
+
relation = User.where(:id => @user1).shard(@shard1)
|
59
|
+
relation.shard_value.should == @shard1
|
60
|
+
relation.shard_source_value.should == :explicit
|
61
|
+
relation.where_values.first.right.should == @user1.global_id
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should infer the shard from a single argument" do
|
65
|
+
relation = User.where(:id => @user2)
|
66
|
+
# execute on @shard1, with id local to that shard
|
67
|
+
relation.shard_value.should == @shard1
|
68
|
+
relation.where_values.first.right.should == @user2.local_id
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should infer the shard from multiple arguments" do
|
72
|
+
relation = User.where(:id => [@user2, @user2])
|
73
|
+
# execute on @shard1, with id local to that shard
|
74
|
+
relation.shard_value.should == @shard1
|
75
|
+
relation.where_values.first.right.should == [@user2.local_id, @user2.local_id]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should infer the correct shard from an array of 1" do
|
79
|
+
relation = User.where(:id => [@user2])
|
80
|
+
# execute on @shard1, with id local to that shard
|
81
|
+
relation.shard_value.should == @shard1
|
82
|
+
relation.where_values.first.right.should == [@user2.local_id]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should do nothing when it's an array of 0" do
|
86
|
+
relation = User.where(:id => [])
|
87
|
+
# execute on @shard1, with id local to that shard
|
88
|
+
relation.shard_value.should == Shard.default
|
89
|
+
relation.where_values.first.right.should == []
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should order the shards preferring the shard it already had as primary" do
|
93
|
+
relation = User.where(:id => [@user1, @user2])
|
94
|
+
relation.shard_value.should == [Shard.default, @shard1]
|
95
|
+
relation.where_values.first.right.should == [@user1.local_id, @user2.global_id]
|
96
|
+
|
97
|
+
@shard1.activate do
|
98
|
+
relation = User.where(:id => [@user1, @user2])
|
99
|
+
relation.shard_value.should == [@shard1, Shard.default]
|
100
|
+
relation.where_values.first.right.should == [@user1.global_id, @user2.local_id]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "with foreign key conditions" do
|
106
|
+
it "should be changeable, and change conditions when it is changed" do
|
107
|
+
relation = Appendage.where(:user_id => @user1)
|
108
|
+
relation.shard_value.should == Shard.default
|
109
|
+
relation.shard_source_value.should == :implicit
|
110
|
+
relation.where_values.first.right.should == @user1.local_id
|
111
|
+
|
112
|
+
relation = relation.shard(@shard1)
|
113
|
+
relation.shard_value.should == @shard1
|
114
|
+
relation.shard_source_value.should == :explicit
|
115
|
+
relation.where_values.first.right.should == @user1.global_id
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should translate ids based on current shard" do
|
119
|
+
relation = Appendage.where(:user_id => [@user1, @user2])
|
120
|
+
relation.where_values.first.right.should == [@user1.local_id, @user2.global_id]
|
121
|
+
|
122
|
+
@shard1.activate do
|
123
|
+
relation = Appendage.where(:user_id => [@user1, @user2])
|
124
|
+
relation.where_values.first.right.should == [@user1.global_id, @user2.local_id]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|