activerecord-turntable 1.1.2 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.travis.yml +3 -5
- data/CHANGELOG.md +70 -0
- data/Guardfile +7 -5
- data/README.md +490 -0
- data/Rakefile +37 -22
- data/activerecord-turntable.gemspec +37 -34
- data/gemfiles/rails4_0.gemfile +6 -0
- data/gemfiles/rails4_1.gemfile +6 -0
- data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +14 -29
- data/lib/active_record/turntable/active_record_ext/activerecord_import_ext.rb +45 -0
- data/lib/active_record/turntable/active_record_ext/acts_as_archive_extension.rb +21 -0
- data/lib/active_record/turntable/active_record_ext/association.rb +85 -0
- data/lib/active_record/turntable/active_record_ext/association_preloader.rb +37 -0
- data/lib/active_record/turntable/active_record_ext/clever_load.rb +33 -76
- data/lib/active_record/turntable/active_record_ext/connection_handler_extension.rb +31 -0
- data/lib/active_record/turntable/active_record_ext/database_tasks.rb +81 -0
- data/lib/active_record/turntable/active_record_ext/fixtures.rb +54 -42
- data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +101 -0
- data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +28 -46
- data/lib/active_record/turntable/active_record_ext/migration_proxy.rb +7 -0
- data/lib/active_record/turntable/active_record_ext/persistence.rb +96 -94
- data/lib/active_record/turntable/active_record_ext/relation.rb +31 -0
- data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +18 -28
- data/lib/active_record/turntable/active_record_ext/transactions.rb +9 -3
- data/lib/active_record/turntable/active_record_ext.rb +26 -11
- data/lib/active_record/turntable/algorithm/base.rb +1 -1
- data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +1 -1
- data/lib/active_record/turntable/algorithm.rb +7 -3
- data/lib/active_record/turntable/base.rb +67 -14
- data/lib/active_record/turntable/cluster.rb +46 -2
- data/lib/active_record/turntable/config.rb +1 -1
- data/lib/active_record/turntable/connection_proxy/mixable.rb +7 -29
- data/lib/active_record/turntable/connection_proxy.rb +61 -72
- data/lib/active_record/turntable/error.rb +5 -6
- data/lib/active_record/turntable/helpers.rb +5 -1
- data/lib/active_record/turntable/migration.rb +9 -49
- data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +13 -2
- data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +17 -6
- data/lib/active_record/turntable/mixer/fader/specified_shard.rb +3 -1
- data/lib/active_record/turntable/mixer/fader.rb +12 -10
- data/lib/active_record/turntable/mixer.rb +59 -29
- data/lib/active_record/turntable/plugin.rb +6 -0
- data/lib/active_record/turntable/pool_proxy.rb +12 -19
- data/lib/active_record/turntable/rack/query_cache.rb +20 -23
- data/lib/active_record/turntable/rack.rb +4 -2
- data/lib/active_record/turntable/railtie.rb +4 -3
- data/lib/active_record/turntable/railties/databases.rake +81 -122
- data/lib/active_record/turntable/seq_shard.rb +1 -1
- data/lib/active_record/turntable/sequencer/api.rb +1 -1
- data/lib/active_record/turntable/sequencer/barrage.rb +28 -0
- data/lib/active_record/turntable/sequencer.rb +27 -9
- data/lib/active_record/turntable/shard.rb +2 -2
- data/lib/active_record/turntable/sql_tree_patch.rb +1 -1
- data/lib/active_record/turntable/version.rb +1 -1
- data/lib/active_record/turntable.rb +26 -16
- data/lib/generators/templates/turntable.yml +9 -7
- data/spec/active_record/turntable/active_record_ext/association_preloader_spec.rb +78 -0
- data/spec/active_record/turntable/active_record_ext/association_spec.rb +72 -0
- data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +25 -46
- data/spec/active_record/turntable/active_record_ext/locking_optimistic_spec.rb +28 -0
- data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +46 -25
- data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +4 -4
- data/spec/active_record/turntable/algorithm/range_bsearch_algorithm_spec.rb +35 -0
- data/spec/active_record/turntable/algorithm_spec.rb +28 -12
- data/spec/active_record/turntable/base_spec.rb +1 -1
- data/spec/active_record/turntable/cluster_spec.rb +27 -5
- data/spec/active_record/turntable/config_spec.rb +2 -2
- data/spec/active_record/turntable/connection_proxy_spec.rb +112 -45
- data/spec/active_record/turntable/finder_spec.rb +24 -11
- data/spec/active_record/turntable/mixer_spec.rb +21 -21
- data/spec/active_record/turntable/rack/query_cache_spec.rb +19 -0
- data/spec/active_record/turntable/sequencer/api_spec.rb +38 -0
- data/spec/active_record/turntable/sequencer/barrage_spec.rb +22 -0
- data/spec/active_record/turntable/sequencer/mysql_spec.rb +22 -0
- data/spec/active_record/turntable/shard_spec.rb +1 -1
- data/spec/active_record/turntable/transaction_spec.rb +35 -0
- data/spec/active_record/turntable_spec.rb +4 -4
- data/spec/config/database.yml +24 -34
- data/spec/config/turntable.yml +18 -1
- data/spec/fabricators/turntable_fabricator.rb +0 -2
- data/spec/models/card.rb +3 -0
- data/spec/models/cards_user.rb +10 -0
- data/spec/models/cards_users_histories.rb +7 -0
- data/spec/models/events_users_history.rb +7 -0
- data/spec/models/user.rb +7 -0
- data/spec/models/user_status.rb +6 -0
- data/spec/spec_helper.rb +10 -4
- data/spec/support/matchers/be_saved_to.rb +6 -0
- data/spec/support/turntable_helper.rb +29 -0
- metadata +124 -74
- data/README.rdoc +0 -294
- data/gemfiles/rails3_0.gemfile +0 -7
- data/gemfiles/rails3_1.gemfile +0 -6
- data/gemfiles/rails3_2.gemfile +0 -6
- data/lib/active_record/turntable/compatible.rb +0 -19
- data/sample_app/.gitignore +0 -16
- data/sample_app/Gemfile +0 -41
- data/sample_app/README.rdoc +0 -261
- data/sample_app/Rakefile +0 -7
- data/sample_app/app/assets/images/rails.png +0 -0
- data/sample_app/app/assets/javascripts/application.js +0 -15
- data/sample_app/app/assets/stylesheets/application.css +0 -13
- data/sample_app/app/controllers/application_controller.rb +0 -3
- data/sample_app/app/helpers/application_helper.rb +0 -2
- data/sample_app/app/mailers/.gitkeep +0 -0
- data/sample_app/app/models/.gitkeep +0 -0
- data/sample_app/app/models/user.rb +0 -4
- data/sample_app/app/views/layouts/application.html.erb +0 -14
- data/sample_app/config/application.rb +0 -65
- data/sample_app/config/boot.rb +0 -6
- data/sample_app/config/database.yml +0 -70
- data/sample_app/config/environment.rb +0 -5
- data/sample_app/config/environments/development.rb +0 -37
- data/sample_app/config/environments/production.rb +0 -67
- data/sample_app/config/environments/test.rb +0 -37
- data/sample_app/config/initializers/backtrace_silencers.rb +0 -7
- data/sample_app/config/initializers/inflections.rb +0 -15
- data/sample_app/config/initializers/mime_types.rb +0 -5
- data/sample_app/config/initializers/secret_token.rb +0 -7
- data/sample_app/config/initializers/session_store.rb +0 -8
- data/sample_app/config/initializers/wrap_parameters.rb +0 -14
- data/sample_app/config/locales/en.yml +0 -5
- data/sample_app/config/routes.rb +0 -58
- data/sample_app/config/turntable.yml +0 -64
- data/sample_app/config.ru +0 -4
- data/sample_app/db/migrate/20120316073058_create_users.rb +0 -11
- data/sample_app/db/seeds.rb +0 -7
- data/sample_app/lib/assets/.gitkeep +0 -0
- data/sample_app/lib/tasks/.gitkeep +0 -0
- data/sample_app/log/.gitkeep +0 -0
- data/sample_app/public/404.html +0 -26
- data/sample_app/public/422.html +0 -26
- data/sample_app/public/500.html +0 -25
- data/sample_app/public/favicon.ico +0 -0
- data/sample_app/public/index.html +0 -241
- data/sample_app/public/robots.txt +0 -5
- data/sample_app/script/rails +0 -6
- data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
- data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/sample_app/vendor/plugins/.gitkeep +0 -0
- data/spec/test_models.rb +0 -27
- data/spec/turntable_helper.rb +0 -29
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ActiveRecordExt
|
3
|
+
module Relation
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
version = ActiveRecord::VERSION::STRING
|
8
|
+
if version >= '4.1'
|
9
|
+
if version < '4.1.2'
|
10
|
+
alias_method :_update_record_without_turntable, :update_record
|
11
|
+
alias_method :update_record, :_update_record_with_turntable
|
12
|
+
else
|
13
|
+
alias_method_chain :_update_record, :turntable
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
|
19
|
+
substitutes, binds = substitute_values values
|
20
|
+
condition_scope = @klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id))
|
21
|
+
condition_scope = condition_scope.merge(turntable_scope) if turntable_scope
|
22
|
+
um = condition_scope.arel.compile_update(substitutes, @klass.primary_key)
|
23
|
+
|
24
|
+
@klass.connection.update(
|
25
|
+
um,
|
26
|
+
'SQL',
|
27
|
+
binds)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -22,51 +22,41 @@ module ActiveRecord::Turntable
|
|
22
22
|
pk = @connection.primary_key(table)
|
23
23
|
end
|
24
24
|
|
25
|
-
# turntable sequencer dump
|
26
25
|
if table =~ /\A(.*)_id_seq\z/
|
27
|
-
tbl.print " create_sequence_for #{$1.inspect}"
|
26
|
+
tbl.print " create_sequence_for #{remove_prefix_and_suffix($1).inspect}"
|
28
27
|
else
|
29
|
-
tbl.print " create_table #{table.inspect}"
|
28
|
+
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
30
29
|
end
|
31
|
-
|
32
|
-
if
|
30
|
+
pkcol = columns.detect { |c| c.name == pk }
|
31
|
+
if pkcol
|
33
32
|
if pk != 'id'
|
34
|
-
tbl.print %Q(, :
|
33
|
+
tbl.print %Q(, primary_key: "#{pk}")
|
34
|
+
elsif pkcol.sql_type == 'uuid'
|
35
|
+
tbl.print ", id: :uuid"
|
36
|
+
tbl.print %Q(, default: "#{pkcol.default_function}") if pkcol.default_function
|
35
37
|
end
|
36
38
|
else
|
37
|
-
tbl.print ", :
|
39
|
+
tbl.print ", id: false"
|
38
40
|
end
|
39
|
-
tbl.print ", :
|
41
|
+
tbl.print ", force: true"
|
40
42
|
tbl.puts " do |t|"
|
41
43
|
|
42
44
|
# then dump all non-primary key columns
|
43
45
|
column_specs = columns.map do |column|
|
44
|
-
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'"
|
46
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
45
47
|
next if column.name == pk
|
46
|
-
|
47
|
-
spec[:name] = column.name.inspect
|
48
|
-
|
49
|
-
# AR has an optimisation which handles zero-scale decimals as integers. This
|
50
|
-
# code ensures that the dumper still dumps the column as a decimal.
|
51
|
-
spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
|
52
|
-
'decimal'
|
53
|
-
else
|
54
|
-
column.type.to_s
|
55
|
-
end
|
56
|
-
spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
|
57
|
-
spec[:precision] = column.precision.inspect if column.precision
|
58
|
-
spec[:scale] = column.scale.inspect if column.scale
|
59
|
-
spec[:null] = 'false' unless column.null
|
60
|
-
spec[:default] = default_string(column.default) if column.has_default?
|
61
|
-
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
|
62
|
-
spec
|
48
|
+
@connection.column_spec(column, @types)
|
63
49
|
end.compact
|
64
50
|
|
65
51
|
# find all migration keys used in this table
|
66
|
-
keys =
|
52
|
+
keys = @connection.migration_keys
|
67
53
|
|
68
54
|
# figure out the lengths for each column based on above keys
|
69
|
-
lengths = keys.map{ |key|
|
55
|
+
lengths = keys.map { |key|
|
56
|
+
column_specs.map { |spec|
|
57
|
+
spec[key] ? spec[key].length + 2 : 0
|
58
|
+
}.max
|
59
|
+
}
|
70
60
|
|
71
61
|
# the string we're going to sprintf our values against, with standardized column widths
|
72
62
|
format_string = lengths.map{ |len| "%-#{len}s" }
|
@@ -5,12 +5,18 @@ module ActiveRecord::Turntable
|
|
5
5
|
if self.class.turntable_enabled?
|
6
6
|
status = nil
|
7
7
|
if self.new_record? and self.turntable_shard_key.to_s == self.class.primary_key and
|
8
|
-
self.id.nil? and connection.prefetch_primary_key?(self.class.table_name)
|
9
|
-
self.id = connection.next_sequence_value(self.class.sequence_name)
|
8
|
+
self.id.nil? and self.class.connection.prefetch_primary_key?(self.class.table_name)
|
9
|
+
self.id = self.class.connection.next_sequence_value(self.class.sequence_name)
|
10
10
|
end
|
11
11
|
self.class.connection.shards_transaction([self.turntable_shard]) do
|
12
12
|
add_to_transaction
|
13
|
-
|
13
|
+
begin
|
14
|
+
status = yield
|
15
|
+
rescue ActiveRecord::Rollback
|
16
|
+
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
|
17
|
+
status = nil
|
18
|
+
end
|
19
|
+
|
14
20
|
raise ActiveRecord::Rollback unless status
|
15
21
|
end
|
16
22
|
status
|
@@ -1,14 +1,22 @@
|
|
1
1
|
module ActiveRecord::Turntable
|
2
2
|
module ActiveRecordExt
|
3
3
|
extend ActiveSupport::Concern
|
4
|
+
extend ActiveSupport::Autoload
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
eager_autoload do
|
7
|
+
autoload :AbstractAdapter
|
8
|
+
autoload :CleverLoad
|
9
|
+
autoload :ConnectionHandlerExtension
|
10
|
+
autoload :LogSubscriber
|
11
|
+
autoload :Persistence
|
12
|
+
autoload :SchemaDumper
|
13
|
+
autoload :Sequencer
|
14
|
+
autoload :Relation
|
15
|
+
autoload :Transactions
|
16
|
+
autoload :AssociationPreloader
|
17
|
+
autoload :Association
|
18
|
+
autoload :LockingOptimistic
|
19
|
+
end
|
12
20
|
|
13
21
|
included do
|
14
22
|
include Transactions
|
@@ -16,11 +24,18 @@ module ActiveRecord::Turntable
|
|
16
24
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, AbstractAdapter)
|
17
25
|
ActiveRecord::LogSubscriber.send(:include, LogSubscriber)
|
18
26
|
ActiveRecord::Persistence.send(:include, Persistence)
|
19
|
-
ActiveRecord::
|
20
|
-
ActiveRecord::
|
21
|
-
|
22
|
-
|
27
|
+
ActiveRecord::Locking::Optimistic.send(:include, LockingOptimistic)
|
28
|
+
ActiveRecord::Relation.send(:include, CleverLoad, Relation)
|
29
|
+
ActiveRecord::Migration.send(:include, ActiveRecord::Turntable::Migration)
|
30
|
+
ActiveRecord::ConnectionAdapters::ConnectionHandler.instance_exec do
|
31
|
+
include ConnectionHandlerExtension
|
32
|
+
end
|
33
|
+
ActiveRecord::Associations::Preloader::Association.send(:include, AssociationPreloader)
|
34
|
+
ActiveRecord::Associations::Association.send(:include, Association)
|
23
35
|
require 'active_record/turntable/active_record_ext/fixtures'
|
36
|
+
require 'active_record/turntable/active_record_ext/migration_proxy'
|
37
|
+
require 'active_record/turntable/active_record_ext/activerecord_import_ext'
|
38
|
+
require 'active_record/turntable/active_record_ext/acts_as_archive_extension'
|
24
39
|
end
|
25
40
|
end
|
26
41
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module ActiveRecord::Turntable
|
2
2
|
module Algorithm
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
|
5
|
+
eager_autoload do
|
6
|
+
autoload :Base
|
7
|
+
autoload :RangeAlgorithm
|
8
|
+
autoload :RangeBsearchAlgorithm
|
9
|
+
end
|
6
10
|
end
|
7
11
|
end
|
@@ -3,15 +3,15 @@ module ActiveRecord::Turntable
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
|
7
|
-
class_attribute :turntable_connections,
|
6
|
+
class_attribute :turntable_connections, :turntable_clusters,
|
8
7
|
:turntable_enabled, :turntable_sequencer_enabled
|
9
8
|
|
10
9
|
self.turntable_connections = {}
|
10
|
+
self.turntable_clusters = Hash.new {|h,k| h[k]={}}
|
11
11
|
self.turntable_enabled = false
|
12
12
|
self.turntable_sequencer_enabled = false
|
13
13
|
class << self
|
14
|
-
delegate :shards_transaction, :to => :connection
|
14
|
+
delegate :shards_transaction, :with_all, :to => :connection
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -28,7 +28,10 @@ module ActiveRecord::Turntable
|
|
28
28
|
turntable_config[:clusters][cluster_name],
|
29
29
|
options
|
30
30
|
)
|
31
|
+
self.turntable_clusters[cluster_name][self] = turntable_cluster
|
32
|
+
|
31
33
|
turntable_replace_connection_pool
|
34
|
+
turntable_define_cluster_methods(cluster_name)
|
32
35
|
end
|
33
36
|
|
34
37
|
def force_transaction_all_shards!(options={}, &block)
|
@@ -51,7 +54,8 @@ module ActiveRecord::Turntable
|
|
51
54
|
|
52
55
|
def force_connect_all_shards!
|
53
56
|
conf = configurations[Rails.env]
|
54
|
-
shards =
|
57
|
+
shards = {}
|
58
|
+
shards = shards.merge(conf["shards"]) if conf["shards"]
|
55
59
|
shards = shards.merge(conf["seq"]) if conf["seq"]
|
56
60
|
shards.each do |name, config|
|
57
61
|
turntable_connections[name] ||=
|
@@ -62,12 +66,9 @@ module ActiveRecord::Turntable
|
|
62
66
|
def turntable_replace_connection_pool
|
63
67
|
ch = connection_handler
|
64
68
|
cp = turntable_cluster.connection_proxy
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
ch.connection_pools[name] = PoolProxy.new(cp)
|
70
|
-
end
|
69
|
+
pp = PoolProxy.new(cp)
|
70
|
+
ch.class_to_pool.clear if defined?(ch.class_to_pool)
|
71
|
+
ch.send(:class_to_pool)[name] = ch.send(:owner_to_pool)[name] = pp
|
71
72
|
end
|
72
73
|
|
73
74
|
def spec_for(config)
|
@@ -77,7 +78,7 @@ module ActiveRecord::Turntable
|
|
77
78
|
raise "Please install the #{config['adapter']} adapter: `gem install activerecord-#{config['adapter']}-adapter` (#{e})"
|
78
79
|
end
|
79
80
|
adapter_method = "#{config['adapter']}_connection"
|
80
|
-
ActiveRecord::
|
81
|
+
ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(config, adapter_method)
|
81
82
|
end
|
82
83
|
|
83
84
|
def clear_all_connections!
|
@@ -86,10 +87,11 @@ module ActiveRecord::Turntable
|
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
89
|
-
def sequencer
|
90
|
+
def sequencer(sequence_name, *args)
|
90
91
|
class_attribute :turntable_sequencer
|
92
|
+
|
91
93
|
self.turntable_sequencer_enabled = true
|
92
|
-
self.turntable_sequencer = ActiveRecord::Turntable::Sequencer.build(self)
|
94
|
+
self.turntable_sequencer = ActiveRecord::Turntable::Sequencer.build(self, sequence_name, *args)
|
93
95
|
end
|
94
96
|
|
95
97
|
def turntable_enabled?
|
@@ -117,6 +119,53 @@ module ActiveRecord::Turntable
|
|
117
119
|
}
|
118
120
|
self.connection.with_recursive_shards(shard.name, *klasses, &block)
|
119
121
|
end
|
122
|
+
|
123
|
+
def with_shard(any_shard)
|
124
|
+
shard = case any_shard
|
125
|
+
when Numeric
|
126
|
+
turntable_cluster.shard_for(any_shard)
|
127
|
+
when ActiveRecord::Base
|
128
|
+
turntable_cluster.shard_for(any_shard.send(any_shard.turntable_shard_key))
|
129
|
+
else
|
130
|
+
shard_or_key
|
131
|
+
end
|
132
|
+
connection.with_shard(shard) { yield }
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def turntable_define_cluster_methods(cluster_name)
|
138
|
+
turntable_define_cluster_class_methods(cluster_name)
|
139
|
+
end
|
140
|
+
|
141
|
+
def turntable_define_cluster_class_methods(cluster_name)
|
142
|
+
(class << ActiveRecord::Base; self; end).class_eval <<-EOD
|
143
|
+
unless respond_to?(:#{cluster_name}_transaction)
|
144
|
+
def #{cluster_name}_transaction(shards = [], options = {})
|
145
|
+
cluster = turntable_clusters[#{cluster_name.inspect}].values.first
|
146
|
+
cluster.shards_transaction(shards, options) { yield }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
unless respond_to?(:all_cluster_transaction)
|
151
|
+
def all_cluster_transaction(options = {})
|
152
|
+
clusters = turntable_clusters.values.map { |v| v.values.first }
|
153
|
+
recursive_cluster_transaction(clusters) { yield }
|
154
|
+
end
|
155
|
+
|
156
|
+
def recursive_cluster_transaction(clusters, options = {}, &block)
|
157
|
+
current_cluster = clusters.shift
|
158
|
+
current_cluster.shards_transaction do
|
159
|
+
if clusters.present?
|
160
|
+
recursive_cluster_transaction(clusters, options, &block)
|
161
|
+
else
|
162
|
+
yield
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
EOD
|
168
|
+
end
|
120
169
|
end
|
121
170
|
|
122
171
|
def shards_transaction(options = {}, &block)
|
@@ -124,7 +173,11 @@ module ActiveRecord::Turntable
|
|
124
173
|
end
|
125
174
|
|
126
175
|
def turntable_shard
|
127
|
-
turntable_cluster.
|
176
|
+
turntable_cluster.shard_for(self.send(turntable_shard_key))
|
177
|
+
end
|
178
|
+
|
179
|
+
def with_shard(shard)
|
180
|
+
self.class.connection.with_shard(shard) { yield }
|
128
181
|
end
|
129
182
|
end
|
130
183
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
|
1
3
|
module ActiveRecord::Turntable
|
2
4
|
class Cluster
|
3
5
|
|
@@ -16,7 +18,7 @@ module ActiveRecord::Turntable
|
|
16
18
|
@master_shard = MasterShard.new(klass)
|
17
19
|
|
18
20
|
# setup sequencer
|
19
|
-
if (seq = (@options[:seq] || @config[:seq]))
|
21
|
+
if (seq = (@options[:seq] || @config[:seq])) && seq[:type] == :mysql
|
20
22
|
@seq_shard = SeqShard.new(seq)
|
21
23
|
end
|
22
24
|
|
@@ -53,13 +55,55 @@ module ActiveRecord::Turntable
|
|
53
55
|
@connection_proxy
|
54
56
|
end
|
55
57
|
|
56
|
-
def
|
58
|
+
def shard_for(key)
|
57
59
|
@shards[@algorithm.calculate(key)]
|
58
60
|
rescue
|
59
61
|
raise ActiveRecord::Turntable::CannotSpecifyShardError,
|
60
62
|
"[#{klass}] cannot select_shard for key:#{key}"
|
61
63
|
end
|
62
64
|
|
65
|
+
def select_shard(key)
|
66
|
+
ActiveSupport::Deprecation.warn "Cluster#select_shard is deprecated, use shard_for() instead.", caller
|
67
|
+
shard_for(key)
|
68
|
+
end
|
69
|
+
|
70
|
+
def shards_transaction(shards = [], options = {}, in_recursion = false, &block)
|
71
|
+
unless in_recursion
|
72
|
+
shards = Array.wrap(shards).dup
|
73
|
+
if shards.blank?
|
74
|
+
shards = @shards.values.dup
|
75
|
+
end
|
76
|
+
end
|
77
|
+
shard_or_object = shards.shift
|
78
|
+
shard = to_shard(shard_or_object)
|
79
|
+
if shards.present?
|
80
|
+
shard.connection.transaction(options) do
|
81
|
+
shards_transaction(shards, options, true, &block)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
shard.connection.transaction(options) do
|
85
|
+
block.call
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_shard(shard_or_object)
|
91
|
+
case shard_or_object
|
92
|
+
when ActiveRecord::Turntable::Shard
|
93
|
+
shard_or_object
|
94
|
+
when ActiveRecord::Base
|
95
|
+
shard_or_object.turntable_shard
|
96
|
+
when Numeric, String
|
97
|
+
shard_for(shard_or_object)
|
98
|
+
when Symbol
|
99
|
+
shards[shard_or_object]
|
100
|
+
else
|
101
|
+
binding.pry
|
102
|
+
raise ActiveRecord::Turntable::TurntableError,
|
103
|
+
"transaction cannot call to object: #{shard_or_object}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
63
107
|
def weighted_shards(key = nil)
|
64
108
|
key ||= @klass.current_sequence
|
65
109
|
Hash[@algorithm.calculate_used_shards_with_weight(key).map do |k,v|
|
@@ -3,36 +3,14 @@ module ActiveRecord::Turntable
|
|
3
3
|
module Mixable
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
else
|
10
|
-
include Rails3x
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module Rails3x
|
15
|
-
METHODS_REGEXP = /\A(insert|select|update|delete|exec_)/
|
16
|
-
EXCLUDE_QUERY_REGEXP = /\A\s*SHOW/i
|
17
|
-
QUERY_REGEXP = /\A\s*(INSERT|DELETE|UPDATE|SELECT)/i
|
18
|
-
|
19
|
-
def mixable?(method, *args)
|
20
|
-
(method.to_s =~ METHODS_REGEXP &&
|
21
|
-
args.first !~ EXCLUDE_QUERY_REGEXP) ||
|
22
|
-
(method.to_s == 'execute' && args.first =~ QUERY_REGEXP)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
module Rails30
|
27
|
-
METHODS_REGEXP = /\A(insert|select|update|delete)/
|
28
|
-
EXCLUDE_QUERY_REGEXP = /\A\s*SHOW/i
|
29
|
-
QUERY_REGEXP = /\A\s*(INSERT|DELETE|UPDATE|SELECT)/i
|
6
|
+
METHODS_REGEXP = /\A(insert|select|update|delete|exec_)/
|
7
|
+
EXCLUDE_QUERY_REGEXP = /\A\s*SHOW/i
|
8
|
+
QUERY_REGEXP = /\A\s*(INSERT|DELETE|UPDATE|SELECT)/i
|
30
9
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
10
|
+
def mixable?(method, *args)
|
11
|
+
(method.to_s =~ METHODS_REGEXP &&
|
12
|
+
args.first !~ EXCLUDE_QUERY_REGEXP) ||
|
13
|
+
(method.to_s == 'execute' && args.first =~ QUERY_REGEXP)
|
36
14
|
end
|
37
15
|
end
|
38
16
|
end
|