activerecord-turntable 2.0.6 → 2.1.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -3
- data/CHANGELOG.md +8 -0
- data/Rakefile +1 -0
- data/activerecord-turntable.gemspec +3 -0
- data/gemfiles/rails4_2.gemfile +2 -2
- data/lib/active_record/turntable/active_record_ext/association.rb +81 -29
- data/lib/active_record/turntable/active_record_ext/clever_load.rb +2 -1
- data/lib/active_record/turntable/active_record_ext/locking_optimistic.rb +61 -3
- data/lib/active_record/turntable/active_record_ext/persistence.rb +48 -20
- data/lib/active_record/turntable/active_record_ext/relation.rb +36 -10
- data/lib/active_record/turntable/base.rb +20 -84
- data/lib/active_record/turntable/cluster.rb +4 -26
- data/lib/active_record/turntable/cluster_helper_methods.rb +85 -0
- data/lib/active_record/turntable/config.rb +3 -1
- data/lib/active_record/turntable/connection_proxy.rb +13 -11
- data/lib/active_record/turntable/mixer.rb +6 -6
- data/lib/active_record/turntable/railtie.rb +7 -0
- data/lib/active_record/turntable/version.rb +1 -1
- data/lib/active_record/turntable.rb +5 -0
- data/spec/active_record/turntable/active_record_ext/association_spec.rb +2 -2
- data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +22 -20
- data/spec/active_record/turntable/cluster_spec.rb +1 -2
- data/spec/active_record/turntable/connection_proxy_spec.rb +2 -2
- data/spec/active_record/turntable/mixer_spec.rb +2 -2
- data/spec/active_record/turntable/transaction_spec.rb +2 -2
- data/spec/spec_helper.rb +5 -0
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd8da73b8e0ac2f22797a0eb070c3624038b2ea3
|
4
|
+
data.tar.gz: 57b762fbd0ef0d06c5f7562c4cf68d5cc3c8f8bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74cb71bdcd32cca8731ce965b5fd7d0e8b8dd9d7bde6484abb6aa83021d530c3a54ac22d33c73bc2bb8d7c491a0401562b827e78eef3e56eb3bb5e6a56121f8e
|
7
|
+
data.tar.gz: 8ffc60cb0b0dd8e4428f4b3d76690a6135eeb2c60bf5bb0a7ffb0c8655e0be7a835c72bfa8580841c46b0a44bb60d57f88b04d7a48ae7b54ea620cc44f5bc909
|
data/.travis.yml
CHANGED
@@ -2,7 +2,7 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 1.9.3
|
4
4
|
- 2.0.0
|
5
|
-
- 2.1
|
5
|
+
- 2.1
|
6
6
|
- 2.2
|
7
7
|
- ruby-head
|
8
8
|
gemfile:
|
@@ -14,6 +14,4 @@ before_script:
|
|
14
14
|
script: bundle exec rake spec
|
15
15
|
matrix:
|
16
16
|
allow_failures:
|
17
|
-
- rvm: 2.2
|
18
17
|
- rvm: ruby-head
|
19
|
-
- gemfile: gemfiles/rails4_2.gemfile
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## activerecord-turntable 2.1.0 (unreleased) ##
|
2
|
+
|
3
|
+
Support activerecord 4.2.0
|
4
|
+
|
5
|
+
### Bugfixes
|
6
|
+
|
7
|
+
* Fix cluster helper methods(i.e xxxx_cluster_transaction helper) on lazy load environments(development, test)
|
8
|
+
|
1
9
|
## activerecord-turntable 2.0.6 ##
|
2
10
|
|
3
11
|
### Bugfixes
|
data/Rakefile
CHANGED
@@ -85,6 +85,7 @@ namespace :turntable do
|
|
85
85
|
ActiveRecord::Base.connection.create_table :cards_users do |t|
|
86
86
|
t.belongs_to :card, :null => false
|
87
87
|
t.belongs_to :user, :null => false
|
88
|
+
t.integer :num, :default => 1, :null => false
|
88
89
|
t.timestamps
|
89
90
|
end
|
90
91
|
ActiveRecord::Base.connection.create_sequence_for :cards_users
|
@@ -43,6 +43,9 @@ Gem::Specification.new do |spec|
|
|
43
43
|
spec.add_development_dependency "faker"
|
44
44
|
spec.add_development_dependency "webmock"
|
45
45
|
spec.add_development_dependency "pry"
|
46
|
+
if RUBY_VERSION > "2.0"
|
47
|
+
spec.add_development_dependency "pry-byebug"
|
48
|
+
end
|
46
49
|
spec.add_development_dependency "guard-rspec"
|
47
50
|
spec.add_development_dependency "coveralls"
|
48
51
|
|
data/gemfiles/rails4_2.gemfile
CHANGED
@@ -11,33 +11,58 @@ module ActiveRecord::Turntable
|
|
11
11
|
ActiveRecord::Associations::Builder::Association.valid_options += [:foreign_shard_key]
|
12
12
|
end
|
13
13
|
|
14
|
+
private
|
15
|
+
|
16
|
+
def turntable_scope(scope, bind = nil)
|
17
|
+
if should_use_shard_key?
|
18
|
+
scope = scope.where(klass.turntable_shard_key => owner.send(foreign_shard_key))
|
19
|
+
end
|
20
|
+
scope
|
21
|
+
end
|
22
|
+
|
14
23
|
module SingularAssociationExt
|
15
24
|
extend ActiveSupport::Concern
|
16
25
|
|
17
26
|
included do
|
18
|
-
|
27
|
+
if ActiveRecord::Turntable.rails42_later?
|
28
|
+
alias_method_chain :get_records, :turntable
|
29
|
+
else
|
30
|
+
alias_method_chain :find_target, :turntable
|
31
|
+
end
|
19
32
|
end
|
20
33
|
|
21
|
-
private
|
22
|
-
|
23
34
|
# @note Override to add sharding condition for singular association
|
24
|
-
if ActiveRecord::Turntable.
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
35
|
+
if ActiveRecord::Turntable.rails42_later?
|
36
|
+
def get_records_with_turntable
|
37
|
+
if reflection.scope_chain.any?(&:any?) ||
|
38
|
+
scope.eager_loading? ||
|
39
|
+
klass.current_scope ||
|
40
|
+
klass.default_scopes.any? ||
|
41
|
+
should_use_shard_key? # OPTIMIZE: Use bind values if cachable scope
|
42
|
+
|
43
|
+
return turntable_scope(scope).limit(1).to_a
|
29
44
|
end
|
30
|
-
|
45
|
+
|
46
|
+
conn = klass.connection
|
47
|
+
sc = reflection.association_scope_cache(conn, owner) do
|
48
|
+
ActiveRecord::StatementCache.create(conn) { |params|
|
49
|
+
as = ActiveRecord::Associations::AssociationScope.create { params.bind }
|
50
|
+
target_scope.merge(as.scope(self, conn)).limit(1)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
binds = ActiveRecord::Associations::AssociationScope.get_bind_values(owner, reflection.chain)
|
55
|
+
sc.execute binds, klass, klass.connection
|
56
|
+
end
|
57
|
+
elsif ActiveRecord::Turntable.rails41_later?
|
58
|
+
def find_target_with_turntable
|
59
|
+
if record = turntable_scope(scope).take
|
31
60
|
set_inverse_instance record
|
32
61
|
end
|
33
62
|
end
|
34
63
|
else
|
35
64
|
def find_target_with_turntable
|
36
|
-
|
37
|
-
if should_use_shard_key?
|
38
|
-
current_scope = current_scope.where(klass.turntable_shard_key => owner.send(foreign_shard_key))
|
39
|
-
end
|
40
|
-
current_scope.take.tap { |record| set_inverse_instance(record) }
|
65
|
+
turntable_scope(scope).take.tap { |record| set_inverse_instance(record) }
|
41
66
|
end
|
42
67
|
end
|
43
68
|
end
|
@@ -46,27 +71,54 @@ module ActiveRecord::Turntable
|
|
46
71
|
extend ActiveSupport::Concern
|
47
72
|
|
48
73
|
included do
|
49
|
-
|
74
|
+
if ActiveRecord::Turntable.rails42_later?
|
75
|
+
alias_method_chain :get_records, :turntable
|
76
|
+
else
|
77
|
+
alias_method_chain :find_target, :turntable
|
78
|
+
end
|
50
79
|
end
|
51
80
|
|
52
81
|
private
|
53
82
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
83
|
+
if ActiveRecord::Turntable.rails42_later?
|
84
|
+
def get_records_with_turntable
|
85
|
+
if reflection.scope_chain.any?(&:any?) ||
|
86
|
+
scope.eager_loading? ||
|
87
|
+
klass.current_scope ||
|
88
|
+
klass.default_scopes.any? ||
|
89
|
+
should_use_shard_key? # OPTIMIZE: Use bind values if cachable scope
|
90
|
+
|
91
|
+
return turntable_scope(scope).to_a
|
92
|
+
end
|
93
|
+
|
94
|
+
conn = klass.connection
|
95
|
+
sc = reflection.association_scope_cache(conn, owner) do
|
96
|
+
ActiveRecord::StatementCache.create(conn) { |params|
|
97
|
+
as = ActiveRecord::Associations::AssociationScope.create { params.bind }
|
98
|
+
target_scope.merge as.scope(self, conn)
|
99
|
+
}
|
65
100
|
end
|
66
|
-
records.each { |record| set_inverse_instance(record) }
|
67
|
-
records
|
68
|
-
end
|
69
101
|
|
102
|
+
binds = ActiveRecord::Associations::AssociationScope.get_bind_values(owner, reflection.chain)
|
103
|
+
sc.execute binds, klass, klass.connection
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# @note Override to add sharding condition for collection association
|
107
|
+
def find_target_with_turntable
|
108
|
+
records =
|
109
|
+
if options[:finder_sql]
|
110
|
+
reflection.klass.find_by_sql(custom_finder_sql)
|
111
|
+
else
|
112
|
+
current_scope = scope
|
113
|
+
if should_use_shard_key?
|
114
|
+
current_scope = current_scope.where(klass.turntable_shard_key => owner.send(foreign_shard_key))
|
115
|
+
end
|
116
|
+
current_scope.to_a
|
117
|
+
end
|
118
|
+
records.each { |record| set_inverse_instance(record) }
|
119
|
+
records
|
120
|
+
end
|
121
|
+
end
|
70
122
|
end
|
71
123
|
|
72
124
|
private
|
@@ -12,7 +12,8 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
12
12
|
# load records
|
13
13
|
records = self.to_a
|
14
14
|
klass = records.first.class
|
15
|
-
|
15
|
+
association_key = ActiveRecord::Turntable.rails42_later? ? association_name.to_s : association_name
|
16
|
+
reflection = klass.reflections[association_key]
|
16
17
|
|
17
18
|
if reflection
|
18
19
|
foreign_class = reflection.klass
|
@@ -29,7 +29,11 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
29
29
|
)
|
30
30
|
)
|
31
31
|
if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
|
32
|
-
condition_scope = condition_scope.where(
|
32
|
+
condition_scope = condition_scope.where(
|
33
|
+
relation.table[klass.turntable_shard_key].eq(
|
34
|
+
self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
|
35
|
+
)
|
36
|
+
)
|
33
37
|
end
|
34
38
|
stmt = condition_scope.arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
|
35
39
|
|
@@ -48,7 +52,7 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
48
52
|
end
|
49
53
|
end
|
50
54
|
EOD
|
51
|
-
|
55
|
+
elsif ar_version < "4.2"
|
52
56
|
method_name = ar_version =~ /\A4\.1\.[01]\z/ ? "update_record" : "_update_record"
|
53
57
|
|
54
58
|
class_eval <<-EOD
|
@@ -73,7 +77,11 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
73
77
|
)
|
74
78
|
)
|
75
79
|
if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
|
76
|
-
condition_scope = condition_scope.where(
|
80
|
+
condition_scope = condition_scope.where(
|
81
|
+
relation.table[klass.turntable_shard_key].eq(
|
82
|
+
self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
|
83
|
+
)
|
84
|
+
)
|
77
85
|
end
|
78
86
|
stmt = condition_scope.arel.compile_update(
|
79
87
|
arel_attributes_with_values_for_update(attribute_names),
|
@@ -88,6 +96,56 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
88
96
|
|
89
97
|
affected_rows
|
90
98
|
|
99
|
+
# If something went wrong, revert the version.
|
100
|
+
rescue Exception
|
101
|
+
send(lock_col + '=', previous_lock_value)
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
end
|
105
|
+
EOD
|
106
|
+
else
|
107
|
+
class_eval <<-EOD
|
108
|
+
def _update_record(attribute_names = self.attribute_names) #:nodoc:
|
109
|
+
return super unless locking_enabled?
|
110
|
+
return 0 if attribute_names.empty?
|
111
|
+
|
112
|
+
klass = self.class
|
113
|
+
lock_col = self.class.locking_column
|
114
|
+
previous_lock_value = send(lock_col).to_i
|
115
|
+
increment_lock
|
116
|
+
|
117
|
+
attribute_names += [lock_col]
|
118
|
+
attribute_names.uniq!
|
119
|
+
|
120
|
+
begin
|
121
|
+
relation = self.class.unscoped
|
122
|
+
|
123
|
+
condition_scope = relation.where(
|
124
|
+
relation.table[self.class.primary_key].eq(id).and(
|
125
|
+
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
126
|
+
)
|
127
|
+
)
|
128
|
+
if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
|
129
|
+
condition_scope = condition_scope.where(
|
130
|
+
relation.table[klass.turntable_shard_key].eq(
|
131
|
+
self.class.quote_value(self.send(turntable_shard_key), column_for_attribute(klass.turntable_shard_key))
|
132
|
+
)
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
stmt = condition_scope.arel.compile_update(
|
137
|
+
arel_attributes_with_values_for_update(attribute_names),
|
138
|
+
self.class.primary_key
|
139
|
+
)
|
140
|
+
|
141
|
+
affected_rows = self.class.connection.update stmt
|
142
|
+
|
143
|
+
unless affected_rows == 1
|
144
|
+
raise ActiveRecord::StaleObjectError.new(self, "update")
|
145
|
+
end
|
146
|
+
|
147
|
+
affected_rows
|
148
|
+
|
91
149
|
# If something went wrong, revert the version.
|
92
150
|
rescue Exception
|
93
151
|
send(lock_col + '=', previous_lock_value)
|
@@ -21,11 +21,16 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
21
21
|
finder_scope.find(id)
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
if ActiveRecord::Turntable.rails42_later?
|
25
|
+
@attributes = fresh_object.instance_variable_get('@attributes')
|
26
|
+
else
|
27
|
+
@attributes.update(fresh_object.instance_variable_get('@attributes'))
|
28
|
+
|
29
|
+
@column_types = self.class.column_types
|
30
|
+
@column_types_override = fresh_object.instance_variable_get('@column_types_override')
|
31
|
+
@attributes_cache = {}
|
32
|
+
end
|
33
|
+
@new_record = false
|
29
34
|
self
|
30
35
|
end
|
31
36
|
|
@@ -57,6 +62,8 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
57
62
|
end
|
58
63
|
|
59
64
|
finder_scope.where(primary_key => self[primary_key]).update_all(changes) == 1
|
65
|
+
else
|
66
|
+
true
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
@@ -85,26 +92,47 @@ module ActiveRecord::Turntable::ActiveRecordExt
|
|
85
92
|
|
86
93
|
private
|
87
94
|
|
95
|
+
ar_version = ActiveRecord::VERSION::STRING
|
96
|
+
|
88
97
|
# @note Override to add sharding scope on destroying
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
self.class.
|
97
|
-
|
98
|
-
relation =
|
98
|
+
if ActiveRecord::Turntable.rails42_later?
|
99
|
+
def relation_for_destroy
|
100
|
+
pk = self.class.primary_key
|
101
|
+
column = self.class.columns_hash[pk]
|
102
|
+
substitute = self.class.connection.substitute_at(column, 0)
|
103
|
+
klass = self.class
|
104
|
+
|
105
|
+
relation = self.class.unscoped.where(
|
106
|
+
self.class.arel_table[pk].eq(substitute))
|
107
|
+
relation.bind_values = [[column, id]]
|
108
|
+
|
109
|
+
if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
|
110
|
+
shard_key_column = klass.columns_hash[klass.turntable_shard_key]
|
111
|
+
shard_key_substitute = klass.connection.substitute_at(shard_key_column)
|
112
|
+
|
113
|
+
relation = relation.where(self.class.arel_table[klass.turntable_shard_key].eq(shard_key_substitute))
|
114
|
+
relation.bind_values << [shard_key_column, self[klass.turntable_shard_key]]
|
115
|
+
end
|
116
|
+
relation
|
117
|
+
end
|
118
|
+
else
|
119
|
+
def relation_for_destroy
|
120
|
+
pk = self.class.primary_key
|
121
|
+
column = self.class.columns_hash[pk]
|
122
|
+
substitute = self.class.connection.substitute_at(column, 0)
|
123
|
+
klass = self.class
|
124
|
+
|
125
|
+
relation = self.class.unscoped.where(
|
126
|
+
self.class.arel_table[pk].eq(substitute))
|
127
|
+
if klass.turntable_enabled? and klass.primary_key != klass.turntable_shard_key.to_s
|
128
|
+
relation = relation.where(klass.turntable_shard_key => self.send(turntable_shard_key))
|
129
|
+
end
|
130
|
+
relation.bind_values = [[column, id]]
|
131
|
+
relation
|
99
132
|
end
|
100
|
-
|
101
|
-
relation.bind_values = [[column, id]]
|
102
|
-
relation
|
103
133
|
end
|
104
134
|
|
105
|
-
|
106
135
|
# @note Override to add sharding scope on updating
|
107
|
-
ar_version = ActiveRecord::VERSION::STRING
|
108
136
|
if ar_version < "4.1"
|
109
137
|
method_name = ar_version =~ /\A4\.0\.[0-5]\z/ ? "update_record" : "_update_record"
|
110
138
|
class_eval <<-EOD
|
@@ -16,16 +16,42 @@ module ActiveRecord::Turntable
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# @note Override to add sharding scope on updating
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
if ActiveRecord::Turntable.rails42_later?
|
20
|
+
def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
|
21
|
+
substitutes, binds = substitute_values values
|
22
|
+
|
23
|
+
scope = @klass.unscoped
|
24
|
+
|
25
|
+
if @klass.finder_needs_type_condition?
|
26
|
+
scope.unscope!(where: @klass.inheritance_column)
|
27
|
+
end
|
28
|
+
|
29
|
+
relation = scope.where(@klass.primary_key => (id_was || id))
|
30
|
+
relation = relation.merge(turntable_scope) if turntable_scope
|
31
|
+
|
32
|
+
bvs = binds + relation.bind_values
|
33
|
+
um = relation
|
34
|
+
.arel
|
35
|
+
.compile_update(substitutes, @klass.primary_key)
|
36
|
+
|
37
|
+
@klass.connection.update(
|
38
|
+
um,
|
39
|
+
'SQL',
|
40
|
+
bvs,
|
41
|
+
)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
def _update_record_with_turntable(values, id, id_was, turntable_scope = nil) # :nodoc:
|
45
|
+
substitutes, binds = substitute_values values
|
46
|
+
condition_scope = @klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id))
|
47
|
+
condition_scope = condition_scope.merge(turntable_scope) if turntable_scope
|
48
|
+
um = condition_scope.arel.compile_update(substitutes, @klass.primary_key)
|
49
|
+
|
50
|
+
@klass.connection.update(
|
51
|
+
um,
|
52
|
+
'SQL',
|
53
|
+
binds)
|
54
|
+
end
|
29
55
|
end
|
30
56
|
end
|
31
57
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
2
|
+
|
1
3
|
module ActiveRecord::Turntable
|
2
4
|
module Base
|
3
5
|
extend ActiveSupport::Concern
|
@@ -7,12 +9,17 @@ module ActiveRecord::Turntable
|
|
7
9
|
:turntable_enabled, :turntable_sequencer_enabled
|
8
10
|
|
9
11
|
self.turntable_connections = {}
|
10
|
-
self.turntable_clusters =
|
12
|
+
self.turntable_clusters = {}.with_indifferent_access
|
11
13
|
self.turntable_enabled = false
|
12
14
|
self.turntable_sequencer_enabled = false
|
13
15
|
class << self
|
14
16
|
delegate :shards_transaction, :with_all, :to => :connection
|
15
17
|
end
|
18
|
+
|
19
|
+
ActiveSupport.on_load(:turntable_config_loaded) do
|
20
|
+
self.initialize_clusters!
|
21
|
+
end
|
22
|
+
include ClusterHelperMethods
|
16
23
|
end
|
17
24
|
|
18
25
|
module ClassMethods
|
@@ -26,55 +33,29 @@ module ActiveRecord::Turntable
|
|
26
33
|
self.turntable_enabled = true
|
27
34
|
self.turntable_cluster_name = cluster_name
|
28
35
|
self.turntable_shard_key = shard_key_name
|
29
|
-
self.turntable_cluster =
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
self.turntable_clusters[cluster_name][self] = turntable_cluster
|
35
|
-
|
36
|
+
self.turntable_cluster =
|
37
|
+
self.turntable_clusters[cluster_name] ||= Cluster.new(
|
38
|
+
turntable_config[:clusters][cluster_name],
|
39
|
+
options
|
40
|
+
)
|
36
41
|
turntable_replace_connection_pool
|
37
|
-
turntable_define_cluster_methods(cluster_name)
|
38
|
-
end
|
39
|
-
|
40
|
-
#
|
41
|
-
def force_transaction_all_shards!(options={}, &block)
|
42
|
-
force_connect_all_shards!
|
43
|
-
shards = turntable_connections.values
|
44
|
-
shards += [ActiveRecord::Base.connection_pool]
|
45
|
-
recursive_transaction(shards, options, &block)
|
46
42
|
end
|
47
43
|
|
48
|
-
def recursive_transaction(pools, options, &block)
|
49
|
-
pool = pools.shift
|
50
|
-
if pools.present?
|
51
|
-
pool.connection.transaction(options) do
|
52
|
-
recursive_transaction(pools, options, &block)
|
53
|
-
end
|
54
|
-
else
|
55
|
-
pool.connection.transaction(options, &block)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def force_connect_all_shards!
|
60
|
-
conf = configurations[Rails.env]
|
61
|
-
shards = {}
|
62
|
-
shards = shards.merge(conf["shards"]) if conf["shards"]
|
63
|
-
shards = shards.merge(conf["seq"]) if conf["seq"]
|
64
|
-
shards.each do |name, config|
|
65
|
-
turntable_connections[name] ||=
|
66
|
-
ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec_for(config))
|
67
|
-
end
|
68
|
-
end
|
69
44
|
|
70
45
|
def turntable_replace_connection_pool
|
71
46
|
ch = connection_handler
|
72
|
-
cp = turntable_cluster
|
47
|
+
cp = ConnectionProxy.new(self, turntable_cluster)
|
73
48
|
pp = PoolProxy.new(cp)
|
74
49
|
ch.class_to_pool.clear if defined?(ch.class_to_pool)
|
75
50
|
ch.send(:class_to_pool)[name] = ch.send(:owner_to_pool)[name] = pp
|
76
51
|
end
|
77
52
|
|
53
|
+
def initialize_clusters!
|
54
|
+
turntable_config[:clusters].each do |name, spec|
|
55
|
+
self.turntable_clusters[name] ||= Cluster.new(spec, {})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
78
59
|
def spec_for(config)
|
79
60
|
begin
|
80
61
|
require "active_record/connection_adapters/#{config['adapter']}_adapter"
|
@@ -114,16 +95,6 @@ module ActiveRecord::Turntable
|
|
114
95
|
turntable_cluster.select_shard(current_sequence) if sequencer_enabled?
|
115
96
|
end
|
116
97
|
|
117
|
-
def weighted_random_shard_with(*klasses, &block)
|
118
|
-
shards_weight = self.turntable_cluster.weighted_shards
|
119
|
-
sum = shards_weight.values.inject(&:+)
|
120
|
-
idx = rand(sum)
|
121
|
-
shard, weight = shards_weight.find {|k,v|
|
122
|
-
(idx -= v) < 0
|
123
|
-
}
|
124
|
-
self.connection.with_recursive_shards(shard.name, *klasses, &block)
|
125
|
-
end
|
126
|
-
|
127
98
|
def with_shard(any_shard)
|
128
99
|
shard = case any_shard
|
129
100
|
when Numeric
|
@@ -135,41 +106,6 @@ module ActiveRecord::Turntable
|
|
135
106
|
end
|
136
107
|
connection.with_shard(shard) { yield }
|
137
108
|
end
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
def turntable_define_cluster_methods(cluster_name)
|
142
|
-
turntable_define_cluster_class_methods(cluster_name)
|
143
|
-
end
|
144
|
-
|
145
|
-
def turntable_define_cluster_class_methods(cluster_name)
|
146
|
-
(class << ActiveRecord::Base; self; end).class_eval <<-EOD
|
147
|
-
unless respond_to?(:#{cluster_name}_transaction)
|
148
|
-
def #{cluster_name}_transaction(shards = [], options = {})
|
149
|
-
cluster = turntable_clusters[#{cluster_name.inspect}].values.first
|
150
|
-
cluster.shards_transaction(shards, options) { yield }
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
unless respond_to?(:all_cluster_transaction)
|
155
|
-
def all_cluster_transaction(options = {})
|
156
|
-
clusters = turntable_clusters.values.map { |v| v.values.first }
|
157
|
-
recursive_cluster_transaction(clusters) { yield }
|
158
|
-
end
|
159
|
-
|
160
|
-
def recursive_cluster_transaction(clusters, options = {}, &block)
|
161
|
-
current_cluster = clusters.shift
|
162
|
-
current_cluster.shards_transaction do
|
163
|
-
if clusters.present?
|
164
|
-
recursive_cluster_transaction(clusters, options, &block)
|
165
|
-
else
|
166
|
-
yield
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
EOD
|
172
|
-
end
|
173
109
|
end
|
174
110
|
|
175
111
|
def shards_transaction(options = {}, &block)
|
@@ -8,15 +8,11 @@ module ActiveRecord::Turntable
|
|
8
8
|
"algorithm" => "range",
|
9
9
|
}.with_indifferent_access
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@klass = klass
|
11
|
+
def initialize(cluster_spec, options = {})
|
13
12
|
@config = DEFAULT_CONFIG.merge(cluster_spec)
|
14
13
|
@options = options.with_indifferent_access
|
15
14
|
@shards = {}.with_indifferent_access
|
16
15
|
|
17
|
-
# setup master shard
|
18
|
-
@master_shard = MasterShard.new(klass)
|
19
|
-
|
20
16
|
# setup sequencer
|
21
17
|
if (seq = (@options[:seq] || @config[:seq])) && seq[:type] == :mysql
|
22
18
|
@seq_shard = SeqShard.new(seq)
|
@@ -30,36 +26,21 @@ module ActiveRecord::Turntable
|
|
30
26
|
# setup algorithm
|
31
27
|
alg_name = "ActiveRecord::Turntable::Algorithm::#{@config["algorithm"].camelize}Algorithm"
|
32
28
|
@algorithm = alg_name.constantize.new(@config)
|
33
|
-
|
34
|
-
# setup proxy
|
35
|
-
@connection_proxy = ConnectionProxy.new(self, cluster_spec)
|
36
|
-
end
|
37
|
-
|
38
|
-
def klass
|
39
|
-
@klass
|
40
|
-
end
|
41
|
-
|
42
|
-
def master
|
43
|
-
@master_shard
|
44
29
|
end
|
45
30
|
|
46
31
|
def seq
|
47
|
-
@seq_shard
|
32
|
+
@seq_shard
|
48
33
|
end
|
49
34
|
|
50
35
|
def shards
|
51
36
|
@shards
|
52
37
|
end
|
53
38
|
|
54
|
-
def connection_proxy
|
55
|
-
@connection_proxy
|
56
|
-
end
|
57
|
-
|
58
39
|
def shard_for(key)
|
59
40
|
@shards[@algorithm.calculate(key)]
|
60
41
|
rescue
|
61
42
|
raise ActiveRecord::Turntable::CannotSpecifyShardError,
|
62
|
-
|
43
|
+
"cannot select_shard for key:#{key}"
|
63
44
|
end
|
64
45
|
|
65
46
|
def select_shard(key)
|
@@ -74,8 +55,7 @@ module ActiveRecord::Turntable
|
|
74
55
|
shards = @shards.values.dup
|
75
56
|
end
|
76
57
|
end
|
77
|
-
|
78
|
-
shard = to_shard(shard_or_object)
|
58
|
+
shard = to_shard(shards.shift)
|
79
59
|
if shards.present?
|
80
60
|
shard.connection.transaction(options) do
|
81
61
|
shards_transaction(shards, options, true, &block)
|
@@ -98,14 +78,12 @@ module ActiveRecord::Turntable
|
|
98
78
|
when Symbol
|
99
79
|
shards[shard_or_object]
|
100
80
|
else
|
101
|
-
binding.pry
|
102
81
|
raise ActiveRecord::Turntable::TurntableError,
|
103
82
|
"transaction cannot call to object: #{shard_or_object}"
|
104
83
|
end
|
105
84
|
end
|
106
85
|
|
107
86
|
def weighted_shards(key = nil)
|
108
|
-
key ||= @klass.current_sequence
|
109
87
|
Hash[@algorithm.calculate_used_shards_with_weight(key).map do |k,v|
|
110
88
|
[@shards[k], v]
|
111
89
|
end]
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module ActiveRecord::Turntable
|
2
|
+
module ClusterHelperMethods
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
ActiveSupport.on_load(:turntable_config_loaded) do
|
7
|
+
turntable_clusters.each do |name, cluster|
|
8
|
+
turntable_define_cluster_methods(name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def force_transaction_all_shards!(options={}, &block)
|
15
|
+
force_connect_all_shards!
|
16
|
+
shards = turntable_connections.values
|
17
|
+
shards += [ActiveRecord::Base.connection_pool]
|
18
|
+
recursive_transaction(shards, options, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def recursive_transaction(pools, options, &block)
|
22
|
+
pool = pools.shift
|
23
|
+
if pools.present?
|
24
|
+
pool.connection.transaction(options) do
|
25
|
+
recursive_transaction(pools, options, &block)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
pool.connection.transaction(options, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def force_connect_all_shards!
|
33
|
+
conf = configurations[Rails.env]
|
34
|
+
shards = {}
|
35
|
+
shards = shards.merge(conf["shards"]) if conf["shards"]
|
36
|
+
shards = shards.merge(conf["seq"]) if conf["seq"]
|
37
|
+
shards.each do |name, config|
|
38
|
+
turntable_connections[name] ||=
|
39
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec_for(config))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def weighted_random_shard_with(*klasses, &block)
|
44
|
+
shards_weight = self.turntable_cluster.weighted_shards(self.current_sequence)
|
45
|
+
sum = shards_weight.values.inject(&:+)
|
46
|
+
idx = rand(sum)
|
47
|
+
shard, weight = shards_weight.find {|k,v|
|
48
|
+
(idx -= v) < 0
|
49
|
+
}
|
50
|
+
self.connection.with_recursive_shards(shard.name, *klasses, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def all_cluster_transaction(options = {})
|
54
|
+
clusters = turntable_clusters.values
|
55
|
+
recursive_cluster_transaction(clusters) { yield }
|
56
|
+
end
|
57
|
+
|
58
|
+
def recursive_cluster_transaction(clusters, options = {}, &block)
|
59
|
+
current_cluster = clusters.shift
|
60
|
+
current_cluster.shards_transaction do
|
61
|
+
if clusters.present?
|
62
|
+
recursive_cluster_transaction(clusters, options, &block)
|
63
|
+
else
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def turntable_define_cluster_methods(cluster_name)
|
70
|
+
turntable_define_cluster_class_methods(cluster_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def turntable_define_cluster_class_methods(cluster_name)
|
74
|
+
(class << ActiveRecord::Base; self; end).class_eval <<-EOD
|
75
|
+
unless respond_to?(:#{cluster_name}_transaction)
|
76
|
+
def #{cluster_name}_transaction(shards = [], options = {})
|
77
|
+
cluster = turntable_clusters[#{cluster_name.inspect}]
|
78
|
+
cluster.shards_transaction(shards, options) { yield }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
EOD
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
1
2
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
3
|
|
3
4
|
module ActiveRecord::Turntable
|
@@ -13,12 +14,13 @@ module ActiveRecord::Turntable
|
|
13
14
|
@config[key]
|
14
15
|
end
|
15
16
|
|
16
|
-
def self.load!(config_file, env = (defined?(Rails) ? Rails.env : 'development'))
|
17
|
+
def self.load!(config_file = ActiveRecord::Base.turntable_config_file, env = (defined?(Rails) ? Rails.env : 'development'))
|
17
18
|
instance.load!(config_file, env)
|
18
19
|
end
|
19
20
|
|
20
21
|
def load!(config_file, env)
|
21
22
|
@config = YAML.load(ERB.new(IO.read(config_file)).result).with_indifferent_access[env]
|
23
|
+
ActiveSupport.run_load_hooks(:turntable_config_loaded, ActiveRecord::Base)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -6,12 +6,14 @@ module ActiveRecord::Turntable
|
|
6
6
|
# for expiring query cache
|
7
7
|
CLEAR_CACHE_METHODS = [:update, :insert, :delete, :exec_insert, :exec_update, :exec_delete, :insert_many]
|
8
8
|
|
9
|
+
attr_reader :klass
|
9
10
|
attr_writer :spec
|
10
11
|
|
11
|
-
def initialize(cluster, options = {})
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
12
|
+
def initialize(klass, cluster, options = {})
|
13
|
+
@klass = klass
|
14
|
+
@cluster = cluster
|
15
|
+
@master_shard = MasterShard.new(klass)
|
16
|
+
@default_current_shard = @master_shard
|
15
17
|
@mixer = ActiveRecord::Turntable::Mixer.new(self)
|
16
18
|
end
|
17
19
|
|
@@ -36,7 +38,7 @@ module ActiveRecord::Turntable
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def enable_query_cache!
|
39
|
-
|
41
|
+
klass.turntable_connections.each do |k,v|
|
40
42
|
v.connection.enable_query_cache!
|
41
43
|
end
|
42
44
|
end
|
@@ -46,7 +48,7 @@ module ActiveRecord::Turntable
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def clear_query_cache
|
49
|
-
|
51
|
+
klass.turntable_connections.each do |k,v|
|
50
52
|
v.connection.clear_query_cache
|
51
53
|
end
|
52
54
|
end
|
@@ -91,7 +93,7 @@ module ActiveRecord::Turntable
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def master
|
94
|
-
@
|
96
|
+
@master_shard
|
95
97
|
end
|
96
98
|
|
97
99
|
def master_connection
|
@@ -99,7 +101,7 @@ module ActiveRecord::Turntable
|
|
99
101
|
end
|
100
102
|
|
101
103
|
def seq
|
102
|
-
@cluster.seq
|
104
|
+
@cluster.seq || master
|
103
105
|
end
|
104
106
|
|
105
107
|
def current_shard
|
@@ -107,7 +109,7 @@ module ActiveRecord::Turntable
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def current_shard=(shard)
|
110
|
-
logger.debug { "Changing #{
|
112
|
+
logger.debug { "Changing #{klass}'s shard to #{shard.name}"}
|
111
113
|
current_shard_entry[object_id] = shard
|
112
114
|
end
|
113
115
|
|
@@ -170,7 +172,7 @@ module ActiveRecord::Turntable
|
|
170
172
|
# Send queries to master connection and all shards in this cluster
|
171
173
|
# @param [Boolean] continue_on_error when a shard raises error, ignore exception and continue
|
172
174
|
def with_master_and_all(continue_on_error = false)
|
173
|
-
([
|
175
|
+
([master] + @cluster.shards.values).map do |shard|
|
174
176
|
begin
|
175
177
|
with_shard(shard) {
|
176
178
|
yield
|
@@ -185,7 +187,7 @@ module ActiveRecord::Turntable
|
|
185
187
|
end
|
186
188
|
|
187
189
|
def with_master(&block)
|
188
|
-
with_shard(
|
190
|
+
with_shard(master) do
|
189
191
|
yield
|
190
192
|
end
|
191
193
|
end
|
@@ -126,12 +126,12 @@ module ActiveRecord::Turntable
|
|
126
126
|
def build_select_fader(tree, method, query, *args, &block)
|
127
127
|
shard_keys = if !tree.where and tree.from.size == 1 and SQLTree::Node::SubQuery === tree.from.first.table_reference.table
|
128
128
|
find_shard_keys(tree.from.first.table_reference.table.where,
|
129
|
-
@proxy.
|
130
|
-
@proxy.
|
129
|
+
@proxy.klass.table_name,
|
130
|
+
@proxy.klass.turntable_shard_key.to_s)
|
131
131
|
else
|
132
132
|
find_shard_keys(tree.where,
|
133
|
-
@proxy.
|
134
|
-
@proxy.
|
133
|
+
@proxy.klass.table_name,
|
134
|
+
@proxy.klass.turntable_shard_key.to_s)
|
135
135
|
end
|
136
136
|
|
137
137
|
if shard_keys.size == 1 # shard
|
@@ -186,7 +186,7 @@ module ActiveRecord::Turntable
|
|
186
186
|
end
|
187
187
|
|
188
188
|
def build_update_fader(tree, method, query, *args, &block)
|
189
|
-
shard_keys = find_shard_keys(tree.where, @proxy.
|
189
|
+
shard_keys = find_shard_keys(tree.where, @proxy.klass.table_name, @proxy.klass.turntable_shard_key.to_s)
|
190
190
|
shards_with_query = if shard_keys.present?
|
191
191
|
build_shards_with_same_query(shard_keys.map {|k| @proxy.cluster.shard_for(k) }, query)
|
192
192
|
else
|
@@ -208,7 +208,7 @@ module ActiveRecord::Turntable
|
|
208
208
|
end
|
209
209
|
|
210
210
|
def build_insert_fader(tree, method, query, *args, &block)
|
211
|
-
values_hash = divide_insert_values(tree, @proxy.
|
211
|
+
values_hash = divide_insert_values(tree, @proxy.klass.turntable_shard_key)
|
212
212
|
shards_with_query = {}
|
213
213
|
values_hash.each do |k,vs|
|
214
214
|
tree.values = [[SQLTree::Node::Expression::Variable.new("\\0")]]
|
@@ -12,6 +12,13 @@ module ActiveRecord::Turntable
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
# initialize
|
16
|
+
initializer "turntable.initialize_clusters" do
|
17
|
+
ActiveSupport.on_load(:active_record) do
|
18
|
+
ActiveRecord::Turntable::Config.load!
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
15
22
|
# QueryCache Middleware for turntable shards
|
16
23
|
initializer "turntable.insert_query_cache_middleware" do |app|
|
17
24
|
app.middleware.insert_after ActiveRecord::QueryCache, ActiveRecord::Turntable::Rack::QueryCache
|
@@ -20,6 +20,7 @@ module ActiveRecord::Turntable
|
|
20
20
|
autoload :Algorithm
|
21
21
|
autoload :Base
|
22
22
|
autoload :Cluster
|
23
|
+
autoload :ClusterHelperMethods
|
23
24
|
autoload :Config
|
24
25
|
autoload :ConnectionProxy
|
25
26
|
autoload :MasterShard
|
@@ -64,5 +65,9 @@ module ActiveRecord::Turntable
|
|
64
65
|
rails4? && ActiveRecord::VERSION::MINOR >= 1
|
65
66
|
end
|
66
67
|
|
68
|
+
def self.rails42_later?
|
69
|
+
rails4? && ActiveRecord::VERSION::MINOR >= 2
|
70
|
+
end
|
71
|
+
|
67
72
|
require "active_record/turntable/railtie" if defined?(Rails)
|
68
73
|
end
|
@@ -49,14 +49,14 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Association do
|
|
49
49
|
let(:cards_user) { CardsUser.where(user: user).first }
|
50
50
|
|
51
51
|
context "associated objects has same turntable_key" do
|
52
|
-
subject { cards_user.cards_users_histories }
|
52
|
+
subject { cards_user.cards_users_histories.to_a }
|
53
53
|
it { expect { subject }.to_not raise_error }
|
54
54
|
it { is_expected.to include(*cards_users_histories.select { |history| history.cards_user_id == cards_user.id }) }
|
55
55
|
end
|
56
56
|
|
57
57
|
context "associated objects has different turntable_key" do
|
58
58
|
context "when foreign_shard_key option passed" do
|
59
|
-
subject { cards_user.events_users_histories_with_foreign_shard_key }
|
59
|
+
subject { cards_user.events_users_histories_with_foreign_shard_key.to_a }
|
60
60
|
|
61
61
|
it { expect { subject }.to_not raise_error }
|
62
62
|
it { is_expected.to include(*events_users_histories.select { |history| history.cards_user_id == cards_user.id }) }
|
@@ -34,7 +34,9 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
|
|
34
34
|
let(:card){
|
35
35
|
Card.create!(:name => 'foobar')
|
36
36
|
}
|
37
|
-
|
37
|
+
let(:cards_user){
|
38
|
+
user.cards_users.create(card: card)
|
39
|
+
}
|
38
40
|
context "When creating record" do
|
39
41
|
context "with blob column" do
|
40
42
|
let(:blob_value) { "\123\123\123" }
|
@@ -108,31 +110,31 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
|
|
108
110
|
|
109
111
|
context "When the model is sharded by other key" do
|
110
112
|
it "should send shard_key condition when updating" do
|
111
|
-
|
113
|
+
cards_user.num = 10
|
112
114
|
|
113
115
|
strio = StringIO.new
|
114
116
|
ActiveRecord::Base.logger = Logger.new(strio)
|
115
117
|
expect {
|
116
|
-
|
118
|
+
cards_user.save!
|
117
119
|
}.to_not raise_error
|
118
|
-
expect(strio.string).to match(/`
|
120
|
+
expect(strio.string).to match(/`cards_users`\.`user_id` = #{cards_user.user_id}[^\s]*($|\s)/)
|
119
121
|
end
|
120
122
|
|
121
123
|
it "should change updated_at when updating" do
|
122
|
-
|
124
|
+
cards_user.num = 2
|
123
125
|
|
124
126
|
expect {
|
125
|
-
|
126
|
-
}.to change(
|
127
|
+
cards_user.save!
|
128
|
+
}.to change(cards_user, :updated_at)
|
127
129
|
end
|
128
130
|
|
129
131
|
it "should send shard_key condition when destroying" do
|
130
132
|
strio = StringIO.new
|
131
133
|
ActiveRecord::Base.logger = Logger.new(strio)
|
132
134
|
expect {
|
133
|
-
|
135
|
+
cards_user.destroy
|
134
136
|
}.to_not raise_error
|
135
|
-
expect(strio.string).to match(/`
|
137
|
+
expect(strio.string).to match(/`cards_users`\.`user_id` = #{cards_user.user_id}[^\s]*($|\s)/)
|
136
138
|
end
|
137
139
|
|
138
140
|
it "should warn when creating without shard_key" do
|
@@ -140,39 +142,39 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
|
|
140
142
|
end
|
141
143
|
|
142
144
|
it "should execute one query when reloading" do
|
143
|
-
user;
|
145
|
+
user; cards_user
|
144
146
|
strio = StringIO.new
|
145
147
|
ActiveRecord::Base.logger = Logger.new(strio)
|
146
148
|
|
147
|
-
expect {
|
149
|
+
expect { cards_user.reload }.to_not raise_error
|
148
150
|
|
149
151
|
expect(strio.string.split("\n").select {|stmt| stmt =~ /SELECT/ and stmt !~ /Turntable/ }).to have(1).items
|
150
152
|
end
|
151
153
|
|
152
154
|
it "should execute one query when touching" do
|
153
|
-
user;
|
155
|
+
user; cards_user
|
154
156
|
strio = StringIO.new
|
155
157
|
ActiveRecord::Base.logger = Logger.new(strio)
|
156
158
|
|
157
|
-
expect {
|
159
|
+
expect { cards_user.touch }.to_not raise_error
|
158
160
|
expect(strio.string.split("\n").select {|stmt| stmt =~ /UPDATE/ and stmt !~ /Turntable/ }).to have(1).items
|
159
161
|
end
|
160
162
|
|
161
163
|
it "should execute one query when locking" do
|
162
|
-
user;
|
164
|
+
user; cards_user
|
163
165
|
strio = StringIO.new
|
164
166
|
ActiveRecord::Base.logger = Logger.new(strio)
|
165
167
|
|
166
|
-
expect {
|
168
|
+
expect { cards_user.lock! }.to_not raise_error
|
167
169
|
expect(strio.string.split("\n").select {|stmt| stmt =~ /SELECT/ and stmt !~ /Turntable/ }).to have(1).items
|
168
170
|
end
|
169
171
|
|
170
172
|
it "should execute one query when update_columns" do
|
171
|
-
user;
|
173
|
+
user; cards_user
|
172
174
|
strio = StringIO.new
|
173
175
|
ActiveRecord::Base.logger = Logger.new(strio)
|
174
176
|
|
175
|
-
expect {
|
177
|
+
expect { cards_user.update_columns(num: 10) }.to_not raise_error
|
176
178
|
expect(strio.string.split("\n").select {|stmt| stmt =~ /UPDATE/ and stmt !~ /Turntable/ }).to have(1).items
|
177
179
|
end
|
178
180
|
end
|
@@ -199,9 +201,9 @@ describe ActiveRecord::Turntable::ActiveRecordExt::Persistence do
|
|
199
201
|
end
|
200
202
|
|
201
203
|
context "When call reload" do
|
202
|
-
subject {
|
203
|
-
it { is_expected.to be_instance_of(
|
204
|
-
it { is_expected.to eq(
|
204
|
+
subject { cards_user.reload }
|
205
|
+
it { is_expected.to be_instance_of(CardsUser) }
|
206
|
+
it { is_expected.to eq(cards_user) }
|
205
207
|
end
|
206
208
|
|
207
209
|
end
|
@@ -10,14 +10,13 @@ describe ActiveRecord::Turntable::Cluster do
|
|
10
10
|
truncate_shard
|
11
11
|
end
|
12
12
|
let(:cluster_config) { ActiveRecord::Base.turntable_config[:clusters][:user_cluster] }
|
13
|
-
let(:cluster) { ActiveRecord::Turntable::Cluster.new(
|
13
|
+
let(:cluster) { ActiveRecord::Turntable::Cluster.new(cluster_config) }
|
14
14
|
let(:in_range_shard_key_value) { cluster_config[:shards].last[:less_than] - 1 }
|
15
15
|
let(:out_of_range_shard_key_value) { cluster_config[:shards].last[:less_than] }
|
16
16
|
|
17
17
|
context "When initialized" do
|
18
18
|
subject { cluster }
|
19
19
|
|
20
|
-
its(:klass) { should == User }
|
21
20
|
its(:shards) { should have(3).items }
|
22
21
|
end
|
23
22
|
|
@@ -11,8 +11,8 @@ describe ActiveRecord::Turntable::ConnectionProxy do
|
|
11
11
|
truncate_shard
|
12
12
|
end
|
13
13
|
|
14
|
-
let(:cluster) { ActiveRecord::Turntable::Cluster.new(
|
15
|
-
subject { ActiveRecord::Turntable::ConnectionProxy.new(cluster) }
|
14
|
+
let(:cluster) { ActiveRecord::Turntable::Cluster.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster]) }
|
15
|
+
subject { ActiveRecord::Turntable::ConnectionProxy.new(User, cluster) }
|
16
16
|
|
17
17
|
its(:master_connection) { is_expected.to eql(ActiveRecord::Base.connection) }
|
18
18
|
end
|
@@ -8,8 +8,8 @@ describe ActiveRecord::Turntable::Mixer do
|
|
8
8
|
before do
|
9
9
|
establish_connection_to(:test)
|
10
10
|
truncate_shard
|
11
|
-
@cluster = ActiveRecord::Turntable::Cluster.new(
|
12
|
-
@connection_proxy = ActiveRecord::Turntable::ConnectionProxy.new(@cluster)
|
11
|
+
@cluster = ActiveRecord::Turntable::Cluster.new(ActiveRecord::Base.turntable_config[:clusters][:user_cluster])
|
12
|
+
@connection_proxy = ActiveRecord::Turntable::ConnectionProxy.new(User, @cluster)
|
13
13
|
end
|
14
14
|
|
15
15
|
context "When initialized" do
|
@@ -12,7 +12,7 @@ describe "transaction" do
|
|
12
12
|
let(:clusters) { ActiveRecord::Base.turntable_clusters }
|
13
13
|
|
14
14
|
describe "all_cluster_transaction" do
|
15
|
-
let(:all_clusters) { clusters.values
|
15
|
+
let(:all_clusters) { clusters.values }
|
16
16
|
let(:shards) { all_clusters.map { |c| c.shards.values }.flatten(1) }
|
17
17
|
|
18
18
|
it "all shards should begin transaction" do
|
@@ -23,7 +23,7 @@ describe "transaction" do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
describe "cluster_transaction" do
|
26
|
-
let(:cluster) { clusters[:user_cluster]
|
26
|
+
let(:cluster) { clusters[:user_cluster] }
|
27
27
|
let(:shards) { cluster.shards.values }
|
28
28
|
|
29
29
|
it "all shards in the cluster should begin transaction" do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-turntable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.1.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gussan
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-01-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -261,6 +261,20 @@ dependencies:
|
|
261
261
|
- - ">="
|
262
262
|
- !ruby/object:Gem::Version
|
263
263
|
version: '0'
|
264
|
+
- !ruby/object:Gem::Dependency
|
265
|
+
name: pry-byebug
|
266
|
+
requirement: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - ">="
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: '0'
|
271
|
+
type: :development
|
272
|
+
prerelease: false
|
273
|
+
version_requirements: !ruby/object:Gem::Requirement
|
274
|
+
requirements:
|
275
|
+
- - ">="
|
276
|
+
- !ruby/object:Gem::Version
|
277
|
+
version: '0'
|
264
278
|
- !ruby/object:Gem::Dependency
|
265
279
|
name: guard-rspec
|
266
280
|
requirement: !ruby/object:Gem::Requirement
|
@@ -354,6 +368,7 @@ files:
|
|
354
368
|
- lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb
|
355
369
|
- lib/active_record/turntable/base.rb
|
356
370
|
- lib/active_record/turntable/cluster.rb
|
371
|
+
- lib/active_record/turntable/cluster_helper_methods.rb
|
357
372
|
- lib/active_record/turntable/config.rb
|
358
373
|
- lib/active_record/turntable/connection_proxy.rb
|
359
374
|
- lib/active_record/turntable/connection_proxy/mixable.rb
|
@@ -445,9 +460,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
445
460
|
version: 1.9.3
|
446
461
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
447
462
|
requirements:
|
448
|
-
- - "
|
463
|
+
- - ">"
|
449
464
|
- !ruby/object:Gem::Version
|
450
|
-
version:
|
465
|
+
version: 1.3.1
|
451
466
|
requirements: []
|
452
467
|
rubyforge_project: activerecord-turntable
|
453
468
|
rubygems_version: 2.4.4
|