switchman 1.16.0 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/switchman/shard.rb +10 -5
- data/db/migrate/20130328212039_create_switchman_shards.rb +2 -0
- data/db/migrate/20130328224244_create_default_shard.rb +3 -1
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +2 -0
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -0
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +2 -0
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +2 -0
- data/lib/switchman.rb +3 -1
- data/lib/switchman/action_controller/caching.rb +2 -0
- data/lib/switchman/active_record/abstract_adapter.rb +8 -2
- data/lib/switchman/active_record/association.rb +10 -4
- data/lib/switchman/active_record/attribute_methods.rb +2 -0
- data/lib/switchman/active_record/base.rb +13 -11
- data/lib/switchman/active_record/batches.rb +2 -0
- data/lib/switchman/active_record/calculations.rb +2 -0
- data/lib/switchman/active_record/connection_handler.rb +8 -6
- data/lib/switchman/active_record/connection_pool.rb +2 -0
- data/lib/switchman/active_record/finder_methods.rb +2 -0
- data/lib/switchman/active_record/log_subscriber.rb +2 -0
- data/lib/switchman/active_record/migration.rb +3 -1
- data/lib/switchman/active_record/model_schema.rb +2 -0
- data/lib/switchman/active_record/persistence.rb +3 -1
- data/lib/switchman/active_record/postgresql_adapter.rb +3 -1
- data/lib/switchman/active_record/predicate_builder.rb +2 -0
- data/lib/switchman/active_record/query_cache.rb +2 -0
- data/lib/switchman/active_record/query_methods.rb +121 -72
- data/lib/switchman/active_record/reflection.rb +2 -0
- data/lib/switchman/active_record/relation.rb +7 -5
- data/lib/switchman/active_record/spawn_methods.rb +2 -0
- data/lib/switchman/active_record/statement_cache.rb +3 -1
- data/lib/switchman/active_record/table_definition.rb +4 -2
- data/lib/switchman/active_record/type_caster.rb +2 -0
- data/lib/switchman/active_record/where_clause_factory.rb +2 -0
- data/lib/switchman/active_support/cache.rb +4 -2
- data/lib/switchman/arel.rb +2 -0
- data/lib/switchman/call_super.rb +2 -0
- data/lib/switchman/connection_pool_proxy.rb +13 -11
- data/lib/switchman/database_server.rb +18 -16
- data/lib/switchman/default_shard.rb +2 -0
- data/lib/switchman/engine.rb +10 -8
- data/lib/switchman/environment.rb +2 -0
- data/lib/switchman/errors.rb +2 -0
- data/lib/switchman/{shackles.rb → guard_rail.rb} +6 -4
- data/lib/switchman/{shackles → guard_rail}/relation.rb +7 -5
- data/lib/switchman/open4.rb +2 -0
- data/lib/switchman/r_spec_helper.rb +7 -5
- data/lib/switchman/rails.rb +2 -0
- data/lib/switchman/schema_cache.rb +2 -0
- data/lib/switchman/sharded_instrumenter.rb +3 -1
- data/lib/switchman/standard_error.rb +2 -0
- data/lib/switchman/test_helper.rb +5 -3
- data/lib/switchman/version.rb +3 -1
- data/lib/tasks/switchman.rake +3 -3
- metadata +30 -16
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module Relation
|
@@ -5,7 +7,7 @@ module Switchman
|
|
5
7
|
klass::SINGLE_VALUE_METHODS.concat [ :shard, :shard_source ]
|
6
8
|
end
|
7
9
|
|
8
|
-
def initialize(
|
10
|
+
def initialize(*, **)
|
9
11
|
super
|
10
12
|
self.shard_value = Shard.current(klass ? klass.shard_category : :primary) unless shard_value
|
11
13
|
self.shard_source_value = :implicit unless shard_source_value
|
@@ -17,7 +19,7 @@ module Switchman
|
|
17
19
|
result
|
18
20
|
end
|
19
21
|
|
20
|
-
def merge(*
|
22
|
+
def merge(*)
|
21
23
|
relation = super
|
22
24
|
if relation.shard_value != self.shard_value && relation.shard_source_value == :implicit
|
23
25
|
relation.shard_value = self.shard_value
|
@@ -26,15 +28,15 @@ module Switchman
|
|
26
28
|
relation
|
27
29
|
end
|
28
30
|
|
29
|
-
def new(
|
31
|
+
def new(*, &block)
|
30
32
|
primary_shard.activate(klass.shard_category) { super }
|
31
33
|
end
|
32
34
|
|
33
|
-
def create(
|
35
|
+
def create(*, &block)
|
34
36
|
primary_shard.activate(klass.shard_category) { super }
|
35
37
|
end
|
36
38
|
|
37
|
-
def create!(
|
39
|
+
def create!(*, &block)
|
38
40
|
primary_shard.activate(klass.shard_category) { super }
|
39
41
|
end
|
40
42
|
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module StatementCache
|
4
6
|
module ClassMethods
|
5
|
-
def create(connection, block
|
7
|
+
def create(connection, &block)
|
6
8
|
relation = block.call ::ActiveRecord::StatementCache::Params.new
|
7
9
|
|
8
10
|
if ::Rails.version >= "5.2"
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module TableDefinition
|
4
|
-
def column(name, type,
|
5
|
-
Engine.foreign_key_check(name, type,
|
6
|
+
def column(name, type, limit: nil, **)
|
7
|
+
Engine.foreign_key_check(name, type, limit: limit)
|
6
8
|
super
|
7
9
|
end
|
8
10
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveSupport
|
3
5
|
module Cache
|
@@ -15,12 +17,12 @@ module Switchman
|
|
15
17
|
end
|
16
18
|
|
17
19
|
module RedisCacheStore
|
18
|
-
def clear(
|
20
|
+
def clear(namespace: nil, **)
|
19
21
|
# RedisCacheStore tries to be smart and only clear the cache under your namespace, if you have one set
|
20
22
|
# unfortunately, it uses the keys command, which is extraordinarily inefficient in a large redis instance
|
21
23
|
# fortunately, we can assume we control the entire instance, because we set up the namespacing, so just
|
22
24
|
# always unset it temporarily for clear calls
|
23
|
-
|
25
|
+
namespace = nil
|
24
26
|
super
|
25
27
|
end
|
26
28
|
end
|
data/lib/switchman/arel.rb
CHANGED
data/lib/switchman/call_super.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'switchman/schema_cache'
|
2
4
|
|
3
5
|
module Switchman
|
@@ -37,13 +39,13 @@ module Switchman
|
|
37
39
|
Shard.current(@category)
|
38
40
|
end
|
39
41
|
|
40
|
-
def
|
41
|
-
::Rails.env.test? ? :
|
42
|
+
def active_guard_rail_environment
|
43
|
+
::Rails.env.test? ? :primary : active_shard.database_server.guard_rail_environment
|
42
44
|
end
|
43
45
|
|
44
46
|
def current_pool
|
45
47
|
current_active_shard = active_shard
|
46
|
-
pool = self.default_pool if current_active_shard.database_server == Shard.default.database_server &&
|
48
|
+
pool = self.default_pool if current_active_shard.database_server == Shard.default.database_server && active_guard_rail_environment == :primary && (current_active_shard.default? || current_active_shard.database_server.shareable?)
|
47
49
|
pool = @connection_pools[pool_key] ||= create_pool unless pool
|
48
50
|
pool.shard = current_active_shard
|
49
51
|
pool
|
@@ -60,8 +62,8 @@ module Switchman
|
|
60
62
|
connection.instance_variable_set(:@schema_cache, @schema_cache) unless ::Rails.version >= '6'
|
61
63
|
connection
|
62
64
|
rescue ConnectionError
|
63
|
-
raise if active_shard.database_server == Shard.default.database_server &&
|
64
|
-
configs = active_shard.database_server.config(
|
65
|
+
raise if active_shard.database_server == Shard.default.database_server && active_guard_rail_environment == :primary
|
66
|
+
configs = active_shard.database_server.config(active_guard_rail_environment)
|
65
67
|
raise unless configs.is_a?(Array)
|
66
68
|
configs.each_with_index do |config, idx|
|
67
69
|
pool = create_pool(config.dup)
|
@@ -120,7 +122,7 @@ module Switchman
|
|
120
122
|
end
|
121
123
|
|
122
124
|
def pool_key
|
123
|
-
[
|
125
|
+
[active_guard_rail_environment,
|
124
126
|
active_shard.database_server.shareable? ? active_shard.database_server.pool_key : active_shard]
|
125
127
|
end
|
126
128
|
|
@@ -128,7 +130,7 @@ module Switchman
|
|
128
130
|
shard = active_shard
|
129
131
|
unless config
|
130
132
|
if shard != Shard.default
|
131
|
-
config = shard.database_server.config(
|
133
|
+
config = shard.database_server.config(active_guard_rail_environment)
|
132
134
|
config = config.first if config.is_a?(Array)
|
133
135
|
config = config.dup
|
134
136
|
else
|
@@ -138,10 +140,10 @@ module Switchman
|
|
138
140
|
# different models could be using different configs on the default
|
139
141
|
# shard, and database server wouldn't know about that
|
140
142
|
config = default_pool.spec.instance_variable_get(:@config)
|
141
|
-
if config[
|
142
|
-
config = config.merge(config[
|
143
|
-
elsif config[
|
144
|
-
config = config.merge(config[
|
143
|
+
if config[active_guard_rail_environment].is_a?(Hash)
|
144
|
+
config = config.merge(config[active_guard_rail_environment])
|
145
|
+
elsif config[active_guard_rail_environment].is_a?(Array)
|
146
|
+
config = config.merge(config[active_guard_rail_environment].first)
|
145
147
|
else
|
146
148
|
config = config.dup
|
147
149
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "securerandom"
|
2
4
|
|
3
5
|
module Switchman
|
@@ -69,12 +71,12 @@ module Switchman
|
|
69
71
|
@fake
|
70
72
|
end
|
71
73
|
|
72
|
-
def config(environment = :
|
74
|
+
def config(environment = :primary)
|
73
75
|
@configs[environment] ||= begin
|
74
76
|
if @config[environment].is_a?(Array)
|
75
77
|
@config[environment].map do |config|
|
76
78
|
config = @config.merge((config || {}).symbolize_keys)
|
77
|
-
# make sure
|
79
|
+
# make sure GuardRail doesn't get any brilliant ideas about choosing the first possible server
|
78
80
|
config.delete(environment)
|
79
81
|
config
|
80
82
|
end
|
@@ -86,33 +88,33 @@ module Switchman
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
def
|
90
|
-
@
|
91
|
+
def guard_rail_environment
|
92
|
+
@guard_rail_environment || ::GuardRail.environment
|
91
93
|
end
|
92
94
|
|
93
95
|
# locks this db to a specific environment, except for
|
94
96
|
# when doing writes (then it falls back to the current
|
95
|
-
# value of
|
96
|
-
def
|
97
|
-
@
|
97
|
+
# value of GuardRail.environment)
|
98
|
+
def guard!(environment = :secondary)
|
99
|
+
@guard_rail_environment = environment
|
98
100
|
end
|
99
101
|
|
100
|
-
def
|
101
|
-
@
|
102
|
+
def unguard!
|
103
|
+
@guard_rail_environment = nil
|
102
104
|
end
|
103
105
|
|
104
|
-
def
|
105
|
-
old_env = @
|
106
|
-
|
106
|
+
def unguard
|
107
|
+
old_env = @guard_rail_environment
|
108
|
+
unguard!
|
107
109
|
yield
|
108
110
|
ensure
|
109
|
-
|
111
|
+
guard!(old_env)
|
110
112
|
end
|
111
113
|
|
112
114
|
def shareable?
|
113
115
|
@shareable_environment_key ||= []
|
114
|
-
environment =
|
115
|
-
explicit_user = ::
|
116
|
+
environment = guard_rail_environment
|
117
|
+
explicit_user = ::GuardRail.global_config[:username]
|
116
118
|
return @shareable if @shareable_environment_key == [environment, explicit_user]
|
117
119
|
@shareable_environment_key = [environment, explicit_user]
|
118
120
|
if explicit_user
|
@@ -190,7 +192,7 @@ module Switchman
|
|
190
192
|
begin
|
191
193
|
self.class.creating_new_shard = true
|
192
194
|
shard.activate(*Shard.categories) do
|
193
|
-
::
|
195
|
+
::GuardRail.activate(:deploy) do
|
194
196
|
begin
|
195
197
|
if create_statement
|
196
198
|
if (::ActiveRecord::Base.connection.select_value("SELECT 1 FROM pg_namespace WHERE nspname=#{::ActiveRecord::Base.connection.quote(name)}"))
|
data/lib/switchman/engine.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
class Engine < ::Rails::Engine
|
3
5
|
isolate_namespace Switchman
|
@@ -87,7 +89,7 @@ module Switchman
|
|
87
89
|
require "switchman/arel"
|
88
90
|
require "switchman/call_super"
|
89
91
|
require "switchman/rails"
|
90
|
-
require "switchman/
|
92
|
+
require "switchman/guard_rail/relation"
|
91
93
|
require_dependency "switchman/shard"
|
92
94
|
require "switchman/standard_error"
|
93
95
|
|
@@ -133,7 +135,7 @@ module Switchman
|
|
133
135
|
::ActiveRecord::Relation.prepend(ActiveRecord::Calculations)
|
134
136
|
::ActiveRecord::Relation.include(ActiveRecord::FinderMethods)
|
135
137
|
::ActiveRecord::Relation.include(ActiveRecord::QueryMethods)
|
136
|
-
::ActiveRecord::Relation.prepend(
|
138
|
+
::ActiveRecord::Relation.prepend(GuardRail::Relation)
|
137
139
|
::ActiveRecord::Relation.prepend(ActiveRecord::Relation)
|
138
140
|
::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
|
139
141
|
::ActiveRecord::Relation.include(CallSuper)
|
@@ -150,8 +152,8 @@ module Switchman
|
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
153
|
-
def self.foreign_key_check(name, type,
|
154
|
-
if name.to_s =~ /_id\z/ && type.to_s == 'integer' &&
|
155
|
+
def self.foreign_key_check(name, type, limit: nil)
|
156
|
+
if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
|
155
157
|
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`"
|
156
158
|
end
|
157
159
|
end
|
@@ -185,15 +187,15 @@ module Switchman
|
|
185
187
|
end
|
186
188
|
end
|
187
189
|
|
188
|
-
initializer 'switchman.
|
190
|
+
initializer 'switchman.extend_guard_rail', :before => "switchman.extend_ar" do
|
189
191
|
::ActiveSupport.on_load(:active_record) do
|
190
|
-
require "switchman/
|
192
|
+
require "switchman/guard_rail"
|
191
193
|
|
192
|
-
::
|
194
|
+
::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
|
193
195
|
end
|
194
196
|
end
|
195
197
|
|
196
|
-
initializer 'switchman.extend_controller', :after => "
|
198
|
+
initializer 'switchman.extend_controller', :after => "guard_rail.extend_ar" do
|
197
199
|
::ActiveSupport.on_load(:action_controller) do
|
198
200
|
require "switchman/action_controller/caching"
|
199
201
|
|
data/lib/switchman/errors.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
|
-
module
|
4
|
+
module GuardRail
|
3
5
|
module ClassMethods
|
4
6
|
def self.prepended(klass)
|
5
7
|
klass.send(:remove_method, :ensure_handler)
|
6
8
|
end
|
7
9
|
|
8
10
|
# drops the save_handler and ensure_handler calls from the vanilla
|
9
|
-
#
|
11
|
+
# GuardRail' implementation.
|
10
12
|
def activate!(environment)
|
11
|
-
environment ||= :
|
13
|
+
environment ||= :primary
|
12
14
|
activated_environments << environment
|
13
15
|
old_environment = self.environment
|
14
|
-
Thread.current[:
|
16
|
+
Thread.current[:guard_rail_environment] = environment
|
15
17
|
old_environment
|
16
18
|
end
|
17
19
|
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
|
-
module
|
4
|
+
module GuardRail
|
3
5
|
module Relation
|
4
6
|
def exec_queries(*args)
|
5
7
|
if self.lock_value
|
6
8
|
db = Shard.current(shard_category).database_server
|
7
|
-
if ::
|
8
|
-
return db.
|
9
|
+
if ::GuardRail.environment != db.guard_rail_environment
|
10
|
+
return db.unguard { super }
|
9
11
|
end
|
10
12
|
end
|
11
13
|
super
|
@@ -15,8 +17,8 @@ module Switchman
|
|
15
17
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
18
|
def #{method}(*args)
|
17
19
|
db = Shard.current(shard_category).database_server
|
18
|
-
if ::
|
19
|
-
db.
|
20
|
+
if ::GuardRail.environment != db.guard_rail_environment
|
21
|
+
db.unguard { super }
|
20
22
|
else
|
21
23
|
super
|
22
24
|
end
|
data/lib/switchman/open4.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "switchman/test_helper"
|
2
4
|
|
3
5
|
module Switchman
|
@@ -65,7 +67,7 @@ module Switchman
|
|
65
67
|
(@@shard3.drop_database if @@shard3) rescue nil
|
66
68
|
@@shard1 = @@shard2 = @@shard3 = nil
|
67
69
|
Shard.delete_all
|
68
|
-
Shard.default(true)
|
70
|
+
Shard.default(reload: true)
|
69
71
|
next
|
70
72
|
end
|
71
73
|
end
|
@@ -73,7 +75,7 @@ module Switchman
|
|
73
75
|
# in the db before then
|
74
76
|
Shard.delete_all
|
75
77
|
Switchman.cache.delete("default_shard")
|
76
|
-
Shard.default(true)
|
78
|
+
Shard.default(reload: true)
|
77
79
|
puts "Done!"
|
78
80
|
|
79
81
|
at_exit do
|
@@ -102,7 +104,7 @@ module Switchman
|
|
102
104
|
dup.id = @@default_shard.id
|
103
105
|
dup.save!
|
104
106
|
Switchman.cache.delete("default_shard")
|
105
|
-
Shard.default(true)
|
107
|
+
Shard.default(reload: true)
|
106
108
|
dup = @@shard1.dup
|
107
109
|
dup.id = @@shard1.id
|
108
110
|
dup.save!
|
@@ -122,7 +124,7 @@ module Switchman
|
|
122
124
|
raise "Sharding did not set up correctly" if @@sharding_failed
|
123
125
|
Shard.clear_cache
|
124
126
|
if use_transactional_tests
|
125
|
-
Shard.default(true)
|
127
|
+
Shard.default(reload: true)
|
126
128
|
@shard1 = Shard.find(@shard1.id)
|
127
129
|
@shard2 = Shard.find(@shard2.id)
|
128
130
|
shards = [@shard2]
|
@@ -151,7 +153,7 @@ module Switchman
|
|
151
153
|
klass.after(:all) do
|
152
154
|
Shard.connection.update("TRUNCATE #{Shard.quoted_table_name} CASCADE")
|
153
155
|
Switchman.cache.delete("default_shard")
|
154
|
-
Shard.default(true)
|
156
|
+
Shard.default(reload: true)
|
155
157
|
end
|
156
158
|
end
|
157
159
|
end
|