switchman 1.10.4 → 1.11.1
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 +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
|