ar-octopus 0.1.2 → 0.2.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/README.mkdn +69 -64
- data/Rakefile +1 -1
- data/ar-octopus.gemspec +2 -2
- data/lib/octopus/model.rb +9 -1
- data/spec/database_models.rb +6 -1
- data/spec/octopus/model_spec.rb +5 -1
- metadata +4 -4
data/README.mkdn
CHANGED
@@ -26,18 +26,22 @@ When using replication, all writes queries will be sent to master, and read quer
|
|
26
26
|
### Rails 2.x
|
27
27
|
|
28
28
|
Install the octopus gem:
|
29
|
-
|
29
|
+
|
30
|
+
sudo gem install ar-octopus
|
30
31
|
|
31
32
|
Add this line to enviroment.rb:
|
32
|
-
|
33
|
+
|
34
|
+
config.gem 'ar-octopus', :lib => "octopus"
|
33
35
|
|
34
36
|
### Rails 3.x
|
35
37
|
|
36
38
|
Add this line to Gemfile:
|
37
|
-
|
39
|
+
|
40
|
+
gem 'ar-octopus', :require => "octopus"
|
38
41
|
|
39
42
|
Runs a bundle install:
|
40
|
-
|
43
|
+
|
44
|
+
bundle install
|
41
45
|
|
42
46
|
## How to use Octopus?
|
43
47
|
|
@@ -46,75 +50,70 @@ First, you need to create a config file, shards.yml, inside your config/ directo
|
|
46
50
|
### Syntax
|
47
51
|
|
48
52
|
Octopus adds a method to each AR Class and object: the using method is used to select the shard like this:
|
49
|
-
|
53
|
+
|
54
|
+
User.where(:name => "Thiago").limit(3).using(:slave_one)
|
50
55
|
|
51
56
|
Octopus also supports queries within a block. When you pass a block to the using method, all queries inside the block will be sent to the specified shard.
|
52
|
-
|
53
|
-
Octopus.using(:slave_two) do
|
54
|
-
|
55
|
-
end
|
56
|
-
</pre>
|
57
|
+
|
58
|
+
Octopus.using(:slave_two) do
|
59
|
+
User.create(:name => "Mike")
|
60
|
+
end
|
57
61
|
|
58
62
|
Each model instance knows which shard it came from so this will work automatically:
|
59
|
-
<pre>
|
60
|
-
# This will find the user in the shard1
|
61
|
-
@user = User.using(:shard1).find_by_name("Joao")
|
62
63
|
|
63
|
-
# This will find the user in the
|
64
|
-
@
|
64
|
+
# This will find the user in the shard1
|
65
|
+
@user = User.using(:shard1).find_by_name("Joao")
|
65
66
|
|
66
|
-
#
|
67
|
-
@
|
67
|
+
# This will find the user in the master database
|
68
|
+
@user2 = User.find_by_name("Jose")
|
68
69
|
|
69
|
-
#
|
70
|
-
@user.
|
71
|
-
|
70
|
+
#Sets the name
|
71
|
+
@user.name = "Mike"
|
72
|
+
|
73
|
+
# Save the user in the correct shard, shard1.
|
74
|
+
@user.save
|
72
75
|
|
73
76
|
### Migrations
|
74
77
|
|
75
78
|
In migrations, you also have access to the using method. The syntax is basically the same. This migration will run in the brazil and canada shards.
|
76
|
-
<pre>
|
77
|
-
class CreateUsersOnBothShards < ActiveRecord::Migration
|
78
|
-
using(:brazil, :canada)
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
80
|
+
class CreateUsersOnBothShards < ActiveRecord::Migration
|
81
|
+
using(:brazil, :canada)
|
83
82
|
|
84
|
-
|
85
|
-
|
83
|
+
def self.up
|
84
|
+
User.create!(:name => "Both")
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.down
|
88
|
+
User.delete_all
|
89
|
+
end
|
86
90
|
end
|
87
|
-
end
|
88
|
-
</pre>
|
89
91
|
|
90
92
|
You also could send a migration to a group of shards. This migration will be sent to all shards that belongs to history_shards group, specified in shards.yml:
|
91
|
-
<pre>
|
92
|
-
class CreateUsersOnMultiplesGroups < ActiveRecord::Migration
|
93
|
-
using_group(:history_shards)
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
end
|
94
|
+
class CreateUsersOnMultiplesGroups < ActiveRecord::Migration
|
95
|
+
using_group(:history_shards)
|
98
96
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
103
|
-
</pre>
|
97
|
+
def self.up
|
98
|
+
User.create!(:name => "MultipleGroup")
|
99
|
+
end
|
104
100
|
|
101
|
+
def self.down
|
102
|
+
User.delete_all
|
103
|
+
end
|
104
|
+
end
|
105
105
|
|
106
106
|
### Rails Controllers
|
107
107
|
|
108
108
|
If you want to send a specified action, or all actions from a controller, to a specific shard, use this syntax:
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
|
110
|
+
class ApplicationController < ActionController::Base
|
111
|
+
around_filter :select_shard
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
</pre>
|
113
|
+
def select_shard(&block)
|
114
|
+
Octopus.using(:brazil, &block)
|
115
|
+
end
|
116
|
+
end
|
118
117
|
|
119
118
|
To see the complete list of features and syntax, please check out our <a href="http://wiki.github.com/tchandy/octopus/"> Wiki</a>
|
120
119
|
Want to 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>. Also, we have an example that shows how to use Octopus without Rails: <a href="http://github.com/tchandy/octopus_sinatra"> Octopus + Sinatra Example</a>.
|
@@ -123,33 +122,39 @@ Want to see sample rails applications using octopus features? please check it ou
|
|
123
122
|
## Important!
|
124
123
|
Sometimes, when a connection isn't used for much time, this will makes ActiveRecord raising an exception. if you have this kind of applications, please, add the following line to your configuration:
|
125
124
|
|
126
|
-
|
127
|
-
verify_connection: true
|
128
|
-
</pre>
|
125
|
+
verify_connection: true
|
129
126
|
|
130
127
|
This will tell Octopus to verify the connection before sending the query.
|
131
128
|
|
129
|
+
## Mixing Octopus with the Rails multiple database model
|
130
|
+
Octopus will respect if you declare some model to use a specific connection, with the rails syntax, like this example:
|
131
|
+
|
132
|
+
#This class sets its own connection
|
133
|
+
class CustomConnection < ActiveRecord::Base
|
134
|
+
establish_connection(:adapter => "mysql", :database => "octopus_shard2")
|
135
|
+
end
|
136
|
+
|
132
137
|
## Contributing with Octopus
|
133
138
|
Contributors are welcome! To run the test suite, you need mysql, postgresql and sqlite3 installed. This is what you need to setup your Octopus development environment:
|
134
139
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
rake
|
141
|
-
</pre>
|
140
|
+
git clone http://github.com/tchandy/octopus.git
|
141
|
+
cd octopus
|
142
|
+
bundle install
|
143
|
+
rake db:prepare
|
144
|
+
rake
|
142
145
|
|
143
146
|
To run our integrations tests inside sample_app, you need to following commands:
|
144
147
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
cucumber
|
149
|
-
</pre>
|
148
|
+
cd sample_app
|
149
|
+
bundle install
|
150
|
+
cucumber
|
150
151
|
|
151
152
|
If you are having issues running the octopus spec suite, verify your database users and passwords match those inside the config files and your permissions are correct.
|
152
153
|
|
154
|
+
## Contributors:
|
155
|
+
- <a href="http://github.com/carlosbrando">Carlos Brando</a>
|
156
|
+
- <a href="http://github.com/bjones">Brian Jones</a>
|
157
|
+
|
153
158
|
## Thanks
|
154
159
|
|
155
160
|
This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>,
|
data/Rakefile
CHANGED
@@ -37,7 +37,7 @@ begin
|
|
37
37
|
gem.add_development_dependency "jeweler", ">= 1.4"
|
38
38
|
gem.add_development_dependency "actionpack", ">= 2.3"
|
39
39
|
gem.add_dependency('activerecord', '>= 2.3')
|
40
|
-
gem.version = "0.
|
40
|
+
gem.version = "0.2.0"
|
41
41
|
end
|
42
42
|
Jeweler::GemcutterTasks.new
|
43
43
|
rescue LoadError
|
data/ar-octopus.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ar-octopus}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Thiago Pradi", "Mike Perham"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-24}
|
13
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
14
|
s.email = %q{tchandy@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/octopus/model.rb
CHANGED
@@ -3,6 +3,9 @@ module Octopus::Model
|
|
3
3
|
base.send(:include, InstanceMethods)
|
4
4
|
base.extend(ClassMethods)
|
5
5
|
base.hijack_connection()
|
6
|
+
class << base
|
7
|
+
alias_method_chain(:establish_connection, :octopus)
|
8
|
+
end
|
6
9
|
end
|
7
10
|
|
8
11
|
module SharedMethods
|
@@ -43,7 +46,7 @@ module Octopus::Model
|
|
43
46
|
|
44
47
|
def hijack_connection()
|
45
48
|
def self.should_use_normal_connection?
|
46
|
-
defined?(Rails) && Octopus.config() && !Octopus.enviroments.include?(Rails.env.to_s)
|
49
|
+
(defined?(Rails) && Octopus.config() && !Octopus.enviroments.include?(Rails.env.to_s)) || self.read_inheritable_attribute(:establish_connection)
|
47
50
|
end
|
48
51
|
|
49
52
|
def self.connection_proxy
|
@@ -84,6 +87,11 @@ module Octopus::Model
|
|
84
87
|
|
85
88
|
def sharded_model()
|
86
89
|
write_inheritable_attribute(:sharded, true)
|
90
|
+
end
|
91
|
+
|
92
|
+
def establish_connection_with_octopus(spec=nil)
|
93
|
+
write_inheritable_attribute(:establish_connection, true)
|
94
|
+
establish_connection_without_octopus(spec)
|
87
95
|
end
|
88
96
|
end
|
89
97
|
end
|
data/spec/database_models.rb
CHANGED
@@ -19,6 +19,11 @@ class Cat < ActiveRecord::Base
|
|
19
19
|
#sharded_model()
|
20
20
|
end
|
21
21
|
|
22
|
+
#This class sets its own connection
|
23
|
+
class CustomConnection < ActiveRecord::Base
|
24
|
+
establish_connection(:adapter => "mysql", :database => "octopus_shard2", :username => "root", :password => "")
|
25
|
+
end
|
26
|
+
|
22
27
|
#This items belongs to a client
|
23
28
|
class Item < ActiveRecord::Base
|
24
29
|
belongs_to :client
|
@@ -63,4 +68,4 @@ end
|
|
63
68
|
|
64
69
|
class Comment < ActiveRecord::Base
|
65
70
|
belongs_to :commentable, :polymorphic => true
|
66
|
-
end
|
71
|
+
end
|
data/spec/octopus/model_spec.rb
CHANGED
@@ -172,6 +172,10 @@ describe Octopus::Model do
|
|
172
172
|
end
|
173
173
|
|
174
174
|
describe "AR basic methods" do
|
175
|
+
it "establish_connection" do
|
176
|
+
CustomConnection.connection.current_database.should == "octopus_shard2"
|
177
|
+
end
|
178
|
+
|
175
179
|
it "increment" do
|
176
180
|
u = User.using(:brazil).create!(:name => "Teste", :number => 10)
|
177
181
|
u = User.using(:brazil).find_by_number(10)
|
@@ -350,4 +354,4 @@ describe Octopus::Model do
|
|
350
354
|
end
|
351
355
|
end
|
352
356
|
end
|
353
|
-
end
|
357
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar-octopus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 1
|
9
8
|
- 2
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Thiago Pradi
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-24 00:00:00 -02:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|