switchman 3.5.11 → 3.5.13
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/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
|