switchman 1.15.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6521b8f2a993bab5cb400bdc0fa741fd6e2391e7efb9801f058f21fe3c75169f
4
- data.tar.gz: e96468030c6d98b3c93730877ba6943d5c925255f59ed4a09c3ddfa0bce7388a
3
+ metadata.gz: 0d6fc62ea8d63155621448b9dc70e5aab0bfa3e15b766ad6bc8b7282e124933b
4
+ data.tar.gz: 210c939e4c6a5c1c4b340e81c91fa68c0e019adeabf7dd0500f42eaa3605ad1e
5
5
  SHA512:
6
- metadata.gz: 32b791ddb7c5198a5fcd96448ee0abe59d011f0c422ba9115df5b44e50a53c8a6f4ac1bea35e2a98db52cbfb5f46cb501dbf30dde123125bfef599f67c1ccd86
7
- data.tar.gz: ca11fa309c8f3c5bd7f9a9466327e95fddcff2342dc15d7732adaecab09911a2f9bfc0b2ed0d90cdd8899bf470d3a776945b86a470b8c84f5845878f9b46df0c
6
+ metadata.gz: 780cc1c19606c00ecfb8df648a3f2d1e9744f375ff0a1e7793482108f81221f313254e16873db977af14e19adb0cb3d1bd9af3318c15c92ba3e54e01a91eb072
7
+ data.tar.gz: fe688c62be4f0b5e36279b93925377d3165d238a19c37124d90d464b9eac08691f2b8f0f550e56ccf5dd092cd872a3bf1ec23780fc719b8b2cf3a62539a06113
@@ -38,7 +38,10 @@ module Switchman
38
38
  end
39
39
 
40
40
  def default(reload_deprecated = false, reload: false, with_fallback: false)
41
- reload = reload_deprecated if reload_deprecated
41
+ if reload_deprecated
42
+ reload = reload_deprecated
43
+ ::ActiveSupport::Deprecation.warn("positional reload parameter to Switchman::Shard.default is deprecated; use `reload: true`")
44
+ end
42
45
  if !@default || reload
43
46
  # Have to create a dummy object so that several key methods still work
44
47
  # (it's easier to do this in one place here, and just assume that sharding
@@ -351,8 +354,8 @@ module Switchman
351
354
  # prune the prior connection unless it happened to be the same
352
355
  if previous_shard && shard != previous_shard && !previous_shard.database_server.shareable?
353
356
  previous_shard.activate do
354
- ::Shackles.activated_environments.each do |env|
355
- ::Shackles.activate(env) do
357
+ ::GuardRail.activated_environments.each do |env|
358
+ ::GuardRail.activate(env) do
356
359
  if ::ActiveRecord::Base.connected? && ::ActiveRecord::Base.connection.open_transactions == 0
357
360
  ::ActiveRecord::Base.connection_pool.current_pool.disconnect!
358
361
  end
@@ -425,6 +428,19 @@ module Switchman
425
428
  end
426
429
  end
427
430
 
431
+ # it's tedious to hold onto this same
432
+ # kind of sign state and transform the
433
+ # result in multiple places, so
434
+ # here we can operate on the absolute value
435
+ # in a provided block and trust the sign will
436
+ # stay as provided. This assumes no consumer
437
+ # will return a nil value from the block.
438
+ def signed_id_operation(input_id)
439
+ sign = input_id < 0 ? -1 : 1
440
+ output = yield input_id.abs
441
+ output * sign
442
+ end
443
+
428
444
  # converts an AR object, integral id, string id, or string short-global-id to a
429
445
  # integral id. nil if it can't be interpreted
430
446
  def integral_id_for(any_id)
@@ -437,12 +453,13 @@ module Switchman
437
453
  case any_id
438
454
  when ::ActiveRecord::Base
439
455
  any_id.id
440
- when /^(\d+)~(\d+)$/
456
+ when /^(\d+)~(-?\d+)$/
441
457
  local_id = $2.to_i
442
- # doesn't make sense to have a double-global id
443
- return nil if local_id > IDS_PER_SHARD
444
- $1.to_i * IDS_PER_SHARD + local_id
445
- when Integer, /^\d+$/
458
+ signed_id_operation(local_id) do |id|
459
+ return nil if id > IDS_PER_SHARD
460
+ $1.to_i * IDS_PER_SHARD + id
461
+ end
462
+ when Integer, /^-?\d+$/
446
463
  any_id.to_i
447
464
  else
448
465
  nil
@@ -457,13 +474,17 @@ module Switchman
457
474
  def local_id_for(any_id)
458
475
  id = integral_id_for(any_id)
459
476
  return NIL_NIL_ID unless id
460
- if id < IDS_PER_SHARD
461
- [id, nil]
462
- elsif shard = lookup(id / IDS_PER_SHARD)
463
- [id % IDS_PER_SHARD, shard]
464
- else
465
- NIL_NIL_ID
477
+ return_shard = nil
478
+ local_id = signed_id_operation(id) do |abs_id|
479
+ if abs_id < IDS_PER_SHARD
480
+ abs_id
481
+ elsif return_shard = lookup(abs_id / IDS_PER_SHARD)
482
+ abs_id % IDS_PER_SHARD
483
+ else
484
+ return NIL_NIL_ID
485
+ end
466
486
  end
