switchman 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/switchman/shard.rb +1 -1
- data/app/models/switchman/shard_internal.rb +9 -11
- data/db/migrate/20130328212039_create_switchman_shards.rb +1 -1
- data/db/migrate/20130328224244_create_default_shard.rb +1 -1
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +1 -1
- data/lib/switchman/active_record/abstract_adapter.rb +8 -0
- data/lib/switchman/active_record/association.rb +16 -7
- data/lib/switchman/active_record/attribute_methods.rb +3 -3
- data/lib/switchman/active_record/base.rb +11 -3
- data/lib/switchman/active_record/connection_handler.rb +12 -6
- data/lib/switchman/active_record/log_subscriber.rb +10 -7
- data/lib/switchman/active_record/migration.rb +37 -0
- data/lib/switchman/active_record/postgresql_adapter.rb +11 -3
- data/lib/switchman/active_record/query_cache.rb +101 -75
- data/lib/switchman/active_record/query_methods.rb +34 -14
- data/lib/switchman/active_record/statement_cache.rb +15 -5
- data/lib/switchman/active_record/where_clause_factory.rb +1 -1
- data/lib/switchman/call_super.rb +6 -7
- data/lib/switchman/connection_pool_proxy.rb +10 -2
- data/lib/switchman/database_server.rb +7 -2
- data/lib/switchman/engine.rb +10 -3
- data/lib/switchman/r_spec_helper.rb +4 -2
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +15 -13
- metadata +20 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d9bf082be6cc36e99b6be46bdf90c47102c45962
|
|
4
|
+
data.tar.gz: 105fd5544f11577cd939de766a0d2950f727759e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a69a13d8922e15c57a972c4521833f0d1658d7c13198f766e1cc2374a3cc8781765984194bb1b57950b32bc2c52221b3aeb8d1e6474e30bde3a4aa30a6d8cd3
|
|
7
|
+
data.tar.gz: a22298dbbc075b8a69af90bd87c97a74ad598729551f268a7bd3bb9eae08aa28eec6ca1654bf35b2b7863527acd2aab63458a8ad439453d4d86fb5514c0d7447
|
|
@@ -8,4 +8,4 @@ ActiveRecord::Base
|
|
|
8
8
|
# we need to make sure we define the class someone wanted (in which case
|
|
9
9
|
# AR's on_load hook won't be called either yet, and establish_connection
|
|
10
10
|
# will be safe)
|
|
11
|
-
|
|
11
|
+
require_dependency 'switchman/shard_internal'
|
|
@@ -26,6 +26,7 @@ module Switchman
|
|
|
26
26
|
validates_uniqueness_of :default, :if => lambda { |s| s.default? }
|
|
27
27
|
|
|
28
28
|
after_save :clear_cache
|
|
29
|
+
after_destroy :clear_cache
|
|
29
30
|
|
|
30
31
|
scope :primary, -> { where(name: nil).order(:database_server_id, :id).distinct_on(:database_server_id) }
|
|
31
32
|
|
|
@@ -191,14 +192,14 @@ module Switchman
|
|
|
191
192
|
max_procs = determine_max_procs(options.delete(:max_procs), parallel)
|
|
192
193
|
if ::ActiveRecord::Relation === scope
|
|
193
194
|
# still need a post-uniq, cause the default database server could be NULL or Rails.env in the db
|
|
194
|
-
database_servers = scope.reorder('database_server_id').select(:database_server_id).
|
|
195
|
+
database_servers = scope.reorder('database_server_id').select(:database_server_id).distinct.
|
|
195
196
|
map(&:database_server).compact.uniq
|
|
196
197
|
parallel = [(max_procs.to_f / database_servers.count).ceil, parallel].min if max_procs
|
|
197
198
|
|
|
198
199
|
scopes = Hash[database_servers.map do |server|
|
|
199
200
|
server_scope = server.shards.merge(scope)
|
|
200
201
|
if parallel == 1
|
|
201
|
-
subscopes = server_scope
|
|
202
|
+
subscopes = [server_scope]
|
|
202
203
|
else
|
|
203
204
|
subscopes = []
|
|
204
205
|
total = server_scope.count
|
|
@@ -223,6 +224,8 @@ module Switchman
|
|
|
223
224
|
scopes = Hash[scopes.map do |(server, shards)|
|
|
224
225
|
[server, shards.in_groups(parallel, false).compact]
|
|
225
226
|
end]
|
|
227
|
+
else
|
|
228
|
+
scopes = Hash[scopes.map { |(server, shards)| [server, [shards]] }]
|
|
226
229
|
end
|
|
227
230
|
end
|
|
228
231
|
|
|
@@ -250,7 +253,7 @@ module Switchman
|
|
|
250
253
|
|
|
251
254
|
# only one process; don't bother forking
|
|
252
255
|
if scopes.length == 1 && parallel == 1
|
|
253
|
-
return with_each_shard(scopes.first.last, categories, options) { yield }
|
|
256
|
+
return with_each_shard(scopes.first.last.first, categories, options) { yield }
|
|
254
257
|
end
|
|
255
258
|
|
|
256
259
|
# clear connections prior to forking (no more queries will be executed in the parent,
|
|
@@ -259,10 +262,6 @@ module Switchman
|
|
|
259
262
|
::ActiveRecord::Base.clear_all_connections!
|
|
260
263
|
|
|
261
264
|
scopes.each do |server, subscopes|
|
|
262
|
-
if !(::ActiveRecord::Relation === subscopes.first) && subscopes.first.class != Array
|
|
263
|
-
subscopes = [subscopes]
|
|
264
|
-
end
|
|
265
|
-
|
|
266
265
|
subscopes.each_with_index do |subscope, idx|
|
|
267
266
|
if subscopes.length > 1
|
|
268
267
|
name = "#{server.id} #{idx + 1}"
|
|
@@ -274,7 +273,7 @@ module Switchman
|
|
|
274
273
|
exception_pipes << exception_pipe
|
|
275
274
|
pid, io_in, io_out, io_err = Open4.pfork4(lambda do
|
|
276
275
|
begin
|
|
277
|
-
Switchman.config[:on_fork_proc]
|
|
276
|
+
Switchman.config[:on_fork_proc]&.call
|
|
278
277
|
$0 = [$0, ARGV, name].flatten.join(' ')
|
|
279
278
|
with_each_shard(subscope, categories, options) { yield }
|
|
280
279
|
exception_pipe.last.close
|
|
@@ -349,8 +348,7 @@ module Switchman
|
|
|
349
348
|
previous_shard = nil
|
|
350
349
|
close_connections_if_needed = lambda do |shard|
|
|
351
350
|
# prune the prior connection unless it happened to be the same
|
|
352
|
-
if previous_shard && shard != previous_shard &&
|
|
353
|
-
(shard.database_server != previous_shard.database_server || !previous_shard.database_server.shareable?)
|
|
351
|
+
if previous_shard && shard != previous_shard && !previous_shard.database_server.shareable?
|
|
354
352
|
previous_shard.activate do
|
|
355
353
|
::Shackles.activated_environments.each do |env|
|
|
356
354
|
::Shackles.activate(env) do
|
|
@@ -610,7 +608,7 @@ module Switchman
|
|
|
610
608
|
begin
|
|
611
609
|
adapter = self.database_server.config[:adapter]
|
|
612
610
|
sharding_config = Switchman.config || {}
|
|
613
|
-
drop_statement = sharding_config[adapter]
|
|
611
|
+
drop_statement = sharding_config[adapter]&.[](:drop_statement)
|
|
614
612
|
drop_statement ||= sharding_config[:drop_statement]
|
|
615
613
|
if drop_statement
|
|
616
614
|
drop_statement = Array(drop_statement).dup.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class AddBackDefaultStringLimitsSwitchman < ActiveRecord::Migration
|
|
1
|
+
class AddBackDefaultStringLimitsSwitchman < ActiveRecord::Migration[4.2]
|
|
2
2
|
def up
|
|
3
3
|
add_string_limit_if_missing :switchman_shards, :name
|
|
4
4
|
add_string_limit_if_missing :switchman_shards, :database_server_id
|
|
@@ -38,6 +38,14 @@ module Switchman
|
|
|
38
38
|
ensure
|
|
39
39
|
@last_query_at = Time.now
|
|
40
40
|
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def id_value_for_database(value)
|
|
45
|
+
return super unless value.class.sharded_primary_key?
|
|
46
|
+
# do this the Rails 4.2 way, so that if Shard.current != self.shard, the id gets transposed
|
|
47
|
+
quote(value.id)
|
|
48
|
+
end
|
|
41
49
|
end
|
|
42
50
|
end
|
|
43
51
|
end
|
|
@@ -36,14 +36,17 @@ module Switchman
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
module CollectionAssociation
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
method = ::Rails.version < '5.1' ? :get_records : :find_target
|
|
40
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
41
|
+
def #{method}
|
|
42
|
+
shards = reflection.options[:multishard] && owner.respond_to?(:associated_shards) ? owner.associated_shards : [shard]
|
|
43
|
+
# activate both the owner and the target's shard category, so that Reflection#join_id_for,
|
|
44
|
+
# when called for the owner, will be returned relative to shard the query will execute on
|
|
45
|
+
Shard.with_each_shard(shards, [klass.shard_category, owner.class.shard_category].uniq) do
|
|
46
|
+
super
|
|
47
|
+
end
|
|
45
48
|
end
|
|
46
|
-
|
|
49
|
+
RUBY
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
module BelongsToAssociation
|
|
@@ -169,6 +172,12 @@ module Switchman
|
|
|
169
172
|
end
|
|
170
173
|
|
|
171
174
|
module CollectionProxy
|
|
175
|
+
def initialize(*args)
|
|
176
|
+
super
|
|
177
|
+
self.shard_value = scope.shard_value
|
|
178
|
+
self.shard_source_value = :association
|
|
179
|
+
end
|
|
180
|
+
|
|
172
181
|
def shard(*args)
|
|
173
182
|
scope.shard(*args)
|
|
174
183
|
end
|
|
@@ -27,7 +27,7 @@ module Switchman
|
|
|
27
27
|
def reflection_for_integer_attribute(attr_name)
|
|
28
28
|
attr_name = attr_name.to_s
|
|
29
29
|
columns_hash[attr_name] && columns_hash[attr_name].type == :integer &&
|
|
30
|
-
reflections.find { |_, r| r.belongs_to? && r.foreign_key.to_s == attr_name }
|
|
30
|
+
reflections.find { |_, r| r.belongs_to? && r.foreign_key.to_s == attr_name }&.last
|
|
31
31
|
rescue ::ActiveRecord::StatementInvalid
|
|
32
32
|
# this is for when models are referenced in initializers before migrations have been run
|
|
33
33
|
raise if connection.open_transactions > 0
|
|
@@ -65,8 +65,8 @@ module Switchman
|
|
|
65
65
|
if reflection
|
|
66
66
|
if reflection.options[:polymorphic]
|
|
67
67
|
# a polymorphic association has to be discovered at runtime. This code ends up being something like
|
|
68
|
-
# context_type
|
|
69
|
-
"read_attribute(:#{reflection.foreign_type})
|
|
68
|
+
# context_type.&.constantize&.shard_category || :primary
|
|
69
|
+
"read_attribute(:#{reflection.foreign_type})&.constantize&.shard_category || :primary"
|
|
70
70
|
else
|
|
71
71
|
# otherwise we can just return a symbol for the statically known type of the association
|
|
72
72
|
reflection.klass.shard_category.inspect
|
|
@@ -33,7 +33,7 @@ module Switchman
|
|
|
33
33
|
|
|
34
34
|
def integral_id?
|
|
35
35
|
if @integral_id == nil
|
|
36
|
-
@integral_id = columns_hash[primary_key]
|
|
36
|
+
@integral_id = columns_hash[primary_key]&.type == :integer
|
|
37
37
|
end
|
|
38
38
|
@integral_id
|
|
39
39
|
end
|
|
@@ -105,7 +105,7 @@ module Switchman
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def scope_class
|
|
108
|
-
self.class.base_class
|
|
108
|
+
::Rails.version >= '5' ? self.class : self.class.base_class
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def save(*args)
|
|
@@ -138,7 +138,7 @@ module Switchman
|
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def hash
|
|
141
|
-
self.class.sharded_primary_key? ? Shard.global_id_for(id).hash : super
|
|
141
|
+
self.class.sharded_primary_key? ? self.class.hash ^ Shard.global_id_for(id).hash : super
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
def to_param
|
|
@@ -151,6 +151,14 @@ module Switchman
|
|
|
151
151
|
@shard_set_in_stone = false
|
|
152
152
|
copy
|
|
153
153
|
end
|
|
154
|
+
|
|
155
|
+
if ::Rails.version >= '5'
|
|
156
|
+
def quoted_id
|
|
157
|
+
return super unless self.class.sharded_primary_key?
|
|
158
|
+
# do this the Rails 4.2 way, so that if Shard.current != self.shard, the id gets transposed
|
|
159
|
+
self.class.connection.quote(id)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
154
162
|
end
|
|
155
163
|
end
|
|
156
164
|
end
|
|
@@ -40,10 +40,15 @@ module Switchman
|
|
|
40
40
|
Shard.default
|
|
41
41
|
|
|
42
42
|
# automatically change config to allow for sharing connections with simple config
|
|
43
|
-
|
|
43
|
+
config = ::Rails.version < '5.1' ? spec.config : pool.spec.config
|
|
44
|
+
ConnectionHandler.make_sharing_automagic(config)
|
|
44
45
|
ConnectionHandler.make_sharing_automagic(Shard.default.database_server.config)
|
|
45
46
|
|
|
46
|
-
::
|
|
47
|
+
if ::Rails.version < '5.1'
|
|
48
|
+
::ActiveRecord::Base.configurations[::Rails.env] = spec.instance_variable_get(:@config).stringify_keys
|
|
49
|
+
else
|
|
50
|
+
::ActiveRecord::Base.configurations[::Rails.env] = config.stringify_keys
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
@shard_connection_pools ||= { [:master, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
|
|
@@ -162,12 +167,13 @@ module Switchman
|
|
|
162
167
|
# A connection was established in an ancestor process that must have
|
|
163
168
|
# subsequently forked. We can't reuse the connection, but we can copy
|
|
164
169
|
# the specification and establish a new connection with it.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
pool = establish_connection ancestor_pool.default_pool.spec
|
|
170
|
+
spec = if ancestor_pool.is_a?(ConnectionPoolProxy)
|
|
171
|
+
ancestor_pool.default_pool.spec
|
|
168
172
|
else
|
|
169
|
-
|
|
173
|
+
ancestor_pool.spec
|
|
170
174
|
end
|
|
175
|
+
spec = spec.to_hash if ::Rails.version >= '5.1'
|
|
176
|
+
pool = establish_connection spec
|
|
171
177
|
pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
|
|
172
178
|
pool
|
|
173
179
|
elsif spec_name != "primary"
|
|
@@ -17,13 +17,16 @@ module Switchman
|
|
|
17
17
|
shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
|
|
18
18
|
|
|
19
19
|
unless (payload[:binds] || []).empty?
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
if ::Rails.version < '5'
|
|
21
|
+
binds = " " + payload[:binds].map { |col,v|
|
|
22
|
+
render_bind(col, v)
|
|
23
|
+
}.inspect
|
|
24
|
+
else
|
|
25
|
+
casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds])
|
|
26
|
+
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
|
27
|
+
render_bind(attr, value)
|
|
28
|
+
}.inspect
|
|
29
|
+
end
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
if ::Rails.version >= '5'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Switchman
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Migration
|
|
4
|
+
module Compatibility
|
|
5
|
+
module V5_0
|
|
6
|
+
def create_table(*args, **options)
|
|
7
|
+
unless options.key?(:id)
|
|
8
|
+
options[:id] = :bigserial
|
|
9
|
+
end
|
|
10
|
+
if block_given?
|
|
11
|
+
super do |td|
|
|
12
|
+
yield td
|
|
13
|
+
end
|
|
14
|
+
else
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def connection
|
|
22
|
+
conn = super
|
|
23
|
+
if conn.shard != ::ActiveRecord::Base.connection_pool.current_pool.shard
|
|
24
|
+
::ActiveRecord::Base.connection_pool.current_pool.switch_database(conn)
|
|
25
|
+
end
|
|
26
|
+
conn
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module Migrator
|
|
31
|
+
def generate_migrator_advisory_lock_id
|
|
32
|
+
shard_name_hash = Zlib.crc32(Shard.current.name)
|
|
33
|
+
::ActiveRecord::Migrator::MIGRATOR_SALT * shard_name_hash
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
module Switchman
|
|
2
2
|
module ActiveRecord
|
|
3
3
|
module PostgreSQLAdapter
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
if ::Rails.version < '5'
|
|
5
|
+
def self.prepended(klass)
|
|
6
|
+
klass::NATIVE_DATABASE_TYPES[:primary_key] = "bigserial primary key".freeze
|
|
7
|
+
end
|
|
6
8
|
end
|
|
7
9
|
|
|
8
10
|
# copy/paste; use quote_local_table_name
|
|
@@ -137,7 +139,7 @@ module Switchman
|
|
|
137
139
|
end.compact
|
|
138
140
|
end
|
|
139
141
|
|
|
140
|
-
def index_name_exists?(table_name, index_name,
|
|
142
|
+
def index_name_exists?(table_name, index_name, _default = nil)
|
|
141
143
|
schema = shard.name if use_qualified_names?
|
|
142
144
|
|
|
143
145
|
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
|
|
@@ -205,6 +207,12 @@ module Switchman
|
|
|
205
207
|
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(table_name, to_table, options)
|
|
206
208
|
end
|
|
207
209
|
end
|
|
210
|
+
|
|
211
|
+
def add_index_options(_table_name, _column_name, _options = {})
|
|
212
|
+
index_name, index_type, index_columns, index_options, algorithm, using = super
|
|
213
|
+
algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
|
|
214
|
+
[index_name, index_type, index_columns, index_options, algorithm, using]
|
|
215
|
+
end
|
|
208
216
|
end
|
|
209
217
|
end
|
|
210
218
|
end
|
|
@@ -1,99 +1,125 @@
|
|
|
1
1
|
module Switchman
|
|
2
2
|
module ActiveRecord
|
|
3
3
|
module QueryCache
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
if ::Rails.version < '5.0.1'
|
|
5
|
+
# thread local accessors to replace @query_cache_enabled
|
|
6
|
+
def query_cache
|
|
7
|
+
thread_cache = Thread.current[:query_cache] ||= {}
|
|
8
|
+
thread_cache[self.object_id] ||= Hash.new { |h,sql| h[sql] = {} }
|
|
9
|
+
end
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
def query_cache_enabled
|
|
12
|
+
Thread.current[:query_cache_enabled]
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
def query_cache_enabled=(value)
|
|
16
|
+
Thread.current[:query_cache_enabled] = value
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# basically wholesale repeat of the methods from the original (see
|
|
20
|
+
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb),
|
|
21
|
+
# but with self.query_cache_enabled and self.query_cache_enabled= instead
|
|
22
|
+
# of @query_cache_enabled.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
def enable_query_cache!
|
|
25
|
+
self.query_cache_enabled = true
|
|
26
|
+
end
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
def disable_query_cache!
|
|
29
|
+
self.query_cache_enabled = false
|
|
30
|
+
end
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
def cache
|
|
33
|
+
old, self.query_cache_enabled = query_cache_enabled, true
|
|
34
|
+
yield
|
|
35
|
+
ensure
|
|
36
|
+
self.query_cache_enabled = old
|
|
37
|
+
clear_query_cache unless self.query_cache_enabled
|
|
38
|
+
end
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
def uncached
|
|
41
|
+
old, self.query_cache_enabled = query_cache_enabled, false
|
|
42
|
+
yield
|
|
43
|
+
ensure
|
|
44
|
+
self.query_cache_enabled = old
|
|
45
|
+
end
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
def clear_query_cache
|
|
48
|
+
Thread.current[:query_cache]&.clear
|
|
49
|
+
end
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
else
|
|
60
|
-
if ::Rails.version >= '5'
|
|
61
|
-
super
|
|
51
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
|
52
|
+
if self.query_cache_enabled && !locked?(arel)
|
|
53
|
+
arel, binds = binds_from_relation(arel, binds)
|
|
54
|
+
sql = to_sql(arel, binds)
|
|
55
|
+
if ::Rails.version >= '5'
|
|
56
|
+
cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
|
|
57
|
+
else
|
|
58
|
+
cache_sql(sql, binds) { super(sql, name, binds) }
|
|
59
|
+
end
|
|
62
60
|
else
|
|
63
|
-
|
|
61
|
+
if ::Rails.version >= '5'
|
|
62
|
+
super
|
|
63
|
+
else
|
|
64
|
+
super(arel, name, binds)
|
|
65
|
+
end
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
|
-
end
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
# no reason to define these on the including class directly. the super
|
|
70
|
+
# works just as well from a method on the included module
|
|
71
|
+
[:insert, :update, :delete].each do |method_name|
|
|
72
|
+
class_eval <<-end_code, __FILE__, __LINE__ + 1
|
|
73
|
+
def #{method_name}(*args)
|
|
74
|
+
clear_query_cache if self.query_cache_enabled
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
end_code
|
|
78
|
+
end
|
|
77
79
|
end
|
|
78
80
|
|
|
79
81
|
private
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
if ::Rails.version < '5.1'
|
|
84
|
+
def cache_sql(sql, binds)
|
|
85
|
+
# have to include the shard id in the cache key because of switching dbs on the same connection
|
|
86
|
+
sql = "#{self.shard.id}::#{sql}"
|
|
87
|
+
result =
|
|
88
|
+
if query_cache[sql].key?(binds)
|
|
89
|
+
::ActiveSupport::Notifications.instrument("sql.active_record",
|
|
90
|
+
:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
|
|
91
|
+
query_cache[sql][binds]
|
|
92
|
+
else
|
|
93
|
+
query_cache[sql][binds] = yield
|
|
94
|
+
end
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
if ::ActiveRecord::Result === result
|
|
97
|
+
result.dup
|
|
98
|
+
else
|
|
99
|
+
result.collect { |row| row.dup }
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
def cache_sql(sql, name, binds)
|
|
104
|
+
# have to include the shard id in the cache key because of switching dbs on the same connection
|
|
105
|
+
sql = "#{self.shard.id}::#{sql}"
|
|
106
|
+
@lock.synchronize do
|
|
107
|
+
result =
|
|
108
|
+
if query_cache[sql].key?(binds)
|
|
109
|
+
::ActiveSupport::Notifications.instrument(
|
|
110
|
+
"sql.active_record",
|
|
111
|
+
sql: sql,
|
|
112
|
+
binds: binds,
|
|
113
|
+
name: name,
|
|
114
|
+
connection_id: object_id,
|
|
115
|
+
cached: true,
|
|
116
|
+
)
|
|
117
|
+
query_cache[sql][binds]
|
|
118
|
+
else
|
|
119
|
+
query_cache[sql][binds] = yield
|
|
120
|
+
end
|
|
121
|
+
result.dup
|
|
122
|
+
end
|
|
97
123
|
end
|
|
98
124
|
end
|
|
99
125
|
end
|
|
@@ -19,11 +19,11 @@ module Switchman
|
|
|
19
19
|
@values[:shard_source]
|
|
20
20
|
end
|
|
21
21
|
def shard_value=(value)
|
|
22
|
-
raise ImmutableRelation if @loaded
|
|
22
|
+
raise ::ActiveRecord::ImmutableRelation if @loaded
|
|
23
23
|
@values[:shard] = value
|
|
24
24
|
end
|
|
25
25
|
def shard_source_value=(value)
|
|
26
|
-
raise ImmutableRelation if @loaded
|
|
26
|
+
raise ::ActiveRecord::ImmutableRelation if @loaded
|
|
27
27
|
@values[:shard_source] = value
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -126,11 +126,18 @@ module Switchman
|
|
|
126
126
|
def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
|
127
127
|
if ::Rails.version >= '5'
|
|
128
128
|
unless (predicates = #{type}_clause.send(:predicates)).empty?
|
|
129
|
-
new_predicates = transpose_predicates(predicates, source_shard,
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
new_predicates, new_binds = transpose_predicates(predicates, source_shard,
|
|
130
|
+
target_shard, remove_nonlocal_primary_keys,
|
|
131
|
+
binds: #{type}_clause.binds,
|
|
132
|
+
dup_binds_on_mutation: true)
|
|
133
|
+
if new_predicates != predicates || !new_binds.equal?(#{type}_clause.binds)
|
|
132
134
|
self.#{type}_clause = #{type}_clause.dup
|
|
133
|
-
|
|
135
|
+
if new_predicates != predicates
|
|
136
|
+
#{type}_clause.instance_variable_set(:@predicates, new_predicates)
|
|
137
|
+
end
|
|
138
|
+
if !new_binds.equal?(#{type}_clause.binds)
|
|
139
|
+
#{type}_clause.instance_variable_set(:@binds, new_binds)
|
|
140
|
+
end
|
|
134
141
|
end
|
|
135
142
|
end
|
|
136
143
|
else
|
|
@@ -149,6 +156,8 @@ module Switchman
|
|
|
149
156
|
end
|
|
150
157
|
|
|
151
158
|
def infer_shards_from_primary_key(predicates, binds = nil)
|
|
159
|
+
return unless klass.integral_id?
|
|
160
|
+
|
|
152
161
|
primary_key = predicates.detect do |predicate|
|
|
153
162
|
predicate.is_a?(::Arel::Nodes::Binary) && predicate.left.is_a?(::Arel::Attributes::Attribute) &&
|
|
154
163
|
predicate.left.relation.is_a?(::Arel::Table) && predicate.left.relation.model == klass &&
|
|
@@ -181,15 +190,14 @@ module Switchman
|
|
|
181
190
|
when ::Arel::Nodes::BindParam
|
|
182
191
|
# look for a bind param with a matching column name
|
|
183
192
|
if ::Rails.version >= "5"
|
|
184
|
-
binds
|
|
185
|
-
if binds && bind = binds.detect{|b| b.try(:name).to_s == klass.primary_key.to_s}
|
|
193
|
+
if binds && bind = binds.detect{|b| b&.name.to_s == klass.primary_key.to_s}
|
|
186
194
|
unless bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
|
187
195
|
local_id, id_shard = Shard.local_id_for(bind.value)
|
|
188
196
|
id_shard ||= Shard.current(klass.shard_category) if local_id
|
|
189
197
|
end
|
|
190
198
|
end
|
|
191
199
|
else
|
|
192
|
-
if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first
|
|
200
|
+
if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first&.name.to_s == klass.primary_key.to_s}
|
|
193
201
|
column, value = bind_values[idx]
|
|
194
202
|
unless value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
|
195
203
|
local_id, id_shard = Shard.local_id_for(value)
|
|
@@ -268,8 +276,13 @@ module Switchman
|
|
|
268
276
|
|
|
269
277
|
# semi-private
|
|
270
278
|
public
|
|
271
|
-
def transpose_predicates(predicates,
|
|
272
|
-
|
|
279
|
+
def transpose_predicates(predicates,
|
|
280
|
+
source_shard,
|
|
281
|
+
target_shard,
|
|
282
|
+
remove_nonlocal_primary_keys = false,
|
|
283
|
+
binds: nil,
|
|
284
|
+
dup_binds_on_mutation: false)
|
|
285
|
+
result = predicates.map do |predicate|
|
|
273
286
|
next predicate unless predicate.is_a?(::Arel::Nodes::Binary)
|
|
274
287
|
next predicate unless predicate.left.is_a?(::Arel::Attributes::Attribute)
|
|
275
288
|
relation, column = relation_and_column(predicate.left)
|
|
@@ -312,8 +325,13 @@ module Switchman
|
|
|
312
325
|
when ::Arel::Nodes::BindParam
|
|
313
326
|
# look for a bind param with a matching column name
|
|
314
327
|
if ::Rails.version >= "5"
|
|
315
|
-
binds
|
|
316
|
-
|
|
328
|
+
if binds && bind = binds.detect{|b| b&.name.to_s == predicate.left.name.to_s}
|
|
329
|
+
# before we mutate, dup
|
|
330
|
+
if dup_binds_on_mutation
|
|
331
|
+
binds = binds.map(&:dup)
|
|
332
|
+
dup_binds_on_mutation = false
|
|
333
|
+
bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
|
|
334
|
+
end
|
|
317
335
|
if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
|
318
336
|
bind.value.sharded = true # mark for transposition later
|
|
319
337
|
bind.value.primary = true if type == :primary
|
|
@@ -325,7 +343,7 @@ module Switchman
|
|
|
325
343
|
end
|
|
326
344
|
end
|
|
327
345
|
else
|
|
328
|
-
if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first
|
|
346
|
+
if bind_values && idx = bind_values.find_index{|b| b.is_a?(Array) && b.first&.name.to_s == predicate.left.name.to_s}
|
|
329
347
|
column, value = bind_values[idx]
|
|
330
348
|
if value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
|
331
349
|
value.sharded = true # mark for transposition later
|
|
@@ -356,6 +374,8 @@ module Switchman
|
|
|
356
374
|
predicate.class.new(predicate.left, new_right_value)
|
|
357
375
|
end
|
|
358
376
|
end
|
|
377
|
+
result = [result, binds] if ::Rails.version >= '5'
|
|
378
|
+
result
|
|
359
379
|
end
|
|
360
380
|
end
|
|
361
381
|
end
|
|
@@ -44,12 +44,22 @@ module Switchman
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
if ::Rails.version < '5.1'
|
|
48
|
+
def generic_query_builder(connection)
|
|
49
|
+
@query_builder ||= connection.cacheable_query(@arel)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def qualified_query_builder(shard, klass)
|
|
53
|
+
@qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(@arel)
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
def generic_query_builder(connection)
|
|
57
|
+
@query_builder ||= connection.cacheable_query(self.class, @arel)
|
|
58
|
+
end
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
def qualified_query_builder(shard, klass)
|
|
61
|
+
@qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(self.class, @arel)
|
|
62
|
+
end
|
|
53
63
|
end
|
|
54
64
|
|
|
55
65
|
module BindMap
|
|
@@ -21,7 +21,7 @@ module Switchman
|
|
|
21
21
|
where_clause = super
|
|
22
22
|
predicates = where_clause.send(:predicates)
|
|
23
23
|
@scope.send(:infer_shards_from_primary_key, predicates, where_clause.binds) if @scope.shard_source_value == :implicit && @scope.shard_value.is_a?(Shard)
|
|
24
|
-
predicates = @scope.transpose_predicates(predicates, nil, @scope.primary_shard, false, where_clause.binds)
|
|
24
|
+
predicates, _new_binds = @scope.transpose_predicates(predicates, nil, @scope.primary_shard, false, binds: where_clause.binds)
|
|
25
25
|
where_clause.instance_variable_set(:@predicates, predicates)
|
|
26
26
|
where_clause
|
|
27
27
|
else
|
data/lib/switchman/call_super.rb
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module Switchman
|
|
2
2
|
module CallSuper
|
|
3
3
|
def super_method_above(method_name, above_module)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
end
|
|
10
|
-
method.super_method
|
|
4
|
+
method = method(method_name)
|
|
5
|
+
last_owner = method.owner
|
|
6
|
+
while method.owner != above_module
|
|
7
|
+
method = method.super_method
|
|
8
|
+
raise "Could not find super method ``#{method_name}' for #{self.class}" if method.owner == last_owner
|
|
11
9
|
end
|
|
10
|
+
method.super_method
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def call_super(method, above_module, *args, &block)
|
|
@@ -10,7 +10,7 @@ module Switchman
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
class ConnectionPoolProxy
|
|
13
|
-
delegate :spec, :connected?, :default_schema, :with_connection,
|
|
13
|
+
delegate :spec, :connected?, :default_schema, :with_connection, :query_cache_enabled, :active_connection?,
|
|
14
14
|
:to => :current_pool
|
|
15
15
|
|
|
16
16
|
attr_reader :category, :schema_cache
|
|
@@ -71,7 +71,12 @@ module Switchman
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
%w{release_connection disconnect!
|
|
74
|
+
%w{release_connection disconnect!
|
|
75
|
+
clear_reloadable_connections!
|
|
76
|
+
verify_active_connections!
|
|
77
|
+
clear_stale_cached_connections!
|
|
78
|
+
enable_query_cache!
|
|
79
|
+
disable_query_cache! }.each do |method|
|
|
75
80
|
class_eval(<<-EOS)
|
|
76
81
|
def #{method}
|
|
77
82
|
@connection_pools.values.each(&:#{method})
|
|
@@ -126,6 +131,9 @@ module Switchman
|
|
|
126
131
|
|
|
127
132
|
::ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec).tap do |pool|
|
|
128
133
|
pool.shard = shard
|
|
134
|
+
if ::Rails.version >= '5.0.1'
|
|
135
|
+
pool.enable_query_cache! if !@connection_pools.empty? && @connection_pools.first.last.query_cache_enabled
|
|
136
|
+
end
|
|
129
137
|
end
|
|
130
138
|
end
|
|
131
139
|
end
|
|
@@ -3,6 +3,8 @@ module Switchman
|
|
|
3
3
|
attr_accessor :id
|
|
4
4
|
|
|
5
5
|
class << self
|
|
6
|
+
attr_accessor :creating_new_shard
|
|
7
|
+
|
|
6
8
|
def all
|
|
7
9
|
database_servers.values
|
|
8
10
|
end
|
|
@@ -134,7 +136,7 @@ module Switchman
|
|
|
134
136
|
create_schema = options[:schema]
|
|
135
137
|
# look for another shard associated with this db
|
|
136
138
|
other_shard = self.shards.where("name<>':memory:' OR name IS NULL").order(:id).first
|
|
137
|
-
temp_name = other_shard
|
|
139
|
+
temp_name = other_shard&.name unless id == ::Rails.env
|
|
138
140
|
temp_name = Shard.default.name if id == ::Rails.env
|
|
139
141
|
|
|
140
142
|
case config[:adapter]
|
|
@@ -158,7 +160,7 @@ module Switchman
|
|
|
158
160
|
create_statement = lambda { "CREATE DATABASE #{name}" }
|
|
159
161
|
end
|
|
160
162
|
sharding_config = Switchman.config
|
|
161
|
-
config_create_statement = sharding_config[config[:adapter]]
|
|
163
|
+
config_create_statement = sharding_config[config[:adapter]]&.[](:create_statement)
|
|
162
164
|
config_create_statement ||= sharding_config[:create_statement]
|
|
163
165
|
if config_create_statement
|
|
164
166
|
create_commands = Array(config_create_statement).dup
|
|
@@ -173,6 +175,7 @@ module Switchman
|
|
|
173
175
|
shard.id = options[:id] if options[:id]
|
|
174
176
|
end
|
|
175
177
|
begin
|
|
178
|
+
self.class.creating_new_shard = true
|
|
176
179
|
if name.nil?
|
|
177
180
|
base_name = self.config[:database] % self.config
|
|
178
181
|
base_name = $1 if base_name =~ /(?:.*\/)(.+)_shard_\d+(?:\.sqlite3)?$/
|
|
@@ -233,6 +236,8 @@ module Switchman
|
|
|
233
236
|
shard.drop_database if shard.name == name rescue nil
|
|
234
237
|
reset_column_information unless create_schema == false rescue nil
|
|
235
238
|
raise
|
|
239
|
+
ensure
|
|
240
|
+
self.class.creating_new_shard = false
|
|
236
241
|
end
|
|
237
242
|
end
|
|
238
243
|
|
data/lib/switchman/engine.rb
CHANGED
|
@@ -2,7 +2,7 @@ module Switchman
|
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
3
|
isolate_namespace Switchman
|
|
4
4
|
|
|
5
|
-
config.autoload_once_paths << File.expand_path(
|
|
5
|
+
config.autoload_once_paths << File.expand_path("app/models", config.paths.path)
|
|
6
6
|
|
|
7
7
|
def self.lookup_stores(cache_store_config)
|
|
8
8
|
result = {}
|
|
@@ -72,6 +72,7 @@ module Switchman
|
|
|
72
72
|
require "switchman/active_record/connection_pool"
|
|
73
73
|
require "switchman/active_record/finder_methods"
|
|
74
74
|
require "switchman/active_record/log_subscriber"
|
|
75
|
+
require "switchman/active_record/migration"
|
|
75
76
|
require "switchman/active_record/model_schema"
|
|
76
77
|
require "switchman/active_record/persistence"
|
|
77
78
|
require "switchman/active_record/predicate_builder"
|
|
@@ -87,7 +88,7 @@ module Switchman
|
|
|
87
88
|
require "switchman/call_super"
|
|
88
89
|
require "switchman/rails"
|
|
89
90
|
require "switchman/shackles/relation"
|
|
90
|
-
|
|
91
|
+
require_dependency "switchman/shard_internal"
|
|
91
92
|
require "switchman/standard_error"
|
|
92
93
|
|
|
93
94
|
::StandardError.include(StandardError)
|
|
@@ -124,9 +125,15 @@ module Switchman
|
|
|
124
125
|
# we want it to find the definition from
|
|
125
126
|
# ActiveRecord::ConnectionAdapters::DatabaseStatements, not
|
|
126
127
|
# ActiveRecord::ConnectionAdapters::QueryCache
|
|
127
|
-
::ActiveRecord::ConnectionAdapters::QueryCache.send(:remove_method, :select_all)
|
|
128
|
+
::ActiveRecord::ConnectionAdapters::QueryCache.send(:remove_method, :select_all) if ::Rails.version < '5.0.1'
|
|
128
129
|
|
|
129
130
|
::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
|
|
131
|
+
::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
|
|
132
|
+
if ::Rails.version >= '5'
|
|
133
|
+
::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
|
|
134
|
+
end
|
|
135
|
+
::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
|
|
136
|
+
|
|
130
137
|
::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
|
|
131
138
|
::ActiveRecord::Reflection::AssociationReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
|
|
132
139
|
::ActiveRecord::Reflection::ThroughReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
|
|
@@ -118,7 +118,8 @@ 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
|
|
121
|
+
if ::Rails.version >= '5.1' ? use_transactional_tests :
|
|
122
|
+
(::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
|
|
122
123
|
Shard.default(true)
|
|
123
124
|
@shard1 = Shard.find(@shard1.id)
|
|
124
125
|
@shard2 = Shard.find(@shard2.id)
|
|
@@ -134,7 +135,8 @@ module Switchman
|
|
|
134
135
|
|
|
135
136
|
klass.after do
|
|
136
137
|
next if @@sharding_failed
|
|
137
|
-
if
|
|
138
|
+
if ::Rails.version >= '5.1' ? use_transactional_tests :
|
|
139
|
+
(::Rails.version >= '5' && use_transactional_tests) || use_transactional_fixtures
|
|
138
140
|
shards = [@shard2]
|
|
139
141
|
shards << @shard1 unless @shard1.database_server == Shard.default.database_server
|
|
140
142
|
shards.each do |shard|
|
|
@@ -6,7 +6,7 @@ module Switchman
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def instrument(name, payload={})
|
|
9
|
-
shard = @shard_host
|
|
9
|
+
shard = @shard_host&.shard
|
|
10
10
|
# attribute_methods_generated? will be false during a reload -
|
|
11
11
|
# when we might be doing a query while defining attribute methods,
|
|
12
12
|
# so just avoid logging then
|
data/lib/switchman/version.rb
CHANGED
data/lib/tasks/switchman.rake
CHANGED
|
@@ -60,21 +60,23 @@ module Switchman
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
::Shackles.activate(:deploy) do
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
Shard.default.database_server.unshackle do
|
|
64
|
+
begin
|
|
65
|
+
categories = categories.call if categories.respond_to?(:call)
|
|
66
|
+
Shard.with_each_shard(scope, categories, options) do
|
|
67
|
+
shard = Shard.current
|
|
68
|
+
puts "#{shard.id}: #{shard.description}"
|
|
69
|
+
::ActiveRecord::Base.connection_pool.spec.config[:shard_name] = Shard.current.name
|
|
70
|
+
::ActiveRecord::Base.configurations[::Rails.env] = ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys
|
|
71
|
+
shard.database_server.unshackle do
|
|
72
|
+
old_actions.each { |action| action.call(*task_args) }
|
|
73
|
+
end
|
|
74
|
+
nil
|
|
72
75
|
end
|
|
73
|
-
|
|
76
|
+
rescue => e
|
|
77
|
+
puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
|
|
78
|
+
raise
|
|
74
79
|
end
|
|
75
|
-
rescue => e
|
|
76
|
-
puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
|
|
77
|
-
raise
|
|
78
80
|
end
|
|
79
81
|
end
|
|
80
82
|
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.10.0
|
|
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-06-15 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: railties
|
|
@@ -19,9 +19,9 @@ dependencies:
|
|
|
19
19
|
- - ">="
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '4.2'
|
|
22
|
-
- - "
|
|
22
|
+
- - "<"
|
|
23
23
|
- !ruby/object:Gem::Version
|
|
24
|
-
version: '5.
|
|
24
|
+
version: '5.2'
|
|
25
25
|
type: :runtime
|
|
26
26
|
prerelease: false
|
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -29,9 +29,9 @@ dependencies:
|
|
|
29
29
|
- - ">="
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '4.2'
|
|
32
|
-
- - "
|
|
32
|
+
- - "<"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '5.
|
|
34
|
+
version: '5.2'
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
36
|
name: activerecord
|
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,9 +39,9 @@ dependencies:
|
|
|
39
39
|
- - ">="
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '4.2'
|
|
42
|
-
- - "
|
|
42
|
+
- - "<"
|
|
43
43
|
- !ruby/object:Gem::Version
|
|
44
|
-
version: '5.
|
|
44
|
+
version: '5.2'
|
|
45
45
|
type: :runtime
|
|
46
46
|
prerelease: false
|
|
47
47
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -49,23 +49,23 @@ dependencies:
|
|
|
49
49
|
- - ">="
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '4.2'
|
|
52
|
-
- - "
|
|
52
|
+
- - "<"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '5.
|
|
54
|
+
version: '5.2'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: shackles
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 1.3
|
|
61
|
+
version: '1.3'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 1.3
|
|
68
|
+
version: '1.3'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: open4
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -86,14 +86,14 @@ dependencies:
|
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: 2.1
|
|
89
|
+
version: '2.1'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: 2.1
|
|
96
|
+
version: '2.1'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
98
|
name: byebug
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -108,20 +108,6 @@ dependencies:
|
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: mysql2
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - "~>"
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '0.3'
|
|
118
|
-
type: :development
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - "~>"
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '0.3'
|
|
125
111
|
- !ruby/object:Gem::Dependency
|
|
126
112
|
name: pg
|
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,14 +128,14 @@ dependencies:
|
|
|
142
128
|
requirements:
|
|
143
129
|
- - '='
|
|
144
130
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: 3.
|
|
131
|
+
version: 3.5.2
|
|
146
132
|
type: :development
|
|
147
133
|
prerelease: false
|
|
148
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
135
|
requirements:
|
|
150
136
|
- - '='
|
|
151
137
|
- !ruby/object:Gem::Version
|
|
152
|
-
version: 3.
|
|
138
|
+
version: 3.5.2
|
|
153
139
|
- !ruby/object:Gem::Dependency
|
|
154
140
|
name: sqlite3
|
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,14 +156,14 @@ dependencies:
|
|
|
170
156
|
requirements:
|
|
171
157
|
- - "~>"
|
|
172
158
|
- !ruby/object:Gem::Version
|
|
173
|
-
version: '
|
|
159
|
+
version: '12.0'
|
|
174
160
|
type: :development
|
|
175
161
|
prerelease: false
|
|
176
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
163
|
requirements:
|
|
178
164
|
- - "~>"
|
|
179
165
|
- !ruby/object:Gem::Version
|
|
180
|
-
version: '
|
|
166
|
+
version: '12.0'
|
|
181
167
|
description: Sharding
|
|
182
168
|
email:
|
|
183
169
|
- cody@instructure.com
|
|
@@ -203,6 +189,7 @@ files:
|
|
|
203
189
|
- lib/switchman/active_record/connection_pool.rb
|
|
204
190
|
- lib/switchman/active_record/finder_methods.rb
|
|
205
191
|
- lib/switchman/active_record/log_subscriber.rb
|
|
192
|
+
- lib/switchman/active_record/migration.rb
|
|
206
193
|
- lib/switchman/active_record/model_schema.rb
|
|
207
194
|
- lib/switchman/active_record/persistence.rb
|
|
208
195
|
- lib/switchman/active_record/postgresql_adapter.rb
|
|
@@ -256,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
256
243
|
version: '0'
|
|
257
244
|
requirements: []
|
|
258
245
|
rubyforge_project:
|
|
259
|
-
rubygems_version: 2.
|
|
246
|
+
rubygems_version: 2.6.11
|
|
260
247
|
signing_key:
|
|
261
248
|
specification_version: 4
|
|
262
249
|
summary: Rails 4 sharding magic
|