data_fabric 1.0.1 → 1.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/Manifest CHANGED
@@ -19,15 +19,9 @@ example/config/initializers/inflections.rb
19
19
  example/config/initializers/mime_types.rb
20
20
  example/config/initializers/new_rails_defaults.rb
21
21
  example/config/routes.rb
22
- example/db/development.sqlite3
23
22
  example/db/migrate/20080702154628_create_accounts.rb
24
23
  example/db/migrate/20080702154820_create_figments.rb
25
- example/db/s0_development.sqlite3
26
- example/db/s0_test.sqlite3
27
- example/db/s1_development.sqlite3
28
- example/db/s1_test.sqlite3
29
24
  example/db/schema.rb
30
- example/db/test.sqlite3
31
25
  example/public/404.html
32
26
  example/public/422.html
33
27
  example/public/500.html
@@ -61,19 +55,16 @@ example/test/fixtures/accounts.yml
61
55
  example/test/functional/accounts_controller_test.rb
62
56
  example/test/integration/account_figments_test.rb
63
57
  example/test/test_helper.rb
64
- example/vendor/plugins/data_fabric/init.rb
65
- example/vendor/plugins/data_fabric/lib/data_fabric.rb
66
58
  init.rb
67
59
  lib/data_fabric/version.rb
68
60
  lib/data_fabric.rb
61
+ Manifest
69
62
  Rakefile
70
63
  README.rdoc
71
64
  test/connection_test.rb
72
- test/database.yml
65
+ test/database.yml.example
73
66
  test/database_test.rb
74
67
  test/shard_test.rb
75
68
  test/test_helper.rb
76
69
  test/thread_test.rb
77
70
  TESTING.rdoc
78
- TODO
79
- Manifest
data/Rakefile CHANGED
@@ -4,57 +4,70 @@ require 'echoe'
4
4
  require File.dirname(__FILE__) << "/lib/data_fabric/version"
5
5
 
6
6
  Echoe.new 'data_fabric' do |p|
7
- p.version = DataFabric::Version::STRING
8
- p.author = "Mike Perham"
9
- p.email = 'mperham@gmail.com'
10
- p.project = 'fiveruns'
11
- p.summary = 'Sharding and replication support for ActiveRecord 2.x'
12
- p.url = "http://github.com/fiveruns/data_fabric"
13
- p.dependencies = ['activerecord >=2.0.2']
14
- p.include_rakefile = true
7
+ p.version = DataFabric::Version::STRING
8
+ p.author = "Mike Perham"
9
+ p.email = 'mperham@gmail.com'
10
+ p.project = 'fiveruns'
11
+ p.summary = 'Sharding and replication support for ActiveRecord 2.x'
12
+ p.url = "http://github.com/fiveruns/data_fabric"
13
+ p.dependencies = ['activerecord >=2.0.2']
14
+ p.development_dependencies = []
15
+ p.rubygems_version = nil
16
+ p.include_rakefile = true
15
17
  end
16
18
 
17
19
  task :pretest do
18
- setup(false)
20
+ setup(false)
19
21
  end
20
22
 
21
23
  task :create_db do
22
- setup(true)
24
+ setup(true)
23
25
  end
24
26
 
25
27
  task :changelog do
26
- `git log | grep -v git-svn-id > History.txt`
28
+ `git log | grep -v git-svn-id > History.txt`
29
+ end
30
+
31
+ def load_database_yml
32
+ filename = "test/database.yml"
33
+ if !File.exist?(filename)
34
+ STDERR.puts "\n*** ERROR ***:\n" <<
35
+ "You must have a 'test/database.yml' file in order to create the test database. " <<
36
+ "An example is provided in 'test/database.yml.example'.\n\n"
37
+ exit 1
38
+ end
39
+ YAML::load(ERB.new(IO.read(filename)).result)
27
40
  end
28
41
 
29
42
  def setup_connection
30
43
  require 'active_record'
