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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/switchman/shard.rb +10 -5
  3. data/db/migrate/20130328212039_create_switchman_shards.rb +2 -0
  4. data/db/migrate/20130328224244_create_default_shard.rb +3 -1
  5. data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +2 -0
  6. data/db/migrate/20180828183945_add_default_shard_index.rb +2 -0
  7. data/db/migrate/20180828192111_add_timestamps_to_shards.rb +2 -0
  8. data/db/migrate/20190114212900_add_unique_name_indexes.rb +2 -0
  9. data/lib/switchman.rb +3 -1
  10. data/lib/switchman/action_controller/caching.rb +2 -0
  11. data/lib/switchman/active_record/abstract_adapter.rb +8 -2
  12. data/lib/switchman/active_record/association.rb +10 -4
  13. data/lib/switchman/active_record/attribute_methods.rb +2 -0
  14. data/lib/switchman/active_record/base.rb +13 -11
  15. data/lib/switchman/active_record/batches.rb +2 -0
  16. data/lib/switchman/active_record/calculations.rb +2 -0
  17. data/lib/switchman/active_record/connection_handler.rb +8 -6
  18. data/lib/switchman/active_record/connection_pool.rb +2 -0
  19. data/lib/switchman/active_record/finder_methods.rb +2 -0
  20. data/lib/switchman/active_record/log_subscriber.rb +2 -0
  21. data/lib/switchman/active_record/migration.rb +3 -1
  22. data/lib/switchman/active_record/model_schema.rb +2 -0
  23. data/lib/switchman/active_record/persistence.rb +3 -1
  24. data/lib/switchman/active_record/postgresql_adapter.rb +3 -1
  25. data/lib/switchman/active_record/predicate_builder.rb +2 -0
  26. data/lib/switchman/active_record/query_cache.rb +2 -0
  27. data/lib/switchman/active_record/query_methods.rb +121 -72
  28. data/lib/switchman/active_record/reflection.rb +2 -0
  29. data/lib/switchman/active_record/relation.rb +7 -5
  30. data/lib/switchman/active_record/spawn_methods.rb +2 -0
  31. data/lib/switchman/active_record/statement_cache.rb +3 -1
  32. data/lib/switchman/active_record/table_definition.rb +4 -2
  33. data/lib/switchman/active_record/type_caster.rb +2 -0
  34. data/lib/switchman/active_record/where_clause_factory.rb +2 -0
  35. data/lib/switchman/active_support/cache.rb +4 -2
  36. data/lib/switchman/arel.rb +2 -0
  37. data/lib/switchman/call_super.rb +2 -0
  38. data/lib/switchman/connection_pool_proxy.rb +13 -11
  39. data/lib/switchman/database_server.rb +18 -16
  40. data/lib/switchman/default_shard.rb +2 -0
  41. data/lib/switchman/engine.rb +10 -8
  42. data/lib/switchman/environment.rb +2 -0
  43. data/lib/switchman/errors.rb +2 -0
  44. data/lib/switchman/{shackles.rb → guard_rail.rb} +6 -4
  45. data/lib/switchman/{shackles → guard_rail}/relation.rb +7 -5
  46. data/lib/switchman/open4.rb +2 -0
  47. data/lib/switchman/r_spec_helper.rb +7 -5
  48. data/lib/switchman/rails.rb +2 -0
  49. data/lib/switchman/schema_cache.rb +2 -0
  50. data/lib/switchman/sharded_instrumenter.rb +3 -1
  51. data/lib/switchman/standard_error.rb +2 -0
  52. data/lib/switchman/test_helper.rb +5 -3
  53. data/lib/switchman/version.rb +3 -1
  54. data/lib/tasks/switchman.rake +3 -3
  55. metadata +30 -16
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module ActiveRecord
3
5
  module Reflection
@@ -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(*args)
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(*args)
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(*args, &block)
31
+ def new(*, &block)
30
32
  primary_shard.activate(klass.shard_category) { super }
31
33
  end
32
34
 
33
- def create(*args, &block)
35
+ def create(*, &block)
34
36
  primary_shard.activate(klass.shard_category) { super }
