switchman 3.5.11 → 3.5.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/switchman/active_record/abstract_adapter.rb +4 -2
- data/lib/switchman/active_record/associations.rb +42 -5
- data/lib/switchman/active_record/base.rb +12 -4
- data/lib/switchman/active_record/connection_handler.rb +18 -0
- data/lib/switchman/active_record/connection_pool.rb +13 -11
- data/lib/switchman/active_record/database_configurations.rb +19 -7
- data/lib/switchman/active_record/finder_methods.rb +44 -14
- data/lib/switchman/active_record/log_subscriber.rb +9 -3
- data/lib/switchman/active_record/migration.rb +24 -7
- data/lib/switchman/active_record/persistence.rb +4 -0
- data/lib/switchman/active_record/query_cache.rb +49 -20
- data/lib/switchman/active_record/query_methods.rb +2 -2
- data/lib/switchman/active_record/test_fixtures.rb +14 -7
- data/lib/switchman/arel.rb +18 -16
- data/lib/switchman/database_server.rb +5 -1
- data/lib/switchman/engine.rb +4 -1
- data/lib/switchman/shard.rb +15 -4
- data/lib/switchman/test_helper.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- metadata +12 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0ab0712ea0711e482d32ddf5ce6ec740b399b6dc8074ea86eaaa092c13bbdd1
|
4
|
+
data.tar.gz: a3e43929c88727da33b2954966f7cf357bd2b8793eed33563f57908839e2d97d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67a005a7e156773576077ade7723e1500d291e782cdfb4af9662cef6ba2a217b2e0743aaea8a5e8bffc1777295baf465f9d7678f6d8fa6c681215b1ad9c5817a
|
7
|
+
data.tar.gz: 7e72531b558a3fc0d447d63efeec37b5a0480ebe873ff2e76fb6334927aee10d5342a92b0be8336bd324da57c2df6ff154b5efb2d88b5cc0e9e7b16f60bc6c78
|
@@ -298,11 +298,48 @@ module Switchman
|
|
298
298
|
record.has_attribute?(reflection.foreign_key) && record.send(reflection.foreign_key) != key
|
299
299
|
end
|
300
300
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
301
|
+
if ::Rails.version < "7.1"
|
302
|
+
def save_belongs_to_association(reflection)
|
303
|
+
# this seems counter-intuitive, but the autosave code will assign to attribute bypassing switchman,
|
304
|
+
# after reading the id attribute _without_ bypassing switchman. So we need Shard.current for the
|
305
|
+
# category of the associated record to match Shard.current for the category of self
|
306
|
+
shard.activate(connection_class_for_self_for_reflection(reflection)) { super }
|
307
|
+
end
|
308
|
+
else
|
309
|
+
def save_belongs_to_association(reflection)
|
310
|
+
association = association_instance_get(reflection.name)
|
311
|
+
return unless association&.loaded? && !association.stale_target?
|
312
|
+
|
313
|
+
record = association.load_target
|
314
|
+
return unless record && !record.destroyed?
|
315
|
+
|
316
|
+
autosave = reflection.options[:autosave]
|
317
|
+
|
318
|
+
if autosave && record.marked_for_destruction?
|
319
|
+
foreign_key = Array(reflection.foreign_key)
|
320
|
+
foreign_key.each { |key| self[key] = nil }
|
321
|
+
record.destroy
|
322
|
+
elsif autosave != false
|
323
|
+
if record.new_record? || (autosave && record.changed_for_autosave?)
|
324
|
+
saved = record.save(validate: !autosave)
|
325
|
+
end
|
326
|
+
|
327
|
+
if association.updated?
|
328
|
+
primary_key = Array(compute_primary_key(reflection, record)).map(&:to_s)
|
329
|
+
foreign_key = Array(reflection.foreign_key)
|
330
|
+
|
331
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
332
|
+
primary_key_foreign_key_pairs.each do |pk, fk|
|
333
|
+
# Notable change: add relative_id_for here
|
334
|
+
association_id = Shard.relative_id_for(record._read_attribute(pk), record.shard, shard)
|
335
|
+
self[fk] = association_id unless self[fk] == association_id
|
336
|
+
end
|
337
|
+
association.loaded!
|
338
|
+
end
|
339
|
+
|
340
|
+
saved if autosave
|
341
|
+
end
|
342
|
+
end
|
306
343
|
end
|
307
344
|
end
|
308
345
|
end
|
@@ -57,7 +57,7 @@ module Switchman
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def clear_query_caches_for_current_thread
|
60
|
-
::ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
|
60
|
+
::ActiveRecord::Base.connection_handler.connection_pool_list(:all).each do |pool|
|
61
61
|
pool.connection(switch_shard: false).clear_query_cache if pool.active_connection?
|
62
62
|
end
|
63
63
|
end
|
@@ -158,7 +158,15 @@ module Switchman
|
|
158
158
|
end
|
159
159
|
|
160
160
|
@loaded_from_shard ||= Shard.current(self.class.connection_class_for_self)
|
161
|
-
|
161
|
+
if shadow_record? && !Switchman.config[:writable_shadow_records]
|
162
|
+
@readonly = true
|
163
|
+
@readonly_from_shadow ||= true
|
164
|
+
end
|
165
|
+
super
|
166
|
+
end
|
167
|
+
|
168
|
+
def readonly!
|
169
|
+
@readonly_from_shadow = false
|
162
170
|
super
|
163
171
|
end
|
164
172
|
|
@@ -257,9 +265,9 @@ module Switchman
|
|
257
265
|
result
|
258
266
|
end
|
259
267
|
|
260
|
-
def transaction(
|
268
|
+
def transaction(...)
|
261
269
|
shard.activate(self.class.connection_class_for_self) do
|
262
|
-
self.class.transaction(
|
270
|
+
self.class.transaction(...)
|
263
271
|
end
|
264
272
|
end
|
265
273
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionHandler
|
6
|
+
def resolve_pool_config(config, connection_name, role, shard)
|
7
|
+
ret = super
|
8
|
+
# Make *all* pool configs use the same schema reflection
|
9
|
+
ret.schema_reflection = ConnectionHandler.global_schema_reflection
|
10
|
+
ret
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.global_schema_reflection
|
14
|
+
@global_schema_reflection ||= ::ActiveRecord::ConnectionAdapters::SchemaReflection.new(nil)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -3,22 +3,24 @@
|
|
3
3
|
module Switchman
|
4
4
|
module ActiveRecord
|
5
5
|
module ConnectionPool
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
if ::Rails.version < "7.1"
|
7
|
+
def get_schema_cache(connection)
|
8
|
+
self.schema_cache ||= SharedSchemaCache.get_schema_cache(connection)
|
9
|
+
self.schema_cache.connection = connection
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
self.schema_cache
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
# rubocop:disable Naming/AccessorMethodName override method
|
15
|
+
def set_schema_cache(cache)
|
16
|
+
schema_cache = get_schema_cache(cache.connection)
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
cache.instance_variables.each do |x|
|
19
|
+
schema_cache.instance_variable_set(x, cache.instance_variable_get(x))
|
20
|
+
end
|
19
21
|
end
|
22
|
+
# rubocop:enable Naming/AccessorMethodName override method
|
20
23
|
end
|
21
|
-
# rubocop:enable Naming/AccessorMethodName override method
|
22
24
|
|
23
25
|
def default_schema
|
24
26
|
connection unless @schemas
|
@@ -7,14 +7,26 @@ module Switchman
|
|
7
7
|
# since all should point to the same data, even if multiple are writable
|
8
8
|
# (Picks 'primary' since it is guaranteed to exist and switchman handles activating
|
9
9
|
# deploy through other means)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
if ::Rails.version < "7.1"
|
11
|
+
def configs_for(include_replicas: false, name: nil, **)
|
12
|
+
res = super
|
13
|
+
if name && !include_replicas
|
14
|
+
return nil unless name.end_with?("primary")
|
15
|
+
elsif !include_replicas
|
16
|
+
return res.select { |config| config.name.end_with?("primary") }
|
17
|
+
end
|
18
|
+
res
|
19
|
+
end
|
20
|
+
else
|
21
|
+
def configs_for(include_hidden: false, name: nil, **)
|
22
|
+
res = super
|
23
|
+
if name && !include_hidden
|
24
|
+
return nil unless name.end_with?("primary")
|
25
|
+
elsif !include_hidden
|
26
|
+
return res.select { |config| config.name.end_with?("primary") }
|
27
|
+
end
|
28
|
+
res
|
16
29
|
end
|
17
|
-
res
|
18
30
|
end
|
19
31
|
|
20
32
|
private
|
@@ -42,26 +42,56 @@ module Switchman
|
|
42
42
|
primary_shard.activate { super }
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
conditions =
|
47
|
-
|
45
|
+
if ::Rails.version < "7.1"
|
46
|
+
def exists?(conditions = :none)
|
47
|
+
conditions = conditions.id if ::ActiveRecord::Base === conditions
|
48
|
+
return false unless conditions
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
relation = apply_join_dependency(eager_loading: false)
|
51
|
+
return false if ::ActiveRecord::NullRelation === relation
|
51
52
|
|
52
|
-
|
53
|
+
relation = relation.except(:select, :order).select("1 AS one").limit(1)
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
case conditions
|
56
|
+
when Array, Hash
|
57
|
+
relation = relation.where(conditions)
|
58
|
+
else
|
59
|
+
relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
|
60
|
+
end
|
61
|
+
|
62
|
+
relation.activate do |shard_rel|
|
63
|
+
return true if connection.select_value(shard_rel.arel, "#{name} Exists")
|
64
|
+
end
|
65
|
+
false
|
59
66
|
end
|
67
|
+
else
|
68
|
+
def exists?(conditions = :none)
|
69
|
+
return false if @none
|
70
|
+
|
71
|
+
if Base === conditions
|
72
|
+
raise ArgumentError, <<-TEXT.squish
|
73
|
+
You are passing an instance of ActiveRecord::Base to `exists?`.
|
74
|
+
Please pass the id of the object by calling `.id`.
|
75
|
+
TEXT
|
76
|
+
end
|
60
77
|
|
61
|
-
|
62
|
-
|
78
|
+
return false if !conditions || limit_value == 0 # rubocop:disable Style/NumericPredicate
|
79
|
+
|
80
|
+
if eager_loading?
|
81
|
+
relation = apply_join_dependency(eager_loading: false)
|
82
|
+
return relation.exists?(conditions)
|
83
|
+
end
|
84
|
+
|
85
|
+
relation = construct_relation_for_exists(conditions)
|
86
|
+
return false if relation.where_clause.contradiction?
|
87
|
+
|
88
|
+
relation.activate do |shard_rel|
|
89
|
+
return true if skip_query_cache_if_necessary do
|
90
|
+
connection.select_rows(shard_rel.arel, "#{name} Exists?").size == 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
false
|
63
94
|
end
|
64
|
-
false
|
65
95
|
end
|
66
96
|
end
|
67
97
|
end
|
@@ -5,8 +5,10 @@ module Switchman
|
|
5
5
|
module LogSubscriber
|
6
6
|
# sadly, have to completely replace this
|
7
7
|
def sql(event)
|
8
|
-
|
9
|
-
|
8
|
+
if ::Rails.version < "7.1"
|
9
|
+
self.class.runtime += event.duration
|
10
|
+
return unless logger.debug?
|
11
|
+
end
|
10
12
|
|
11
13
|
payload = event.payload
|
12
14
|
|
@@ -27,7 +29,11 @@ module Switchman
|
|
27
29
|
end
|
28
30
|
|
29
31
|
name = colorize_payload_name(name, payload[:name])
|
30
|
-
sql =
|
32
|
+
sql = if ::Rails.version < "7.1"
|
33
|
+
color(sql, sql_color(sql), true)
|
34
|
+
else
|
35
|
+
color(sql, sql_color(sql), bold: true)
|
36
|
+
end
|
31
37
|
|
32
38
|
debug " #{name} #{sql}#{binds}#{shard}"
|
33
39
|
end
|
@@ -29,7 +29,11 @@ module Switchman
|
|
29
29
|
db_name_hash = Zlib.crc32(Shard.current.name)
|
30
30
|
shard_name_hash = ::ActiveRecord::Migrator::MIGRATOR_SALT * db_name_hash
|
31
31
|
# Store in internalmetadata to allow other tools to be able to lock out migrations
|
32
|
-
::
|
32
|
+
if ::Rails.version < "7.1"
|
33
|
+
::ActiveRecord::InternalMetadata[:migrator_advisory_lock_id] = shard_name_hash
|
34
|
+
else
|
35
|
+
::ActiveRecord::InternalMetadata.new(connection)[:migrator_advisory_lock_id] = shard_name_hash
|
36
|
+
end
|
33
37
|
shard_name_hash
|
34
38
|
end
|
35
39
|
|
@@ -48,17 +52,30 @@ module Switchman
|
|
48
52
|
module MigrationContext
|
49
53
|
def migrate(...)
|
50
54
|
connection = ::ActiveRecord::Base.connection
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
schema_cache_holder = ::ActiveRecord::Base.connection_pool
|
56
|
+
schema_cache_holder = schema_cache_holder.schema_reflection if ::Rails.version >= "7.1"
|
57
|
+
previous_schema_cache = if ::Rails.version < "7.1"
|
58
|
+
schema_cache_holder.get_schema_cache(connection)
|
59
|
+
else
|
60
|
+
schema_cache_holder.instance_variable_get(:@cache)
|
61
|
+
end
|
62
|
+
|
63
|
+
if ::Rails.version < "7.1"
|
64
|
+
temporary_schema_cache = ::ActiveRecord::ConnectionAdapters::SchemaCache.new(connection)
|
65
|
+
|
66
|
+
reset_column_information
|
67
|
+
schema_cache_holder.set_schema_cache(temporary_schema_cache)
|
68
|
+
else
|
69
|
+
schema_cache_holder.instance_variable_get(:@cache)
|
54
70
|
|
55
|
-
|
56
|
-
|
71
|
+
reset_column_information
|
72
|
+
schema_cache_holder.clear!
|
73
|
+
end
|
57
74
|
|
58
75
|
begin
|
59
76
|
super(...)
|
60
77
|
ensure
|
61
|
-
|
78
|
+
schema_cache_holder.set_schema_cache(previous_schema_cache)
|
62
79
|
reset_column_information
|
63
80
|
end
|
64
81
|
end
|
@@ -34,6 +34,10 @@ module Switchman
|
|
34
34
|
# When a shadow record is reloaded the real record is returned. So
|
35
35
|
# we need to ensure the loaded_from_shard is set correctly after a reload.
|
36
36
|
@loaded_from_shard = @shard
|
37
|
+
if @readonly_from_shadow
|
38
|
+
@readonly_from_shadow = false
|
39
|
+
@readonly = false
|
40
|
+
end
|
37
41
|
res
|
38
42
|
end
|
39
43
|
|
@@ -5,28 +5,57 @@ module Switchman
|
|
5
5
|
module QueryCache
|
6
6
|
private
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
8
|
+
if ::Rails.version < "7.1"
|
9
|
+
def cache_sql(sql, name, binds)
|
10
|
+
# have to include the shard id in the cache key because of switching dbs on the same connection
|
11
|
+
sql = "#{shard.id}::#{sql}"
|
12
|
+
@lock.synchronize do
|
13
|
+
result =
|
14
|
+
if query_cache[sql].key?(binds)
|
15
|
+
args = {
|
16
|
+
sql: sql,
|
17
|
+
binds: binds,
|
18
|
+
name: name,
|
19
|
+
connection_id: object_id,
|
20
|
+
cached: true,
|
21
|
+
type_casted_binds: -> { type_casted_binds(binds) }
|
22
|
+
}
|
23
|
+
::ActiveSupport::Notifications.instrument(
|
24
|
+
"sql.active_record",
|
25
|
+
args
|
26
|
+
)
|
27
|
+
query_cache[sql][binds]
|
28
|
+
else
|
29
|
+
query_cache[sql][binds] = yield
|
30
|
+
end
|
31
|
+
result.dup
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
def cache_sql(sql, name, binds)
|
36
|
+
# have to include the shard id in the cache key because of switching dbs on the same connection
|
37
|
+
sql = "#{shard.id}::#{sql}"
|
38
|
+
key = binds.empty? ? sql : [sql, binds]
|
39
|
+
result = nil
|
40
|
+
hit = false
|
41
|
+
|
42
|
+
@lock.synchronize do
|
43
|
+
if (result = @query_cache.delete(key))
|
44
|
+
hit = true
|
45
|
+
@query_cache[key] = result
|
27
46
|
else
|
28
|
-
query_cache[
|
47
|
+
result = @query_cache[key] = yield
|
48
|
+
@query_cache.shift if @query_cache_max_size && @query_cache.size > @query_cache_max_size
|
29
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if hit
|
53
|
+
::ActiveSupport::Notifications.instrument(
|
54
|
+
"sql.active_record",
|
55
|
+
cache_notification_info(sql, name, binds)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
30
59
|
result.dup
|
31
60
|
end
|
32
61
|
end
|
@@ -175,7 +175,7 @@ module Switchman
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def sharded_foreign_key?(relation, column)
|
178
|
-
models_for_table(relation.
|
178
|
+
models_for_table(relation.name).any? { |m| m.sharded_column?(column) }
|
179
179
|
end
|
180
180
|
|
181
181
|
def sharded_primary_key?(relation, column)
|
@@ -187,7 +187,7 @@ module Switchman
|
|
187
187
|
|
188
188
|
def source_shard_for_foreign_key(relation, column)
|
189
189
|
reflection = nil
|
190
|
-
models_for_table(relation.
|
190
|
+
models_for_table(relation.name).each do |model|
|
191
191
|
reflection = model.send(:reflection_for_integer_attribute, column)
|
192
192
|
break if reflection
|
193
193
|
end
|
@@ -14,21 +14,28 @@ module Switchman
|
|
14
14
|
# Code adapted from the code in rails proper
|
15
15
|
@connection_subscriber =
|
16
16
|
::ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
17
|
-
spec_name =
|
17
|
+
spec_name = if ::Rails.version < "7.1"
|
18
|
+
payload[:spec_name] if payload.key?(:spec_name)
|
19
|
+
elsif payload.key?(:connection_name)
|
20
|
+
payload[:connection_name]
|
21
|
+
end
|
18
22
|
shard = payload[:shard] if payload.key?(:shard)
|
19
|
-
setup_shared_connection_pool
|
20
23
|
|
21
24
|
if spec_name && !FORBIDDEN_DB_ENVS.include?(shard)
|
22
25
|
begin
|
23
26
|
connection = ::ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
|
27
|
+
connection.connect! if ::Rails.version >= "7.1" # eagerly validate the connection
|
24
28
|
rescue ::ActiveRecord::ConnectionNotEstablished, ::ActiveRecord::NoDatabaseError
|
25
29
|
connection = nil
|
26
30
|
end
|
27
31
|
|
28
|
-
if connection
|
29
|
-
|
30
|
-
connection
|
31
|
-
|
32
|
+
if connection
|
33
|
+
setup_shared_connection_pool
|
34
|
+
unless @fixture_connections.include?(connection)
|
35
|
+
connection.begin_transaction joinable: false, _lazy: false
|
36
|
+
connection.pool.lock_thread = true if lock_threads
|
37
|
+
@fixture_connections << connection
|
38
|
+
end
|
32
39
|
end
|
33
40
|
end
|
34
41
|
end
|
@@ -37,7 +44,7 @@ module Switchman
|
|
37
44
|
def enlist_fixture_connections
|
38
45
|
setup_shared_connection_pool
|
39
46
|
|
40
|
-
::ActiveRecord::Base.connection_handler.connection_pool_list.reject do |cp|
|
47
|
+
::ActiveRecord::Base.connection_handler.connection_pool_list(:primary).reject do |cp|
|
41
48
|
FORBIDDEN_DB_ENVS.include?(cp.db_config.env_name.to_sym)
|
42
49
|
end.map(&:connection)
|
43
50
|
end
|
data/lib/switchman/arel.rb
CHANGED
@@ -24,27 +24,29 @@ module Switchman
|
|
24
24
|
collector << quote_local_table_name(join_name) << "." << quote_column_name(o.name)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
if ::Rails.version < "7.1"
|
28
|
+
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
29
|
+
collector.preparable = false
|
29
30
|
|
30
|
-
|
31
|
+
collector << quote_local_table_name(o.table_name) << "." << quote_column_name(o.column_name)
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
collector << if o.type == :in
|
34
|
+
" IN ("
|
35
|
+
else
|
36
|
+
" NOT IN ("
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
+
values = o.casted_values
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
if values.empty?
|
42
|
+
collector << @connection.quote(nil)
|
43
|
+
else
|
44
|
+
collector.add_binds(values, o.proc_for_binds, &bind_block)
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
collector << ")"
|
48
|
+
collector
|
49
|
+
end
|
48
50
|
end
|
49
51
|
|
50
52
|
# rubocop:enable Naming/MethodName
|
@@ -228,7 +228,11 @@ module Switchman
|
|
228
228
|
unless schema == false
|
229
229
|
shard.activate do
|
230
230
|
::ActiveRecord::Base.connection.transaction(requires_new: true) do
|
231
|
-
::
|
231
|
+
if ::Rails.version < "7.1"
|
232
|
+
::ActiveRecord::Base.connection.migration_context.migrate
|
233
|
+
else
|
234
|
+
::ActiveRecord::MigrationContext.new(::ActiveRecord::Migrator.migrations_paths).migrate
|
235
|
+
end
|
232
236
|
end
|
233
237
|
|
234
238
|
::ActiveRecord::Base.descendants.reject do |m|
|
data/lib/switchman/engine.rb
CHANGED
@@ -5,7 +5,7 @@ module Switchman
|
|
5
5
|
isolate_namespace Switchman
|
6
6
|
|
7
7
|
# enable Rails 6.1 style connection handling
|
8
|
-
config.active_record.legacy_connection_handling = false
|
8
|
+
config.active_record.legacy_connection_handling = false if ::Rails.version < "7.1"
|
9
9
|
config.active_record.writing_role = :primary
|
10
10
|
|
11
11
|
::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
|
@@ -60,6 +60,9 @@ module Switchman
|
|
60
60
|
)
|
61
61
|
end
|
62
62
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
|
63
|
+
unless ::Rails.version < "7.1"
|
64
|
+
::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
|
65
|
+
end
|
63
66
|
::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
|
64
67
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
|
65
68
|
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
|
data/lib/switchman/shard.rb
CHANGED
@@ -166,7 +166,11 @@ module Switchman
|
|
166
166
|
# clear connections prior to forking (no more queries will be executed in the parent,
|
167
167
|
# and we want them gone so that we don't accidentally use them post-fork doing something
|
168
168
|
# silly like dealloc'ing prepared statements)
|
169
|
-
::
|
169
|
+
if ::Rails.version < "7.1"
|
170
|
+
::ActiveRecord::Base.clear_all_connections!(nil)
|
171
|
+
else
|
172
|
+
::ActiveRecord::Base.connection_handler.clear_all_connections!(:all)
|
173
|
+
end
|
170
174
|
|
171
175
|
parent_process_name = sanitized_process_title
|
172
176
|
ret = ::Parallel.map(scopes, in_processes: (scopes.length > 1) ? parallel : 0) do |server, subscope|
|
@@ -258,7 +262,7 @@ module Switchman
|
|
258
262
|
else
|
259
263
|
shard = partition_object.shard
|
260
264
|
end
|
261
|
-
when Integer,
|
265
|
+
when Integer, /\A\d+\Z/, /\A(\d+)~(\d+)\Z/
|
262
266
|
local_id, shard = Shard.local_id_for(partition_object)
|
263
267
|
local_id ||= partition_object
|
264
268
|
object = local_id unless partition_proc
|
@@ -300,14 +304,14 @@ module Switchman
|
|
300
304
|
case any_id
|
301
305
|
when ::ActiveRecord::Base
|
302
306
|
any_id.id
|
303
|
-
when
|
307
|
+
when /\A(\d+)~(-?\d+)\Z/
|
304
308
|
local_id = $2.to_i
|
305
309
|
signed_id_operation(local_id) do |id|
|
306
310
|
return nil if id > IDS_PER_SHARD
|
307
311
|
|
308
312
|
($1.to_i * IDS_PER_SHARD) + id
|
309
313
|
end
|
310
|
-
when Integer,
|
314
|
+
when Integer, /\A-?\d+\Z/
|
311
315
|
any_id.to_i
|
312
316
|
end
|
313
317
|
end
|
@@ -410,7 +414,10 @@ module Switchman
|
|
410
414
|
end
|
411
415
|
end
|
412
416
|
|
417
|
+
# this resets the default shard on rails 7.1+, but we want to preserve it
|
418
|
+
shard_was = klass.default_shard
|
413
419
|
klass.connects_to shards: connects_to_hash
|
420
|
+
klass.default_shard = shard_was
|
414
421
|
end
|
415
422
|
end
|
416
423
|
|
@@ -519,6 +526,10 @@ module Switchman
|
|
519
526
|
id
|
520
527
|
end
|
521
528
|
|
529
|
+
def original_id_value
|
530
|
+
id
|
531
|
+
end
|
532
|
+
|
522
533
|
def activate(*classes, &block)
|
523
534
|
shards = hashify_classes(classes)
|
524
535
|
Shard.activate(shards, &block)
|
@@ -19,7 +19,7 @@ module Switchman
|
|
19
19
|
end
|
20
20
|
|
21
21
|
server1 = Shard.default.database_server
|
22
|
-
server2 = DatabaseServer.create(Shard.default.database_server.config.merge(server2: true))
|
22
|
+
server2 = DatabaseServer.create(Shard.default.database_server.config.merge(server2: true, schema_dump: false))
|
23
23
|
|
24
24
|
if server1 == Shard.default.database_server && server1.config[:shard1] && server1.config[:shard2]
|
25
25
|
# look for the shards in the db already
|
data/lib/switchman/version.rb
CHANGED
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: 3.5.
|
4
|
+
version: 3.5.13
|
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: 2023-10-
|
13
|
+
date: 2023-10-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 6.1.4
|
22
22
|
- - "<"
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: '7.
|
24
|
+
version: '7.2'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
version: 6.1.4
|
32
32
|
- - "<"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '7.
|
34
|
+
version: '7.2'
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: guardrail
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
@@ -69,7 +69,7 @@ dependencies:
|
|
69
69
|
version: '6.1'
|
70
70
|
- - "<"
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version: '7.
|
72
|
+
version: '7.2'
|
73
73
|
type: :runtime
|
74
74
|
prerelease: false
|
75
75
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -79,21 +79,21 @@ dependencies:
|
|
79
79
|
version: '6.1'
|
80
80
|
- - "<"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '7.
|
82
|
+
version: '7.2'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: debug
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '1.8'
|
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: '
|
96
|
+
version: '1.8'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: pg
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,20 +108,6 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.2'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: pry
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
112
|
name: rake
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -255,6 +241,7 @@ files:
|
|
255
241
|
- lib/switchman/active_record/attribute_methods.rb
|
256
242
|
- lib/switchman/active_record/base.rb
|
257
243
|
- lib/switchman/active_record/calculations.rb
|
244
|
+
- lib/switchman/active_record/connection_handler.rb
|
258
245
|
- lib/switchman/active_record/connection_pool.rb
|
259
246
|
- lib/switchman/active_record/database_configurations.rb
|
260
247
|
- lib/switchman/active_record/database_configurations/database_config.rb
|