31
- ENV['RAILS_ENV'] = 'test'
32
-
33
- ActiveRecord::Base.configurations = { 'test' => { :adapter => 'mysql', :host => 'localhost', :database => 'mysql' } }
34
- ActiveRecord::Base.establish_connection 'test'
44
+ ActiveRecord::Base.configurations = load_database_yml
45
+ ActiveRecord::Base.establish_connection('fiveruns_city_austin_test_master')
46
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
47
+ ActiveRecord::Base.logger.level = Logger::DEBUG
35
48
  end
36
49
 
37
- def using_connection(&block)
50
+ def using_connection(database_identifier, &block)
38
51
  ActiveRecord::Base.connection.instance_eval(&block)
39
52
  end
40
53
 
41
54
  def setup(create = false)
42
55
  setup_connection
43
-
44
- databases = %w( vr_austin_master vr_austin_slave vr_dallas_master vr_dallas_slave )
45
- databases.each do |db|
46
- using_connection do
47
- if create
48
- execute "drop database if exists #{db}"
49
- execute "create database #{db}"
50
- end
51
- execute "use #{db}"
56
+
57
+ ActiveRecord::Base.configurations.each_pair do |identifier, config|
58
+ using_connection(identifier) do
59
+ db_name = config['database']
60
+ if create
61
+ execute "drop database if exists #{db_name}"
62
+ execute "create database #{db_name}"
63
+ end
64
+ execute "use #{db_name}"
52
65
  execute "drop table if exists the_whole_burritos"
53
66
  execute "drop table if exists enchiladas"
54
67
  execute "create table enchiladas (id integer not null auto_increment, name varchar(30) not null, primary key(id))"
55
- execute "insert into enchiladas (id, name) values (1, '#{db}')"
68
+ execute "insert into enchiladas (id, name) values (1, '#{db_name}')"
56
69
  execute "create table the_whole_burritos (id integer not null auto_increment, name varchar(30) not null, primary key(id))"
57
- execute "insert into the_whole_burritos (id, name) values (1, '#{db}')"
70
+ execute "insert into the_whole_burritos (id, name) values (1, '#{db_name}')"
58
71
  end
59
72
  end
60
73
  end
data/data_fabric.gemspec CHANGED
@@ -1,18 +1,18 @@
1
1
 
2
- # Gem::Specification for Data_fabric-1.0.1
2
+ # Gem::Specification for Data_fabric-1.0.2
3
3
  # Originally generated by Echoe
4
4
 
5
5
  --- !ruby/object:Gem::Specification
6
6
  name: data_fabric
7
7
  version: !ruby/object:Gem::Version
8
- version: 1.0.1
8
+ version: 1.0.2
9
9
  platform: ruby
10
10
  authors:
11
11
  - Mike Perham
12
12
  autorequire:
13
13
  bindir: bin
14
14
 
15
- date: 2008-07-09 00:00:00 -05:00
15
+ date: 2008-09-30 00:00:00 -05:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -25,16 +25,6 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.0.2
27
27
  version:
28
- - !ruby/object:Gem::Dependency
29
- name: echoe
30
- type: :development
31
- version_requirement:
32
- version_requirements: !ruby/object:Gem::Requirement
33
- requirements:
34
- - - ">="
35
- - !ruby/object:Gem::Version
36
- version: "0"
37
- version:
38
28
  description: Sharding and replication support for ActiveRecord 2.x
39
29
  email: mperham@gmail.com
40
30
  executables: []
@@ -46,7 +36,6 @@ extra_rdoc_files:
46
36
  - lib/data_fabric/version.rb
47
37
  - lib/data_fabric.rb
48
38
  - README.rdoc
49
- - TODO
50
39
  files:
51
40
  - CHANGELOG
52
41
  - example/app/controllers/accounts_controller.rb
@@ -69,15 +58,9 @@ files:
69
58
  - example/config/initializers/mime_types.rb
70
59
  - example/config/initializers/new_rails_defaults.rb
71
60
  - example/config/routes.rb
72
- - example/db/development.sqlite3
73
61
  - example/db/migrate/20080702154628_create_accounts.rb