487
+ [local_id, return_shard]
467
488
  end
468
489
 
469
490
  # takes an id-ish, and returns an integral id relative to
@@ -494,11 +515,13 @@ module Switchman
494
515
  def global_id_for(any_id, source_shard = nil)
495
516
  id = integral_id_for(any_id)
496
517
  return any_id unless id
497
- if id >= IDS_PER_SHARD
498
- id
499
- else
500
- source_shard ||= Shard.current
501
- source_shard.global_id_for(id)
518
+ signed_id_operation(id) do |abs_id|
519
+ if abs_id >= IDS_PER_SHARD
520
+ abs_id
521
+ else
522
+ source_shard ||= Shard.current
523
+ source_shard.global_id_for(abs_id)
524
+ end
502
525
  end
503
526
  end
504
527
 
@@ -639,7 +662,7 @@ module Switchman
639
662
  case adapter
640
663
  when 'mysql', 'mysql2'
641
664
  self.activate do
642
- ::Shackles.activate(:deploy) do
665
+ ::GuardRail.activate(:deploy) do
643
666
  drop_statement ||= "DROP DATABASE #{self.name}"
644
667
  Array(drop_statement).each do |stmt|
645
668
  ::ActiveRecord::Base.connection.execute(stmt)
@@ -648,7 +671,7 @@ module Switchman
648
671
  end
649
672
  when 'postgresql'
650
673
  self.activate do
651
- ::Shackles.activate(:deploy) do
674
+ ::GuardRail.activate(:deploy) do
652
675
  # Shut up, Postgres!
653
676
  conn = ::ActiveRecord::Base.connection
654
677
  old_proc = conn.raw_connection.set_notice_processor {}
@@ -671,7 +694,9 @@ module Switchman
671
694
  # takes an id local to this shard, and returns a global id
672
695
  def global_id_for(local_id)
673
696
  return nil unless local_id
674
- local_id + self.id * IDS_PER_SHARD
697
+ self.class.signed_id_operation(local_id) do |abs_id|
698
+ abs_id + self.id * IDS_PER_SHARD
699
+ end
675
700
  end
676
701
 
677
702
  # skip global_id.hash
@@ -3,7 +3,7 @@ class CreateDefaultShard < ActiveRecord::Migration[4.2]
3
3
  unless Switchman::Shard.default.is_a?(Switchman::Shard)
4
4
  Switchman::Shard.reset_column_information
5
5
  Switchman::Shard.create!(:default => true)
6
- Switchman::Shard.default(true)
6
+ Switchman::Shard.default(reload: true)
7
7
  end
8
8
  end
9
9
  end
@@ -1,4 +1,4 @@
1
- require "shackles"
1
+ require "guard_rail"
2
2
  require "switchman/open4"
3
3
  require "switchman/engine"
4
4
 
@@ -4,8 +4,8 @@ module Switchman
4
4
  module ActiveRecord
5
5
  module AbstractAdapter
6
6
  module ForeignKeyCheck
7
- def add_column(table, name, type, options = {})
8
- Engine.foreign_key_check(name, type, options)
7
+ def add_column(table, name, type, limit: nil, **)
8
+ Engine.foreign_key_check(name, type, limit: limit)
9
9
  super
10
10
  end
11
11
  end
@@ -27,10 +27,6 @@ module Switchman
27
27
  quote_table_name(name)
28
28
  end
29
29
 
30
- def use_qualified_names?
31
- false
32
- end
33
-
34
30
  protected
35
31
 
36
32
  def log(*args, &block)
@@ -31,20 +31,20 @@ module Switchman
31
31
  @integral_id
32
32
  end
33
33
 
34
- def transaction(*args)
34
+ def transaction(**)
35
35
  if self != ::ActiveRecord::Base && current_scope
36
36
  current_scope.activate do
37
37
  db = Shard.current(shard_category).database_server
38
- if ::Shackles.environment != db.shackles_environment
39
- db.unshackle { super }
38
+ if ::GuardRail.environment != db.guard_rail_environment
39
+ db.unguard { super }
40
40
  else
41
41
  super
42
42
  end
43
43
  end
44
44
  else
45
45
  db = Shard.current(shard_category).database_server
46
- if ::Shackles.environment != db.shackles_environment
47
- db.unshackle { super }
46
+ if ::GuardRail.environment != db.guard_rail_environment
47
+ db.unguard { super }
48
48
  else
49
49
  super
50
50
  end
@@ -105,12 +105,12 @@ module Switchman
105
105
  end
106
106
  end
107
107
 
108
- def save(*args)
108
+ def save(*, **)
109
109
  @shard_set_in_stone = true
110
110
  (self.class.current_scope || self.class.default_scoped).shard(shard, :implicit).scoping { super }
111
111
  end
112
112
 
113
- def save!(*args)
113
+ def save!(*, **)
114
114
  @shard_set_in_stone = true
115
115
  (self.class.current_scope || self.class.default_scoped).shard(shard, :implicit).scoping { super }
116
116
  end
@@ -128,9 +128,9 @@ module Switchman
128
128
  result
129
129
  end
