switchman 2.1.0 → 3.0.6
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 +10 -2
- data/app/models/switchman/shard.rb +270 -343
- data/app/models/switchman/unsharded_record.rb +7 -0
- data/db/migrate/20130328212039_create_switchman_shards.rb +1 -1
- data/db/migrate/20130328224244_create_default_shard.rb +5 -5
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +1 -0
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -2
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +8 -6
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +5 -3
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +0 -8
- data/lib/switchman/active_record/association.rb +78 -89
- data/lib/switchman/active_record/attribute_methods.rb +127 -52
- data/lib/switchman/active_record/base.rb +83 -67
- data/lib/switchman/active_record/calculations.rb +73 -66
- data/lib/switchman/active_record/connection_pool.rb +12 -59
- data/lib/switchman/active_record/database_configurations/database_config.rb +13 -0
- data/lib/switchman/active_record/database_configurations.rb +34 -0
- data/lib/switchman/active_record/finder_methods.rb +11 -16
- data/lib/switchman/active_record/log_subscriber.rb +4 -8
- data/lib/switchman/active_record/migration.rb +19 -45
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/persistence.rb +11 -6
- data/lib/switchman/active_record/postgresql_adapter.rb +33 -161
- data/lib/switchman/active_record/predicate_builder.rb +1 -1
- data/lib/switchman/active_record/query_cache.rb +18 -19
- data/lib/switchman/active_record/query_methods.rb +178 -193
- data/lib/switchman/active_record/reflection.rb +7 -22
- data/lib/switchman/active_record/relation.rb +32 -29
- data/lib/switchman/active_record/spawn_methods.rb +27 -29
- data/lib/switchman/active_record/statement_cache.rb +18 -35
- data/lib/switchman/active_record/tasks/database_tasks.rb +16 -0
- data/lib/switchman/active_record/test_fixtures.rb +43 -0
- data/lib/switchman/active_support/cache.rb +3 -5
- data/lib/switchman/arel.rb +13 -8
- data/lib/switchman/database_server.rb +130 -154
- data/lib/switchman/default_shard.rb +52 -16
- data/lib/switchman/engine.rb +65 -58
- data/lib/switchman/environment.rb +4 -8
- data/lib/switchman/errors.rb +1 -0
- data/lib/switchman/guard_rail/relation.rb +5 -7
- data/lib/switchman/guard_rail.rb +6 -19
- data/lib/switchman/r_spec_helper.rb +29 -57
- data/lib/switchman/rails.rb +14 -12
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +15 -3
- data/lib/switchman/test_helper.rb +5 -3
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +3 -3
- data/lib/tasks/switchman.rake +61 -72
- metadata +90 -48
- data/lib/switchman/active_record/batches.rb +0 -11
- data/lib/switchman/active_record/connection_handler.rb +0 -190
- data/lib/switchman/active_record/where_clause_factory.rb +0 -36
- data/lib/switchman/connection_pool_proxy.rb +0 -173
- data/lib/switchman/schema_cache.rb +0 -28
data/lib/switchman/engine.rb
CHANGED
@@ -4,24 +4,30 @@ module Switchman
|
|
4
4
|
class Engine < ::Rails::Engine
|
5
5
|
isolate_namespace Switchman
|
6
6
|
|
7
|
-
|
7
|
+
# enable Rails 6.1 style connection handling
|
8
|
+
config.active_record.legacy_connection_handling = false
|
9
|
+
config.active_record.writing_role = :primary
|
10
|
+
|
11
|
+
config.autoload_once_paths << File.expand_path('app/models', config.paths.path)
|
8
12
|
|
9
13
|
def self.lookup_stores(cache_store_config)
|
10
14
|
result = {}
|
11
15
|
cache_store_config.each do |key, value|
|
12
16
|
next if value.is_a?(String)
|
17
|
+
|
13
18
|
result[key] = ::ActiveSupport::Cache.lookup_store(value)
|
14
19
|
end
|
15
20
|
|
16
|
-
cache_store_config.each do |key, value|
|
21
|
+
cache_store_config.each do |key, value| # rubocop:disable Style/CombinableLoops
|
17
22
|
next unless value.is_a?(String)
|
23
|
+
|
18
24
|
result[key] = result[value]
|
19
25
|
end
|
20
26
|
result
|
21
27
|
end
|
22
28
|
|
23
|
-
initializer 'switchman.initialize_cache', :
|
24
|
-
require
|
29
|
+
initializer 'switchman.initialize_cache', before: 'initialize_cache' do
|
30
|
+
require 'switchman/active_support/cache'
|
25
31
|
::ActiveSupport::Cache.singleton_class.prepend(ActiveSupport::Cache::ClassMethods)
|
26
32
|
|
27
33
|
# if we haven't already setup our cache map out-of-band, set it up from
|
@@ -31,9 +37,7 @@ module Switchman
|
|
31
37
|
# to fill just the Rails.env entry in the cache map.
|
32
38
|
unless Switchman.config[:cache_map].present?
|
33
39
|
cache_store_config = ::Rails.configuration.cache_store
|
34
|
-
unless cache_store_config.is_a?(Hash)
|
35
|
-
cache_store_config = {::Rails.env => cache_store_config}
|
36
|
-
end
|
40
|
+
cache_store_config = { ::Rails.env => cache_store_config } unless cache_store_config.is_a?(Hash)
|
37
41
|
|
38
42
|
Switchman.config[:cache_map] = Engine.lookup_stores(cache_store_config)
|
39
43
|
end
|
@@ -42,7 +46,7 @@ module Switchman
|
|
42
46
|
# config.cache_store) didn't have an entry for Rails.env, add one using
|
43
47
|
# lookup_store(nil); matches the behavior of Rails' default
|
44
48
|
# initialize_cache initializer when config.cache_store is nil.
|
45
|
-
unless Switchman.config[:cache_map].
|
49
|
+
unless Switchman.config[:cache_map].key?(::Rails.env)
|
46
50
|
value = ::ActiveSupport::Cache.lookup_store(nil)
|
47
51
|
Switchman.config[:cache_map][::Rails.env] = value
|
48
52
|
end
|
@@ -51,7 +55,7 @@ module Switchman
|
|
51
55
|
store.middleware if store.respond_to?(:middleware)
|
52
56
|
end.compact.uniq
|
53
57
|
middlewares.each do |middleware|
|
54
|
-
config.middleware.insert_before(
|
58
|
+
config.middleware.insert_before('Rack::Runtime', middleware)
|
55
59
|
end
|
56
60
|
|
57
61
|
# prevent :initialize_cache from trying to (or needing to) set
|
@@ -62,40 +66,43 @@ module Switchman
|
|
62
66
|
::Rails.cache = Switchman.config[:cache_map][::Rails.env]
|
63
67
|
end
|
64
68
|
|
65
|
-
initializer 'switchman.extend_ar', :
|
69
|
+
initializer 'switchman.extend_ar', before: 'active_record.initialize_database' do
|
66
70
|
::ActiveSupport.on_load(:active_record) do
|
67
|
-
require
|
68
|
-
require
|
69
|
-
require
|
70
|
-
require
|
71
|
-
require
|
72
|
-
require
|
73
|
-
require
|
74
|
-
require
|
75
|
-
require
|
76
|
-
require
|
77
|
-
require
|
78
|
-
require
|
79
|
-
require
|
80
|
-
require
|
81
|
-
require
|
82
|
-
require
|
83
|
-
require
|
84
|
-
require
|
85
|
-
require
|
86
|
-
require
|
87
|
-
require
|
88
|
-
require
|
89
|
-
require
|
90
|
-
require
|
91
|
-
require
|
92
|
-
require
|
93
|
-
|
94
|
-
require
|
71
|
+
require 'switchman/active_record/abstract_adapter'
|
72
|
+
require 'switchman/active_record/association'
|
73
|
+
require 'switchman/active_record/attribute_methods'
|
74
|
+
require 'switchman/active_record/base'
|
75
|
+
require 'switchman/active_record/calculations'
|
76
|
+
require 'switchman/active_record/connection_pool'
|
77
|
+
require 'switchman/active_record/database_configurations'
|
78
|
+
require 'switchman/active_record/database_configurations/database_config'
|
79
|
+
require 'switchman/active_record/finder_methods'
|
80
|
+
require 'switchman/active_record/log_subscriber'
|
81
|
+
require 'switchman/active_record/migration'
|
82
|
+
require 'switchman/active_record/model_schema'
|
83
|
+
require 'switchman/active_record/persistence'
|
84
|
+
require 'switchman/active_record/predicate_builder'
|
85
|
+
require 'switchman/active_record/query_cache'
|
86
|
+
require 'switchman/active_record/query_methods'
|
87
|
+
require 'switchman/active_record/reflection'
|
88
|
+
require 'switchman/active_record/relation'
|
89
|
+
require 'switchman/active_record/spawn_methods'
|
90
|
+
require 'switchman/active_record/statement_cache'
|
91
|
+
require 'switchman/active_record/tasks/database_tasks'
|
92
|
+
require 'switchman/active_record/type_caster'
|
93
|
+
require 'switchman/active_record/test_fixtures'
|
94
|
+
require 'switchman/arel'
|
95
|
+
require 'switchman/call_super'
|
96
|
+
require 'switchman/rails'
|
97
|
+
require 'switchman/guard_rail/relation'
|
98
|
+
require 'switchman/standard_error'
|
95
99
|
|
96
100
|
::StandardError.include(StandardError)
|
97
101
|
|
98
|
-
|
102
|
+
self.default_shard = ::Rails.env.to_sym
|
103
|
+
self.default_role = :primary
|
104
|
+
|
105
|
+
prepend ActiveRecord::Base
|
99
106
|
include ActiveRecord::AttributeMethods
|
100
107
|
include ActiveRecord::Persistence
|
101
108
|
singleton_class.prepend ActiveRecord::ModelSchema::ClassMethods
|
@@ -106,6 +113,8 @@ module Switchman
|
|
106
113
|
::ActiveRecord::StatementCache::Substitute.send(:attr_accessor, :primary, :sharded)
|
107
114
|
|
108
115
|
::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::CollectionAssociation)
|
116
|
+
::ActiveRecord::Associations::HasOneAssociation.prepend(ActiveRecord::ForeignAssociation)
|
117
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(ActiveRecord::ForeignAssociation)
|
109
118
|
|
110
119
|
::ActiveRecord::PredicateBuilder.singleton_class.prepend(ActiveRecord::PredicateBuilder)
|
111
120
|
|
@@ -117,21 +126,22 @@ module Switchman
|
|
117
126
|
|
118
127
|
::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Preloader::Association)
|
119
128
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
|
120
|
-
::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
|
121
129
|
::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
|
122
130
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
|
123
131
|
|
132
|
+
::ActiveRecord::DatabaseConfigurations.prepend(ActiveRecord::DatabaseConfigurations)
|
133
|
+
::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(ActiveRecord::DatabaseConfigurations::DatabaseConfig)
|
134
|
+
|
124
135
|
::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
|
125
136
|
::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
|
126
137
|
::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
|
127
|
-
::ActiveRecord::MigrationContext.prepend(ActiveRecord::MigrationContext)
|
138
|
+
::ActiveRecord::MigrationContext.prepend(ActiveRecord::MigrationContext)
|
128
139
|
::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
|
129
140
|
|
130
141
|
::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
|
131
142
|
::ActiveRecord::Reflection::AssociationReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
|
132
143
|
::ActiveRecord::Reflection::ThroughReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
|
133
144
|
::ActiveRecord::Reflection::AssociationReflection.prepend(ActiveRecord::Reflection::AssociationReflection)
|
134
|
-
::ActiveRecord::Relation.prepend(ActiveRecord::Batches)
|
135
145
|
::ActiveRecord::Relation.prepend(ActiveRecord::Calculations)
|
136
146
|
::ActiveRecord::Relation.include(ActiveRecord::FinderMethods)
|
137
147
|
::ActiveRecord::Relation.include(ActiveRecord::QueryMethods)
|
@@ -140,9 +150,13 @@ module Switchman
|
|
140
150
|
::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
|
141
151
|
::ActiveRecord::Relation.include(CallSuper)
|
142
152
|
|
143
|
-
::ActiveRecord::Relation::WhereClauseFactory.prepend(ActiveRecord::WhereClauseFactory)
|
144
153
|
::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
|
145
154
|
::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
|
155
|
+
|
156
|
+
::ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(ActiveRecord::Tasks::DatabaseTasks)
|
157
|
+
|
158
|
+
::ActiveRecord::TestFixtures.prepend(ActiveRecord::TestFixtures)
|
159
|
+
|
146
160
|
::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
|
147
161
|
::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
|
148
162
|
|
@@ -154,12 +168,10 @@ module Switchman
|
|
154
168
|
end
|
155
169
|
|
156
170
|
def self.foreign_key_check(name, type, limit: nil)
|
157
|
-
if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
|
158
|
-
puts "WARNING: All foreign keys need to be 8-byte integers. #{name} looks like a foreign key. If so, please add the option: `:limit => 8`"
|
159
|
-
end
|
171
|
+
puts "WARNING: All foreign keys need to be 8-byte integers. #{name} looks like a foreign key. If so, please add the option: `:limit => 8`" if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
|
160
172
|
end
|
161
173
|
|
162
|
-
initializer 'switchman.extend_connection_adapters', :
|
174
|
+
initializer 'switchman.extend_connection_adapters', after: 'active_record.initialize_database' do
|
163
175
|
::ActiveSupport.on_load(:active_record) do
|
164
176
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.descendants.each do |klass|
|
165
177
|
klass.prepend(ActiveRecord::AbstractAdapter::ForeignKeyCheck)
|
@@ -169,15 +181,11 @@ module Switchman
|
|
169
181
|
::ActiveRecord::ConnectionAdapters::TableDefinition.prepend(ActiveRecord::TableDefinition)
|
170
182
|
|
171
183
|
if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
172
|
-
require
|
184
|
+
require 'switchman/active_record/postgresql_adapter'
|
173
185
|
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
|
174
186
|
end
|
175
187
|
|
176
|
-
|
177
|
-
# establish a connection here instead
|
178
|
-
if !Shard.instance_variable_get(:@default)
|
179
|
-
::ActiveRecord::Base.establish_connection
|
180
|
-
end
|
188
|
+
Shard.send(:initialize_sharding)
|
181
189
|
end
|
182
190
|
end
|
183
191
|
|
@@ -188,21 +196,20 @@ module Switchman
|
|
188
196
|
end
|
189
197
|
end
|
190
198
|
|
191
|
-
initializer 'switchman.extend_guard_rail', :
|
199
|
+
initializer 'switchman.extend_guard_rail', before: 'switchman.extend_ar' do
|
192
200
|
::ActiveSupport.on_load(:active_record) do
|
193
|
-
require
|
201
|
+
require 'switchman/guard_rail'
|
194
202
|
|
195
203
|
::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
|
196
204
|
end
|
197
205
|
end
|
198
206
|
|
199
|
-
initializer 'switchman.extend_controller', :
|
207
|
+
initializer 'switchman.extend_controller', after: 'guard_rail.extend_ar' do
|
200
208
|
::ActiveSupport.on_load(:action_controller) do
|
201
|
-
require
|
209
|
+
require 'switchman/action_controller/caching'
|
202
210
|
|
203
211
|
::ActionController::Base.include(ActionController::Caching)
|
204
212
|
end
|
205
213
|
end
|
206
|
-
|
207
214
|
end
|
208
215
|
end
|
@@ -4,17 +4,13 @@ require 'etc'
|
|
4
4
|
|
5
5
|
module Switchman
|
6
6
|
class Environment
|
7
|
+
def self.cpu_count(nproc_bin = 'nproc')
|
8
|
+
return Etc.nprocessors if Etc.respond_to?(:nprocessors)
|
7
9
|
|
8
|
-
|
9
|
-
if Etc.respond_to?(:nprocessors)
|
10
|
-
return Etc.nprocessors
|
11
|
-
end
|
12
|
-
|
13
|
-
return `#{nproc_bin}`.to_i
|
10
|
+
`#{nproc_bin}`.to_i
|
14
11
|
rescue Errno::ENOENT
|
15
12
|
# an environment where nproc` isnt available
|
16
|
-
|
13
|
+
0
|
17
14
|
end
|
18
|
-
|
19
15
|
end
|
20
16
|
end
|
data/lib/switchman/errors.rb
CHANGED
@@ -4,19 +4,17 @@ module Switchman
|
|
4
4
|
module GuardRail
|
5
5
|
module Relation
|
6
6
|
def exec_queries(*args)
|
7
|
-
if
|
8
|
-
db = Shard.current(
|
9
|
-
if ::GuardRail.environment != db.guard_rail_environment
|
10
|
-
return db.unguard { super }
|
11
|
-
end
|
7
|
+
if lock_value
|
8
|
+
db = Shard.current(connection_classes).database_server
|
9
|
+
return db.unguard { super } if ::GuardRail.environment != db.guard_rail_environment
|
12
10
|
end
|
13
11
|
super
|
14
12
|
end
|
15
13
|
|
16
|
-
%w
|
14
|
+
%w[update_all delete_all].each do |method|
|
17
15
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
18
16
|
def #{method}(*args)
|
19
|
-
db = Shard.current(
|
17
|
+
db = Shard.current(connection_classes).database_server
|
20
18
|
if ::GuardRail.environment != db.guard_rail_environment
|
21
19
|
db.unguard { super }
|
22
20
|
else
|
data/lib/switchman/guard_rail.rb
CHANGED
@@ -3,27 +3,14 @@
|
|
3
3
|
module Switchman
|
4
4
|
module GuardRail
|
5
5
|
module ClassMethods
|
6
|
-
def
|
7
|
-
|
6
|
+
def activate(role)
|
7
|
+
DatabaseServer.send(:reference_role, role)
|
8
|
+
super
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
environment ||= :primary
|
14
|
-
activated_environments << environment
|
15
|
-
old_environment = self.environment
|
16
|
-
Thread.current[:guard_rail_environment] = environment
|
17
|
-
old_environment
|
18
|
-
end
|
19
|
-
|
20
|
-
# since activate! really is just a variable swap now, it's safe to use in
|
21
|
-
# the ensure block, simplifying the implementation
|
22
|
-
def activate(environment)
|
23
|
-
old_environment = activate!(environment)
|
24
|
-
yield
|
25
|
-
ensure
|
26
|
-
activate!(old_environment)
|
11
|
+
def activate!(role)
|
12
|
+
DatabaseServer.send(:reference_role, role)
|
13
|
+
super
|
27
14
|
end
|
28
15
|
end
|
29
16
|
end
|
@@ -1,16 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'switchman/test_helper'
|
4
4
|
|
5
5
|
module Switchman
|
6
6
|
# including this module in your specs will give you several shards to
|
7
7
|
# work with during specs:
|
8
8
|
# * Shard.default - the test database itself
|
9
|
-
# * @shard1 - a shard
|
9
|
+
# * @shard1 - a shard using the same connection as Shard.default
|
10
10
|
# * @shard2 - a shard using a dedicated connection
|
11
|
-
# * @shard3 - a shard using the same connection as @shard1 (this might
|
12
|
-
# be Shard.default if they already share a connection, or
|
13
|
-
# a separate shard)
|
14
11
|
module RSpecHelper
|
15
12
|
@@keep_the_shards = false
|
16
13
|
@@shard1 = nil
|
@@ -31,14 +28,15 @@ module Switchman
|
|
31
28
|
root_group.prepend_before(:all) do |group|
|
32
29
|
next if @@shard1
|
33
30
|
next if @@sharding_failed
|
31
|
+
|
34
32
|
# if we aren't actually going to run a sharding group/example,
|
35
33
|
# don't set it up after all
|
36
34
|
groups = group.class.descendant_filtered_examples.map(&:example_group).uniq
|
37
|
-
next unless groups.any?{ |
|
35
|
+
next unless groups.any? { |descendant_group| RSpecHelper.included_in?(descendant_group) }
|
38
36
|
|
39
|
-
puts
|
37
|
+
puts 'Setting up sharding for all specs...'
|
40
38
|
Shard.delete_all
|
41
|
-
Switchman.cache.delete(
|
39
|
+
Switchman.cache.delete('default_shard')
|
42
40
|
|
43
41
|
@@shard1, @@shard2 = TestHelper.recreate_persistent_test_shards
|
44
42
|
@@default_shard = Shard.default
|
@@ -49,23 +47,17 @@ module Switchman
|
|
49
47
|
begin
|
50
48
|
@@shard1 = @@shard1.create_new_shard
|
51
49
|
@@shard2 = @@shard2.create_new_shard
|
52
|
-
if @@shard1.database_server == Shard.default.database_server
|
53
|
-
@@shard3 = nil
|
54
|
-
else
|
55
|
-
@@shard3 = @@shard1.database_server.create_new_shard
|
56
|
-
end
|
57
50
|
rescue => e
|
58
|
-
|
51
|
+
warn 'Sharding setup FAILED!:'
|
59
52
|
while e
|
60
|
-
|
61
|
-
|
53
|
+
warn "\n#{e}\n"
|
54
|
+
warn e.backtrace
|
62
55
|
e = e.respond_to?(:cause) ? e.cause : nil
|
63
56
|
end
|
64
57
|
@@sharding_failed = true
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@@shard1 = @@shard2 = @@shard3 = nil
|
58
|
+
@@shard1&.drop_database rescue nil
|
59
|
+
@@shard2&.drop_database rescue nil
|
60
|
+
@@shard1 = @@shard2 = nil
|
69
61
|
Shard.delete_all
|
70
62
|
Shard.default(reload: true)
|
71
63
|
next
|
@@ -74,24 +66,20 @@ module Switchman
|
|
74
66
|
# we'll re-persist in the group's `before :all`; we don't want them to exist
|
75
67
|
# in the db before then
|
76
68
|
Shard.delete_all
|
77
|
-
Switchman.cache.delete(
|
69
|
+
Switchman.cache.delete('default_shard')
|
78
70
|
Shard.default(reload: true)
|
79
|
-
puts
|
71
|
+
puts 'Done!'
|
80
72
|
|
81
73
|
at_exit do
|
82
74
|
# preserve rspec's exit status
|
83
|
-
status= $!.is_a?(::SystemExit) ? $!.status : nil
|
84
|
-
puts
|
75
|
+
status = $!.is_a?(::SystemExit) ? $!.status : nil
|
76
|
+
puts 'Tearing down sharding for all specs'
|
85
77
|
@@shard1.database_server.destroy unless @@shard1.database_server == Shard.default.database_server
|
86
78
|
unless @@keep_the_shards
|
87
79
|
@@shard1.drop_database
|
88
80
|
@@shard1.destroy
|
89
81
|
@@shard2.drop_database
|
90
82
|
@@shard2.destroy
|
91
|
-
if @@shard3
|
92
|
-
@@shard3.drop_database
|
93
|
-
@@shard3.destroy
|
94
|
-
end
|
95
83
|
end
|
96
84
|
@@shard2.database_server.destroy
|
97
85
|
exit status if status
|
@@ -100,10 +88,11 @@ module Switchman
|
|
100
88
|
|
101
89
|
klass.before(:all) do
|
102
90
|
next if @@sharding_failed
|
91
|
+
|
103
92
|
dup = @@default_shard.dup
|
104
93
|
dup.id = @@default_shard.id
|
105
94
|
dup.save!
|
106
|
-
Switchman.cache.delete(
|
95
|
+
Switchman.cache.delete('default_shard')
|
107
96
|
Shard.default(reload: true)
|
108
97
|
dup = @@shard1.dup
|
109
98
|
dup.id = @@shard1.id
|
@@ -111,48 +100,31 @@ module Switchman
|
|
111
100
|
dup = @@shard2.dup
|
112
101
|
dup.id = @@shard2.id
|
113
102
|
dup.save!
|
114
|
-
if @@shard3
|
115
|
-
dup = @@shard3.dup
|
116
|
-
dup.id = @@shard3.id
|
117
|
-
dup.save!
|
118
|
-
end
|
119
103
|
@shard1, @shard2 = @@shard1, @@shard2
|
120
|
-
@shard3 = @@shard3 ? @@shard3 : Shard.default
|
121
104
|
end
|
122
105
|
|
123
106
|
klass.before do
|
124
|
-
raise
|
107
|
+
raise 'Sharding did not set up correctly' if @@sharding_failed
|
108
|
+
|
125
109
|
Shard.clear_cache
|
126
|
-
if use_transactional_tests
|
127
|
-
Shard.default(reload: true)
|
128
|
-
@shard1 = Shard.find(@shard1.id)
|
129
|
-
@shard2 = Shard.find(@shard2.id)
|
130
|
-
shards = [@shard2]
|
131
|
-
shards << @shard1 unless @shard1.database_server == Shard.default.database_server
|
132
|
-
shards.each do |shard|
|
133
|
-
shard.activate do
|
134
|
-
::ActiveRecord::Base.connection.begin_transaction joinable: false
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
110
|
end
|
139
111
|
|
140
112
|
klass.after do
|
141
113
|
next if @@sharding_failed
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
114
|
+
|
115
|
+
# clean up after specs
|
116
|
+
DatabaseServer.all.each do |ds|
|
117
|
+
if ds.fake? && ds != @shard2.database_server
|
118
|
+
ds.shards.delete_all unless use_transactional_tests
|
119
|
+
ds.destroy
|
149
120
|
end
|
150
121
|
end
|
151
122
|
end
|
152
123
|
|
153
124
|
klass.after(:all) do
|
154
|
-
|
155
|
-
|
125
|
+
# Don't truncate because that can create some fun cross-connection lock contention
|
126
|
+
Shard.delete_all
|
127
|
+
Switchman.cache.delete('default_shard')
|
156
128
|
Shard.default(reload: true)
|
157
129
|
end
|
158
130
|
end
|
data/lib/switchman/rails.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Switchman
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
module Switchman
|
4
|
+
module Rails
|
5
|
+
module ClassMethods
|
6
|
+
def self.prepended(klass)
|
7
|
+
# in Rails 4+, the Rails.cache= method was used during bootstrap to set
|
8
|
+
# Rails.cache(_without_sharding) to the value from the config file. but now
|
9
|
+
# that that's done (the bootstrap happened before this module is included
|
10
|
+
# into Rails), we want to make sure no one tries to assign to Rails.cache,
|
11
|
+
# because it would be wrong w.r.t. sharding.
|
12
|
+
klass.send(:remove_method, :cache=)
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def cache
|
16
|
+
Switchman::Shard.current.database_server.cache_store
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -7,7 +7,7 @@ module Switchman
|
|
7
7
|
@shard_host = shard_host
|
8
8
|
end
|
9
9
|
|
10
|
-
def instrument(name, payload={})
|
10
|
+
def instrument(name, payload = {})
|
11
11
|
shard = @shard_host&.shard
|
12
12
|
# attribute_methods_generated? will be false during a reload -
|
13
13
|
# when we might be doing a query while defining attribute methods,
|
@@ -3,12 +3,24 @@
|
|
3
3
|
module Switchman
|
4
4
|
module StandardError
|
5
5
|
def initialize(*args)
|
6
|
-
|
6
|
+
# Shard.current can throw this when switchman isn't working right; if we try to
|
7
|
+
# do our stuff here, it'll cause a SystemStackError, which is a pain to deal with
|
8
|
+
if is_a?(::ActiveRecord::ConnectionNotEstablished)
|
9
|
+
super
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
@active_shards = Shard.active_shards if defined?(Shard)
|
15
|
+
rescue ::ActiveRecord::ConnectionNotEstablished
|
16
|
+
# If we hit an error really early in boot, activerecord may not be initialized yet
|
17
|
+
end
|
18
|
+
|
7
19
|
super
|
8
20
|
end
|
9
21
|
|
10
|
-
def current_shard(
|
11
|
-
@active_shards&.[](
|
22
|
+
def current_shard(klass = ::ActiveRecord::Base)
|
23
|
+
@active_shards&.[](klass) || Shard.default
|
12
24
|
end
|
13
25
|
end
|
14
26
|
end
|
@@ -11,6 +11,7 @@ module Switchman
|
|
11
11
|
Shard.create!(default: true)
|
12
12
|
rescue
|
13
13
|
raise unless dont_create
|
14
|
+
|
14
15
|
# database doesn't exist yet, presumably cause we're creating it right now
|
15
16
|
return [nil, nil]
|
16
17
|
end
|
@@ -49,8 +50,8 @@ module Switchman
|
|
49
50
|
shard1.destroy
|
50
51
|
shard2.drop_database rescue nil
|
51
52
|
shard2.destroy
|
52
|
-
shard1 = server1.create_new_shard(:
|
53
|
-
shard2 = server2.create_new_shard(:
|
53
|
+
shard1 = server1.create_new_shard(name: server1.config[:shard1])
|
54
|
+
shard2 = server2.create_new_shard(name: server1.config[:shard2])
|
54
55
|
end
|
55
56
|
[shard1, shard2]
|
56
57
|
else
|
@@ -59,11 +60,12 @@ module Switchman
|
|
59
60
|
end
|
60
61
|
|
61
62
|
private
|
63
|
+
|
62
64
|
def find_existing_test_shard(server, name)
|
63
65
|
if server == Shard.default.database_server
|
64
66
|
server.shards.where(name: name).first
|
65
67
|
else
|
66
|
-
shard = Shard.where(
|
68
|
+
shard = Shard.where('database_server_id IS NOT NULL AND name=?', name).first
|
67
69
|
# if somehow databases got created in a different order, change the shard to match
|
68
70
|
shard.database_server = server if shard
|
69
71
|
shard
|
data/lib/switchman/version.rb
CHANGED
data/lib/switchman.rb
CHANGED