switchman 3.0.5 → 4.0.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/Rakefile +16 -15
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -2
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +1 -1
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +6 -15
- data/lib/switchman/active_record/associations.rb +331 -0
- data/lib/switchman/active_record/attribute_methods.rb +182 -77
- data/lib/switchman/active_record/base.rb +249 -46
- data/lib/switchman/active_record/calculations.rb +98 -44
- data/lib/switchman/active_record/connection_handler.rb +18 -0
- data/lib/switchman/active_record/connection_pool.rb +27 -28
- data/lib/switchman/active_record/database_configurations.rb +44 -6
- data/lib/switchman/active_record/finder_methods.rb +46 -16
- data/lib/switchman/active_record/log_subscriber.rb +11 -5
- data/lib/switchman/active_record/migration.rb +52 -5
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/pending_migration_connection.rb +17 -0
- data/lib/switchman/active_record/persistence.rb +37 -2
- data/lib/switchman/active_record/postgresql_adapter.rb +12 -11
- data/lib/switchman/active_record/predicate_builder.rb +2 -2
- data/lib/switchman/active_record/query_cache.rb +49 -20
- data/lib/switchman/active_record/query_methods.rb +202 -136
- data/lib/switchman/active_record/reflection.rb +1 -1
- data/lib/switchman/active_record/relation.rb +40 -28
- data/lib/switchman/active_record/spawn_methods.rb +2 -2
- data/lib/switchman/active_record/statement_cache.rb +11 -7
- data/lib/switchman/active_record/table_definition.rb +1 -1
- data/lib/switchman/active_record/tasks/database_tasks.rb +6 -1
- data/lib/switchman/active_record/test_fixtures.rb +53 -0
- data/lib/switchman/active_support/cache.rb +25 -4
- data/lib/switchman/arel.rb +45 -7
- data/lib/switchman/call_super.rb +2 -2
- data/lib/switchman/database_server.rb +123 -79
- data/lib/switchman/default_shard.rb +14 -5
- data/lib/switchman/engine.rb +79 -131
- data/lib/switchman/environment.rb +2 -2
- data/lib/switchman/errors.rb +17 -2
- data/lib/switchman/guard_rail/relation.rb +7 -10
- data/lib/switchman/guard_rail.rb +5 -0
- data/lib/switchman/parallel.rb +68 -0
- data/lib/switchman/r_spec_helper.rb +17 -28
- data/lib/switchman/rails.rb +1 -4
- data/{app/models → lib}/switchman/shard.rb +226 -241
- data/lib/switchman/sharded_instrumenter.rb +3 -3
- data/lib/switchman/shared_schema_cache.rb +11 -0
- data/lib/switchman/standard_error.rb +15 -12
- data/lib/switchman/test_helper.rb +2 -2
- data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +44 -12
- data/lib/tasks/switchman.rake +101 -54
- metadata +50 -58
- data/lib/switchman/active_record/association.rb +0 -206
- data/lib/switchman/open4.rb +0 -80
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Switchman
|
|
4
4
|
class ShardedInstrumenter < ::SimpleDelegator
|
|
5
5
|
def initialize(instrumenter, shard_host)
|
|
6
|
-
super
|
|
6
|
+
super(instrumenter)
|
|
7
7
|
@shard_host = shard_host
|
|
8
8
|
end
|
|
9
9
|
|
|
@@ -16,10 +16,10 @@ module Switchman
|
|
|
16
16
|
payload[:shard] = {
|
|
17
17
|
database_server_id: shard.database_server.id,
|
|
18
18
|
id: shard.id,
|
|
19
|
-
env:
|
|
19
|
+
env: @shard_host.pool.connection_class&.current_role
|
|
20
20
|
}
|
|
21
21
|
end
|
|
22
|
-
super
|
|
22
|
+
super(name, payload)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Switchman
|
|
4
|
+
class SharedSchemaCache
|
|
5
|
+
def self.get_schema_cache(connection)
|
|
6
|
+
@schema_cache ||= ::ActiveRecord::ConnectionAdapters::SchemaCache.new(connection)
|
|
7
|
+
@schema_cache.connection = connection
|
|
8
|
+
@schema_cache
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -3,20 +3,23 @@
|
|
|
3
3
|
module Switchman
|
|
4
4
|
module StandardError
|
|
5
5
|
def initialize(*args)
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
if is_a?(::
|
|
9
|
-
super
|
|
10
|
-
return
|
|
11
|
-
end
|
|
6
|
+
super
|
|
7
|
+
# These seem to get themselves into a bad state if we try to lookup shards while processing
|
|
8
|
+
return if is_a?(IO::EAGAINWaitReadable)
|
|
12
9
|
|
|
13
|
-
if
|
|
14
|
-
@active_shards = Shard.sharded_models.map do |klass|
|
|
15
|
-
[klass, Shard.current(klass)]
|
|
16
|
-
end.compact.to_h
|
|
17
|
-
end
|
|
10
|
+
return if Thread.current[:switchman_error_handler]
|
|
18
11
|
|
|
19
|
-
|
|
12
|
+
begin
|
|
13
|
+
Thread.current[:switchman_error_handler] = true
|
|
14
|
+
|
|
15
|
+
@active_shards ||= Shard.active_shards
|
|
16
|
+
rescue
|
|
17
|
+
# intentionally empty - don't allow calculating the active_shards to prevent
|
|
18
|
+
# creating the StandardError for any reason. this prevents various random issues
|
|
19
|
+
# when a StandardError is created within a finalizer
|
|
20
|
+
ensure
|
|
21
|
+
Thread.current[:switchman_error_handler] = nil
|
|
22
|
+
end
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
def current_shard(klass = ::ActiveRecord::Base)
|
|
@@ -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
|
|
@@ -65,7 +65,7 @@ module Switchman
|
|
|
65
65
|
if server == Shard.default.database_server
|
|
66
66
|
server.shards.where(name: name).first
|
|
67
67
|
else
|
|
68
|
-
shard = Shard.where(
|
|
68
|
+
shard = Shard.where("database_server_id IS NOT NULL AND name=?", name).first
|
|
69
69
|
# if somehow databases got created in a different order, change the shard to match
|
|
70
70
|
shard.database_server = server if shard
|
|
71
71
|
shard
|
data/lib/switchman/version.rb
CHANGED
data/lib/switchman.rb
CHANGED
|
@@ -1,22 +1,54 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require 'switchman/engine'
|
|
3
|
+
require "guard_rail"
|
|
4
|
+
require "zeitwerk"
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
class SwitchmanInflector < Zeitwerk::GemInflector
|
|
7
|
+
def camelize(basename, abspath)
|
|
8
|
+
if basename =~ /\Apostgresql_(.*)/
|
|
9
|
+
"PostgreSQL" + super($1, abspath)
|
|
10
|
+
else
|
|
11
|
+
super
|
|
12
|
+
end
|
|
11
13
|
end
|
|
14
|
+
end
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
loader = Zeitwerk::Loader.for_gem
|
|
17
|
+
loader.inflector = SwitchmanInflector.new(__FILE__)
|
|
18
|
+
loader.setup
|
|
19
|
+
|
|
20
|
+
module Switchman
|
|
21
|
+
Deprecation = ::ActiveSupport::Deprecation.new("4.0", "Switchman")
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
attr_writer :cache
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
def config
|
|
27
|
+
# TODO: load from yaml
|
|
28
|
+
@config ||= {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def cache
|
|
32
|
+
(@cache.respond_to?(:call) ? @cache.call : @cache) || ::Rails.cache
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def region
|
|
36
|
+
config[:region]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def foreign_key_check(name, type, limit: nil)
|
|
40
|
+
return unless name.to_s.end_with?("_id") && type.to_s == "integer" && limit.to_i < 8
|
|
41
|
+
|
|
42
|
+
puts <<~TEXT.squish
|
|
43
|
+
WARNING: All foreign keys need to be 8-byte integers.
|
|
44
|
+
#{name} looks like a foreign key.
|
|
45
|
+
If so, please add the option: `:limit => 8`
|
|
46
|
+
TEXT
|
|
47
|
+
end
|
|
19
48
|
end
|
|
20
49
|
|
|
21
50
|
class OrderOnMultiShardQuery < RuntimeError; end
|
|
22
51
|
end
|
|
52
|
+
|
|
53
|
+
# Load the engine and everything associated at gem load time
|
|
54
|
+
Switchman::Engine
|
data/lib/tasks/switchman.rake
CHANGED
|
@@ -2,28 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module Switchman
|
|
4
4
|
module Rake
|
|
5
|
-
def self.filter_database_servers
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
def self.filter_database_servers
|
|
6
|
+
# use a local variable so that the current chain is closed over in the following lambda
|
|
7
|
+
chain = filter_database_servers_chain
|
|
8
|
+
@filter_database_servers_chain = ->(servers) { yield(servers, chain) }
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def self.scope(base_scope = Shard,
|
|
11
|
-
database_server: ENV
|
|
12
|
-
shard: ENV
|
|
12
|
+
database_server: ENV.fetch("DATABASE_SERVER", nil),
|
|
13
|
+
shard: ENV.fetch("SHARD", nil))
|
|
13
14
|
servers = DatabaseServer.all
|
|
14
15
|
|
|
15
16
|
if database_server
|
|
16
17
|
servers = database_server
|
|
17
|
-
if servers.first ==
|
|
18
|
+
if servers.first == "-"
|
|
18
19
|
negative = true
|
|
19
20
|
servers = servers[1..]
|
|
20
21
|
end
|
|
21
|
-
servers = servers.split(
|
|
22
|
-
open = servers.delete(
|
|
22
|
+
servers = servers.split(",")
|
|
23
|
+
open = servers.delete("open")
|
|
23
24
|
|
|
24
|
-
servers = servers.
|
|
25
|
+
servers = servers.filter_map { |server| DatabaseServer.find(server) }
|
|
25
26
|
if open
|
|
26
|
-
open_servers = DatabaseServer.
|
|
27
|
+
open_servers = DatabaseServer.select { |server| server.config[:open] }
|
|
27
28
|
servers.concat(open_servers)
|
|
28
29
|
servers << DatabaseServer.find(nil) if open_servers.empty?
|
|
29
30
|
servers.uniq!
|
|
@@ -31,13 +32,26 @@ module Switchman
|
|
|
31
32
|
servers = DatabaseServer.all - servers if negative
|
|
32
33
|
end
|
|
33
34
|
|
|
35
|
+
ENV["REGION"]&.split(",")&.each do |region|
|
|
36
|
+
method = :select!
|
|
37
|
+
if region[0] == "-"
|
|
38
|
+
method = :reject!
|
|
39
|
+
region = region[1..]
|
|
40
|
+
end
|
|
41
|
+
if region == "self"
|
|
42
|
+
servers.send(method, &:in_current_region?)
|
|
43
|
+
else
|
|
44
|
+
servers.send(method) { |server| server.in_region?(region) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
34
48
|
servers = filter_database_servers_chain.call(servers)
|
|
35
49
|
|
|
36
|
-
scope = base_scope.order(::Arel.sql(
|
|
50
|
+
scope = base_scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
|
|
37
51
|
if servers != DatabaseServer.all
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
scope = scope.where(
|
|
52
|
+
database_server_ids = servers.map(&:id)
|
|
53
|
+
database_server_ids << nil if servers.include?(Shard.default.database_server)
|
|
54
|
+
scope = scope.where(database_server_id: database_server_ids)
|
|
41
55
|
end
|
|
42
56
|
|
|
43
57
|
scope = shard_scope(scope, shard) if shard
|
|
@@ -46,52 +60,93 @@ module Switchman
|
|
|
46
60
|
end
|
|
47
61
|
|
|
48
62
|
def self.options
|
|
49
|
-
{
|
|
63
|
+
{ exception: (ENV["FAIL_FAST"] == "0") ? :defer : :raise, parallel: ENV["PARALLEL"].to_i }
|
|
50
64
|
end
|
|
51
65
|
|
|
52
66
|
# classes - an array or proc, to activate as the current shard during the
|
|
53
|
-
# task.
|
|
54
|
-
# so that schema updates for non-default tables happen against all shards.
|
|
55
|
-
# this is handled automatically for the default migration tasks, below.
|
|
67
|
+
# task.
|
|
56
68
|
def self.shardify_task(task_name, classes: [::ActiveRecord::Base])
|
|
69
|
+
log_format = ENV.fetch("LOG_FORMAT", nil)
|
|
57
70
|
old_task = ::Rake::Task[task_name]
|
|
58
71
|
old_actions = old_task.actions.dup
|
|
59
72
|
old_task.actions.clear
|
|
60
73
|
|
|
61
74
|
old_task.enhance do |*task_args|
|
|
62
75
|
if ::Rails.env.test?
|
|
63
|
-
require
|
|
76
|
+
require "switchman/test_helper"
|
|
64
77
|
TestHelper.recreate_persistent_test_shards(dont_create: true)
|
|
65
78
|
end
|
|
66
79
|
|
|
67
80
|
::GuardRail.activate(:deploy) do
|
|
68
81
|
Shard.default.database_server.unguard do
|
|
69
82
|
classes = classes.call if classes.respond_to?(:call)
|
|
70
|
-
|
|
83
|
+
|
|
84
|
+
# We don't want the shard status messages to be wrapped using a custom log transfomer
|
|
85
|
+
original_stderr = $stderr
|
|
86
|
+
original_stdout = $stdout
|
|
87
|
+
output = if log_format == "json"
|
|
88
|
+
lambda { |msg|
|
|
89
|
+
JSON.dump(shard: Shard.current.id,
|
|
90
|
+
database_server: Shard.current.database_server.id,
|
|
91
|
+
type: "log",
|
|
92
|
+
message: msg)
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
Shard.with_each_shard(scope, classes, output: output, **options) do
|
|
71
98
|
shard = Shard.current
|
|
72
|
-
|
|
99
|
+
|
|
100
|
+
if log_format == "json"
|
|
101
|
+
original_stdout.puts JSON.dump(
|
|
102
|
+
shard: shard.id,
|
|
103
|
+
database_server: shard.database_server.id,
|
|
104
|
+
type: "started"
|
|
105
|
+
)
|
|
106
|
+
else
|
|
107
|
+
original_stdout.puts "#{shard.id}: #{shard.description}"
|
|
108
|
+
end
|
|
73
109
|
|
|
74
110
|
shard.database_server.unguard do
|
|
75
111
|
old_actions.each { |action| action.call(*task_args) }
|
|
76
112
|
end
|
|
113
|
+
|
|
114
|
+
if log_format == "json"
|
|
115
|
+
original_stdout.puts JSON.dump(
|
|
116
|
+
shard: shard.id,
|
|
117
|
+
database_server: shard.database_server.id,
|
|
118
|
+
type: "completed"
|
|
119
|
+
)
|
|
120
|
+
end
|
|
77
121
|
nil
|
|
122
|
+
rescue => e
|
|
123
|
+
if log_format == "json"
|
|
124
|
+
original_stderr.puts JSON.dump(
|
|
125
|
+
shard: shard.id,
|
|
126
|
+
database_server: shard.database_server.id,
|
|
127
|
+
type: "failed",
|
|
128
|
+
message: e.full_message
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
raise
|
|
78
133
|
end
|
|
79
134
|
rescue => e
|
|
80
|
-
|
|
135
|
+
if options[:parallel] != 0
|
|
136
|
+
warn "Exception from #{e.current_shard.id}: #{e.current_shard.description}:\n#{e.full_message}"
|
|
137
|
+
end
|
|
81
138
|
raise
|
|
82
|
-
|
|
83
|
-
#::ActiveRecord::Base.configurations = old_configurations
|
|
84
139
|
end
|
|
85
140
|
end
|
|
86
141
|
end
|
|
87
142
|
end
|
|
88
143
|
|
|
89
144
|
%w[db:migrate db:migrate:up db:migrate:down db:rollback].each do |task_name|
|
|
90
|
-
shardify_task(task_name
|
|
145
|
+
shardify_task(task_name)
|
|
91
146
|
end
|
|
92
147
|
|
|
93
148
|
def self.shard_scope(scope, raw_shard_ids)
|
|
94
|
-
raw_shard_ids = raw_shard_ids.split(
|
|
149
|
+
raw_shard_ids = raw_shard_ids.split(",")
|
|
95
150
|
|
|
96
151
|
shard_ids = []
|
|
97
152
|
negative_shard_ids = []
|
|
@@ -101,13 +156,13 @@ module Switchman
|
|
|
101
156
|
|
|
102
157
|
raw_shard_ids.each do |id|
|
|
103
158
|
case id
|
|
104
|
-
when
|
|
159
|
+
when "default"
|
|
105
160
|
shard_ids << Shard.default.id
|
|
106
|
-
when
|
|
161
|
+
when "-default"
|
|
107
162
|
negative_shard_ids << Shard.default.id
|
|
108
|
-
when
|
|
163
|
+
when "primary"
|
|
109
164
|
shard_ids.concat(Shard.primary.pluck(:id))
|
|
110
|
-
when
|
|
165
|
+
when "-primary"
|
|
111
166
|
negative_shard_ids.concat(Shard.primary.pluck(:id))
|
|
112
167
|
when /^(-?)(\d+)?\.\.(\.)?(\d+)?$/
|
|
113
168
|
negative, start, open, finish = $1.present?, $2, $3.present?, $4
|
|
@@ -115,8 +170,8 @@ module Switchman
|
|
|
115
170
|
|
|
116
171
|
range = []
|
|
117
172
|
range << "id>=#{start}" if start
|
|
118
|
-
range << "id<#{
|
|
119
|
-
(negative ? negative_ranges : ranges) << "(#{range.join(
|
|
173
|
+
range << "id<#{"=" unless open}#{finish}" if finish
|
|
174
|
+
(negative ? negative_ranges : ranges) << "(#{range.join(" AND ")})"
|
|
120
175
|
when /^-(\d+)$/
|
|
121
176
|
negative_shard_ids << $1.to_i
|
|
122
177
|
when /^\d+$/
|
|
@@ -144,21 +199,21 @@ module Switchman
|
|
|
144
199
|
select = []
|
|
145
200
|
if index != 1
|
|
146
201
|
subscope = subscope.offset(per_chunk * (index - 1))
|
|
147
|
-
select <<
|
|
202
|
+
select << "MIN(id) AS min_id"
|
|
148
203
|
end
|
|
149
204
|
if index != denominator
|
|
150
205
|
subscope = subscope.limit(per_chunk)
|
|
151
|
-
select <<
|
|
206
|
+
select << "MAX(id) AS max_id"
|
|
152
207
|
end
|
|
153
208
|
|
|
154
|
-
result = Shard.from(subscope).select(select.join(
|
|
209
|
+
result = Shard.from(subscope).select(select.join(", ")).to_a.first
|
|
155
210
|
range = case index
|
|
156
211
|
when 1
|
|
157
|
-
"id<=#{result[
|
|
212
|
+
"id<=#{result["max_id"]}"
|
|
158
213
|
when denominator
|
|
159
|
-
"id>=#{result[
|
|
214
|
+
"id>=#{result["min_id"]}"
|
|
160
215
|
else
|
|
161
|
-
"(id>=#{result[
|
|
216
|
+
"(id>=#{result["min_id"]} AND id<=#{result["max_id"]})"
|
|
162
217
|
end
|
|
163
218
|
|
|
164
219
|
(numerator.negative? ? negative_ranges : ranges) << range
|
|
@@ -179,16 +234,16 @@ module Switchman
|
|
|
179
234
|
|
|
180
235
|
conditions = []
|
|
181
236
|
positive_queries = []
|
|
182
|
-
positive_queries << ranges.join(
|
|
237
|
+
positive_queries << ranges.join(" OR ") unless ranges.empty?
|
|
183
238
|
unless shard_ids.empty?
|
|
184
|
-
positive_queries <<
|
|
239
|
+
positive_queries << "id IN (?)"
|
|
185
240
|
conditions << shard_ids
|
|
186
241
|
end
|
|
187
|
-
positive_query = positive_queries.join(
|
|
242
|
+
positive_query = positive_queries.join(" OR ")
|
|
188
243
|
scope = scope.where(positive_query, *conditions) unless positive_queries.empty?
|
|
189
244
|
|
|
190
|
-
scope = scope.where("NOT (#{negative_ranges.join(
|
|
191
|
-
scope = scope.where(
|
|
245
|
+
scope = scope.where("NOT (#{negative_ranges.join(" OR")})") unless negative_ranges.empty?
|
|
246
|
+
scope = scope.where("id NOT IN (?)", negative_shard_ids) unless negative_shard_ids.empty?
|
|
192
247
|
scope
|
|
193
248
|
end
|
|
194
249
|
|
|
@@ -199,17 +254,9 @@ module Switchman
|
|
|
199
254
|
|
|
200
255
|
module ActiveRecord
|
|
201
256
|
module PostgreSQLDatabaseTasks
|
|
202
|
-
def structure_dump(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
args.concat(Array(extra_flags)) if extra_flags
|
|
206
|
-
shard = Shard.current.name
|
|
207
|
-
serialized_search_path = shard
|
|
208
|
-
args << "--schema=#{Shellwords.escape(shard)}"
|
|
209
|
-
|
|
210
|
-
args << configuration['database']
|
|
211
|
-
run_cmd('pg_dump', args, 'dumping')
|
|
212
|
-
File.open(filename, 'a') { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
|
|
257
|
+
def structure_dump(...)
|
|
258
|
+
::ActiveRecord.dump_schemas = Switchman::Shard.current.name
|
|
259
|
+
super
|
|
213
260
|
end
|
|
214
261
|
end
|
|
215
262
|
end
|