ar-octopus 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*.*
2
2
  tmp/*
3
3
  *.sqlite3
4
+ .rvmrc
@@ -3,7 +3,7 @@
3
3
  <p> Octopus is a better way to do Database Sharding in ActiveRecord. Sharding allows multiple databases in the same rails application. While there are several projects that implement Sharding (e.g. DbCharmer, DataFabric, MultiDb), each project has its own limitations. The main goal of octopus project is to provide a nice and clean way of doing Database Sharding.</p>
4
4
 
5
5
  <h2>Feature list: </h2>
6
- <p> The design of the api is made to be simple as possible. Octopus is focusing in the end user, giving the power of multiple databases, but with reliable code and flexibility. Octopus is focused on Rails 3, is compatible with Rails 2.x.</p>
6
+ <p> The design of the api is made to be simple as possible. Octopus is focusing in the end user, giving the power of multiple databases, but with reliable code and flexibility. Octopus is focused on Rails 3, but is compatible with Rails 2.x.</p>
7
7
 
8
8
  <p> Octopus supports: </p>
9
9
 
@@ -12,38 +12,95 @@
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></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>
17
-
18
- <h2>Thanks</h2>
15
+ <h3> Replication </h3>
16
+ <p> When using replication, all writes queries will be sent to master, and read queries to slaves. More info could be found at: <a href="http://wiki.github.com/tchandy/octopus/replication"> Wiki</a> </p>
19
17
 
20
- This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>,
21
- and my mentors <a href="http://github.com/mperham">Mike Perham</a> and <a href="http://github.com/amitagarwal">Amit Agarwal</a>.
18
+ <h3> Sharding </h3>
19
+ <p> When using sharding, you need to specify what shard the query will be sent. Octopus support selecting the shard inside a controller, or manually in each object. More could be found at <a href="http://wiki.github.com/tchandy/octopus/sharding"> Wiki</a> </p>
20
+
21
+ <h2> Install </h2>
22
+
23
+ <h3> Rails 2.x </h3>
24
+
25
+ Install the octopus gem:
26
+ <pre> sudo gem install ar-octopus </pre>
27
+
28
+ Add this line to enviroment.rb:
29
+ <pre>config.gem 'ar-octopus', :lib => "octopus"</pre>
22
30
 
31
+ <h3> Rails 3.x </h3>
23
32
 
24
- <h3>If you are writing code that smells using octopus, the EVIL Octopus is going behind you, be careful.</h3>
33
+ Add this line to Gemfile:
34
+ <pre>gem 'ar-octopus', :require => "octopus"</pre>
35
+
36
+ Runs a bundle install:
37
+ <pre>bundle install</pre>
38
+
39
+ <h2> How to use Octopus? </h2>
40
+ <p>First, you need to create a config file, shards.yml, inside your config/ directory. to see the syntax and how this file should look, please checkout <a href="http://wiki.github.com/tchandy/octopus/config-file">this page on wiki</a></p>.
41
+
42
+ <h3> Syntax </h3>
43
+ <p>Octopus adds a method to each AR Class and object. the using method is used to select the shard, like this: </p>
44
+ <pre>User.where(:name => "Thiago").limit(3).using(:slave_one) </pre>
45
+
46
+ <p> Octopus also supports queries inside block. When you pass a block to the using method, all queries inside the block will be sent to the specified shard. </p>
25
47
  <pre>
26
- _________________
27
- ___ | I'm so EVIL! |
28
- .-' `'. |______________ |
29
- / \ /
30
- | ; /
31
- | | / ___.--,
32
- _.._ |0) ~ (0) | _.---'`__.-( (_.
33
- __.--'`_.. '.__.\ '--. \_.-' ,.--'` `""`
34
- ( ,.--'` ',__ /./; ;, '.__.'` __
35
- _`) ) .---.__.' / | |\ \__..--"" """--.,_
36
- `---' .'.''-._.-'`_./ /\ '. \ _.-~~~````~~~-._`-.__.'
37
- | | .' _.-' | | \ \ '. `~---`
38
- \ \/ .' \ \ '. '-._)
39
- \/ / \ \ `=.__`~-.
40
- / /\ `) ) / / `"".`\
41
- , _.-'.'\ \ / / ( ( / /
42
- `--~` ) ) .-'.' '.'. | (
43
- (/` ( (` ) ) '-;
44
- ` '-; (-'
48
+ User.using(:slave_two) do
49
+ User.create(:name => "Mike")
50
+ end
45
51
  </pre>
46
52
 
53
+ <p> Each object knows where is your shard, so you could to thinks like this:</p>
54
+ <pre>
55
+ # This will find the user in the shard1
56
+ @user = User.using(:shard1).find_by_name("Joao")
57
+
58
+ # This will find the user in the master database
59
+ @user2 = User.find_by_name("Jose")
60
+
61
+ #Sets the name
62
+ @user.name = "Mike"
63
+
64
+ # Save the user in the correct shard, shard1.
65
+ @user.save()
66
+ </pre>
67
+
68
+ <p> In migrations, you also have access to the using method. The syntax is basically the same. This migration will run in brazil and canada shards.</p>
69
+ <pre>
70
+ class CreateUsersOnBothShards < ActiveRecord::Migration
71
+ using(:brazil, :canada)
72
+
73
+ def self.up
74
+ User.create!(:name => "Both")
75
+ end
76
+
77
+ def self.down
78
+ User.delete_all()
79
+ end
80
+ end
81
+ </pre>
82
+ <p> 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: </p>
83
+ <pre>
84
+ class CreateUsersOnMultiplesGroups < ActiveRecord::Migration
85
+ using_group(:history_shards)
86
+
87
+ def self.up
88
+ User.create!(:name => "MultipleGroup")
89
+ end
90
+
91
+ def self.down
92
+ User.delete_all()
93
+ end
94
+ end
95
+ </pre>
96
+
97
+ <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>
98
+ <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>
99
+
100
+ <h2>Thanks</h2>
101
+
102
+ This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>,
103
+ and my mentors <a href="http://github.com/mperham">Mike Perham</a> and <a href="http://github.com/amitagarwal">Amit Agarwal</a>.
47
104
 
48
105
  <h2>Copyright</h2>
49
106
 
data/Rakefile CHANGED
@@ -29,7 +29,7 @@ begin
29
29
  gem.authors = ["Thiago Pradi", "Mike Perham", "Amit Agarwal"]
30
30
  gem.add_development_dependency "rspec", ">= 1.2.9"
31
31
  gem.add_dependency('activerecord', '>= 3.0.0beta')
32
- gem.version = "0.0.23"
32
+ gem.version = "0.0.24"
33
33
  end
34
34
  Jeweler::GemcutterTasks.new
35
35
  rescue LoadError
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ar-octopus}
8
- s.version = "0.0.23"
8
+ s.version = "0.0.24"
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", "Amit Agarwal"]
@@ -46,6 +46,7 @@ Gem::Specification.new do |s|
46
46
  "spec/migrations/10_create_users_using_replication.rb",
47
47
  "spec/migrations/11_add_field_in_all_slaves.rb",
48
48
  "spec/migrations/12_create_users_using_block.rb",
49
+ "spec/migrations/13_create_users_using_block_and_using.rb",
49
50
  "spec/migrations/1_create_users_on_master.rb",
50
51
  "spec/migrations/2_create_users_on_canada.rb",
51
52
  "spec/migrations/3_create_users_on_both_shards.rb",
@@ -78,6 +79,7 @@ Gem::Specification.new do |s|
78
79
  "spec/migrations/10_create_users_using_replication.rb",
79
80
  "spec/migrations/11_add_field_in_all_slaves.rb",
80
81
  "spec/migrations/12_create_users_using_block.rb",
82
+ "spec/migrations/13_create_users_using_block_and_using.rb",
81
83
  "spec/migrations/1_create_users_on_master.rb",
82
84
  "spec/migrations/2_create_users_on_canada.rb",
83
85
  "spec/migrations/3_create_users_on_both_shards.rb",
@@ -12,8 +12,8 @@ module Octopus
12
12
  def self.config()
13
13
  @config ||= HashWithIndifferentAccess.new(YAML.load_file(Octopus.directory() + "/config/shards.yml"))
14
14
 
15
- if !@config[Octopus.env].nil? && @config[Octopus.env()]['octopus_enviroments']
16
- self.octopus_enviroments = @config[Octopus.env()]['octopus_enviroments']
15
+ if !@config[Octopus.env].nil? && @config[Octopus.env()]['enviroments']
16
+ self.enviroments = @config[Octopus.env()]['enviroments']
17
17
  end
18
18
 
19
19
  @config
@@ -27,17 +27,17 @@ module Octopus
27
27
 
28
28
  # This is the default way to do Octopus Setup
29
29
  # Available variables:
30
- # :excluded_enviroments => the enviroments that octopus will not run. default: :development, :cucumber and :test
30
+ # :enviroments => the enviroments that octopus will run. default: :production
31
31
  def self.setup
32
32
  yield self
33
33
  end
34
34
 
35
- def self.octopus_enviroments=(octopus_enviroments)
36
- @octopus_enviroments = octopus_enviroments.map { |element| element.to_s }
35
+ def self.enviroments=(enviroments)
36
+ @enviroments = enviroments.map { |element| element.to_s }
37
37
  end
38
38
 
39
- def self.octopus_enviroments
40
- @octopus_enviroments || ['production']
39
+ def self.enviroments
40
+ @enviroments || ['production']
41
41
  end
42
42
 
43
43
  def self.rails3?
@@ -1,12 +1,12 @@
1
1
  module Octopus::Association
2
2
  def has_many(association_id, options = {}, &extension)
3
3
  default_octopus_opts(options)
4
- super(association_id, options, &extension)
4
+ super
5
5
  end
6
6
 
7
7
  def has_and_belongs_to_many(association_id, options = {}, &extension)
8
8
  default_octopus_opts(options)
9
- super(association_id, options, &extension)
9
+ super
10
10
  end
11
11
 
12
12
  def default_octopus_opts(options)
@@ -1,20 +1,17 @@
1
1
  module Octopus::Migration
2
2
  def self.extended(base)
3
3
  class << base
4
- alias_method_chain :migrate, :octopus
5
-
6
- def announce(message)
7
- version = defined?(@version) ? @version : nil
8
-
9
- text = "#{version} #{name}: #{message} - #{get_current_shard}"
10
- length = [0, 75 - text.length].max
11
- write "== %s %s" % [text, "=" * length]
4
+ def announce_with_octopus(message)
5
+ announce_without_octopus("#{message} - #{get_current_shard}")
12
6
  end
7
+
8
+ alias_method_chain :migrate, :octopus
9
+ alias_method_chain :announce, :octopus
13
10
  end
14
11
  end
15
12
 
16
13
  def using(*args, &block)
17
- if self.connection().is_a?(Octopus::Proxy)
14
+ if self.connection().is_a?(Octopus::Proxy) && !block_given?
18
15
  args.each do |shard|
19
16
  self.connection().check_schema_migrations(shard)
20
17
  end
@@ -23,13 +20,14 @@ module Octopus::Migration
23
20
  self.connection().current_shard = args
24
21
  end
25
22
 
26
- yield if block_given?
23
+ if block_given?
24
+ self.connection.run_queries_on_shard(args, &block)
25
+ end
27
26
 
28
27
  return self
29
28
  end
30
29
 
31
30
  def using_group(*args)
32
-
33
31
  if self.connection().is_a?(Octopus::Proxy)
34
32
  args.each do |group_shard|
35
33
  shards = self.connection().instance_variable_get(:@groups)[group_shard] || []
@@ -55,19 +53,21 @@ module Octopus::Migration
55
53
  conn = ActiveRecord::Base.connection
56
54
  groups = conn.instance_variable_get(:@groups)
57
55
 
58
- return migrate_without_octopus(direction) unless conn.is_a?(Octopus::Proxy)
56
+ begin
57
+ return migrate_without_octopus(direction) unless conn.is_a?(Octopus::Proxy)
59
58
 
60
- if conn.current_group.is_a?(Array)
61
- conn.current_group.each { |group| conn.send_queries_to_multiple_shards(groups[group]) { migrate_without_octopus(direction) } }
62
- elsif conn.current_group.is_a?(Symbol)
63
- conn.send_queries_to_multiple_shards(groups[conn.current_group]) { migrate_without_octopus(direction) }
64
- elsif conn.current_shard.is_a?(Array)
65
- conn.send_queries_to_multiple_shards(conn.current_shard) { migrate_without_octopus(direction) }
66
- else
67
- migrate_without_octopus(direction)
59
+ if conn.current_group.is_a?(Array)
60
+ conn.current_group.each { |group| conn.send_queries_to_multiple_shards(groups[group]) { migrate_without_octopus(direction) } }
61
+ elsif conn.current_group.is_a?(Symbol)
62
+ conn.send_queries_to_multiple_shards(groups[conn.current_group]) { migrate_without_octopus(direction) }
63
+ elsif conn.current_shard.is_a?(Array)
64
+ conn.send_queries_to_multiple_shards(conn.current_shard) { migrate_without_octopus(direction) }
65
+ else
66
+ migrate_without_octopus(direction)
67
+ end
68
+ ensure
69
+ conn.clean_proxy()
68
70
  end
69
-
70
- conn.clean_proxy()
71
71
  end
72
72
  end
73
73
 
@@ -15,7 +15,7 @@ module Octopus::Model
15
15
  end
16
16
 
17
17
  def using(shard, &block)
18
- return self if defined?(::Rails) && !Octopus.octopus_enviroments.include?(Rails.env.to_s)
18
+ return self if defined?(::Rails) && !Octopus.enviroments.include?(Rails.env.to_s)
19
19
 
20
20
  hijack_connection()
21
21
  clean_table_name()
@@ -58,7 +58,7 @@ module Octopus::Model
58
58
  def self.connection_with_octopus()
59
59
  if defined?(::Rails)
60
60
  Octopus.config()
61
- if Octopus.octopus_enviroments.include?(Rails.env.to_s)
61
+ if Octopus.enviroments.include?(Rails.env.to_s)
62
62
  self.connection_proxy().current_model = self
63
63
  return self.connection_proxy()
64
64
  else
@@ -7,17 +7,17 @@ module Octopus
7
7
 
8
8
  def update_attribute(name, value)
9
9
  reload_connection()
10
- super(name, value)
10
+ super
11
11
  end
12
12
 
13
13
  def update_attributes(attributes)
14
14
  reload_connection()
15
- super(attributes)
15
+ super
16
16
  end
17
17
 
18
18
  def update_attributes!(attributes)
19
19
  reload_connection()
20
- super(attributes)
20
+ super
21
21
  end
22
22
 
23
23
  def reload
@@ -104,7 +104,7 @@ production_entire_replicated:
104
104
 
105
105
  octopus_rails:
106
106
  replicated: true
107
- octopus_enviroments:
107
+ enviroments:
108
108
  - staging
109
109
  - production
110
110
 
@@ -0,0 +1,15 @@
1
+ class CreateUsersUsingBlockAndUsing < ActiveRecord::Migration
2
+ using(:brazil)
3
+
4
+ def self.up
5
+ using(:canada) do
6
+ User.create!(:name => "Canada")
7
+ end
8
+
9
+ User.create!(:name => "Brazil")
10
+ end
11
+
12
+ def self.down
13
+ User.delete_all()
14
+ end
15
+ end
@@ -46,6 +46,15 @@ describe Octopus::Migration do
46
46
  User.using(:canada).find(:all, :conditions => {:name => "UsingCanada2"}).size.should == 1
47
47
  end
48
48
  end
49
+
50
+ it "should send the query to the correct shard" do
51
+ migrating_to_version 13 do
52
+ User.using(:brazil).find(:all, :conditions => {:name => "Brazil"}).size.should == 1
53
+ User.using(:brazil).find(:all, :conditions => {:name => "Canada"}).size.should == 0
54
+ User.using(:canada).find(:all, :conditions => {:name => "Brazil"}).size.should == 0
55
+ User.using(:canada).find(:all, :conditions => {:name => "Canada"}).size.should == 1
56
+ end
57
+ end
49
58
 
50
59
  describe "should raise a exception when" do
51
60
  it "you specify a invalid shard name" do
@@ -21,18 +21,18 @@ describe Octopus do
21
21
 
22
22
  describe "#setup method" do
23
23
  it "should have the default octopus enviroment as production" do
24
- Octopus.octopus_enviroments.should == ["production"]
24
+ Octopus.enviroments.should == ["production"]
25
25
  end
26
26
 
27
27
  it "should allow the user to configure the octopus enviroments" do
28
28
  Octopus.setup do |config|
29
- config.octopus_enviroments = [:production, :staging]
29
+ config.enviroments = [:production, :staging]
30
30
  end
31
31
 
32
- Octopus.octopus_enviroments.should == ['production', 'staging']
32
+ Octopus.enviroments.should == ['production', 'staging']
33
33
 
34
34
  Octopus.setup do |config|
35
- config.octopus_enviroments = [:production]
35
+ config.enviroments = [:production]
36
36
  end
37
37
  end
38
38
  end
@@ -71,7 +71,7 @@ describe Octopus::Proxy do
71
71
  Octopus.config()
72
72
 
73
73
  proxy.instance_variable_get(:@replicated).should be_true
74
- Octopus.octopus_enviroments.should == ["staging", "production"]
74
+ Octopus.enviroments.should == ["staging", "production"]
75
75
  end
76
76
 
77
77
  it "should initialize correctly the shards for the staging enviroment" do
@@ -9,7 +9,7 @@ end
9
9
 
10
10
  require 'spec'
11
11
  require 'spec/autorun'
12
- require "spec/database_connection"
12
+ require File.expand_path(File.dirname(__FILE__)) + "/database_connection"
13
13
  require "action_controller"
14
14
  require 'octopus'
15
15
  require "octopus_helper"
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: 49
4
+ hash: 47
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 23
10
- version: 0.0.23
9
+ - 24
10
+ version: 0.0.24
11
11
  platform: ruby
12
12
  authors:
13
13
  - Thiago Pradi
@@ -91,6 +91,7 @@ files:
91
91
  - spec/migrations/10_create_users_using_replication.rb
92
92
  - spec/migrations/11_add_field_in_all_slaves.rb
93
93
  - spec/migrations/12_create_users_using_block.rb
94
+ - spec/migrations/13_create_users_using_block_and_using.rb
94
95
  - spec/migrations/1_create_users_on_master.rb
95
96
  - spec/migrations/2_create_users_on_canada.rb
96
97
  - spec/migrations/3_create_users_on_both_shards.rb
@@ -151,6 +152,7 @@ test_files:
151
152
  - spec/migrations/10_create_users_using_replication.rb
152
153
  - spec/migrations/11_add_field_in_all_slaves.rb
153
154
  - spec/migrations/12_create_users_using_block.rb
155
+ - spec/migrations/13_create_users_using_block_and_using.rb
154
156
  - spec/migrations/1_create_users_on_master.rb
155
157
  - spec/migrations/2_create_users_on_canada.rb
156
158
  - spec/migrations/3_create_users_on_both_shards.rb