74
62
  - example/db/migrate/20080702154820_create_figments.rb
75
- - example/db/s0_development.sqlite3
76
- - example/db/s0_test.sqlite3
77
- - example/db/s1_development.sqlite3
78
- - example/db/s1_test.sqlite3
79
63
  - example/db/schema.rb
80
- - example/db/test.sqlite3
81
64
  - example/public/404.html
82
65
  - example/public/422.html
83
66
  - example/public/500.html
@@ -111,22 +94,19 @@ files:
111
94
  - example/test/functional/accounts_controller_test.rb
112
95
  - example/test/integration/account_figments_test.rb
113
96
  - example/test/test_helper.rb
114
- - example/vendor/plugins/data_fabric/init.rb
115
- - example/vendor/plugins/data_fabric/lib/data_fabric.rb
116
97
  - init.rb
117
98
  - lib/data_fabric/version.rb
118
99
  - lib/data_fabric.rb
100
+ - Manifest
119
101
  - Rakefile
120
102
  - README.rdoc
121
103
  - test/connection_test.rb
122
- - test/database.yml
104
+ - test/database.yml.example
123
105
  - test/database_test.rb
124
106
  - test/shard_test.rb
125
107
  - test/test_helper.rb
126
108
  - test/thread_test.rb
127
109
  - TESTING.rdoc
128
- - TODO
129
- - Manifest
130
110
  - data_fabric.gemspec
131
111
  has_rdoc: true
132
112
  homepage: http://github.com/fiveruns/data_fabric
@@ -148,9 +128,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
128
  version:
149
129
  required_rubygems_version: !ruby/object:Gem::Requirement
150
130
  requirements:
151
- - - "="
131
+ - - ">="
152
132
  - !ruby/object:Gem::Version
153
- version: "1.2"
133
+ version: "0"
154
134
  version:
155
135
  requirements: []
156
136
 
@@ -10,7 +10,7 @@ class AccountFigmentsTest < ActionController::IntegrationTest
10
10
  assert_equal 0, conn0.count_for('figments')
11
11
  assert_equal 0, conn1.count_for('figments')
12
12
 
13
- new_session do |user|
13
+ new_session(0) do |user|
14
14
  user.goes_home
15
15
  mike = user.creates_account('mike', '0')
16
16
  user.selects_account(mike)
@@ -25,7 +25,7 @@ class AccountFigmentsTest < ActionController::IntegrationTest
25
25
  assert_equal 1, conn0.count_for('figments')
26
26
  assert_equal 0, conn1.count_for('figments')
27
27
 
28
- new_session do |user|
28
+ new_session(1) do |user|
29
29
  user.goes_home
30
30
  bob = user.creates_account('bob', '1')
31
31
  user.selects_account(bob)
@@ -54,10 +54,12 @@ class AccountFigmentsTest < ActionController::IntegrationTest
54
54
  conn
55
55
  end
56
56
 
57
- def new_session
57
+ def new_session(shard)
58
58
  open_session do |sess|
59
- sess.extend(Operations)
60
- yield sess if block_given?
59
+ DataFabric.activate_shard :shard => shard do
60
+ sess.extend(Operations)
61
+ yield sess if block_given?
62
+ end
61
63
  end
62
64
  end
63
65
 
data/lib/data_fabric.rb CHANGED
@@ -36,29 +36,41 @@ require 'active_record/version'
36
36
  # end
37
37
  # end
38
38
  module DataFabric
39
- VERSION = "1.0.0"
40
39
 
41
40
  def self.logger
42
41
  ActiveRecord::Base.logger
43
42
  end
44
43
 
45
44
  def self.init
46
- logger.info "Loading data_fabric #{VERSION} with ActiveRecord #{ActiveRecord::VERSION::STRING}"
45
+ logger.info "Loading data_fabric #{DataFabric::Version::STRING} with ActiveRecord #{ActiveRecord::VERSION::STRING}"
47
46
  ActiveRecord::Base.send(:include, self)
48
47
  end
49
48
 
