data_fabric 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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