ar-octopus 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +10 -2
- data/Appraisals +4 -0
- data/README.mkdn +1 -1
- data/gemfiles/rails51.gemfile +7 -0
- data/lib/octopus.rb +11 -6
- data/lib/octopus/collection_association.rb +9 -3
- data/lib/octopus/finder_methods.rb +1 -1
- data/lib/octopus/load_balancing/round_robin.rb +1 -0
- data/lib/octopus/log_subscriber.rb +6 -2
- data/lib/octopus/migration.rb +25 -9
- data/lib/octopus/model.rb +17 -25
- data/lib/octopus/proxy.rb +78 -279
- data/lib/octopus/proxy_config.rb +252 -0
- data/lib/octopus/relation_proxy.rb +7 -1
- data/lib/octopus/scope_proxy.rb +1 -1
- data/lib/octopus/shard_tracking.rb +2 -1
- data/lib/octopus/version.rb +1 -1
- data/spec/migrations/10_create_users_using_replication.rb +1 -1
- data/spec/migrations/11_add_field_in_all_slaves.rb +1 -1
- data/spec/migrations/12_create_users_using_block.rb +1 -1
- data/spec/migrations/13_create_users_using_block_and_using.rb +1 -1
- data/spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb +1 -1
- data/spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb +1 -1
- data/spec/migrations/1_create_users_on_master.rb +1 -1
- data/spec/migrations/2_create_users_on_canada.rb +1 -1
- data/spec/migrations/3_create_users_on_both_shards.rb +1 -1
- data/spec/migrations/4_create_users_on_shards_of_a_group.rb +1 -1
- data/spec/migrations/5_create_users_on_multiples_groups.rb +1 -1
- data/spec/migrations/6_raise_exception_with_invalid_shard_name.rb +1 -1
- data/spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb +1 -1
- data/spec/migrations/8_raise_exception_with_invalid_group_name.rb +1 -1
- data/spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb +1 -1
- data/spec/octopus/association_shard_tracking_spec.rb +15 -15
- data/spec/octopus/load_balancing/round_robin_spec.rb +15 -0
- data/spec/octopus/log_subscriber_spec.rb +1 -1
- data/spec/octopus/model_spec.rb +34 -5
- data/spec/octopus/octopus_spec.rb +1 -1
- data/spec/octopus/proxy_spec.rb +16 -38
- data/spec/octopus/relation_proxy_spec.rb +4 -0
- data/spec/octopus/replication_spec.rb +5 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/support/octopus_helper.rb +1 -2
- data/spec/tasks/octopus.rake_spec.rb +2 -4
- metadata +7 -6
- data/.ruby-version +0 -1
- data/init.rb +0 -1
- data/rails/init.rb +0 -1
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Octopus::LoadBalancing::RoundRobin do
|
4
|
+
it "raises an error when no shards are given" do
|
5
|
+
expect do
|
6
|
+
Octopus::LoadBalancing::RoundRobin.new([])
|
7
|
+
end.to raise_error Octopus::Exception
|
8
|
+
end
|
9
|
+
|
10
|
+
it "does not raise an error if slaves given" do
|
11
|
+
expect do
|
12
|
+
Octopus::LoadBalancing::RoundRobin.new([:stub])
|
13
|
+
end.to_not raise_error Octopus::Exception
|
14
|
+
end
|
15
|
+
end
|
@@ -9,7 +9,7 @@ describe Octopus::LogSubscriber, :shards => [:canada] do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
after :each do
|
12
|
-
ActiveRecord::Base.logger =
|
12
|
+
ActiveRecord::Base.logger = Logger.new(File.open('database.log', 'a'))
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should add to the default logger the shard name the query was sent to' do
|
data/spec/octopus/model_spec.rb
CHANGED
@@ -90,7 +90,7 @@ describe Octopus::Model do
|
|
90
90
|
Octopus.using(:canada) do
|
91
91
|
fail 'Some Exception'
|
92
92
|
end
|
93
|
-
end.to raise_error
|
93
|
+
end.to raise_error(RuntimeError)
|
94
94
|
|
95
95
|
expect(ActiveRecord::Base.connection.current_shard).to eq(:master)
|
96
96
|
end
|
@@ -103,7 +103,7 @@ describe Octopus::Model do
|
|
103
103
|
Octopus.using(:canada) do
|
104
104
|
fail 'Some Exception'
|
105
105
|
end
|
106
|
-
end.to raise_error
|
106
|
+
end.to raise_error(RuntimeError)
|
107
107
|
|
108
108
|
expect(ActiveRecord::Base.connection.current_shard).to eq(:brazil)
|
109
109
|
Octopus.config[:master_shard] = nil
|
@@ -476,6 +476,34 @@ describe Octopus::Model do
|
|
476
476
|
expect(User.using(:master).count).to eq(1)
|
477
477
|
end
|
478
478
|
|
479
|
+
describe "#finder methods" do
|
480
|
+
before(:each) do
|
481
|
+
@user1 = User.using(:brazil).create!(:name => 'User1')
|
482
|
+
@user2 = User.using(:brazil).create!(:name => 'User2')
|
483
|
+
@user3 = User.using(:brazil).create!(:name => 'User3')
|
484
|
+
end
|
485
|
+
|
486
|
+
it "#find_each should work" do
|
487
|
+
result_array = []
|
488
|
+
|
489
|
+
User.using(:brazil).where("name is not NULL").find_each do |user|
|
490
|
+
result_array << user
|
491
|
+
end
|
492
|
+
|
493
|
+
expect(result_array).to eq([@user1, @user2, @user3])
|
494
|
+
end
|
495
|
+
|
496
|
+
it "#find_in_batches, should work" do
|
497
|
+
result_array = []
|
498
|
+
|
499
|
+
User.using(:brazil).where("name is not NULL").find_in_batches(batch_size: 1) do |user|
|
500
|
+
result_array << user
|
501
|
+
end
|
502
|
+
|
503
|
+
expect(result_array).to eq([[@user1], [@user2], [@user3]])
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
479
507
|
describe 'deleting a record' do
|
480
508
|
before(:each) do
|
481
509
|
@user = User.using(:brazil).create!(:name => 'User1')
|
@@ -665,20 +693,21 @@ describe Octopus::Model do
|
|
665
693
|
it 'should work correctly when using validations' do
|
666
694
|
@key = Keyboard.create!(:name => 'Key')
|
667
695
|
expect { Keyboard.using(:brazil).create!(:name => 'Key') }.not_to raise_error
|
668
|
-
expect { Keyboard.create!(:name => 'Key') }.to raise_error
|
696
|
+
expect { Keyboard.create!(:name => 'Key') }.to raise_error(ActiveRecord::RecordInvalid)
|
669
697
|
end
|
670
698
|
|
671
699
|
it 'should work correctly when using validations with using syntax' do
|
672
700
|
@key = Keyboard.using(:brazil).create!(:name => 'Key')
|
673
701
|
expect { Keyboard.create!(:name => 'Key') }.not_to raise_error
|
674
|
-
expect { Keyboard.using(:brazil).create!(:name => 'Key') }
|
702
|
+
expect { Keyboard.using(:brazil).create!(:name => 'Key') }
|
703
|
+
.to raise_error(ActiveRecord::RecordInvalid)
|
675
704
|
end
|
676
705
|
end
|
677
706
|
|
678
707
|
describe '#replicated_model method' do
|
679
708
|
it 'should be replicated' do
|
680
709
|
OctopusHelper.using_environment :production_replicated do
|
681
|
-
expect(ActiveRecord::Base.connection_proxy.
|
710
|
+
expect(ActiveRecord::Base.connection_proxy.replicated).to be true
|
682
711
|
end
|
683
712
|
end
|
684
713
|
|
@@ -37,7 +37,7 @@ describe Octopus, :shards => [] do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should permit users to configure shards on initializer files, instead of on a yml file.' do
|
40
|
-
expect { User.using(:crazy_shard).create!(:name => 'Joaquim') }.to raise_error
|
40
|
+
expect { User.using(:crazy_shard).create!(:name => 'Joaquim') }.to raise_error(RuntimeError)
|
41
41
|
|
42
42
|
Octopus.setup do |config|
|
43
43
|
config.shards = { :crazy_shard => { :adapter => 'mysql2', :database => 'octopus_shard_5', :username => 'root', :password => '' } }
|
data/spec/octopus/proxy_spec.rb
CHANGED
@@ -6,10 +6,10 @@ describe Octopus::Proxy do
|
|
6
6
|
describe 'creating a new instance', :shards => [] do
|
7
7
|
it 'should initialize all shards and groups' do
|
8
8
|
# FIXME: Don't test implementation details
|
9
|
-
expect(proxy.
|
9
|
+
expect(proxy.shards).to include('canada', 'brazil', 'master', 'sqlite_shard', 'russia', 'alone_shard',
|
10
10
|
'aug2009', 'postgresql_shard', 'aug2010', 'aug2011')
|
11
11
|
|
12
|
-
expect(proxy.
|
12
|
+
expect(proxy.shards).to include('protocol_shard')
|
13
13
|
|
14
14
|
expect(proxy.has_group?('country_shards')).to be true
|
15
15
|
expect(proxy.shards_for_group('country_shards')).to include(:canada, :brazil, :russia)
|
@@ -23,23 +23,17 @@ describe Octopus::Proxy do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'should initialize replicated attribute as false' do
|
26
|
-
expect(proxy.
|
26
|
+
expect(proxy.replicated).to be_falsey
|
27
27
|
end
|
28
28
|
|
29
|
-
it 'should work with
|
30
|
-
config = proxy.
|
29
|
+
it 'should work with thinking sphinx' do
|
30
|
+
config = proxy.config
|
31
31
|
expect(config[:adapter]).to eq('mysql2')
|
32
32
|
expect(config[:database]).to eq('octopus_shard_1')
|
33
33
|
expect(config[:username]).to eq('root')
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
adapters = proxy.instance_variable_get(:@adapters)
|
38
|
-
expect(adapters).to be_kind_of(Set)
|
39
|
-
expect(adapters.to_a).to match_array(%w(sqlite3 mysql2 postgresql))
|
40
|
-
end
|
41
|
-
|
42
|
-
unless Octopus.rails5?
|
36
|
+
unless Octopus.rails50? || Octopus.rails51?
|
43
37
|
it 'should respond correctly to respond_to?(:pk_and_sequence_for)' do
|
44
38
|
expect(proxy.respond_to?(:pk_and_sequence_for)).to be true
|
45
39
|
end
|
@@ -63,22 +57,6 @@ describe Octopus::Proxy do
|
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
66
|
-
describe '#should_clean_table_name?' do
|
67
|
-
it 'should return true when you have a environment with multiple database types' do
|
68
|
-
expect(proxy.should_clean_table_name?).to be true
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'when using a environment with a single table name' do
|
72
|
-
before(:each) do
|
73
|
-
OctopusHelper.octopus_env = 'production_replicated'
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'should return false' do
|
77
|
-
expect(proxy.should_clean_table_name?).to be false
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
60
|
describe 'should raise error if you have duplicated shard names' do
|
83
61
|
before(:each) do
|
84
62
|
OctopusHelper.octopus_env = 'production_raise_error'
|
@@ -95,11 +73,11 @@ describe Octopus::Proxy do
|
|
95
73
|
end
|
96
74
|
|
97
75
|
it 'should initialize just the master shard' do
|
98
|
-
expect(proxy.
|
76
|
+
expect(proxy.shards.keys).to eq(['master'])
|
99
77
|
end
|
100
78
|
|
101
79
|
it 'should not initialize replication' do
|
102
|
-
expect(proxy.
|
80
|
+
expect(proxy.replicated).to be_nil
|
103
81
|
end
|
104
82
|
end
|
105
83
|
end
|
@@ -110,11 +88,11 @@ describe Octopus::Proxy do
|
|
110
88
|
end
|
111
89
|
|
112
90
|
it 'should have the replicated attribute as true' do
|
113
|
-
expect(proxy.
|
91
|
+
expect(proxy.replicated).to be true
|
114
92
|
end
|
115
93
|
|
116
94
|
it 'should initialize the list of shards' do
|
117
|
-
expect(proxy.
|
95
|
+
expect(proxy.slaves_list).to eq(%w(slave1 slave2 slave3 slave4))
|
118
96
|
end
|
119
97
|
end
|
120
98
|
|
@@ -137,7 +115,7 @@ describe Octopus::Proxy do
|
|
137
115
|
Octopus.instance_variable_set(:@environments, nil)
|
138
116
|
Octopus.config
|
139
117
|
|
140
|
-
expect(proxy.
|
118
|
+
expect(proxy.replicated).to be true
|
141
119
|
expect(Octopus.environments).to eq(%w(staging production))
|
142
120
|
end
|
143
121
|
|
@@ -147,7 +125,7 @@ describe Octopus::Proxy do
|
|
147
125
|
Octopus.instance_variable_set(:@environments, nil)
|
148
126
|
Octopus.config
|
149
127
|
|
150
|
-
expect(proxy.
|
128
|
+
expect(proxy.shards.keys.to_set).to eq(Set.new(%w(slave1 slave2 master)))
|
151
129
|
end
|
152
130
|
|
153
131
|
it 'should initialize correctly the shard octopus_shard value for logging' do
|
@@ -156,7 +134,7 @@ describe Octopus::Proxy do
|
|
156
134
|
Octopus.instance_variable_set(:@environments, nil)
|
157
135
|
Octopus.config
|
158
136
|
|
159
|
-
expect(proxy.
|
137
|
+
expect(proxy.shards['slave1'].spec.config).to have_key :octopus_shard
|
160
138
|
end
|
161
139
|
|
162
140
|
it 'should initialize correctly the shards for the production environment' do
|
@@ -165,7 +143,7 @@ describe Octopus::Proxy do
|
|
165
143
|
Octopus.instance_variable_set(:@environments, nil)
|
166
144
|
Octopus.config
|
167
145
|
|
168
|
-
expect(proxy.
|
146
|
+
expect(proxy.shards.keys.to_set).to eq(Set.new(%w(slave3 slave4 master)))
|
169
147
|
end
|
170
148
|
|
171
149
|
describe 'using the master connection', :shards => [:russia, :master] do
|
@@ -234,12 +212,12 @@ describe Octopus::Proxy do
|
|
234
212
|
|
235
213
|
describe 'should return the connection based on shard_name' do
|
236
214
|
it 'when current_shard is empty' do
|
237
|
-
expect(proxy.select_connection).to eq(proxy.
|
215
|
+
expect(proxy.select_connection).to eq(proxy.shards[:master].connection)
|
238
216
|
end
|
239
217
|
|
240
218
|
it 'when current_shard is a single shard' do
|
241
219
|
proxy.current_shard = :canada
|
242
|
-
expect(proxy.select_connection).to eq(proxy.
|
220
|
+
expect(proxy.select_connection).to eq(proxy.shards[:canada].connection)
|
243
221
|
end
|
244
222
|
end
|
245
223
|
end
|
@@ -38,6 +38,10 @@ describe Octopus::RelationProxy do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
it "can deliver methods in ActiveRecord::Batches correctly" do
|
42
|
+
expect { @relation.find_each(&:inspect) }.not_to raise_error
|
43
|
+
end
|
44
|
+
|
41
45
|
context 'under Rails 4' do
|
42
46
|
it 'is an Octopus::RelationProxy' do
|
43
47
|
expect{@relation.ar_relation}.not_to raise_error
|
@@ -42,7 +42,11 @@ describe 'when the database is replicated' do
|
|
42
42
|
expect(Cat.find(cat3.id).id).to eq(cat3.id)
|
43
43
|
expect(Cat.find(cat3.id).id).to eq(cat3.id)
|
44
44
|
|
45
|
-
|
45
|
+
# Rails 5.1 count the cached queries as regular queries.
|
46
|
+
# TODO: How we can verify if the queries are using cache on Rails 5.1? - @thiagopradi
|
47
|
+
expected_records = Octopus.rails51? ? 19 : 14
|
48
|
+
|
49
|
+
expect(counter.query_count).to eq(expected_records)
|
46
50
|
end
|
47
51
|
end
|
48
52
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,8 @@ require 'octopus'
|
|
5
5
|
|
6
6
|
Octopus.instance_variable_set(:@directory, File.dirname(__FILE__))
|
7
7
|
|
8
|
+
BaseOctopusMigrationClass = (Octopus.rails4? ? ActiveRecord::Migration : ActiveRecord::Migration[ActiveRecord::VERSION::STRING[0..2]])
|
9
|
+
|
8
10
|
# Requires supporting files with custom matchers and macros, etc,
|
9
11
|
# in ./support/ and its subdirectories.
|
10
12
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module OctopusHelper
|
2
2
|
def self.clean_all_shards(shards)
|
3
3
|
if shards.nil?
|
4
|
-
shards = BlankModel.using(:master).connection.
|
4
|
+
shards = BlankModel.using(:master).connection.shards.keys
|
5
5
|
end
|
6
6
|
|
7
7
|
shards.each do |shard_symbol|
|
@@ -23,7 +23,6 @@ module OctopusHelper
|
|
23
23
|
Thread.current['octopus.current_group'] = nil
|
24
24
|
Thread.current['octopus.current_slave_group'] = nil
|
25
25
|
Thread.current['octopus.block'] = nil
|
26
|
-
Thread.current['octopus.last_current_shard'] = nil
|
27
26
|
|
28
27
|
ActiveRecord::Base.class_variable_set(:@@connection_proxy, nil)
|
29
28
|
end
|
@@ -24,10 +24,8 @@ describe 'octopus.rake' do
|
|
24
24
|
|
25
25
|
Rake::Task['octopus:copy_schema_versions'].invoke
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
ActiveRecord::Base.connection.shard_names.reject { |sh_name| sh_name == 'sqlite_shard' }.each do |shard_name|
|
30
|
-
expect(Octopus.using(shard_name) { ActiveRecord::Migrator.get_all_versions }).to eq([1, 2, 3])
|
27
|
+
ActiveRecord::Base.connection.shard_names.each do |shard_name|
|
28
|
+
expect(Octopus.using(shard_name) { ActiveRecord::SchemaMigration.all.pluck(:version).map(&:to_i).sort }).to eq([1, 2, 3])
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar-octopus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thiago Pradi
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2017-07-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -167,7 +167,6 @@ files:
|
|
167
167
|
- ".rspec"
|
168
168
|
- ".rubocop.yml"
|
169
169
|
- ".rubocop_todo.yml"
|
170
|
-
- ".ruby-version"
|
171
170
|
- ".travis.yml"
|
172
171
|
- Appraisals
|
173
172
|
- Gemfile
|
@@ -179,7 +178,7 @@ files:
|
|
179
178
|
- gemfiles/rails41.gemfile
|
180
179
|
- gemfiles/rails42.gemfile
|
181
180
|
- gemfiles/rails5.gemfile
|
182
|
-
-
|
181
|
+
- gemfiles/rails51.gemfile
|
183
182
|
- lib/ar-octopus.rb
|
184
183
|
- lib/octopus.rb
|
185
184
|
- lib/octopus/abstract_adapter.rb
|
@@ -197,6 +196,7 @@ files:
|
|
197
196
|
- lib/octopus/model.rb
|
198
197
|
- lib/octopus/persistence.rb
|
199
198
|
- lib/octopus/proxy.rb
|
199
|
+
- lib/octopus/proxy_config.rb
|
200
200
|
- lib/octopus/railtie.rb
|
201
201
|
- lib/octopus/relation_proxy.rb
|
202
202
|
- lib/octopus/scope_proxy.rb
|
@@ -207,7 +207,6 @@ files:
|
|
207
207
|
- lib/octopus/slave_group.rb
|
208
208
|
- lib/octopus/version.rb
|
209
209
|
- lib/tasks/octopus.rake
|
210
|
-
- rails/init.rb
|
211
210
|
- sample_app/.gitignore
|
212
211
|
- sample_app/.rspec
|
213
212
|
- sample_app/Gemfile
|
@@ -301,6 +300,7 @@ files:
|
|
301
300
|
- spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb
|
302
301
|
- spec/octopus/association_shard_tracking_spec.rb
|
303
302
|
- spec/octopus/collection_proxy_spec.rb
|
303
|
+
- spec/octopus/load_balancing/round_robin_spec.rb
|
304
304
|
- spec/octopus/log_subscriber_spec.rb
|
305
305
|
- spec/octopus/migration_spec.rb
|
306
306
|
- spec/octopus/model_spec.rb
|
@@ -344,7 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
344
344
|
version: '0'
|
345
345
|
requirements: []
|
346
346
|
rubyforge_project:
|
347
|
-
rubygems_version: 2.
|
347
|
+
rubygems_version: 2.2.2
|
348
348
|
signing_key:
|
349
349
|
specification_version: 4
|
350
350
|
summary: Easy Database Sharding for ActiveRecord
|
@@ -367,6 +367,7 @@ test_files:
|
|
367
367
|
- spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb
|
368
368
|
- spec/octopus/association_shard_tracking_spec.rb
|
369
369
|
- spec/octopus/collection_proxy_spec.rb
|
370
|
+
- spec/octopus/load_balancing/round_robin_spec.rb
|
370
371
|
- spec/octopus/log_subscriber_spec.rb
|
371
372
|
- spec/octopus/migration_spec.rb
|
372
373
|
- spec/octopus/model_spec.rb
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.1.5
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'rails', 'init')
|
data/rails/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'octopus'
|