49
+ mattr_writer :debugging
50
+ @@debugging = false
51
+
52
+ def self.debugging?
53
+ if @@debugging.nil? && logger
54
+ logger.debug?
55
+ else
56
+ !!@@debugging
57
+ end
58
+ end
59
+
50
60
  def self.activate_shard(shards, &block)
51
61
  ensure_setup
52
- shards.each do |key, value|
62
+
63
+ # Save the old shard settings to handle nested activation
64
+ old = Thread.current[:shards].dup
65
+
66
+ shards.each_pair do |key, value|
53
67
  Thread.current[:shards][key.to_s] = value.to_s
54
68
  end
55
69
  if block_given?
56
70
  begin
57
71
  yield
58
72
  ensure
59
- shards.each do |key, value|
60
- Thread.current[:shards].delete(key.to_s)
61
- end
73
+ Thread.current[:shards] = old
62
74
  end
63
75
  end
64
76
  end
@@ -128,7 +140,7 @@ module DataFabric
128
140
 
129
141
  delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
130
142
  :change_column, :change_column_default, :rename_column, :add_index, :remove_index, :initialize_schema_information,
131
- :dump_schema_information, :to => :master
143
+ :dump_schema_information, :execute, :to => :master
132
144
 
133
145
  def transaction(start_db_transaction = true, &block)
134
146
  with_master { raw_connection.transaction(start_db_transaction, &block) }
@@ -139,10 +151,10 @@ module DataFabric
139
151
  raw_connection
140
152
  @role_changed = false
141
153
  end
142
- if logger.debug?
154
+ if DataFabric.debugging?
143
155
  logger.debug("Calling #{method} on #{@cached_connection}")
144
156
  end
145
- @cached_connection.send(method, *args, &block)
157
+ raw_connection.send(method, *args, &block)
146
158
  end
147
159
 
148
160
  def connection_name
@@ -184,8 +196,8 @@ module DataFabric
184
196
  config = ActiveRecord::Base.configurations[conn_name]
185
197
  raise ArgumentError, "Unknown database config: #{conn_name}, have #{ActiveRecord::Base.configurations.inspect}" unless config
186
198
  @model_class.establish_connection config
187
- if logger.debug?
188
- logger.debug "Switching from #{@current_connection_name} to #{conn_name}"
199
+ if DataFabric.debugging?
200
+ logger.debug "Switching from #{@current_connection_name || "(none)"} to #{conn_name}"
189
201
  end
190
202
  @current_connection_name = conn_name
191
203
  conn = @model_class.connection
@@ -1,5 +1,5 @@
1
1
  module DataFabric
2
2
  module Version
3
- STRING = "1.0.1"
3
+ STRING = "1.0.2"
4
4
  end
5
5
  end
@@ -1,3 +1,12 @@
1
+ # The unit tests make use of the data populated in these databases.
2
+ #
3
+ # Notes:
4
+ # - The database identifiers (e.g. "fiveruns_city_austin_test_master") MUST NOT
5
+ # be changed! Everything else may be changed.
6
+ # - The user defined for "fiveruns_city_austin_test_master" MUST have the
7
+ # privilege to create and drop databases and tables.
8
+
9
+
1
10
  fiveruns_city_austin_test_master:
2
11
  adapter: mysql
3
12
  host: localhost
@@ -9,8 +9,7 @@ end
9
9
  class DatabaseTest < Test::Unit::TestCase
10
10
 
11
11
  def setup
12
- filename = File.join(File.dirname(__FILE__), "database.yml")
13
- ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(filename)).result)
12
+ ActiveRecord::Base.configurations = load_database_yml
14
13
  end
15
14
 
16
15
  def test_live_burrito
@@ -36,4 +35,4 @@ class DatabaseTest < Test::Unit::TestCase
36
35
  end
37
36
  end
38
37
  end
39
- end
38
+ end
data/test/shard_test.rb CHANGED
@@ -21,4 +21,38 @@ class ShardTest < Test::Unit::TestCase
21
21
  assert_equal 'dallas', DataFabric.active_shard(:city)