35
37
  end
36
38
 
37
- def create!(*args, &block)
39
+ def create!(*, &block)
38
40
  primary_shard.activate(klass.shard_category) { super }
39
41
  end
40
42
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module ActiveRecord
3
5
  module SpawnMethods
@@ -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 = Proc.new)
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, options = {})
5
- Engine.foreign_key_check(name, type, options)
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 ActiveRecord
3
5
  module TypeCaster
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module ActiveRecord
3
5
  module WhereClauseFactory
@@ -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(options = {})
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
- options[:namespace] = nil
25
+ namespace = nil
24
26
  super
25
27
  end
26
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module Arel
3
5
  module Table
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  module CallSuper
3
5
  def super_method_above(method_name, above_module)
@@ -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 active_shackles_environment
41
- ::Rails.env.test? ? :master : active_shard.database_server.shackles_environment
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 && active_shackles_environment == :master && (current_active_shard.default? || current_active_shard.database_server.shareable?)
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 && active_shackles_environment == :master
64
- configs = active_shard.database_server.config(active_shackles_environment)
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
- [active_shackles_environment,
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(active_shackles_environment)
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[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)
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 = :master)
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 Shackles doesn't get any brilliant ideas about choosing the first possible server
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 shackles_environment
90
- @shackles_environment || ::Shackles.environment
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 Shackles.environment)
96
- def shackle!(environment = :slave)
97
- @shackles_environment = environment
97
+ # value of GuardRail.environment)
98
+ def guard!(environment = :secondary)
99
+ @guard_rail_environment = environment
98
100
  end
99
101
 
100
- def unshackle!
101
- @shackles_environment = nil
102
+ def unguard!
103
+ @guard_rail_environment = nil
102
104
  end
103
105
 
104
- def unshackle
105
- old_env = @shackles_environment
106
- unshackle!
106
+ def unguard
107
+ old_env = @guard_rail_environment
108
+ unguard!
107
109
  yield
108
110
  ensure
109
- shackle!(old_env)
111
+ guard!(old_env)
110
112
  end
111
113
 
112
114
  def shareable?
113
115
  @shareable_environment_key ||= []
114
- environment = shackles_environment
115
- explicit_user = ::Shackles.global_config[:username]
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
- ::Shackles.activate(:deploy) do
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)}"))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'switchman/database_server'
2
4
 
3
5
  module Switchman
@@ -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/shackles/relation"
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(Shackles::Relation)
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, options)
154
- if name.to_s =~ /_id\z/ && type.to_s == 'integer' && options[:limit].to_i < 8
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.extend_shackles', :before => "switchman.extend_ar" do
190
+ initializer 'switchman.extend_guard_rail', :before => "switchman.extend_ar" do
189
191
  ::ActiveSupport.on_load(:active_record) do
190
- require "switchman/shackles"
192
+ require "switchman/guard_rail"
191
193
 
192
- ::Shackles.singleton_class.prepend(Shackles::ClassMethods)
194
+ ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
193
195
  end
194
196
  end
195
197
 
196
- initializer 'switchman.extend_controller', :after => "shackles.extend_ar" do
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'etc'
2
4
 
3
5
  module Switchman
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
4
  class NonExistentShardError < RuntimeError; end
3
5
  class ParallelShardExecError < RuntimeError; end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
- module Shackles
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
- # Shackles' implementation.
11
+ # GuardRail' implementation.
10
12
  def activate!(environment)
11
- environment ||= :master
13
+ environment ||= :primary
12
14
  activated_environments << environment
13
15
  old_environment = self.environment
14
- Thread.current[:shackles_environment] = environment
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 Shackles
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 ::Shackles.environment != db.shackles_environment
8
- return db.unshackle { super }
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 ::Shackles.environment != db.shackles_environment
19
- db.unshackle { super }
20
+ if ::GuardRail.environment != db.guard_rail_environment
21
+ db.unguard { super }
20
22
  else
21
23
  super
22
24
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open4'
2
4
 
3
5
  # This fixes a bug with exception handling,
@@ -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