switchman 1.10.4 → 1.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/db/shard_1708.sqlite3 +0 -0
- data/lib/switchman/active_record/association.rb +6 -16
- data/lib/switchman/active_record/base.rb +10 -28
- data/lib/switchman/active_record/calculations.rb +1 -1
- data/lib/switchman/active_record/connection_handler.rb +30 -86
- data/lib/switchman/active_record/connection_pool.rb +1 -6
- data/lib/switchman/active_record/finder_methods.rb +1 -1
- data/lib/switchman/active_record/log_subscriber.rb +3 -16
- data/lib/switchman/active_record/postgresql_adapter.rb +13 -34
- data/lib/switchman/active_record/query_cache.rb +2 -10
- data/lib/switchman/active_record/query_methods.rb +35 -109
- data/lib/switchman/active_record/reflection.rb +21 -23
- data/lib/switchman/active_record/relation.rb +9 -12
- data/lib/switchman/active_record/statement_cache.rb +15 -35
- data/lib/switchman/arel.rb +1 -5
- data/lib/switchman/connection_pool_proxy.rb +1 -1
- data/lib/switchman/database_server.rb +37 -30
- data/lib/switchman/engine.rb +5 -12
- data/lib/switchman/r_spec_helper.rb +2 -4
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +0 -14
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 67d816fd26624b395d3ff11e802340dedeac19af
|
4
|
+
data.tar.gz: 4775afc373abd08b450b2af8ac3c150e4c786676
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce07a665d16609b09ac3c4bd7f8e12d7ade79b1bebf4b12cfb98c4da70f7851b3229e9f65fb12b716b917e9ac24ecab48dd4e289ca69beacd723ddb39e21e81a
|
7
|
+
data.tar.gz: 25ed4aafe75a02fdcc9db632ececb598a73778219ac957c255c21ee5aa0e1606a69c7e04f1528a3e67acdee89046b99123ce17e13a6cf5735b003352e21a4209
|
File without changes
|
@@ -69,27 +69,17 @@ module Switchman
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
def self.build(_model, _reflection)
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.valid_options
|
78
|
-
[:multishard]
|
79
|
-
end
|
72
|
+
module Extension
|
73
|
+
def self.build(_model, _reflection)
|
80
74
|
end
|
81
75
|
|
82
|
-
|
83
|
-
|
84
|
-
module Builder
|
85
|
-
module CollectionAssociation
|
86
|
-
def valid_options
|
87
|
-
super + [:multishard]
|
88
|
-
end
|
89
|
-
end
|
76
|
+
def self.valid_options
|
77
|
+
[:multishard]
|
90
78
|
end
|
91
79
|
end
|
92
80
|
|
81
|
+
::ActiveRecord::Associations::Builder::Association.extensions << Extension
|
82
|
+
|
93
83
|
module Preloader
|
94
84
|
module Association
|
95
85
|
def associated_records_by_owner(preloader = nil)
|
@@ -4,14 +4,8 @@ module Switchman
|
|
4
4
|
module ClassMethods
|
5
5
|
delegate :shard, to: :all
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
@shard_category || (self.superclass < ::ActiveRecord::Base && self.superclass.shard_category) || :primary
|
10
|
-
end
|
11
|
-
else
|
12
|
-
def shard_category
|
13
|
-
connection_specification_name.to_sym
|
14
|
-
end
|
7
|
+
def shard_category
|
8
|
+
connection_specification_name.to_sym
|
15
9
|
end
|
16
10
|
|
17
11
|
def shard_category=(category)
|
@@ -22,13 +16,7 @@ module Switchman
|
|
22
16
|
end
|
23
17
|
categories[category] ||= []
|
24
18
|
categories[category] << self
|
25
|
-
|
26
|
-
connection_handler.uninitialize_ar(self)
|
27
|
-
@shard_category = category
|
28
|
-
connection_handler.initialize_categories(superclass)
|
29
|
-
else
|
30
|
-
self.connection_specification_name = category.to_s
|
31
|
-
end
|
19
|
+
self.connection_specification_name = category.to_s
|
32
20
|
end
|
33
21
|
|
34
22
|
def integral_id?
|
@@ -104,22 +92,18 @@ module Switchman
|
|
104
92
|
end
|
105
93
|
end
|
106
94
|
|
107
|
-
def scope_class
|
108
|
-
::Rails.version >= '5' ? self.class : self.class.base_class
|
109
|
-
end
|
110
|
-
|
111
95
|
def save(*args)
|
112
96
|
@shard_set_in_stone = true
|
113
|
-
|
97
|
+
self.class.shard(shard, :implicit).scoping { super }
|
114
98
|
end
|
115
99
|
|
116
100
|
def save!(*args)
|
117
101
|
@shard_set_in_stone = true
|
118
|
-
|
102
|
+
self.class.shard(shard, :implicit).scoping { super }
|
119
103
|
end
|
120
104
|
|
121
105
|
def destroy
|
122
|
-
|
106
|
+
self.class.shard(shard, :implicit).scoping { super }
|
123
107
|
end
|
124
108
|
|
125
109
|
def clone
|
@@ -152,12 +136,10 @@ module Switchman
|
|
152
136
|
copy
|
153
137
|
end
|
154
138
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
self.class.connection.quote(id)
|
160
|
-
end
|
139
|
+
def quoted_id
|
140
|
+
return super unless self.class.sharded_primary_key?
|
141
|
+
# do this the Rails 4.2 way, so that if Shard.current != self.shard, the id gets transposed
|
142
|
+
self.class.connection.quote(id)
|
161
143
|
end
|
162
144
|
end
|
163
145
|
end
|
@@ -159,7 +159,7 @@ module Switchman
|
|
159
159
|
'count', opts[:distinct]).as('count')
|
160
160
|
end
|
161
161
|
|
162
|
-
haves =
|
162
|
+
haves = having_clause.send(:predicates)
|
163
163
|
select_values += select_values unless haves.empty?
|
164
164
|
select_values.concat opts[:group_fields].zip(opts[:group_aliases]).map { |field,aliaz|
|
165
165
|
if field.respond_to?(:as)
|
@@ -22,9 +22,8 @@ module Switchman
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def establish_connection(
|
25
|
+
def establish_connection(spec)
|
26
26
|
pool = super
|
27
|
-
owner, spec = ::Rails.version < '5' ? args : [nil, args.first]
|
28
27
|
|
29
28
|
# this is the first place that the adapter would have been required; but now we
|
30
29
|
# need this addition ASAP since it will be called when loading the default shard below
|
@@ -53,16 +52,11 @@ module Switchman
|
|
53
52
|
|
54
53
|
@shard_connection_pools ||= { [:master, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
|
55
54
|
|
56
|
-
category =
|
55
|
+
category = pool.spec.name.to_sym
|
57
56
|
proxy = ConnectionPoolProxy.new(category,
|
58
57
|
pool,
|
59
58
|
@shard_connection_pools)
|
60
|
-
|
61
|
-
owner_to_pool[owner.name] = proxy
|
62
|
-
class_to_pool.clear
|
63
|
-
else
|
64
|
-
owner_to_pool[pool.spec.name] = proxy
|
65
|
-
end
|
59
|
+
owner_to_pool[pool.spec.name] = proxy
|
66
60
|
|
67
61
|
if first_time
|
68
62
|
if Shard.default.database_server.config[:prefer_slave]
|
@@ -107,96 +101,46 @@ module Switchman
|
|
107
101
|
proxy
|
108
102
|
end
|
109
103
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
result
|
116
|
-
end
|
104
|
+
def remove_connection(spec_name)
|
105
|
+
pool = owner_to_pool[spec_name]
|
106
|
+
owner_to_pool[spec_name] = pool.default_pool if pool.is_a?(ConnectionPoolProxy)
|
107
|
+
super
|
108
|
+
end
|
117
109
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
if ancestor_pool.is_a?(ConnectionPoolProxy)
|
127
|
-
establish_connection owner, ancestor_pool.default_pool.spec
|
128
|
-
else
|
129
|
-
establish_connection owner, ancestor_pool.spec
|
130
|
-
end
|
110
|
+
def retrieve_connection_pool(spec_name)
|
111
|
+
owner_to_pool.fetch(spec_name) do
|
112
|
+
if ancestor_pool = pool_from_any_process_for(spec_name)
|
113
|
+
# A connection was established in an ancestor process that must have
|
114
|
+
# subsequently forked. We can't reuse the connection, but we can copy
|
115
|
+
# the specification and establish a new connection with it.
|
116
|
+
spec = if ancestor_pool.is_a?(ConnectionPoolProxy)
|
117
|
+
ancestor_pool.default_pool.spec
|
131
118
|
else
|
132
|
-
|
133
|
-
end
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
def retrieve_connection_pool(klass)
|
138
|
-
class_to_pool[klass.name] ||= begin
|
139
|
-
original_klass = klass
|
140
|
-
until pool = pool_for(klass)
|
141
|
-
klass = klass.superclass
|
142
|
-
break unless klass <= Base
|
143
|
-
end
|
144
|
-
|
145
|
-
if pool.is_a?(ConnectionPoolProxy) && pool.category != original_klass.shard_category
|
146
|
-
default_pool = pool.default_pool
|
147
|
-
pool = nil
|
148
|
-
class_to_pool.each_value { |p| pool = p if p.is_a?(ConnectionPoolProxy) &&
|
149
|
-
p.category == original_klass.shard_category &&
|
150
|
-
p.default_pool == default_pool }
|
151
|
-
pool ||= ConnectionPoolProxy.new(original_klass.shard_category, default_pool, @shard_connection_pools)
|
119
|
+
ancestor_pool.spec
|
152
120
|
end
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
super
|
162
|
-
end
|
163
|
-
|
164
|
-
def retrieve_connection_pool(spec_name)
|
165
|
-
owner_to_pool.fetch(spec_name) do
|
166
|
-
if ancestor_pool = pool_from_any_process_for(spec_name)
|
167
|
-
# A connection was established in an ancestor process that must have
|
168
|
-
# subsequently forked. We can't reuse the connection, but we can copy
|
169
|
-
# the specification and establish a new connection with it.
|
170
|
-
spec = if ancestor_pool.is_a?(ConnectionPoolProxy)
|
171
|
-
ancestor_pool.default_pool.spec
|
172
|
-
else
|
173
|
-
ancestor_pool.spec
|
174
|
-
end
|
175
|
-
spec = spec.to_hash if ::Rails.version >= '5.1'
|
176
|
-
pool = establish_connection spec
|
177
|
-
pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
|
178
|
-
pool
|
179
|
-
elsif spec_name != "primary"
|
180
|
-
primary_pool = retrieve_connection_pool("primary")
|
181
|
-
if primary_pool.is_a?(ConnectionPoolProxy)
|
182
|
-
ConnectionPoolProxy.new(spec_name.to_sym, primary_pool.default_pool, @shard_connection_pools)
|
183
|
-
else
|
184
|
-
primary_pool
|
185
|
-
end
|
121
|
+
spec = spec.to_hash if ::Rails.version >= '5.1'
|
122
|
+
pool = establish_connection spec
|
123
|
+
pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
|
124
|
+
pool
|
125
|
+
elsif spec_name != "primary"
|
126
|
+
primary_pool = retrieve_connection_pool("primary")
|
127
|
+
if primary_pool.is_a?(ConnectionPoolProxy)
|
128
|
+
ConnectionPoolProxy.new(spec_name.to_sym, primary_pool.default_pool, @shard_connection_pools)
|
186
129
|
else
|
187
|
-
|
130
|
+
primary_pool
|
188
131
|
end
|
132
|
+
else
|
133
|
+
owner_to_pool[spec_name] = nil
|
189
134
|
end
|
190
135
|
end
|
191
136
|
end
|
192
137
|
|
193
138
|
def clear_idle_connections!(since_when)
|
194
|
-
|
195
|
-
connection_pools.values.each{ |pool| pool.clear_idle_connections!(since_when) }
|
139
|
+
connection_pool_list.each{ |pool| pool.clear_idle_connections!(since_when) }
|
196
140
|
end
|
197
141
|
|
198
142
|
def switchman_connection_pool_proxies
|
199
|
-
|
143
|
+
owner_to_pool.values.uniq.select{|p| p.is_a?(ConnectionPoolProxy)}
|
200
144
|
end
|
201
145
|
|
202
146
|
private
|
@@ -39,12 +39,7 @@ module Switchman
|
|
39
39
|
conn
|
40
40
|
end
|
41
41
|
|
42
|
-
def release_connection(with_id =
|
43
|
-
with_id ||= if ::Rails.version >= '5'
|
44
|
-
Thread.current
|
45
|
-
else
|
46
|
-
current_connection_id
|
47
|
-
end
|
42
|
+
def release_connection(with_id = Thread.current)
|
48
43
|
super(with_id)
|
49
44
|
|
50
45
|
if spec.config[:idle_timeout]
|
@@ -58,7 +58,7 @@ module Switchman
|
|
58
58
|
end
|
59
59
|
|
60
60
|
relation.activate do |shard_rel|
|
61
|
-
return true if connection.select_value(shard_rel, "#{name} Exists", shard_rel.
|
61
|
+
return true if connection.select_value(shard_rel, "#{name} Exists", shard_rel.bound_attributes)
|
62
62
|
end
|
63
63
|
false
|
64
64
|
end
|
@@ -17,11 +17,7 @@ module Switchman
|
|
17
17
|
shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
|
18
18
|
|
19
19
|
unless (payload[:binds] || []).empty?
|
20
|
-
if ::Rails.version < '5'
|
21
|
-
binds = " " + payload[:binds].map { |col,v|
|
22
|
-
render_bind(col, v)
|
23
|
-
}.inspect
|
24
|
-
elsif ::Rails.version < '5.0.3'
|
20
|
+
if ::Rails.version < '5.0.3'
|
25
21
|
binds = " " + payload[:binds].map { |attr| render_bind(attr) }.inspect
|
26
22
|
else
|
27
23
|
casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
|
@@ -31,17 +27,8 @@ module Switchman
|
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
sql = color(sql, sql_color(sql), true)
|
37
|
-
else
|
38
|
-
if odd?
|
39
|
-
name = color(name, self.class::CYAN, true)
|
40
|
-
sql = color(sql, nil, true)
|
41
|
-
else
|
42
|
-
name = color(name, self.class::MAGENTA, true)
|
43
|
-
end
|
44
|
-
end
|
30
|
+
name = colorize_payload_name(name, payload[:name])
|
31
|
+
sql = color(sql, sql_color(sql), true)
|
45
32
|
|
46
33
|
debug " #{name} #{sql}#{binds}#{shard}"
|
47
34
|
end
|
@@ -1,12 +1,6 @@
|
|
1
1
|
module Switchman
|
2
2
|
module ActiveRecord
|
3
3
|
module PostgreSQLAdapter
|
4
|
-
if ::Rails.version < '5'
|
5
|
-
def self.prepended(klass)
|
6
|
-
klass::NATIVE_DATABASE_TYPES[:primary_key] = "bigserial primary key".freeze
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
4
|
# copy/paste; use quote_local_table_name
|
11
5
|
def create_database(name, options = {})
|
12
6
|
options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
|
@@ -58,9 +52,16 @@ module Switchman
|
|
58
52
|
SQL
|
59
53
|
end
|
60
54
|
|
61
|
-
|
62
|
-
|
63
|
-
|
55
|
+
if ::Rails.version >= '5.1'
|
56
|
+
def extract_schema_qualified_name(string)
|
57
|
+
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(string.to_s)
|
58
|
+
if string && !name.schema && use_qualified_names?
|
59
|
+
name.instance_variable_set(:@schema, shard.name)
|
60
|
+
end
|
61
|
+
[name.schema, name.identifier]
|
62
|
+
end
|
63
|
+
else
|
64
|
+
def data_source_exists?(name)
|
64
65
|
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
|
65
66
|
return false unless name.identifier
|
66
67
|
if !name.schema && use_qualified_names?
|
@@ -72,11 +73,11 @@ module Switchman
|
|
72
73
|
FROM pg_class c
|
73
74
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
74
75
|
WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
|
75
|
-
AND c.relname = '
|
76
|
-
AND n.nspname =
|
76
|
+
AND c.relname = '#{name.identifier}'
|
77
|
+
AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
|
77
78
|
SQL
|
78
79
|
end
|
79
|
-
|
80
|
+
end
|
80
81
|
|
81
82
|
def view_exists?(name)
|
82
83
|
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
|
@@ -213,28 +214,6 @@ module Switchman
|
|
213
214
|
algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
|
214
215
|
[index_name, index_type, index_columns, index_options, algorithm, using]
|
215
216
|
end
|
216
|
-
|
217
|
-
def rename_table(table_name, new_name)
|
218
|
-
clear_cache!
|
219
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_local_table_name(new_name)}"
|
220
|
-
pk, seq = pk_and_sequence_for(new_name)
|
221
|
-
if pk
|
222
|
-
idx = "#{table_name}_pkey"
|
223
|
-
new_idx = "#{new_name}_pkey"
|
224
|
-
execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_local_table_name(new_idx)}"
|
225
|
-
if seq && seq.identifier == "#{table_name}_#{pk}_seq"
|
226
|
-
new_seq = "#{new_name}_#{pk}_seq"
|
227
|
-
execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_local_table_name(new_seq)}"
|
228
|
-
end
|
229
|
-
end
|
230
|
-
rename_table_indexes(table_name, new_name)
|
231
|
-
end
|
232
|
-
|
233
|
-
def rename_index(table_name, old_name, new_name)
|
234
|
-
validate_index_length!(table_name, new_name)
|
235
|
-
|
236
|
-
execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_local_table_name(new_name)}"
|
237
|
-
end
|
238
217
|
end
|
239
218
|
end
|
240
219
|
end
|
@@ -52,17 +52,9 @@ module Switchman
|
|
52
52
|
if self.query_cache_enabled && !locked?(arel)
|
53
53
|
arel, binds = binds_from_relation(arel, binds)
|
54
54
|
sql = to_sql(arel, binds)
|
55
|
-
|
56
|
-
cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
|
57
|
-
else
|
58
|
-
cache_sql(sql, binds) { super(sql, name, binds) }
|
59
|
-
end
|
55
|
+
cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
|
60
56
|
else
|
61
|
-
|
62
|
-
super
|
63
|
-
else
|
64
|
-
super(arel, name, binds)
|
65
|
-
end
|
57
|
+
super
|
66
58
|
end
|
67
59
|
end
|
68
60
|
|
@@ -42,33 +42,6 @@ module Switchman
|
|
42
42
|
self
|
43
43
|
end
|
44
44
|
|
45
|
-
if ::Rails.version < '5'
|
46
|
-
# moved to WhereClauseFactory#build in Rails 5
|
47
|
-
def build_where(opts, other = [])
|
48
|
-
case opts
|
49
|
-
when String, Array
|
50
|
-
values = Hash === other.first ? other.first.values : other
|
51
|
-
|
52
|
-
values.grep(ActiveRecord::Relation) do |rel|
|
53
|
-
# serialize subqueries against the same shard as the outer query is currently
|
54
|
-
# targeted to run against
|
55
|
-
if rel.shard_source_value == :implicit && rel.primary_shard != primary_shard
|
56
|
-
rel.shard!(primary_shard)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
61
|
-
when Hash, ::Arel::Nodes::Node
|
62
|
-
predicates = super
|
63
|
-
infer_shards_from_primary_key(predicates) if shard_source_value == :implicit && shard_value.is_a?(Shard)
|
64
|
-
predicates = transpose_predicates(predicates, nil, primary_shard)
|
65
|
-
predicates
|
66
|
-
else
|
67
|
-
super
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
45
|
# the shard that where_values are relative to. if it's multiple shards, they're stored
|
73
46
|
# relative to the first shard
|
74
47
|
def primary_shard
|
@@ -103,49 +76,26 @@ module Switchman
|
|
103
76
|
end
|
104
77
|
end
|
105
78
|
|
106
|
-
if ::Rails.version < '5'
|
107
|
-
# fixes an issue in Rails 4.2 with `reverse_sql_order` and qualified names
|
108
|
-
# where quoted_table_name is called before shard(s) have been activated
|
109
|
-
# if there's no ordering
|
110
|
-
def reverse_order!
|
111
|
-
orders = order_values.uniq
|
112
|
-
orders.reject!(&:blank?)
|
113
|
-
if orders.empty?
|
114
|
-
self.order_values = [arel_table[primary_key].desc]
|
115
|
-
else
|
116
|
-
self.order_values = reverse_sql_order(orders)
|
117
|
-
end
|
118
|
-
self
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
79
|
private
|
123
80
|
|
124
81
|
[:where, :having].each do |type|
|
125
82
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
126
|
-
def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
#{type}_clause.instance_variable_set(:@binds, new_binds)
|
140
|
-
end
|
83
|
+
def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
84
|
+
unless (predicates = #{type}_clause.send(:predicates)).empty?
|
85
|
+
new_predicates, new_binds = transpose_predicates(predicates, source_shard,
|
86
|
+
target_shard, remove_nonlocal_primary_keys,
|
87
|
+
binds: #{type}_clause.binds,
|
88
|
+
dup_binds_on_mutation: true)
|
89
|
+
if new_predicates != predicates || !new_binds.equal?(#{type}_clause.binds)
|
90
|
+
self.#{type}_clause = #{type}_clause.dup
|
91
|
+
if new_predicates != predicates
|
92
|
+
#{type}_clause.instance_variable_set(:@predicates, new_predicates)
|
93
|
+
end
|
94
|
+
if !new_binds.equal?(#{type}_clause.binds)
|
95
|
+
#{type}_clause.instance_variable_set(:@binds, new_binds)
|
141
96
|
end
|
142
97
|
end
|
143
|
-
|
144
|
-
unless #{type}_values.empty?
|
145
|
-
self.#{type}_values = transpose_predicates(#{type}_values,
|
146
|
-
source_shard, target_shard, remove_nonlocal_primary_keys)
|
147
|
-
end
|
148
|
-
end
|
98
|
+
end
|
149
99
|
end
|
150
100
|
RUBY
|
151
101
|
end
|
@@ -189,20 +139,10 @@ module Switchman
|
|
189
139
|
end
|
190
140
|
when ::Arel::Nodes::BindParam
|
191
141
|
# look for a bind param with a matching column name
|
192
|
-
if
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
id_shard ||= Shard.current(klass.shard_category) if local_id
|
197
|
-
end
|
198
|
-
end
|
199
|
-
else
|
200
|
-
if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first&.name.to_s == klass.primary_key.to_s}
|
201
|
-
column, value = bind_values[idx]
|
202
|
-
unless value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
203
|
-
local_id, id_shard = Shard.local_id_for(value)
|
204
|
-
id_shard ||= Shard.current(klass.shard_category) if local_id
|
205
|
-
end
|
142
|
+
if binds && bind = binds.detect{|b| b&.name.to_s == klass.primary_key.to_s}
|
143
|
+
unless bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
144
|
+
local_id, id_shard = Shard.local_id_for(bind.value)
|
145
|
+
id_shard ||= Shard.current(klass.shard_category) if local_id
|
206
146
|
end
|
207
147
|
end
|
208
148
|
else
|
@@ -260,9 +200,9 @@ module Switchman
|
|
260
200
|
|
261
201
|
def arel_columns(columns)
|
262
202
|
columns.map do |field|
|
263
|
-
if (Symbol === field || String === field) &&
|
203
|
+
if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
|
264
204
|
klass.arel_attribute(field, table)
|
265
|
-
elsif (Symbol === field || String === field) &&
|
205
|
+
elsif (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_value
|
266
206
|
arel_table[field]
|
267
207
|
elsif Symbol === field
|
268
208
|
# the rest of this is pulled from AR - the only change is from quote_table_name to quote_column_name here
|
@@ -324,35 +264,21 @@ module Switchman
|
|
324
264
|
local_ids
|
325
265
|
when ::Arel::Nodes::BindParam
|
326
266
|
# look for a bind param with a matching column name
|
327
|
-
if
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
|
334
|
-
end
|
335
|
-
if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
336
|
-
bind.value.sharded = true # mark for transposition later
|
337
|
-
bind.value.primary = true if type == :primary
|
338
|
-
else
|
339
|
-
local_id = Shard.relative_id_for(bind.value, current_source_shard, target_shard)
|
340
|
-
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
341
|
-
bind.instance_variable_set(:@value, local_id)
|
342
|
-
bind.instance_variable_set(:@value_for_database, nil)
|
343
|
-
end
|
267
|
+
if binds && bind = binds.detect{|b| b&.name.to_s == predicate.left.name.to_s}
|
268
|
+
# before we mutate, dup
|
269
|
+
if dup_binds_on_mutation
|
270
|
+
binds = binds.map(&:dup)
|
271
|
+
dup_binds_on_mutation = false
|
272
|
+
bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
|
344
273
|
end
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
354
|
-
bind_values[idx] = [column, local_id]
|
355
|
-
end
|
274
|
+
if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
275
|
+
bind.value.sharded = true # mark for transposition later
|
276
|
+
bind.value.primary = true if type == :primary
|
277
|
+
else
|
278
|
+
local_id = Shard.relative_id_for(bind.value, current_source_shard, target_shard)
|
279
|
+
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
280
|
+
bind.instance_variable_set(:@value, local_id)
|
281
|
+
bind.instance_variable_set(:@value_for_database, nil)
|
356
282
|
end
|
357
283
|
end
|
358
284
|
predicate.right
|
@@ -374,7 +300,7 @@ module Switchman
|
|
374
300
|
predicate.class.new(predicate.left, new_right_value)
|
375
301
|
end
|
376
302
|
end
|
377
|
-
result = [result, binds]
|
303
|
+
result = [result, binds]
|
378
304
|
result
|
379
305
|
end
|
380
306
|
end
|
@@ -12,31 +12,29 @@ module Switchman
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
15
|
+
module AssociationScopeCache
|
16
|
+
def initialize(*args)
|
17
|
+
super
|
18
|
+
# on ThroughReflection, these won't be initialized (cause it doesn't
|
19
|
+
# inherit from AssociationReflection), so make sure they're
|
20
|
+
# initialized here
|
21
|
+
@association_scope_cache ||= {}
|
22
|
+
@scope_lock ||= Mutex.new
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
key = [key, shard(owner).id].flatten
|
36
|
-
@association_scope_cache[key] ||= @scope_lock.synchronize {
|
37
|
-
@association_scope_cache[key] ||= yield
|
38
|
-
}
|
25
|
+
# cache association scopes by shard.
|
26
|
+
# this technically belongs on AssociationReflection, but we put it on
|
27
|
+
# ThroughReflection as well, instead of delegating to its internal
|
28
|
+
# HasManyAssociation, losing its proper `klass`
|
29
|
+
def association_scope_cache(conn, owner)
|
30
|
+
key = conn.prepared_statements
|
31
|
+
if polymorphic?
|
32
|
+
key = [key, owner._read_attribute(@foreign_type)]
|
39
33
|
end
|
34
|
+
key = [key, shard(owner).id].flatten
|
35
|
+
@association_scope_cache[key] ||= @scope_lock.synchronize {
|
36
|
+
@association_scope_cache[key] ||= yield
|
37
|
+
}
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -46,19 +46,16 @@ module Switchman
|
|
46
46
|
self.activate { |relation| relation.call_super(:explain, Relation) }
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@records = results
|
57
|
-
@loaded = true
|
58
|
-
end
|
59
|
-
results
|
49
|
+
def records
|
50
|
+
return @records if loaded?
|
51
|
+
results = self.activate { |relation| relation.call_super(:records, Relation) }
|
52
|
+
case shard_value
|
53
|
+
when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base
|
54
|
+
@records = results
|
55
|
+
@loaded = true
|
60
56
|
end
|
61
|
-
|
57
|
+
results
|
58
|
+
end
|
62
59
|
|
63
60
|
%I{update_all delete_all}.each do |method|
|
64
61
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
@@ -5,8 +5,7 @@ module Switchman
|
|
5
5
|
def create(connection, block = Proc.new)
|
6
6
|
relation = block.call ::ActiveRecord::StatementCache::Params.new
|
7
7
|
|
8
|
-
|
9
|
-
bind_map = ::ActiveRecord::StatementCache::BindMap.new(binds)
|
8
|
+
bind_map = ::ActiveRecord::StatementCache::BindMap.new(relation.bound_attributes )
|
10
9
|
new relation.arel, bind_map
|
11
10
|
end
|
12
11
|
end
|
@@ -65,44 +64,25 @@ module Switchman
|
|
65
64
|
module BindMap
|
66
65
|
# performs id transposition here instead of query_methods.rb
|
67
66
|
def bind(values, current_shard, target_shard)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
new_value = values[i]
|
76
|
-
end
|
77
|
-
bas[offset] = ba.with_cast_value(new_value)
|
67
|
+
bas = @bound_attributes.dup
|
68
|
+
@indexes.each_with_index do |offset,i|
|
69
|
+
ba = bas[offset]
|
70
|
+
if ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.sharded
|
71
|
+
new_value = Shard.relative_id_for(values[i], current_shard, target_shard || current_shard)
|
72
|
+
else
|
73
|
+
new_value = values[i]
|
78
74
|
end
|
79
|
-
bas
|
80
|
-
else
|
81
|
-
bvs = @bind_values.map { |pair| pair.dup }
|
82
|
-
@indexes.each_with_index do |offset,i|
|
83
|
-
bv = bvs[offset]
|
84
|
-
if bv[1].sharded
|
85
|
-
bv[1] = Shard.relative_id_for(values[i], current_shard, target_shard || current_shard)
|
86
|
-
else
|
87
|
-
bv[1] = values[i]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
bvs
|
75
|
+
bas[offset] = ba.with_cast_value(new_value)
|
91
76
|
end
|
77
|
+
bas
|
92
78
|
end
|
93
79
|
|
94
80
|
def primary_value_index
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
@indexes.index(primary_ba_index)
|
101
|
-
end
|
102
|
-
else
|
103
|
-
if primary_bv_index = @bind_values.index{|col, sub| sub.primary}
|
104
|
-
@indexes.index(primary_bv_index)
|
105
|
-
end
|
81
|
+
primary_ba_index = @bound_attributes.index do |ba|
|
82
|
+
ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.primary
|
83
|
+
end
|
84
|
+
if primary_ba_index
|
85
|
+
@indexes.index(primary_ba_index)
|
106
86
|
end
|
107
87
|
end
|
108
88
|
end
|
data/lib/switchman/arel.rb
CHANGED
@@ -123,7 +123,7 @@ module Switchman
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
args = [config, "#{config[:adapter]}_connection"]
|
126
|
-
args.unshift(pool_key.join("/"))
|
126
|
+
args.unshift(pool_key.join("/"))
|
127
127
|
spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(*args)
|
128
128
|
# unfortunately the AR code that does this require logic can't really be
|
129
129
|
# called in isolation
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "securerandom"
|
2
|
-
|
3
1
|
module Switchman
|
4
2
|
class DatabaseServer
|
5
3
|
attr_accessor :id
|
@@ -138,14 +136,27 @@ module Switchman
|
|
138
136
|
create_schema = options[:schema]
|
139
137
|
# look for another shard associated with this db
|
140
138
|
other_shard = self.shards.where("name<>':memory:' OR name IS NULL").order(:id).first
|
139
|
+
temp_name = other_shard&.name unless id == ::Rails.env
|
140
|
+
temp_name = Shard.default.name if id == ::Rails.env
|
141
141
|
|
142
142
|
case config[:adapter]
|
143
143
|
when 'postgresql'
|
144
|
+
temp_name ||= 'public'
|
144
145
|
create_statement = lambda { "CREATE SCHEMA #{name}" }
|
145
146
|
password = " PASSWORD #{::ActiveRecord::Base.connection.quote(config[:password])}" if config[:password]
|
146
147
|
when 'sqlite3'
|
147
|
-
|
148
|
+
if name
|
149
|
+
# Try to create a db on-disk even if the only shards for sqlite are in-memory
|
150
|
+
temp_name = nil if temp_name == ':memory:'
|
151
|
+
# Put it in the db directory if there are no other sqlite shards
|
152
|
+
temp_name ||= 'db/dummy'
|
153
|
+
temp_name = File.join(File.dirname(temp_name), "#{name}.sqlite3")
|
154
|
+
# If they really asked for :memory:, give them :memory:
|
155
|
+
temp_name = name if name == ':memory:'
|
156
|
+
name = temp_name
|
157
|
+
end
|
148
158
|
else
|
159
|
+
temp_name ||= self.config[:database] % self.config
|
149
160
|
create_statement = lambda { "CREATE DATABASE #{name}" }
|
150
161
|
end
|
151
162
|
sharding_config = Switchman.config
|
@@ -159,35 +170,27 @@ module Switchman
|
|
159
170
|
end
|
160
171
|
|
161
172
|
create_shard = lambda do
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
id_seq = Shard.connection.quote(Shard.connection.quote_table_name('switchman_shards_id_seq'))
|
166
|
-
next_id = Shard.connection.select_value("SELECT nextval(#{id_seq})")
|
167
|
-
next_id.to_i
|
168
|
-
else
|
169
|
-
nil
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
if name.nil?
|
174
|
-
base_name = self.config[:database].to_s % self.config
|
175
|
-
base_name = $1 if base_name =~ /(?:.*\/)(.+)_shard_\d+(?:\.sqlite3)?$/
|
176
|
-
base_name = nil if base_name == ':memory:'
|
177
|
-
base_name << '_' if base_name
|
178
|
-
base_id = shard_id || SecureRandom.uuid
|
179
|
-
name = "#{base_name}shard_#{base_id}"
|
180
|
-
if config[:adapter] == 'sqlite3'
|
181
|
-
name = File.join('db', "#{name}.sqlite3")
|
182
|
-
end
|
173
|
+
shard = Shard.create!(:name => temp_name,
|
174
|
+
:database_server => self) do |shard|
|
175
|
+
shard.id = options[:id] if options[:id]
|
183
176
|
end
|
184
|
-
|
185
|
-
shard = Shard.create!(:id => shard_id,
|
186
|
-
:name => name,
|
187
|
-
:database_server => self)
|
188
|
-
|
189
177
|
begin
|
190
178
|
self.class.creating_new_shard = true
|
179
|
+
if name.nil?
|
180
|
+
base_name = self.config[:database] % self.config
|
181
|
+
base_name = $1 if base_name =~ /(?:.*\/)(.+)_shard_\d+(?:\.sqlite3)?$/
|
182
|
+
base_name = nil if base_name == ':memory:'
|
183
|
+
base_name << '_' if base_name
|
184
|
+
name = "#{base_name}shard_#{shard.id}"
|
185
|
+
if config[:adapter] == 'sqlite3'
|
186
|
+
# Try to create a db on-disk even if the only shards for sqlite are in-memory
|
187
|
+
temp_name = nil if temp_name == ':memory:'
|
188
|
+
# Put it in the db directory if there are no other sqlite shards
|
189
|
+
temp_name ||= 'db/dummy'
|
190
|
+
name = File.join(File.dirname(temp_name), "#{name}.sqlite3")
|
191
|
+
shard.name = name
|
192
|
+
end
|
193
|
+
end
|
191
194
|
shard.activate(*Shard.categories) do
|
192
195
|
::Shackles.activate(:deploy) do
|
193
196
|
begin
|
@@ -196,11 +199,14 @@ module Switchman
|
|
196
199
|
::ActiveRecord::Base.connection.execute(stmt)
|
197
200
|
end
|
198
201
|
# have to disconnect and reconnect to the correct db
|
202
|
+
shard.name = name
|
199
203
|
if self.shareable? && other_shard
|
200
204
|
other_shard.activate { ::ActiveRecord::Base.connection }
|
201
205
|
else
|
202
206
|
::ActiveRecord::Base.connection_pool.current_pool.disconnect!
|
203
207
|
end
|
208
|
+
else
|
209
|
+
shard.name = name
|
204
210
|
end
|
205
211
|
old_proc = ::ActiveRecord::Base.connection.raw_connection.set_notice_processor {} if config[:adapter] == 'postgresql'
|
206
212
|
old_verbose = ::ActiveRecord::Migration.verbose
|
@@ -223,10 +229,11 @@ module Switchman
|
|
223
229
|
end
|
224
230
|
end
|
225
231
|
end
|
232
|
+
shard.save!
|
226
233
|
shard
|
227
234
|
rescue
|
228
235
|
shard.destroy
|
229
|
-
shard.drop_database rescue nil
|
236
|
+
shard.drop_database if shard.name == name rescue nil
|
230
237
|
reset_column_information unless create_schema == false rescue nil
|
231
238
|
raise
|
232
239
|
ensure
|
data/lib/switchman/engine.rb
CHANGED
@@ -112,9 +112,6 @@ module Switchman
|
|
112
112
|
::ActiveRecord::Associations::Association.prepend(ActiveRecord::Association)
|
113
113
|
::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::BelongsToAssociation)
|
114
114
|
::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::CollectionProxy)
|
115
|
-
if ::Rails.version < '5'
|
116
|
-
::ActiveRecord::Associations::Builder::CollectionAssociation.include(ActiveRecord::Builder::CollectionAssociation)
|
117
|
-
end
|
118
115
|
|
119
116
|
::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Preloader::Association)
|
120
117
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
|
@@ -129,9 +126,7 @@ module Switchman
|
|
129
126
|
|
130
127
|
::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
|
131
128
|
::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
|
132
|
-
|
133
|
-
::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
|
134
|
-
end
|
129
|
+
::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
|
135
130
|
::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
|
136
131
|
|
137
132
|
::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
|
@@ -147,12 +142,10 @@ module Switchman
|
|
147
142
|
::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
|
148
143
|
::ActiveRecord::Relation.include(CallSuper)
|
149
144
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
|
155
|
-
end
|
145
|
+
::ActiveRecord::Relation::WhereClauseFactory.prepend(ActiveRecord::WhereClauseFactory)
|
146
|
+
::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
|
147
|
+
::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
|
148
|
+
::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
|
156
149
|
|
157
150
|
::Rails.singleton_class.prepend(Rails::ClassMethods)
|
158
151
|
|
@@ -118,8 +118,7 @@ module Switchman
|
|
118
118
|
klass.before do
|
119
119
|
raise "Sharding did not set up correctly" if @@sharding_failed
|
120
120
|
Shard.clear_cache
|
121
|
-
if ::Rails.version >= '5.1' ? use_transactional_tests :
|
122
|
-
(::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
|
121
|
+
if ::Rails.version >= '5.1' ? use_transactional_tests : (use_transactional_tests || use_transactional_fixtures)
|
123
122
|
Shard.default(true)
|
124
123
|
@shard1 = Shard.find(@shard1.id)
|
125
124
|
@shard2 = Shard.find(@shard2.id)
|
@@ -135,8 +134,7 @@ module Switchman
|
|
135
134
|
|
136
135
|
klass.after do
|
137
136
|
next if @@sharding_failed
|
138
|
-
if ::Rails.version >= '5.1' ? use_transactional_tests :
|
139
|
-
(::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
|
137
|
+
if ::Rails.version >= '5.1' ? use_transactional_tests : (use_transactional_tests || use_transactional_fixtures)
|
140
138
|
shards = [@shard2]
|
141
139
|
shards << @shard1 unless @shard1.database_server == Shard.default.database_server
|
142
140
|
shards.each do |shard|
|
data/lib/switchman/version.rb
CHANGED
data/lib/tasks/switchman.rake
CHANGED
@@ -219,20 +219,6 @@ module Switchman
|
|
219
219
|
run_cmd('pg_dump', args, 'dumping')
|
220
220
|
File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
|
221
221
|
end
|
222
|
-
|
223
|
-
if ::Rails.version < '4.2.5'
|
224
|
-
# These methods are backported from rails 4.2.5 to work with the above
|
225
|
-
def run_cmd(cmd, args, action)
|
226
|
-
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
227
|
-
end
|
228
|
-
|
229
|
-
def run_cmd_error(cmd, args, action)
|
230
|
-
msg = "failed to execute:\n"
|
231
|
-
msg << "#{cmd} #{args.join(' ')}\n\n"
|
232
|
-
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
233
|
-
msg
|
234
|
-
end
|
235
|
-
end
|
236
222
|
end
|
237
223
|
end
|
238
224
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: switchman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2017-07-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: railties
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
21
|
+
version: '5.0'
|
22
22
|
- - "<"
|
23
23
|
- !ruby/object:Gem::Version
|
24
24
|
version: '5.2'
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version: '
|
31
|
+
version: '5.0'
|
32
32
|
- - "<"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '5.2'
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
41
|
+
version: '5.0'
|
42
42
|
- - "<"
|
43
43
|
- !ruby/object:Gem::Version
|
44
44
|
version: '5.2'
|
@@ -48,7 +48,7 @@ dependencies:
|
|
48
48
|
requirements:
|
49
49
|
- - ">="
|
50
50
|
- !ruby/object:Gem::Version
|
51
|
-
version: '
|
51
|
+
version: '5.0'
|
52
52
|
- - "<"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.2'
|
@@ -177,6 +177,7 @@ files:
|
|
177
177
|
- db/migrate/20130328212039_create_switchman_shards.rb
|
178
178
|
- db/migrate/20130328224244_create_default_shard.rb
|
179
179
|
- db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
|
180
|
+
- db/shard_1708.sqlite3
|
180
181
|
- lib/switchman.rb
|
181
182
|
- lib/switchman/action_controller/caching.rb
|
182
183
|
- lib/switchman/active_record/abstract_adapter.rb
|
@@ -243,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
243
244
|
version: '0'
|
244
245
|
requirements: []
|
245
246
|
rubyforge_project:
|
246
|
-
rubygems_version: 2.
|
247
|
+
rubygems_version: 2.6.10
|
247
248
|
signing_key:
|
248
249
|
specification_version: 4
|
249
250
|
summary: Rails 4 sharding magic
|