22
22
  end.join
23
23
  end
24
- end
24
+
25
+ def test_activations_can_be_nested
26
+ DataFabric.activate_shard(:name => 'Belldandy') do
27
+ DataFabric.activate_shard(:technique => 'Thousand Years of Pain') do
28
+ DataFabric.activate_shard(:name => 'Lelouche') do
29
+ DataFabric.activate_shard(:technique => 'Shadow Replication') do
30
+ assert_equal 'Shadow Replication', DataFabric.active_shard(:technique)
31
+ assert_equal 'Lelouche', DataFabric.active_shard(:name)
32
+ end
33
+ assert_equal 'Thousand Years of Pain', DataFabric.active_shard(:technique)
34
+ assert_equal 'Lelouche', DataFabric.active_shard(:name)
35
+ end
36
+ assert_equal 'Thousand Years of Pain', DataFabric.active_shard(:technique)
37
+ assert_equal 'Belldandy', DataFabric.active_shard(:name)
38
+ end
39
+ assert_raises ArgumentError do
40
+ DataFabric.active_shard(:technique)
41
+ end
42
+ assert_equal 'Belldandy', DataFabric.active_shard(:name)
43
+ end
44
+ assert_raises ArgumentError do
45
+ DataFabric.active_shard(:technique)
46
+ end
47
+ assert_raises ArgumentError do
48
+ DataFabric.active_shard(:name)
49
+ end
50
+ end
51
+
52
+ def test_activate_shard_returns_result_of_block
53
+ result = DataFabric.activate_shard(:gundam => 'Exia') do
54
+ 1234
55
+ end
56
+ assert_equal 1234, result
57
+ end
58
+ end
data/test/test_helper.rb CHANGED
@@ -1,17 +1,34 @@
1
- ENV['RAILS_ENV']='test'
2
- RAILS_ENV='test'
1
+ if !defined?(ROOT_PATH) # Don't evaluate this file twice.
2
+ ENV['RAILS_ENV'] = 'test'
3
+ RAILS_ENV = 'test'
4
+ ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), ".."))
5
+ DATABASE_YML_PATH = File.join(ROOT_PATH, "test", "database.yml")
6
+ Dir.chdir(ROOT_PATH)
3
7
 
4
- require 'rubygems'
5
- require 'test/unit'
8
+ require 'rubygems'
9
+ require 'test/unit'
6
10
 
7
- # Bootstrap AR
8
- gem 'activerecord', '=2.0.2'
9
- require 'active_record'
10
- require 'active_record/version'
11
- ActiveRecord::Base.logger = Logger.new(STDOUT)
12
- ActiveRecord::Base.logger.level = Logger::WARN
13
- ActiveRecord::Base.allow_concurrency = false
11
+ # Bootstrap AR
12
+ gem 'activerecord', '=2.0.2'
13
+ require 'active_record'
14
+ require 'active_record/version'
15
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
16
+ ActiveRecord::Base.logger.level = Logger::WARN
17
+ ActiveRecord::Base.allow_concurrency = false
14
18
 
15
- # Bootstrap DF
16
- Dependencies.load_paths << File.join(File.dirname(__FILE__), '../lib')
17
- require 'init'
19
+ # Bootstrap DF
20
+ Dependencies.load_paths << File.join(File.dirname(__FILE__), '../lib')
21
+ require 'init'
22
+
23
+ def load_database_yml
24
+ filename = DATABASE_YML_PATH
25
+ YAML::load(ERB.new(IO.read(filename)).result)
26
+ end
27
+
28
+ if !File.exist?(DATABASE_YML_PATH)
29
+ STDERR.puts "\n*** ERROR ***:\n" <<
30
+ "You must have a 'test/database.yml' file in order to run the unit tests. " <<
31
+ "An example is provided in 'test/database.yml.example'.\n\n"
32
+ exit 1
33
+ end
34
+ end
data/test/thread_test.rb CHANGED
@@ -18,8 +18,7 @@ class ThreadTest < Test::Unit::TestCase
18
18
  end
