activerecord-turntable 2.0.6 → 2.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|