ar-octopus 0.0.1 → 0.0.2
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/.gitignore +1 -0
- data/README.mkdn +2 -1
- data/Rakefile +1 -1
- data/ar-octopus.gemspec +95 -0
- data/lib/octopus.rb +4 -12
- data/lib/octopus/controller.rb +15 -2
- data/lib/octopus/model.rb +3 -0
- data/lib/octopus/proxy.rb +26 -15
- data/spec/migrations/10_create_users_using_replication.rb +9 -0
- data/spec/migrations/11_add_field_in_all_slaves.rb +11 -0
- data/spec/octopus/controller_spec.rb +31 -1
- data/spec/octopus/migration_spec.rb +38 -35
- data/spec/octopus/model_spec.rb +29 -50
- data/spec/octopus/proxy_spec.rb +0 -1
- data/spec/spec_helper.rb +22 -0
- metadata +9 -3
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/*.*
|
data/README.mkdn
CHANGED
@@ -12,7 +12,8 @@
|
|
12
12
|
- Moving data between shards with migrations.
|
13
13
|
- Tools to manage database configurations. (soon)
|
14
14
|
|
15
|
-
<p> To see the complete list of features and syntax, please check out our <a href="http://wiki.github.com/tchandy/octopus/"> Wiki</a>
|
15
|
+
<p> To see the complete list of features and syntax, please check out our <a href="http://wiki.github.com/tchandy/octopus/"> Wiki</a></p>
|
16
|
+
<p>Wanna see sample rails applications using octopus features? please check it out: <a href="http://github.com/tchandy/octopus_sharding_example">Sharding Example</a> and <a href="http://github.com/tchandy/octopus_replication_example">Replication Example</a> </p>
|
16
17
|
|
17
18
|
<h2>Thanks</h2>
|
18
19
|
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
gem.homepage = "http://github.com/tchandy/octopus"
|
13
13
|
gem.authors = ["Thiago Pradi", "Mike Perham", "Amit Agarwal"]
|
14
14
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
-
gem.version = "0.0.
|
15
|
+
gem.version = "0.0.2"
|
16
16
|
end
|
17
17
|
Jeweler::GemcutterTasks.new
|
18
18
|
rescue LoadError
|
data/ar-octopus.gemspec
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ar-octopus}
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Thiago Pradi", "Mike Perham", "Amit Agarwal"]
|
12
|
+
s.date = %q{2010-06-14}
|
13
|
+
s.description = %q{This gem allows you to use sharded databases with ActiveRecord. this also provides a interface for replication and for running migrations with multiples shards.}
|
14
|
+
s.email = %q{tchandy@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.mkdn"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.mkdn",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"ar-octopus.gemspec",
|
24
|
+
"doc/api.textile",
|
25
|
+
"doc/features.textile",
|
26
|
+
"doc/libraries.textile",
|
27
|
+
"doc/shards.yml",
|
28
|
+
"lib/octopus.rb",
|
29
|
+
"lib/octopus/controller.rb",
|
30
|
+
"lib/octopus/migration.rb",
|
31
|
+
"lib/octopus/model.rb",
|
32
|
+
"lib/octopus/proxy.rb",
|
33
|
+
"spec/config/shards.yml",
|
34
|
+
"spec/database_connection.rb",
|
35
|
+
"spec/database_models.rb",
|
36
|
+
"spec/migrations/10_create_users_using_replication.rb",
|
37
|
+
"spec/migrations/11_add_field_in_all_slaves.rb",
|
38
|
+
"spec/migrations/1_create_users_on_master.rb",
|
39
|
+
"spec/migrations/2_create_users_on_canada.rb",
|
40
|
+
"spec/migrations/3_create_users_on_both_shards.rb",
|
41
|
+
"spec/migrations/4_create_users_on_shards_of_a_group.rb",
|
42
|
+
"spec/migrations/5_create_users_on_multiples_groups.rb",
|
43
|
+
"spec/migrations/6_raise_exception_with_invalid_shard_name.rb",
|
44
|
+
"spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb",
|
45
|
+
"spec/migrations/8_raise_exception_with_invalid_group_name.rb",
|
46
|
+
"spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb",
|
47
|
+
"spec/octopus/controller_spec.rb",
|
48
|
+
"spec/octopus/migration_spec.rb",
|
49
|
+
"spec/octopus/model_spec.rb",
|
50
|
+
"spec/octopus/octopus_spec.rb",
|
51
|
+
"spec/octopus/proxy_spec.rb",
|
52
|
+
"spec/spec.opts",
|
53
|
+
"spec/spec_helper.rb"
|
54
|
+
]
|
55
|
+
s.homepage = %q{http://github.com/tchandy/octopus}
|
56
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
57
|
+
s.require_paths = ["lib"]
|
58
|
+
s.rubygems_version = %q{1.3.6}
|
59
|
+
s.summary = %q{Easy Database Sharding for ActiveRecord}
|
60
|
+
s.test_files = [
|
61
|
+
"spec/database_connection.rb",
|
62
|
+
"spec/database_models.rb",
|
63
|
+
"spec/migrations/10_create_users_using_replication.rb",
|
64
|
+
"spec/migrations/11_add_field_in_all_slaves.rb",
|
65
|
+
"spec/migrations/1_create_users_on_master.rb",
|
66
|
+
"spec/migrations/2_create_users_on_canada.rb",
|
67
|
+
"spec/migrations/3_create_users_on_both_shards.rb",
|
68
|
+
"spec/migrations/4_create_users_on_shards_of_a_group.rb",
|
69
|
+
"spec/migrations/5_create_users_on_multiples_groups.rb",
|
70
|
+
"spec/migrations/6_raise_exception_with_invalid_shard_name.rb",
|
71
|
+
"spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb",
|
72
|
+
"spec/migrations/8_raise_exception_with_invalid_group_name.rb",
|
73
|
+
"spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb",
|
74
|
+
"spec/octopus/controller_spec.rb",
|
75
|
+
"spec/octopus/migration_spec.rb",
|
76
|
+
"spec/octopus/model_spec.rb",
|
77
|
+
"spec/octopus/octopus_spec.rb",
|
78
|
+
"spec/octopus/proxy_spec.rb",
|
79
|
+
"spec/spec_helper.rb"
|
80
|
+
]
|
81
|
+
|
82
|
+
if s.respond_to? :specification_version then
|
83
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
84
|
+
s.specification_version = 3
|
85
|
+
|
86
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
87
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
88
|
+
else
|
89
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
data/lib/octopus.rb
CHANGED
@@ -2,25 +2,17 @@ require "yaml"
|
|
2
2
|
|
3
3
|
module Octopus
|
4
4
|
def self.env()
|
5
|
-
|
6
|
-
Rails.env.to_s
|
7
|
-
else
|
8
|
-
"production"
|
9
|
-
end
|
5
|
+
@@env ||= defined?(Rails) ? Rails.env.to_s : "production"
|
10
6
|
end
|
11
7
|
|
12
8
|
def self.config()
|
13
9
|
@@config ||= YAML.load_file(Octopus.directory() + "/config/shards.yml")
|
14
10
|
end
|
15
11
|
|
12
|
+
# Returns the Rails.root_to_s when you are using rails
|
13
|
+
# Running the current directory in a generic Ruby process
|
16
14
|
def self.directory()
|
17
|
-
|
18
|
-
# Running in a normal Rails application
|
19
|
-
Rails.root.to_s
|
20
|
-
else
|
21
|
-
# Running in a generic Ruby process
|
22
|
-
Dir.pwd
|
23
|
-
end
|
15
|
+
@@directory ||= defined?(Rails) ? Rails.root.to_s : Dir.pwd
|
24
16
|
end
|
25
17
|
end
|
26
18
|
|
data/lib/octopus/controller.rb
CHANGED
@@ -1,2 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Octopus::Controller
|
2
|
+
def using(shard, &block)
|
3
|
+
older_shard = ActiveRecord::Base.connection_proxy.current_shard
|
4
|
+
ActiveRecord::Base.connection_proxy.block = true
|
5
|
+
ActiveRecord::Base.connection_proxy.current_shard = shard
|
6
|
+
begin
|
7
|
+
yield
|
8
|
+
ensure
|
9
|
+
ActiveRecord::Base.connection_proxy.block = false
|
10
|
+
ActiveRecord::Base.connection_proxy.current_shard = older_shard
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActionController::Base.send(:include, Octopus::Controller) if defined?(ActionController)
|
data/lib/octopus/model.rb
CHANGED
@@ -28,6 +28,8 @@ module Octopus::Model
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
self.reset_table_name() if self != ActiveRecord::Base && self.respond_to?(:reset_table_name)
|
32
|
+
|
31
33
|
if block_given?
|
32
34
|
older_shard = self.connection_proxy.current_shard
|
33
35
|
self.connection_proxy.block = true
|
@@ -40,6 +42,7 @@ module Octopus::Model
|
|
40
42
|
end
|
41
43
|
else
|
42
44
|
self.connection_proxy.current_shard = shard
|
45
|
+
self.connection_proxy.using_enabled = true
|
43
46
|
return self
|
44
47
|
end
|
45
48
|
end
|
data/lib/octopus/proxy.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "set"
|
2
2
|
|
3
3
|
class Octopus::Proxy
|
4
|
-
attr_accessor :shards, :current_shard, :block, :groups, :current_group, :replicated, :slaves_list, :replicated_models
|
4
|
+
attr_accessor :shards, :current_shard, :block, :groups, :current_group, :replicated, :slaves_list, :replicated_models, :using_enabled
|
5
5
|
|
6
6
|
delegate :increment_open_transactions, :decrement_open_transactions, :to => :select_connection
|
7
7
|
|
@@ -13,6 +13,7 @@ class Octopus::Proxy
|
|
13
13
|
@replicated = config[Octopus.env()]["replicated"] || false
|
14
14
|
@shards[:master] = ActiveRecord::Base.connection_pool()
|
15
15
|
@current_shard = :master
|
16
|
+
@using_enabled = false
|
16
17
|
|
17
18
|
config[Octopus.env()]["shards"].each do |key, value|
|
18
19
|
if value.has_key?("adapter")
|
@@ -72,19 +73,25 @@ class Octopus::Proxy
|
|
72
73
|
def set_replicated_model(model)
|
73
74
|
replicated_models << model.to_s
|
74
75
|
end
|
76
|
+
|
77
|
+
def add_transaction_record(record)
|
78
|
+
if !select_connection().instance_variable_get(:@_current_transaction_records).nil?
|
79
|
+
select_connection().add_transaction_record(record)
|
80
|
+
end
|
81
|
+
end
|
75
82
|
|
76
|
-
def transaction(
|
83
|
+
def transaction(options = {}, &block)
|
77
84
|
if should_send_queries_to_multiple_shards?
|
78
|
-
self.send_transaction_to_multiple_shards(current_shard,
|
85
|
+
self.send_transaction_to_multiple_shards(current_shard, options, &block)
|
79
86
|
self.current_shard = :master
|
80
87
|
elsif should_send_queries_to_multiple_groups?
|
81
|
-
self.send_transaction_to_multiple_groups(
|
88
|
+
self.send_transaction_to_multiple_groups(options, &block)
|
82
89
|
self.current_group = nil
|
83
90
|
elsif should_send_queries_to_a_group_of_shards?
|
84
|
-
self.send_transaction_to_multiple_shards(@groups[current_group],
|
91
|
+
self.send_transaction_to_multiple_shards(@groups[current_group], options, &block)
|
85
92
|
self.current_group = nil
|
86
93
|
else
|
87
|
-
select_connection.transaction(
|
94
|
+
select_connection.transaction(options, &block)
|
88
95
|
end
|
89
96
|
end
|
90
97
|
|
@@ -92,6 +99,7 @@ class Octopus::Proxy
|
|
92
99
|
if should_clean_connection?(method)
|
93
100
|
conn = select_connection()
|
94
101
|
self.current_shard = :master
|
102
|
+
@using_enabled = nil
|
95
103
|
conn.send(method, *args, &block)
|
96
104
|
elsif should_send_queries_to_replicated_databases?(method)
|
97
105
|
send_queries_to_selected_slave(method, *args, &block)
|
@@ -166,30 +174,33 @@ class Octopus::Proxy
|
|
166
174
|
end
|
167
175
|
|
168
176
|
def send_queries_to_selected_slave(method, *args, &block)
|
169
|
-
#TODO:
|
177
|
+
#TODO: UGLY code, needs refactor
|
178
|
+
old_shard = self.current_shard
|
179
|
+
|
170
180
|
if args.last =~ /#{replicated_models.to_a.join('|')}/
|
171
|
-
|
172
|
-
|
173
|
-
|
181
|
+
if !using_enabled
|
182
|
+
self.current_shard = slaves_list.shift.to_sym
|
183
|
+
slaves_list << self.current_shard
|
184
|
+
end
|
174
185
|
else
|
175
|
-
old_shard = self.current_shard
|
176
186
|
self.current_shard = :master
|
177
187
|
end
|
178
188
|
|
179
189
|
sql = select_connection().send(method, *args, &block)
|
180
190
|
self.current_shard = old_shard
|
191
|
+
@using_enabled = nil
|
181
192
|
return sql
|
182
193
|
end
|
183
194
|
|
184
|
-
def send_transaction_to_multiple_shards(shard_array,
|
195
|
+
def send_transaction_to_multiple_shards(shard_array, options, &block)
|
185
196
|
shard_array.each do |shard_symbol|
|
186
|
-
@shards[shard_symbol].connection().transaction(
|
197
|
+
@shards[shard_symbol].connection().transaction(options, &block)
|
187
198
|
end
|
188
199
|
end
|
189
200
|
|
190
|
-
def send_transaction_to_multiple_groups(
|
201
|
+
def send_transaction_to_multiple_groups(options, &block)
|
191
202
|
current_group.each do |group_symbol|
|
192
|
-
self.send_transaction_to_multiple_shards(@groups[group_symbol],
|
203
|
+
self.send_transaction_to_multiple_shards(@groups[group_symbol], options, &block)
|
193
204
|
end
|
194
205
|
end
|
195
206
|
end
|
@@ -2,6 +2,36 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
|
3
3
|
describe Octopus::Controller do
|
4
4
|
it "should have the using method to select the shard" do
|
5
|
-
|
5
|
+
a = ActionController::Base.new
|
6
|
+
a.respond_to?(:using).should be_true
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should use #using method to in all requests" do
|
10
|
+
class UsersControllers < ActionController::Base
|
11
|
+
around_filter :select_shard
|
12
|
+
def create
|
13
|
+
User.create!(:name => "ActionController")
|
14
|
+
render :nothing => true
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_shard
|
18
|
+
using(:brazil) do
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self._router
|
24
|
+
ActionDispatch::Routing::RouteSet.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
UsersControllers.action_methods.include?("create").should be_true
|
29
|
+
a = UsersControllers.new
|
30
|
+
a.stub!(:request).and_return(mock({:fullpath => "", :filtered_parameters => {}, :formats => ["xml"], :method => "GET"}))
|
31
|
+
a.instance_variable_set(:@_response, mock(:content_type => "xml", :body= => "", :status => 401))
|
32
|
+
a.process(:create)
|
33
|
+
|
34
|
+
User.using(:brazil).find_by_name("ActionController").should_not be_nil
|
35
|
+
User.using(:master).find_by_name("ActionController").should be_nil
|
6
36
|
end
|
7
37
|
end
|
@@ -2,50 +2,40 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
|
3
3
|
describe Octopus::Migration do
|
4
4
|
it "should run just in the master shard" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, 1)
|
5
|
+
migrating_to_version 1 do
|
6
|
+
User.using(:master).find_by_name("Master").should_not be_nil
|
7
|
+
User.using(:canada).find_by_name("Master").should be_nil
|
8
|
+
end
|
11
9
|
end
|
12
10
|
|
13
11
|
it "should run on specific shard" do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, 2)
|
12
|
+
migrating_to_version 2 do
|
13
|
+
User.using(:master).find_by_name("Sharding").should be_nil
|
14
|
+
User.using(:canada).find_by_name("Sharding").should_not be_nil
|
15
|
+
end
|
20
16
|
end
|
21
17
|
|
22
18
|
it "should run on specifieds shards" do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, 3)
|
19
|
+
migrating_to_version 3 do
|
20
|
+
User.using(:brazil).find_by_name("Both").should_not be_nil
|
21
|
+
User.using(:canada).find_by_name("Both").should_not be_nil
|
22
|
+
end
|
29
23
|
end
|
30
24
|
|
31
25
|
it "should run on specified group" do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, 4)
|
26
|
+
migrating_to_version 4 do
|
27
|
+
User.using(:canada).find_by_name("Group").should_not be_nil
|
28
|
+
User.using(:brazil).find_by_name("Group").should_not be_nil
|
29
|
+
User.using(:russia).find_by_name("Group").should_not be_nil
|
30
|
+
end
|
39
31
|
end
|
40
32
|
|
41
33
|
it "should run on multiples groups" do
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, 5)
|
34
|
+
migrating_to_version 5 do
|
35
|
+
User.using(:canada).where(:name => "MultipleGroup").all.size.should == 2
|
36
|
+
User.using(:brazil).where(:name => "MultipleGroup").all.size.should == 2
|
37
|
+
User.using(:russia).where(:name => "MultipleGroup").all.size.should == 2
|
38
|
+
end
|
49
39
|
end
|
50
40
|
|
51
41
|
describe "should raise a exception when" do
|
@@ -66,13 +56,26 @@ describe Octopus::Migration do
|
|
66
56
|
end
|
67
57
|
end
|
68
58
|
|
69
|
-
describe "when using replication" do
|
59
|
+
describe "when using replication" do
|
70
60
|
it "should run writes on master when you use replication" do
|
71
|
-
|
61
|
+
using_enviroment :production_replicated do
|
62
|
+
migrating_to_version 10 do
|
63
|
+
Cat.using(:master).where(:name => "Replication").first.should_not be_nil
|
64
|
+
Cat.where(:name => "Replication").first.should be_nil
|
65
|
+
end
|
66
|
+
end
|
72
67
|
end
|
73
68
|
|
74
69
|
it "should run in all shards, master or another shards" do
|
75
|
-
|
70
|
+
using_enviroment :production_replicated do
|
71
|
+
migrating_to_version 11 do
|
72
|
+
[:slave4, :slave1, :slave2, :slave3].each do |sym|
|
73
|
+
Cat.using(sym).find_by_name("Slaves").should_not be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
Cat.using(:master).find_by_name("Slaves").should be_nil
|
77
|
+
end
|
78
|
+
end
|
76
79
|
end
|
77
80
|
end
|
78
81
|
end
|
data/spec/octopus/model_spec.rb
CHANGED
@@ -30,26 +30,26 @@ describe Octopus::Model do
|
|
30
30
|
User.using(:brazil).count.should == 0
|
31
31
|
User.count.should == 0
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
describe "passing a block" do
|
35
35
|
it "should allow queries be executed inside the block, ponting to a specific shard" do
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
User.using(:canada) do
|
37
|
+
User.create(:name => "oi")
|
38
|
+
end
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
User.using(:canada).count.should == 1
|
41
|
+
User.using(:master).count.should == 0
|
42
|
+
User.count.should == 0
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
it "should allow execute queries inside a model" do
|
46
|
+
u = User.new
|
47
|
+
u.awesome_queries()
|
48
|
+
User.using(:canada).count.should == 1
|
49
|
+
User.count.should == 0
|
50
|
+
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
describe "when you have a relationship" do
|
54
54
|
it "should find all models in the specified shard" do
|
55
55
|
pending()
|
@@ -63,7 +63,7 @@ describe Octopus::Model do
|
|
63
63
|
# c.items.should == [item_brazil]
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
describe "raising errors" do
|
68
68
|
it "should raise a error when you specify a shard that doesn't exist" do
|
69
69
|
lambda { User.using(:crazy_shard) }.should raise_error("Nonexistent Shard Name: crazy_shard")
|
@@ -72,51 +72,30 @@ describe Octopus::Model do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
describe "using a postgresql shard" do
|
75
|
-
after(:each) do
|
76
|
-
User.using(:postgresql_shard).delete_all
|
77
|
-
end
|
78
|
-
|
79
75
|
it "should update the Arel Engine" do
|
80
76
|
User.using(:postgresql_shard).arel_engine.connection.adapter_name.should == "PostgreSQL"
|
81
77
|
User.using(:alone_shard).arel_engine.connection.adapter_name.should == "MySQL"
|
82
78
|
end
|
83
|
-
|
79
|
+
|
84
80
|
it "should works with writes and reads" do
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
# User.using(:postgresql_shard).scoped.should == ""
|
89
|
-
# User.using(:alone_shard).find(:all).should == []
|
81
|
+
u = User.using(:postgresql_shard).create!(:name => "PostgreSQL User")
|
82
|
+
User.using(:postgresql_shard).all.should == [u]
|
83
|
+
User.using(:alone_shard).find(:all).should == []
|
90
84
|
end
|
91
85
|
end
|
92
|
-
|
86
|
+
|
93
87
|
describe "#replicated_model method" do
|
94
|
-
before(:each) do
|
95
|
-
Octopus.stub!(:env).and_return("production_replicated")
|
96
|
-
@proxy = Octopus::Proxy.new(Octopus.config())
|
97
|
-
#TODO - This is ugly, but is better than mocking
|
98
|
-
ActiveRecord::Base.class_eval("@@connection_proxy = nil")
|
99
|
-
#TODO - This is ugly, but is better than mocking
|
100
|
-
end
|
101
|
-
|
102
|
-
after(:each) do
|
103
|
-
#TODO - One little Kitten dies each time this code is executed.
|
104
|
-
ActiveRecord::Base.class_eval("@@connection_proxy = nil")
|
105
|
-
end
|
106
|
-
|
107
88
|
it "should be replicated" do
|
108
|
-
|
89
|
+
using_enviroment :production_replicated do
|
90
|
+
ActiveRecord::Base.connection_proxy.replicated.should be_true
|
91
|
+
end
|
109
92
|
end
|
110
|
-
|
93
|
+
|
111
94
|
it "should mark the Cat model as replicated" do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
describe "#sharded_by method" do
|
118
|
-
it "should send all queries to the specify shard" do
|
119
|
-
pending()
|
95
|
+
using_enviroment :production_replicated do
|
96
|
+
Cat.all.should == []
|
97
|
+
ActiveRecord::Base.connection_proxy.replicated_models.first.should == "Cat"
|
98
|
+
end
|
120
99
|
end
|
121
100
|
end
|
122
101
|
end
|
data/spec/octopus/proxy_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,8 @@ MIGRATIONS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), 'migration
|
|
2
2
|
require 'spec'
|
3
3
|
require 'spec/autorun'
|
4
4
|
require "database_connection"
|
5
|
+
require "action_pack"
|
6
|
+
require "action_controller"
|
5
7
|
require 'octopus'
|
6
8
|
|
7
9
|
Spec::Runner.configure do |config|
|
@@ -24,4 +26,24 @@ def clean_all_shards()
|
|
24
26
|
ActiveRecord::Base.using(shard_symbol).connection.execute("DELETE FROM #{tables};")
|
25
27
|
end
|
26
28
|
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def migrating_to_version(version, &block)
|
32
|
+
begin
|
33
|
+
ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT, version)
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT, version)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def using_enviroment(enviroment, &block)
|
41
|
+
begin
|
42
|
+
Octopus.class_eval("@@env = '#{enviroment.to_s}'")
|
43
|
+
ActiveRecord::Base.class_eval("@@connection_proxy = nil")
|
44
|
+
yield
|
45
|
+
ensure
|
46
|
+
Octopus.class_eval("@@env = 'production'")
|
47
|
+
ActiveRecord::Base.class_eval("@@connection_proxy = nil")
|
48
|
+
end
|
27
49
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Thiago Pradi
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-06-
|
19
|
+
date: 2010-06-14 00:00:00 -03:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -42,9 +42,11 @@ extensions: []
|
|
42
42
|
extra_rdoc_files:
|
43
43
|
- README.mkdn
|
44
44
|
files:
|
45
|
+
- .gitignore
|
45
46
|
- README.mkdn
|
46
47
|
- Rakefile
|
47
48
|
- VERSION
|
49
|
+
- ar-octopus.gemspec
|
48
50
|
- doc/api.textile
|
49
51
|
- doc/features.textile
|
50
52
|
- doc/libraries.textile
|
@@ -57,6 +59,8 @@ files:
|
|
57
59
|
- spec/config/shards.yml
|
58
60
|
- spec/database_connection.rb
|
59
61
|
- spec/database_models.rb
|
62
|
+
- spec/migrations/10_create_users_using_replication.rb
|
63
|
+
- spec/migrations/11_add_field_in_all_slaves.rb
|
60
64
|
- spec/migrations/1_create_users_on_master.rb
|
61
65
|
- spec/migrations/2_create_users_on_canada.rb
|
62
66
|
- spec/migrations/3_create_users_on_both_shards.rb
|
@@ -106,6 +110,8 @@ summary: Easy Database Sharding for ActiveRecord
|
|
106
110
|
test_files:
|
107
111
|
- spec/database_connection.rb
|
108
112
|
- spec/database_models.rb
|
113
|
+
- spec/migrations/10_create_users_using_replication.rb
|
114
|
+
- spec/migrations/11_add_field_in_all_slaves.rb
|
109
115
|
- spec/migrations/1_create_users_on_master.rb
|
110
116
|
- spec/migrations/2_create_users_on_canada.rb
|
111
117
|
- spec/migrations/3_create_users_on_both_shards.rb
|