19
19
 
20
20
  def xtest_class_and_instance_connections
21
- filename = File.join(File.dirname(__FILE__), "database.yml")
22
- ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(filename)).result)
21
+ ActiveRecord::Base.configurations = load_database_yml
23
22
 
24
23
  cconn = ThreadedEnchilada.connection
25
24
  iconn = ThreadedEnchilada.new.connection
@@ -30,7 +29,7 @@ class ThreadTest < Test::Unit::TestCase
30
29
  clear_databases
31
30
 
32
31
  filename = File.join(File.dirname(__FILE__), "database.yml")
33
- ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(filename)).result)
32
+ ActiveRecord::Base.configurations = load_database_yml
34
33
 
35
34
  counts = {:austin => 0, :dallas => 0}
36
35
  threads = []
@@ -88,4 +87,4 @@ class ThreadTest < Test::Unit::TestCase
88
87
  def using_connection(&block)
89
88
  ActiveRecord::Base.connection.instance_eval(&block)
90
89
  end
91
- end
90
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_fabric
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-09 00:00:00 -05:00
12
+ date: 2008-09-30 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,16 +22,6 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: 2.0.2
24
24
  version:
25
- - !ruby/object:Gem::Dependency
26
- name: echoe
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: "0"
34
- version:
35
25
  description: Sharding and replication support for ActiveRecord 2.x
36
26
  email: mperham@gmail.com
37
27
  executables: []
@@ -43,7 +33,6 @@ extra_rdoc_files:
43
33
  - lib/data_fabric/version.rb
44
34
  - lib/data_fabric.rb
45
35
  - README.rdoc
46
- - TODO
47
36
  files:
48
37
  - CHANGELOG
49
38
  - example/app/controllers/accounts_controller.rb
@@ -66,15 +55,9 @@ files:
66
55
  - example/config/initializers/mime_types.rb
67
56
  - example/config/initializers/new_rails_defaults.rb
68
57
  - example/config/routes.rb
69
- - example/db/development.sqlite3
70
58
  - example/db/migrate/20080702154628_create_accounts.rb
71
59
  - example/db/migrate/20080702154820_create_figments.rb
72
- - example/db/s0_development.sqlite3
73
- - example/db/s0_test.sqlite3
74
- - example/db/s1_development.sqlite3
75
- - example/db/s1_test.sqlite3
76
60
  - example/db/schema.rb
77
- - example/db/test.sqlite3
78
61
  - example/public/404.html
79
62
  - example/public/422.html
80
63
  - example/public/500.html
@@ -108,22 +91,19 @@ files:
108
91
  - example/test/functional/accounts_controller_test.rb
109
92
  - example/test/integration/account_figments_test.rb
110
93
  - example/test/test_helper.rb
111
- - example/vendor/plugins/data_fabric/init.rb
112
- - example/vendor/plugins/data_fabric/lib/data_fabric.rb
113
94
  - init.rb
114
95
  - lib/data_fabric/version.rb
115
96
  - lib/data_fabric.rb
97
+ - Manifest
116
98
  - Rakefile
117
99
  - README.rdoc
118
100
  - test/connection_test.rb
119
- - test/database.yml
101
+ - test/database.yml.example
120
102
  - test/database_test.rb
121
103
  - test/shard_test.rb
122
104
  - test/test_helper.rb
123
105
  - test/thread_test.rb
124
106
  - TESTING.rdoc
125
- - TODO
126
- - Manifest
127
107
  - data_fabric.gemspec
128
108
  has_rdoc: true
129
109
  homepage: http://github.com/fiveruns/data_fabric
@@ -145,9 +125,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
125
  version:
146
126
  required_rubygems_version: !ruby/object:Gem::Requirement
147
127
  requirements:
148
- - - "="
128
+ - - ">="
149
129
  - !ruby/object:Gem::Version
150
- version: "1.2"
130
+ version: "0"
151
131
  version:
152
132
  requirements: []
153
133
 