130
130
 
131
- def transaction(options={}, &block)
131
+ def transaction(**kwargs, &block)
132
132
  shard.activate(self.class.shard_category) do
133
- self.class.transaction(options, &block)
133
+ self.class.transaction(**kwargs, &block)
134
134
  end
135
135
  end
136
136
 
@@ -155,6 +155,15 @@ module Switchman
155
155
  self.class.connection.quote(id)
156
156
  end
157
157
 
158
+ def update_columns(*)
159
+ db = Shard.current(self.class.shard_category).database_server
160
+ if ::GuardRail.environment != db.guard_rail_environment
161
+ return db.unguard { super }
162
+ else
163
+ super
164
+ end
165
+ end
166
+
158
167
  protected
159
168
 
160
169
  # see also AttributeMethods#shard_category_code_for_reflection
@@ -4,8 +4,6 @@ module Switchman
4
4
  module ActiveRecord
5
5
  module ConnectionHandler
6
6
  def self.make_sharing_automagic(config, shard = Shard.current)
7
- key = config[:adapter] == 'postgresql' ? :schema_search_path : :database
8
-
9
7
  # only load the shard name from the db if we have to
10
8
  if !config[:shard_name]
11
9
  # we may not be able to connect to this shard yet, cause it might be an empty database server
@@ -15,12 +13,6 @@ module Switchman
15
13
 
16
14
  config[:shard_name] ||= shard_name
17
15
  end
18
-
19
- if !config[key] || config[key] == shard_name
20
- # this may truncate the schema_search_path if it was not specified in database.yml
21
- # but that's what our old behavior was anyway, so I guess it's okay
22
- config[key] = '%{shard_name}'
23
- end
24
16
  end
25
17
 
26
18
  def establish_connection(spec)
@@ -63,7 +55,7 @@ module Switchman
63
55
  Shard.default.remove_instance_variable(:@name) if Shard.default.instance_variable_defined?(:@name)
64
56
  end
65
57
 
