switchman 1.15.0 → 2.0.1

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 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: []