data/TODO DELETED
@@ -1 +0,0 @@
1
- Process or Documentation for how to migrate existing data to shards
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1 +0,0 @@
1
- DataFabric.init
@@ -1,231 +0,0 @@
1
- require 'active_record'
2
- require 'active_record/version'
3
-
4
- # DataFabric adds a new level of flexibility to ActiveRecord connection handling.
5
- # You need to describe the topology for your database infrastructure in your model(s). As with ActiveRecord normally, different models can use different topologies.
6
- #
7
- # class MyHugeVolumeOfDataModel < ActiveRecord::Base
8
- # connection_topology :replicated => true, :shard_by => :city
9
- # end
10
- #
11
- # There are four supported modes of operation, depending on the options given to the connection_topology method. The plugin will look for connections in your config/database.yml with the following convention:
12
- #
13
- # No connection topology:
14
- # #{environment} - this is the default, as with ActiveRecord, e.g. "production"
15
- #
16
- # connection_topology :replicated => true
17
- # #{environment}_#{role} - no sharding, just replication, where role is "master" or "slave", e.g. "production_master"
18
- #
19
- # connection_topology :shard_by => :city
20
- # #{group}_#{shard}_#{environment} - sharding, no replication, e.g. "city_austin_production"
21
- #
22
- # connection_topology :replicated => true, :shard_by => :city
23
- # #{group}_#{shard}_#{environment}_#{role} - sharding with replication, e.g. "city_austin_production_master"
24
- #
25
- #
26
- # When marked as replicated, all write and transactional operations for the model go to the master, whereas read operations go to the slave.
27
- #
28
- # Since sharding is an application-level concern, your application must set the shard to use based on the current request or environment. The current shard for a group is set on a thread local variable. For example, you can set the shard in an ActionController around_filter based on the user as follows:
29
- #
30
- # class ApplicationController < ActionController::Base
31
- # around_filter :select_shard
32
- #
33
- # private
34
- # def select_shard(&action_block)
35
- # DataFabric.activate_shard(:city => @current_user.city, &action_block)
36
- # end
37
- # end
38
- module DataFabric
39
- VERSION = "1.0.0"
40
-
41
- def self.logger
42
- ActiveRecord::Base.logger
43
- end
44
-
45
- def self.init
46
- logger.info "Loading data_fabric #{VERSION} with ActiveRecord #{ActiveRecord::VERSION::STRING}"
47
- ActiveRecord::Base.send(:include, self)
48
- end
49
-
50
- def self.activate_shard(shards, &block)
51
- ensure_setup
52
- shards.each do |key, value|
53
- Thread.current[:shards][key.to_s] = value.to_s
54
- end
55
- if block_given?
56
- begin
57
- yield
58
- ensure
59
- shards.each do |key, value|
60
- Thread.current[:shards].delete(key.to_s)
61
- end
62
- end
63
- end
64
- end
65
-
66
- # For cases where you can't pass a block to activate_shards, you can
67
- # clean up the thread local settings by calling this method at the
68
- # end of processing
69
- def self.deactivate_shard(shards)
70
- ensure_setup
71
- shards.each do |key, value|
72
- Thread.current[:shards].delete(key.to_s)
73
- end
74
- end
75
-
76
- def self.active_shard(group)
77
- raise ArgumentError, 'No shard has been activated' unless Thread.current[:shards]
78
-
79
- returning(Thread.current[:shards][group.to_s]) do |shard|
80
- raise ArgumentError, "No active shard for #{group}" unless shard
81
- end
82
- end
83
-
84
- def self.included(model)
85
- # Wire up ActiveRecord::Base
86
- model.extend ClassMethods
87
- end
88
-
89
- def self.ensure_setup
90
- Thread.current[:shards] = {} unless Thread.current[:shards]
91
- end
92
-
93
- # Class methods injected into ActiveRecord::Base
94
- module ClassMethods
95
- def connection_topology(options)
96
- proxy = DataFabric::ConnectionProxy.new(self, options)
97
- ActiveRecord::Base.active_connections[name] = proxy
98
-
99
- raise ArgumentError, "data_fabric does not support ActiveRecord's allow_concurrency = true" if allow_concurrency
100
- DataFabric.logger.info "Creating data_fabric proxy for class #{name}"
101
- end
102
- end
103
-
104
- class StringProxy
105
- def initialize(&block)
106
- @proc = block
107
- end
108
- def to_s
109
- @proc.call
110
- end
111
- end
112
-
113
- class ConnectionProxy
114
- def initialize(model_class, options)
115
- @model_class = model_class
116
- @replicated = options[:replicated]
117
- @shard_group = options[:shard_by]
118
- @prefix = options[:prefix]
119
- @current_role = 'slave' if @replicated
120
- @current_connection_name_builder = connection_name_builder
121
- @cached_connection = nil
122
- @current_connection_name = nil
123
- @role_changed = false
124
-
125
- @model_class.send :include, ActiveRecordConnectionMethods if @replicated
126
- end
127
-
128
- delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
129
- :change_column, :change_column_default, :rename_column, :add_index, :remove_index, :initialize_schema_information,
130
- :dump_schema_information, :to => :master
131
-
132
- def transaction(start_db_transaction = true, &block)
133
- with_master { raw_connection.transaction(start_db_transaction, &block) }
134
- end
135
-
136
- def method_missing(method, *args, &block)
137
- unless @cached_connection and !@role_changed
138
- raw_connection
139
- @role_changed = false
140
- end
141
- if logger.debug?
142
- logger.debug("Calling #{method} on #{@cached_connection}")
143
- end
144
- @cached_connection.send(method, *args, &block)
145
- end
146
-
147
- def connection_name
148
- @current_connection_name_builder.join('_')
149
- end
150
-
151
- def disconnect!
152
- @cached_connection.disconnect! if @cached_connection
153
- @cached_connection = nil
154
- end
155
-
156
- def verify!(arg)
157
- @cached_connection.verify!(0) if @cached_connection
158
- end
159
-
160
- def with_master
161
- set_role('master')
162
- yield
163
- ensure
164
- set_role('slave')
165
- end
166
-
167
- private
168
-
169
- def connection_name_builder
170
- clauses = []
171
- clauses << @prefix if @prefix
172
- clauses << @shard_group if @shard_group
173
- clauses << StringProxy.new { DataFabric.active_shard(@shard_group) } if @shard_group
174
- clauses << RAILS_ENV
175
- clauses << StringProxy.new { @current_role } if @replicated
176
- clauses
177
- end
178
-
179
- def raw_connection
180
- conn_name = connection_name
181
- unless already_connected_to? conn_name
182
- @cached_connection = begin
183
- config = ActiveRecord::Base.configurations[conn_name]
184
- raise ArgumentError, "Unknown database config: #{conn_name}, have #{ActiveRecord::Base.configurations.inspect}" unless config
185
- @model_class.establish_connection config
186
- if logger.debug?
187
- logger.debug "Switching from #{@current_connection_name} to #{conn_name}"
188
- end
189
- @current_connection_name = conn_name
190
- conn = @model_class.connection
191
- conn.verify! 0
192
- conn
193
- end
194
- @model_class.active_connections[@model_class.name] = self
195
- end
196
- @cached_connection
197
- end
198
-
199
- def already_connected_to?(conn_name)
200
- conn_name == @current_connection_name and @cached_connection
201
- end
202
-
203
- def set_role(role)
204
- if @replicated and @current_role != role
205
- @current_role = role
206
- @role_changed = true
207
- end
208
- end
209
-
210
- def master
211
- set_role('master')
212
- return raw_connection
213
- ensure
214
- set_role('slave')
215
- end
216
-
217
- def logger
218
- DataFabric.logger
219
- end
220
- end
221
-
222
- module ActiveRecordConnectionMethods
223
- def self.included(base)
224
- base.alias_method_chain :reload, :master
225
- end
226
-
227
- def reload_with_master(*args, &block)
228
- connection.with_master { reload_without_master }
229
- end
230
- end
231
- end