66
- @shard_connection_pools ||= { [:master, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
58
+ @shard_connection_pools ||= { [:primary, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
67
59
 
68
60
  category = pool.spec.name.to_sym
69
61
  proxy = ConnectionPoolProxy.new(category,
@@ -72,13 +64,13 @@ module Switchman
72
64
  owner_to_pool[pool.spec.name] = proxy
73
65
 
74
66
  if first_time
75
- if Shard.default.database_server.config[:prefer_slave]
76
- Shard.default.database_server.shackle!
67
+ if Shard.default.database_server.config[:prefer_secondary]
68
+ Shard.default.database_server.guard!
77
69
  end
78
70
 
79
- if Shard.default.is_a?(DefaultShard) && Shard.default.database_server.config[:slave]
80
- Shard.default.database_server.shackle!
81
- Shard.default(true)
71
+ if Shard.default.is_a?(DefaultShard) && Shard.default.database_server.config[:secondary]
72
+ Shard.default.database_server.guard!
73
+ Shard.default(reload: true)
82
74
  end
83
75
  end
84
76
 
@@ -84,18 +84,6 @@ module Switchman
84
84
  end
85
85
 
86
86
  spec.config[:shard_name] = self.shard.name
87
- case conn.adapter_name
88
- when 'MySQL', 'Mysql2'
89
- conn.execute("USE #{spec.config[:database]}")
90
- when 'PostgreSQL'
91
- if conn.schema_search_path != spec.config[:schema_search_path]
92
- conn.schema_search_path = spec.config[:schema_search_path]
93
- end
94
- when 'SQLite'
95
- # This is an artifact of the adapter modifying the path to be an absolute path when it is instantiated; just let it slide
96
- else
97
- raise("Cannot switch databases on same DatabaseServer with adapter type: #{conn.adapter_name}. Limit one Shard per DatabaseServer.")
98
- end
99
87
  conn.shard = shard
100
88
  end
101
89
 
@@ -33,5 +33,14 @@ module Switchman
33
33
  ::ActiveRecord::Migrator::MIGRATOR_SALT * shard_name_hash
34
34
  end
35
35
  end
36
+
37
+ module MigrationContext
38
+ def migrations
39
+ return @migrations if instance_variable_defined?(:@migrations)
40
+ migrations_cache = Thread.current[:migrations_cache] ||= {}
41
+ key = Digest::MD5.hexdigest(migration_files.sort.join(','))
42
+ @migrations = migrations_cache[key] ||= super
43
+ end
44
+ end
36
45
  end
37
46
  end
@@ -2,7 +2,7 @@ module Switchman
2
2
  module ActiveRecord
3
3
  module Persistence
4
4
  # touch reads the id attribute directly, so it's not relative to the current shard
5
- def touch(*)
5
+ def touch(*, **)
6
6
  shard.activate(self.class.shard_category) { super }
7
7
  end
8
8
 
@@ -38,23 +38,17 @@ module Switchman
38
38
  select_values("SELECT * FROM unnest(current_schemas(false))")
39
39
  end
40
40
 
41
- def use_qualified_names?
42
- @config[:use_qualified_names]
43
- end
44
-
45
41
  def tables(name = nil)
46
- schema = shard.name if use_qualified_names?
47
-
48
42
  query(<<-SQL, 'SCHEMA').map { |row| row[0] }
49
43
  SELECT tablename
50
44
  FROM pg_tables
51
- WHERE schemaname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'}
45
+ WHERE schemaname = '#{shard.name}'
52
46
  SQL
53
47
  end
54
48
 
55
49
  def extract_schema_qualified_name(string)
56
50
  name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(string.to_s)
57
- if string && !name.schema && use_qualified_names?
51
+ if string && !name.schema
58
52
  name.instance_variable_set(:@schema, shard.name)
59
53
  end
60
54
  [name.schema, name.identifier]
@@ -63,7 +57,7 @@ module Switchman
63
57
  def view_exists?(name)
64
58
  name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
65
59
  return false unless name.identifier
66
- if !name.schema && use_qualified_names?
60
+ if !name.schema
67
61
  name.instance_variable_set(:@schema, shard.name)
68
62
  end
69
63
 
@@ -73,13 +67,11 @@ module Switchman
73
67
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
74
68
  WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
75
69
  AND c.relname = '#{name.identifier}'
76
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
70
+ AND n.nspname = '#{shard.name}'
77
71
  SQL
78
72
  end
79
73
 
80
74
  def indexes(table_name)
81
- schema = shard.name if use_qualified_names?
82
-
83
75
  result = query(<<-SQL, 'SCHEMA')
84
76
  SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
85
77
  FROM pg_class t
@@ -88,7 +80,7 @@ module Switchman
88
80
  WHERE i.relkind = 'i'
89
81
  AND d.indisprimary = 'f'
90
82
  AND t.relname = '#{table_name}'
91
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'} )
83
+ AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = '#{shard.name}' )
92
84
  ORDER BY i.relname
93
85
  SQL
94
86
 
@@ -126,8 +118,6 @@ module Switchman
126
118
  end
127
119
 
128
120
  def index_name_exists?(table_name, index_name, _default = nil)
129
- schema = shard.name if use_qualified_names?
130
-
131
121
  exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
132
122
  SELECT COUNT(*)
133
123
  FROM pg_class t
@@ -136,7 +126,7 @@ module Switchman
136
126
  WHERE i.relkind = 'i'
137
127
  AND i.relname = '#{index_name}'
138
128
  AND t.relname = '#{table_name}'
139
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'} )
129
+ AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = '#{shard.name}' )
140
130
  SQL
141
131
  end
142
132
 
@@ -150,7 +140,7 @@ module Switchman
150
140
  def quote_table_name(name)
151
141
  return quote_local_table_name(name) if @use_local_table_name
152
142
  name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
153
- if !name.schema && use_qualified_names?
143
+ if !name.schema
154
144
  name.instance_variable_set(:@schema, shard.name)
155
145
  end
156
146
  name.quoted
@@ -165,7 +155,6 @@ module Switchman
165
155
  end
166
156
 
167
157
  def foreign_keys(table_name)
168
- schema = shard.name if use_qualified_names?
169
158
 
170
159
  # mostly copy-pasted from AR - only change is to the nspname condition for qualified names support
171
160
  fk_info = select_all <<-SQL.strip_heredoc
@@ -178,7 +167,7 @@ module Switchman
178
167
  JOIN pg_namespace t3 ON c.connamespace = t3.oid
179
168
  WHERE c.contype = 'f'
180
169
  AND t1.relname = #{quote(table_name)}
181
- AND t3.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'}
170
+ AND t3.nspname = '#{shard.name}'
182
171
  ORDER BY c.conname
183
172
  SQL
184
173
 
@@ -195,7 +184,7 @@ module Switchman
195
184
  # strip the schema name from to_table if it matches
196
185
  to_table = row['to_table']
197
186
  to_table_qualified_name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(to_table)
198
- if use_qualified_names? && to_table_qualified_name.schema == shard.name
187
+ if to_table_qualified_name.schema == shard.name
199
188
  to_table = to_table_qualified_name.identifier
200
189
  end
201
190
 
@@ -203,7 +192,7 @@ module Switchman
203
192
  end
204
193
  end
205
194
 
206
- def add_index_options(_table_name, _column_name, _options = {})
195
+ def add_index_options(_table_name, _column_name, **)
207
196
  index_name, index_type, index_columns, index_options, algorithm, using = super
208
197
  algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
209
198
  [index_name, index_type, index_columns, index_options, algorithm, using]
@@ -5,7 +5,7 @@ module Switchman
5
5
  klass::SINGLE_VALUE_METHODS.concat [ :shard, :shard_source ]
6
6
  end
7
7
 
8
- def initialize(*args)
8
+ def initialize(*, **)
9
9
  super
10
10
  self.shard_value = Shard.current(klass ? klass.shard_category : :primary) unless shard_value
11
11
  self.shard_source_value = :implicit unless shard_source_value
@@ -17,7 +17,7 @@ module Switchman
17
17
  result
18
18
  end
19
19
 
20
- def merge(*args)
20
+ def merge(*)
21
21
  relation = super
22
22
  if relation.shard_value != self.shard_value && relation.shard_source_value == :implicit
23
23
  relation.shard_value = self.shard_value
@@ -26,15 +26,15 @@ module Switchman
26
26
  relation
27
27
  end
28
28
 
29
- def new(*args, &block)
29
+ def new(*, &block)
30
30
  primary_shard.activate(klass.shard_category) { super }
31
31
  end
32
32
 
33
- def create(*args, &block)
33
+ def create(*, &block)
34
34
  primary_shard.activate(klass.shard_category) { super }
35
35
  end
36
36
 
37
- def create!(*args, &block)
37
+ def create!(*, &block)
38
38
  primary_shard.activate(klass.shard_category) { super }
39
39
  end
40
40
 
@@ -2,7 +2,7 @@ module Switchman
2
2
  module ActiveRecord
3
3
  module StatementCache
4
4
  module ClassMethods
5
- def create(connection, block = Proc.new)
5
+ def create(connection, &block)
6
6
  relation = block.call ::ActiveRecord::StatementCache::Params.new
7
7
 
8
8
  if ::Rails.version >= "5.2"
@@ -46,29 +46,16 @@ module Switchman
46
46
  bind_values = bind_map.bind(params, current_shard, target_shard)
47
47
 
48
48
  target_shard.activate(klass.shard_category) do
49
- if connection.use_qualified_names?
50
- sql = qualified_query_builder(target_shard, klass).sql_for(bind_values, connection)
51
- klass.find_by_sql(sql, bind_values)
52
- else
53
- sql = generic_query_builder(connection).sql_for(bind_values, connection)
54
- klass.find_by_sql(sql, bind_values)
55
- end
49
+ sql = qualified_query_builder(target_shard, klass).sql_for(bind_values, connection)
50
+ klass.find_by_sql(sql, bind_values)
56
51
  end
57
52
  end
58
53
 
59
54
  if ::Rails.version < '5.2'
60
- def generic_query_builder(connection)
61
- @query_builder ||= connection.cacheable_query(self.class, @arel)
62
- end
63
-
64
55
  def qualified_query_builder(shard, klass)
65
56
  @qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(self.class, @arel)
66
57
  end
67
58
  else
68
- def generic_query_builder(connection)
69
- @query_builder ||= connection.cacheable_query(self.class, @arel).first
70
- end
71
-
72
59
  def qualified_query_builder(shard, klass)
73
60
  @qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(self.class, @arel).first
74
61
  end
@@ -1,8 +1,8 @@
1
1
  module Switchman
2
2
  module ActiveRecord
3
3
  module TableDefinition
4
- def column(name, type, options = {})
5
- Engine.foreign_key_check(name, type, options)
4
+ def column(name, type, limit: nil, **)
5
+ Engine.foreign_key_check(name, type, limit: limit)
6
6
  super
7
7
  end
8
8
  end
@@ -15,12 +15,12 @@ module Switchman
15
15
  end
16
16
 
17
17
  module RedisCacheStore
18
- def clear(options = {})
18
+ def clear(namespace: nil, **)
19
19
  # RedisCacheStore tries to be smart and only clear the cache under your namespace, if you have one set
20
20
  # unfortunately, it uses the keys command, which is extraordinarily inefficient in a large redis instance
21
21
  # fortunately, we can assume we control the entire instance, because we set up the namespacing, so just
22
22
  # always unset it temporarily for clear calls
23
- options[:namespace] = nil
23
+ namespace = nil
24
24
  super
25
25
  end
26
26
  end
@@ -37,13 +37,13 @@ module Switchman
37
37
  Shard.current(@category)
38
38
  end
39
39
 
40
- def active_shackles_environment
41
- ::Rails.env.test? ? :master : active_shard.database_server.shackles_environment
40
+ def active_guard_rail_environment
41
+ ::Rails.env.test? ? :primary : active_shard.database_server.guard_rail_environment
42
42
  end
43
43
 
44
44
  def current_pool
45
45
  current_active_shard = active_shard
46
- pool = self.default_pool if current_active_shard.database_server == Shard.default.database_server && active_shackles_environment == :master && (current_active_shard.default? || current_active_shard.database_server.shareable?)
46
+ 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
47
  pool = @connection_pools[pool_key] ||= create_pool unless pool
48
48
  pool.shard = current_active_shard
49
49
  pool
@@ -60,8 +60,8 @@ module Switchman
60
60
  connection.instance_variable_set(:@schema_cache, @schema_cache) unless ::Rails.version >= '6'
61
61
  connection
62
62
  rescue ConnectionError
63
- raise if active_shard.database_server == Shard.default.database_server && active_shackles_environment == :master
64
- configs = active_shard.database_server.config(active_shackles_environment)
63
+ raise if active_shard.database_server == Shard.default.database_server && active_guard_rail_environment == :primary
64
+ configs = active_shard.database_server.config(active_guard_rail_environment)
65
65
  raise unless configs.is_a?(Array)
66
66
  configs.each_with_index do |config, idx|
67
67
  pool = create_pool(config.dup)
@@ -120,7 +120,7 @@ module Switchman
120
120
  end
121
121
 
122
122
  def pool_key
123
- [active_shackles_environment,
123
+ [active_guard_rail_environment,
124
124
  active_shard.database_server.shareable? ? active_shard.database_server.pool_key : active_shard]
125
125
  end
126
126
 
@@ -128,7 +128,7 @@ module Switchman
128
128
  shard = active_shard
129
129
  unless config
130
130
  if shard != Shard.default
131
- config = shard.database_server.config(active_shackles_environment)
131
+ config = shard.database_server.config(active_guard_rail_environment)
132
132
  config = config.first if config.is_a?(Array)
133
133
  config = config.dup
134
134
  else
@@ -138,10 +138,10 @@ module Switchman
138
138
  # different models could be using different configs on the default
139
139
  # shard, and database server wouldn't know about that
140
140
  config = default_pool.spec.instance_variable_get(:@config)
141
- if config[active_shackles_environment].is_a?(Hash)
142
- config = config.merge(config[active_shackles_environment])
143
- elsif config[active_shackles_environment].is_a?(Array)
144
- config = config.merge(config[active_shackles_environment].first)
141
+ if config[active_guard_rail_environment].is_a?(Hash)
142
+ config = config.merge(config[active_guard_rail_environment])
143
+ elsif config[active_guard_rail_environment].is_a?(Array)
144
+ config = config.merge(config[active_guard_rail_environment].first)
145
145
  else
146
146
  config = config.dup
147
147
  end
@@ -69,12 +69,12 @@ module Switchman
69
69
  @fake
70
70
  end
71
71
 
72
- def config(environment = :master)
72
+ def config(environment = :primary)
73
73
  @configs[environment] ||= begin
74
74
  if @config[environment].is_a?(Array)
75
75
  @config[environment].map do |config|
76
76
  config = @config.merge((config || {}).symbolize_keys)
77
- # make sure Shackles doesn't get any brilliant ideas about choosing the first possible server
77
+ # make sure GuardRail doesn't get any brilliant ideas about choosing the first possible server
78
78
  config.delete(environment)
79
79
  config
80
80
  end
@@ -86,33 +86,33 @@ module Switchman
86
86
  end
87
87
  end
88
88
 
89
- def shackles_environment
90
- @shackles_environment || ::Shackles.environment
89
+ def guard_rail_environment
90
+ @guard_rail_environment || ::GuardRail.environment
91
91
  end
92
92
 
93
93
  # locks this db to a specific environment, except for
94
94
  # when doing writes (then it falls back to the current
95
- # value of Shackles.environment)
96
- def shackle!(environment = :slave)
97
- @shackles_environment = environment
95
+ # value of GuardRail.environment)
96
+ def guard!(environment = :secondary)
97
+ @guard_rail_environment = environment
98
98
  end
99
99
 
100
- def unshackle!
101
- @shackles_environment = nil
100
+ def unguard!
101
+ @guard_rail_environment = nil
102
102
  end
103
103
 
104
- def unshackle
105
- old_env = @shackles_environment
106
- unshackle!
104
+ def unguard
105
+ old_env = @guard_rail_environment
106
+ unguard!
107
107
  yield
108
108
  ensure
109
- shackle!(old_env)
109
+ guard!(old_env)
110
110
  end
111
111
 
112
112
  def shareable?
113
113
  @shareable_environment_key ||= []
114
- environment = shackles_environment
115
- explicit_user = ::Shackles.global_config[:username]
114
+ environment = guard_rail_environment
115
+ explicit_user = ::GuardRail.global_config[:username]
116
116
  return @shareable if @shareable_environment_key == [environment, explicit_user]
117
117
  @shareable_environment_key = [environment, explicit_user]
118
118
  if explicit_user
@@ -190,7 +190,7 @@ module Switchman
190
190
  begin
191
191
  self.class.creating_new_shard = true
192
192
  shard.activate(*Shard.categories) do
193
- ::Shackles.activate(:deploy) do
193
+ ::GuardRail.activate(:deploy) do
194
194
  begin
195
195
  if create_statement
196
196
  if (::ActiveRecord::Base.connection.select_value("SELECT 1 FROM pg_namespace WHERE nspname=#{::ActiveRecord::Base.connection.quote(name)}"))
@@ -87,7 +87,7 @@ module Switchman
87
87
  require "switchman/arel"
88
88
  require "switchman/call_super"
89
89
  require "switchman/rails"
90
- require "switchman/shackles/relation"
90
+ require "switchman/guard_rail/relation"
91
91
  require_dependency "switchman/shard"
92
92
  require "switchman/standard_error"
93
93
 
@@ -122,6 +122,7 @@ module Switchman
122
122
  ::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
123
123
  ::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
124
124
  ::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
125
+ ::ActiveRecord::MigrationContext.prepend(ActiveRecord::MigrationContext) if ::Rails.version >= '5.2'
125
126
  ::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
126
127
 
127
128
  ::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
@@ -132,7 +133,7 @@ module Switchman
132
133
  ::ActiveRecord::Relation.prepend(ActiveRecord::Calculations)
133
134
  ::ActiveRecord::Relation.include(ActiveRecord::FinderMethods)
134
135
  ::ActiveRecord::Relation.include(ActiveRecord::QueryMethods)
135
- ::ActiveRecord::Relation.prepend(Shackles::Relation)
136
+ ::ActiveRecord::Relation.prepend(GuardRail::Relation)
136
137
  ::ActiveRecord::Relation.prepend(ActiveRecord::Relation)
137
138
  ::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
138
139
  ::ActiveRecord::Relation.include(CallSuper)
@@ -149,8 +150,8 @@ module Switchman
149
150
  end
150
151
  end
151
152
 
152
- def self.foreign_key_check(name, type, options)
153
- if name.to_s =~ /_id\z/ && type.to_s == 'integer' && options[:limit].to_i < 8
153
+ def self.foreign_key_check(name, type, limit: nil)
154
+ if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
154
155
  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`"
155
156
  end
156
157
  end
@@ -184,15 +185,15 @@ module Switchman
184
185
  end
185
186
  end
186
187
 
187
- initializer 'switchman.extend_shackles', :before => "switchman.extend_ar" do
188
+ initializer 'switchman.extend_guard_rail', :before => "switchman.extend_ar" do
188
189
  ::ActiveSupport.on_load(:active_record) do
189
- require "switchman/shackles"
190
+ require "switchman/guard_rail"
190
191
 
191
- ::Shackles.singleton_class.prepend(Shackles::ClassMethods)
192
+ ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
192
193
  end
193
194
  end
194
195
 
195
- initializer 'switchman.extend_controller', :after => "shackles.extend_ar" do
196
+ initializer 'switchman.extend_controller', :after => "guard_rail.extend_ar" do
196
197
  ::ActiveSupport.on_load(:action_controller) do
197
198
  require "switchman/action_controller/caching"
198
199
 
@@ -1,17 +1,17 @@
1
1
  module Switchman
2
- module Shackles
2
+ module GuardRail
3
3
  module ClassMethods
4
4
  def self.prepended(klass)
5
5
  klass.send(:remove_method, :ensure_handler)
6
6
  end
7
7
 
8
8
  # drops the save_handler and ensure_handler calls from the vanilla
9
- # Shackles' implementation.
9
+ # GuardRail' implementation.
10
10
  def activate!(environment)
11
- environment ||= :master
11
+ environment ||= :primary
12
12
  activated_environments << environment
13
13
  old_environment = self.environment
14
- Thread.current[:shackles_environment] = environment
14
+ Thread.current[:guard_rail_environment] = environment
15
15
  old_environment
16
16
  end
17
17
 
@@ -1,11 +1,11 @@
1
1
  module Switchman
2
- module Shackles
2
+ module GuardRail
3
3
  module Relation
4
4
  def exec_queries(*args)
5
5
  if self.lock_value
6
6
  db = Shard.current(shard_category).database_server
7
- if ::Shackles.environment != db.shackles_environment
8
- return db.unshackle { super }
7
+ if ::GuardRail.environment != db.guard_rail_environment
8
+ return db.unguard { super }
9
9
  end
10
10
  end
11
11
  super
@@ -15,8 +15,8 @@ module Switchman
15
15
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
16
  def #{method}(*args)
17
17
  db = Shard.current(shard_category).database_server
18
- if ::Shackles.environment != db.shackles_environment
19
- db.unshackle { super }
18
+ if ::GuardRail.environment != db.guard_rail_environment
19
+ db.unguard { super }
20
20
  else
21
21
  super
22
22
  end
@@ -65,7 +65,7 @@ module Switchman
65
65
  (@@shard3.drop_database if @@shard3) rescue nil
66
66
  @@shard1 = @@shard2 = @@shard3 = nil
67
67
  Shard.delete_all
68
- Shard.default(true)
68
+ Shard.default(reload: true)
69
69
  next
70
70
  end
71
71
  end
@@ -73,7 +73,7 @@ module Switchman
73
73
  # in the db before then
74
74
  Shard.delete_all
75
75
  Switchman.cache.delete("default_shard")
76
- Shard.default(true)
76
+ Shard.default(reload: true)
77
77
  puts "Done!"
78
78
 
79
79
  at_exit do
@@ -102,7 +102,7 @@ module Switchman
102
102
  dup.id = @@default_shard.id
103
103
  dup.save!
104
104
  Switchman.cache.delete("default_shard")
105
- Shard.default(true)
105
+ Shard.default(reload: true)
106
106
  dup = @@shard1.dup
107
107
  dup.id = @@shard1.id
108
108
  dup.save!
@@ -122,7 +122,7 @@ module Switchman
122
122
  raise "Sharding did not set up correctly" if @@sharding_failed
123
123
  Shard.clear_cache
124
124
  if use_transactional_tests
125
- Shard.default(true)
125
+ Shard.default(reload: true)
126
126
  @shard1 = Shard.find(@shard1.id)
127
127
  @shard2 = Shard.find(@shard2.id)
128
128
  shards = [@shard2]
@@ -151,7 +151,7 @@ module Switchman
151
151
  klass.after(:all) do
152
152
  Shard.connection.update("TRUNCATE #{Shard.quoted_table_name} CASCADE")
153
153
  Switchman.cache.delete("default_shard")
154
- Shard.default(true)
154
+ Shard.default(reload: true)
155
155
  end
156
156
  end
157
157
  end
@@ -14,7 +14,7 @@ module Switchman
14
14
  payload[:shard] = {
15
15
  database_server_id: shard.database_server.id,
16
16
  id: shard.id,
17
- env: shard.database_server.shackles_environment
17
+ env: shard.database_server.guard_rail_environment
18
18
  }
19
19
  end
20
20
  super name, payload
@@ -3,8 +3,8 @@ module Switchman
3
3
  class << self
4
4
  def recreate_persistent_test_shards(dont_create: false)
5
5
  # recreate the default shard (it got buhleted)
6
- ::Shackles.activate(:deploy) { Switchman.cache.clear }
7
- if Shard.default(true).is_a?(DefaultShard)
6
+ ::GuardRail.activate(:deploy) { Switchman.cache.clear }
7
+ if Shard.default(reload: true).is_a?(DefaultShard)
8
8
  begin
9
9
  Shard.create!(default: true)
10
10
  rescue
@@ -12,7 +12,7 @@ module Switchman
12
12
  # database doesn't exist yet, presumably cause we're creating it right now
13
13
  return [nil, nil]
14
14
  end
15
- Shard.default(true)
15
+ Shard.default(reload: true)
16
16
  end
17
17
 
18
18
  # can't auto-create a new shard on the default shard's db server if the
@@ -1,3 +1,3 @@
1
1
  module Switchman
2
- VERSION = "1.15.0"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -64,8 +64,8 @@ module Switchman
64
64
  TestHelper.recreate_persistent_test_shards(dont_create: true)
65
65
  end
66
66
 
67
- ::Shackles.activate(:deploy) do
68
- Shard.default.database_server.unshackle do
67
+ ::GuardRail.activate(:deploy) do
68
+ Shard.default.database_server.unguard do
69
69
  begin
70
70
  categories = categories.call if categories.respond_to?(:call)
71
71
  Shard.with_each_shard(scope, categories, options) do
@@ -83,7 +83,7 @@ module Switchman
83
83
 
84
84
  ::ActiveRecord::Base.configurations = new_configs
85
85
  end
86
- shard.database_server.unshackle do
86
+ shard.database_server.unguard do
87
87
  old_actions.each { |action| action.call(*task_args) }
88
88
  end
89
89
  nil
@@ -218,16 +218,9 @@ module Switchman
218
218
  args = ['-s', '-x', '-O', '-f', filename]
219
219
  args.concat(Array(extra_flags)) if extra_flags
220
220
  search_path = configuration['schema_search_path']
221
- if configuration['use_qualified_names']
222
- shard = Shard.current.name
223
- serialized_search_path = shard
224
- args << "--schema=#{Shellwords.escape(shard)}"
225
- elsif !search_path.blank?
226
- args << search_path.split(',').map do |part|
227
- "--schema=#{part.strip}"
228
- end.join(' ')
229
- serialized_search_path = connection.schema_search_path
230
- end
221
+ shard = Shard.current.name
222
+ serialized_search_path = shard
223
+ args << "--schema=#{Shellwords.escape(shard)}"
231
224
 
232
225
  args << configuration['database']
233
226
  run_cmd('pg_dump', args, 'dumping')
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  - James Williams
9
9
  - Jacob Fugal
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-05-18 00:00:00.000000000 Z
13
+ date: 2020-10-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
@@ -53,19 +53,19 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '6.1'
55
55
  - !ruby/object:Gem::Dependency
56
- name: shackles
56
+ name: guardrail
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.4.2
61
+ version: 2.0.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.4.2
68
+ version: 2.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: open4
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
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'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: pg
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -214,12 +228,12 @@ files:
214
228
  - lib/switchman/engine.rb
215
229
  - lib/switchman/environment.rb
216
230
  - lib/switchman/errors.rb
231
+ - lib/switchman/guard_rail.rb
232
+ - lib/switchman/guard_rail/relation.rb
217
233
  - lib/switchman/open4.rb
218
234
  - lib/switchman/r_spec_helper.rb
219
235
  - lib/switchman/rails.rb
220
236
  - lib/switchman/schema_cache.rb
221
- - lib/switchman/shackles.rb
222
- - lib/switchman/shackles/relation.rb
223
237
  - lib/switchman/sharded_instrumenter.rb
224
238
  - lib/switchman/standard_error.rb
225
239
  - lib/switchman/test_helper.rb
@@ -229,7 +243,7 @@ homepage: http://www.instructure.com/
229
243
  licenses:
230
244
  - MIT
231
245
  metadata: {}
232
- post_install_message:
246
+ post_install_message:
233
247
  rdoc_options: []
234
248
  require_paths:
235
249
  - lib
@@ -237,15 +251,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
237
251
  requirements:
238
252
  - - ">="
239
253
  - !ruby/object:Gem::Version
240
- version: '2.4'
254
+ version: '2.5'
241
255
  required_rubygems_version: !ruby/object:Gem::Requirement
242
256
  requirements:
243
257
  - - ">="
244
258
  - !ruby/object:Gem::Version
245
259
  version: '0'
246
260
  requirements: []
247
- rubygems_version: 3.0.3
248
- signing_key:
261
+ rubygems_version: 3.1.2
262
+ signing_key:
249
263
  specification_version: 4
250
- summary: Rails 4 sharding magic
264
+ summary: Rails sharding magic
251
265
  test_files: []