switchman 1.13.3 → 2.0.0

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/switchman/shard.rb +743 -11
  3. data/db/migrate/20130328224244_create_default_shard.rb +1 -1
  4. data/lib/switchman/active_record/abstract_adapter.rb +2 -6
  5. data/lib/switchman/active_record/association.rb +35 -12
  6. data/lib/switchman/active_record/attribute_methods.rb +3 -0
  7. data/lib/switchman/active_record/base.rb +47 -9
  8. data/lib/switchman/active_record/calculations.rb +2 -1
  9. data/lib/switchman/active_record/connection_handler.rb +23 -20
  10. data/lib/switchman/active_record/connection_pool.rb +17 -15
  11. data/lib/switchman/active_record/log_subscriber.rb +8 -12
  12. data/lib/switchman/active_record/migration.rb +9 -0
  13. data/lib/switchman/active_record/model_schema.rb +1 -1
  14. data/lib/switchman/active_record/postgresql_adapter.rb +22 -47
  15. data/lib/switchman/active_record/query_cache.rb +17 -107
  16. data/lib/switchman/active_record/query_methods.rb +4 -0
  17. data/lib/switchman/active_record/relation.rb +5 -5
  18. data/lib/switchman/active_record/statement_cache.rb +4 -25
  19. data/lib/switchman/active_record/table_definition.rb +2 -2
  20. data/lib/switchman/active_support/cache.rb +16 -0
  21. data/lib/switchman/connection_pool_proxy.rb +38 -22
  22. data/lib/switchman/database_server.rb +32 -19
  23. data/lib/switchman/default_shard.rb +1 -0
  24. data/lib/switchman/engine.rb +16 -14
  25. data/lib/switchman/{shackles → guard_rail}/relation.rb +5 -5
  26. data/lib/switchman/{shackles.rb → guard_rail.rb} +4 -4
  27. data/lib/switchman/r_spec_helper.rb +7 -7
  28. data/lib/switchman/sharded_instrumenter.rb +1 -1
  29. data/lib/switchman/test_helper.rb +3 -3
  30. data/lib/switchman/version.rb +1 -1
  31. data/lib/switchman.rb +1 -1
  32. data/lib/tasks/switchman.rake +23 -17
  33. metadata +35 -22
  34. data/app/models/switchman/shard_internal.rb +0 -714
@@ -1,122 +1,32 @@
1
1
  module Switchman
2
2
  module ActiveRecord
3
3
  module QueryCache
4
- if ::Rails.version < '5.0.1'
5
- # thread local accessors to replace @query_cache_enabled
6
- def query_cache
7
- thread_cache = Thread.current[:query_cache] ||= {}
8
- thread_cache[self.object_id] ||= Hash.new { |h,sql| h[sql] = {} }
9
- end
10
-
11
- def query_cache_enabled
12
- Thread.current[:query_cache_enabled]
13
- end
14
-
15
- def query_cache_enabled=(value)
16
- Thread.current[:query_cache_enabled] = value
17
- end
18
-
19
- # basically wholesale repeat of the methods from the original (see
20
- # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb),
21
- # but with self.query_cache_enabled and self.query_cache_enabled= instead
22
- # of @query_cache_enabled.
23
-
24
- def enable_query_cache!
25
- self.query_cache_enabled = true
26
- end
27
-
28
- def disable_query_cache!
29
- self.query_cache_enabled = false
30
- end
31
-
32
- def cache
33
- old, self.query_cache_enabled = query_cache_enabled, true
34
- yield
35
- ensure
36
- self.query_cache_enabled = old
37
- clear_query_cache unless self.query_cache_enabled
38
- end
39
-
40
- def uncached
41
- old, self.query_cache_enabled = query_cache_enabled, false
42
- yield
43
- ensure
44
- self.query_cache_enabled = old
45
- end
46
-
47
- def clear_query_cache
48
- Thread.current[:query_cache]&.clear
49
- end
50
-
51
- def select_all(arel, name = nil, binds = [], preparable: nil)
52
- if self.query_cache_enabled && !locked?(arel)
53
- arel, binds = binds_from_relation(arel, binds)
54
- sql = to_sql(arel, binds)
55
- cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
56
- else
57
- super
58
- end
59
- end
60
-
61
- # no reason to define these on the including class directly. the super
62
- # works just as well from a method on the included module
63
- [:insert, :update, :delete].each do |method_name|
64
- class_eval <<-end_code, __FILE__, __LINE__ + 1
65
- def #{method_name}(*args)
66
- clear_query_cache if self.query_cache_enabled
67
- super
68
- end
69
- end_code
70
- end
71
- end
72
4
 
73
5
  private
74
6
 
75
- if ::Rails.version < '5.1'
76
- def cache_sql(sql, binds)
77
- # have to include the shard id in the cache key because of switching dbs on the same connection
78
- sql = "#{self.shard.id}::#{sql}"
7
+ def cache_sql(sql, name, binds)
8
+ # have to include the shard id in the cache key because of switching dbs on the same connection
9
+ sql = "#{self.shard.id}::#{sql}"
10
+ @lock.synchronize do
79
11
  result =
80
12
  if query_cache[sql].key?(binds)
81
- args = {:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id}
82
- args[:type_casted_binds] = -> { type_casted_binds(binds) } if ::Rails.version >= '5.0.7'
83
- ::ActiveSupport::Notifications.instrument("sql.active_record", args)
13
+ args = {
14
+ sql: sql,
15
+ binds: binds,
16
+ name: name,
17
+ connection_id: object_id,
18
+ cached: true
19
+ }
20
+ args[:type_casted_binds] = -> { type_casted_binds(binds) } if ::Rails.version >= '5.1.5'
21
+ ::ActiveSupport::Notifications.instrument(
22
+ "sql.active_record",
23
+ args
24
+ )
84
25
  query_cache[sql][binds]
85
26
  else
86
27
  query_cache[sql][binds] = yield
87
28
  end
88
-
89
- if ::ActiveRecord::Result === result
90
- result.dup
91
- else
92
- result.collect { |row| row.dup }
93
- end
94
- end
95
- else
96
- def cache_sql(sql, name, binds)
97
- # have to include the shard id in the cache key because of switching dbs on the same connection
98
- sql = "#{self.shard.id}::#{sql}"
99
- @lock.synchronize do
100
- result =
101
- if query_cache[sql].key?(binds)
102
- args = {
103
- sql: sql,
104
- binds: binds,
105
- name: name,
106
- connection_id: object_id,
107
- cached: true
108
- }
109
- args[:type_casted_binds] = -> { type_casted_binds(binds) } if ::Rails.version >= '5.1.5'
110
- ::ActiveSupport::Notifications.instrument(
111
- "sql.active_record",
112
- args
113
- )
114
- query_cache[sql][binds]
115
- else
116
- query_cache[sql][binds] = yield
117
- end
118
- result.dup
119
- end
29
+ result.dup
120
30
  end
121
31
  end
122
32
  end
@@ -227,6 +227,10 @@ module Switchman
227
227
  connection.with_local_table_name { super }
228
228
  end
229
229
 
230
+ def arel_column(columns)
231
+ connection.with_local_table_name { super }
232
+ end
233
+
230
234
  # semi-private
231
235
  public
232
236
  def transpose_predicates(predicates,
@@ -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,37 +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
- if ::Rails.version < '5.1'
60
- def generic_query_builder(connection)
61
- @query_builder ||= connection.cacheable_query(@arel)
62
- end
63
-
64
- def qualified_query_builder(shard, klass)
65
- @qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(@arel)
66
- end
67
- elsif ::Rails.version < '5.2'
68
- def generic_query_builder(connection)
69
- @query_builder ||= connection.cacheable_query(self.class, @arel)
70
- end
71
-
54
+ if ::Rails.version < '5.2'
72
55
  def qualified_query_builder(shard, klass)
73
56
  @qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(self.class, @arel)
74
57
  end
75
58
  else
76
- def generic_query_builder(connection)
77
- @query_builder ||= connection.cacheable_query(self.class, @arel).first
78
- end
79
-
80
59
  def qualified_query_builder(shard, klass)
81
60
  @qualified_query_builders[shard.id] ||= klass.connection.cacheable_query(self.class, @arel).first
82
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
@@ -4,10 +4,26 @@ module Switchman
4
4
  module ClassMethods
5
5
  def lookup_store(*store_options)
6
6
  store = super
7
+ # can't use defined?, because it's a _ruby_ autoloaded constant,
8
+ # so just checking that will cause it to get required
9
+ if store.class.name == "ActiveSupport::Cache::RedisCacheStore" && !::ActiveSupport::Cache::RedisCacheStore.ancestors.include?(RedisCacheStore)
10
+ ::ActiveSupport::Cache::RedisCacheStore.prepend(RedisCacheStore)
11
+ end
7
12
  store.options[:namespace] ||= lambda { Shard.current.default? ? nil : "shard_#{Shard.current.id}" }
8
13
  store
9
14
  end
10
15
  end
16
+
17
+ module RedisCacheStore
18
+ def clear(options = {})
19
+ # RedisCacheStore tries to be smart and only clear the cache under your namespace, if you have one set
20
+ # unfortunately, it uses the keys command, which is extraordinarily inefficient in a large redis instance
21
+ # fortunately, we can assume we control the entire instance, because we set up the namespacing, so just
22
+ # always unset it temporarily for clear calls
23
+ options[:namespace] = nil
24
+ super
25
+ end
26
+ end
11
27
  end
12
28
  end
13
29
  end
@@ -23,20 +23,27 @@ module Switchman
23
23
  @category = category
24
24
  @default_pool = default_pool
25
25
  @connection_pools = shard_connection_pools
26
- @schema_cache = SchemaCache.new(self)
26
+ @schema_cache = default_pool.get_schema_cache(nil) if ::Rails.version >= '6'
27
+ @schema_cache = SchemaCache.new(self) unless @schema_cache.is_a?(SchemaCache)
28
+ if ::Rails.version >= '6'
29
+ @default_pool.set_schema_cache(@schema_cache)
30
+ @connection_pools.each_value do |pool|
31
+ pool.set_schema_cache(@schema_cache)
32
+ end
33
+ end
27
34
  end
28
35
 
29
36
  def active_shard
30
37
  Shard.current(@category)
31
38
  end
32
39
 
33
- def active_shackles_environment
34
- ::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
35
42
  end
36
43
 
37
44
  def current_pool
38
45
  current_active_shard = active_shard
39
- 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?)
40
47
  pool = @connection_pools[pool_key] ||= create_pool unless pool
41
48
  pool.shard = current_active_shard
42
49
  pool
@@ -46,21 +53,21 @@ module Switchman
46
53
  connection_pools.map(&:connections).inject([], &:+)
47
54
  end
48
55
 
49
- def connection
56
+ def connection(switch_shard: true)
50
57
  pool = current_pool
51
58
  begin
52
- connection = pool.connection
53
- connection.instance_variable_set(:@schema_cache, @schema_cache)
59
+ connection = pool.connection(switch_shard: switch_shard)
60
+ connection.instance_variable_set(:@schema_cache, @schema_cache) unless ::Rails.version >= '6'
54
61
  connection
55
62
  rescue ConnectionError
56
- raise if active_shard.database_server == Shard.default.database_server && active_shackles_environment == :master
57
- 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)
58
65
  raise unless configs.is_a?(Array)
59
66
  configs.each_with_index do |config, idx|
60
67
  pool = create_pool(config.dup)
61
68
  begin
62
69
  connection = pool.connection
63
- connection.instance_variable_set(:@schema_cache, @schema_cache)
70
+ connection.instance_variable_set(:@schema_cache, @schema_cache) unless ::Rails.version >= '6'
64
71
  rescue ConnectionError
65
72
  raise if idx == configs.length - 1
66
73
  next
@@ -71,6 +78,10 @@ module Switchman
71
78
  end
72
79
  end
73
80
 
81
+ def get_schema_cache(_connection)
82
+ @schema_cache
83
+ end
84
+
74
85
  %w{release_connection
75
86
  disconnect!
76
87
  flush!
@@ -98,6 +109,10 @@ module Switchman
98
109
  connection_pools.each { |pool| pool.clear_idle_connections!(since_when) }
99
110
  end
100
111
 
112
+ def remove_shard!(shard)
113
+ connection_pools.each { |pool| pool.remove_shard!(shard) }
114
+ end
115
+
101
116
  protected
102
117
 
103
118
  def connection_pools
@@ -105,7 +120,7 @@ module Switchman
105
120
  end
106
121
 
107
122
  def pool_key
108
- [active_shackles_environment,
123
+ [active_guard_rail_environment,
109
124
  active_shard.database_server.shareable? ? active_shard.database_server.pool_key : active_shard]
110
125
  end
111
126
 
@@ -113,7 +128,7 @@ module Switchman
113
128
  shard = active_shard
114
129
  unless config
115
130
  if shard != Shard.default
116
- config = shard.database_server.config(active_shackles_environment)
131
+ config = shard.database_server.config(active_guard_rail_environment)
117
132
  config = config.first if config.is_a?(Array)
118
133
  config = config.dup
119
134
  else
@@ -123,27 +138,28 @@ module Switchman
123
138
  # different models could be using different configs on the default
124
139
  # shard, and database server wouldn't know about that
125
140
  config = default_pool.spec.instance_variable_get(:@config)
126
- if config[active_shackles_environment].is_a?(Hash)
127
- config = config.merge(config[active_shackles_environment])
128
- elsif config[active_shackles_environment].is_a?(Array)
129
- 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)
130
145
  else
131
146
  config = config.dup
132
147
  end
133
148
  end
134
149
  end
135
- args = [config, "#{config[:adapter]}_connection"]
136
- args.unshift(pool_key.join("/"))
137
- spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(*args)
150
+ spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(
151
+ category,
152
+ config,
153
+ "#{config[:adapter]}_connection"
154
+ )
138
155
  # unfortunately the AR code that does this require logic can't really be
139
156
  # called in isolation
140
157
  require "active_record/connection_adapters/#{config[:adapter]}_adapter"
141
158
 
142
159
  ::ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec).tap do |pool|
143
160
  pool.shard = shard
144
- if ::Rails.version >= '5.0.1'
145
- pool.enable_query_cache! if !@connection_pools.empty? && @connection_pools.first.last.query_cache_enabled
146
- end
161
+ pool.set_schema_cache(@schema_cache) if ::Rails.version >= '6'
162
+ pool.enable_query_cache! if !@connection_pools.empty? && @connection_pools.first.last.query_cache_enabled
147
163
  end
148
164
  end
149
165
  end
@@ -40,8 +40,14 @@ module Switchman
40
40
  def database_servers
41
41
  unless @database_servers
42
42
  @database_servers = {}.with_indifferent_access
43
- ::ActiveRecord::Base.configurations.each do |(id, config)|
44
- @database_servers[id] = DatabaseServer.new(id, config)
43
+ if ::Rails.version >= '6.0'
44
+ ::ActiveRecord::Base.configurations.configurations.each do |config|
45
+ @database_servers[config.env_name] = DatabaseServer.new(config.env_name, config.config)
46
+ end
47
+ else
48
+ ::ActiveRecord::Base.configurations.each do |(id, config)|
49
+ @database_servers[id] = DatabaseServer.new(id, config)
50
+ end
45
51
  end
46
52
  end
47
53
  @database_servers
@@ -63,12 +69,12 @@ module Switchman
63
69
  @fake
64
70
  end
65
71
 
66
- def config(environment = :master)
72
+ def config(environment = :primary)
67
73
  @configs[environment] ||= begin
68
74
  if @config[environment].is_a?(Array)
69
75
  @config[environment].map do |config|
70
76
  config = @config.merge((config || {}).symbolize_keys)
71
- # 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
72
78
  config.delete(environment)
73
79
  config
74
80
  end
@@ -80,33 +86,33 @@ module Switchman
80
86
  end
81
87
  end
82
88
 
83
- def shackles_environment
84
- @shackles_environment || ::Shackles.environment
89
+ def guard_rail_environment
90
+ @guard_rail_environment || ::GuardRail.environment
85
91
  end
86
92
 
87
93
  # locks this db to a specific environment, except for
88
94
  # when doing writes (then it falls back to the current
89
- # value of Shackles.environment)
90
- def shackle!(environment = :slave)
91
- @shackles_environment = environment
95
+ # value of GuardRail.environment)
96
+ def guard!(environment = :secondary)
97
+ @guard_rail_environment = environment
92
98
  end
93
99
 
94
- def unshackle!
95
- @shackles_environment = nil
100
+ def unguard!
101
+ @guard_rail_environment = nil
96
102
  end
97
103
 
98
- def unshackle
99
- old_env = @shackles_environment
100
- unshackle!
104
+ def unguard
105
+ old_env = @guard_rail_environment
106
+ unguard!
101
107
  yield
102
108
  ensure
103
- shackle!(old_env)
109
+ guard!(old_env)
104
110
  end
105
111
 
106
112
  def shareable?
107
113
  @shareable_environment_key ||= []
108
- environment = shackles_environment
109
- explicit_user = ::Shackles.global_config[:username]
114
+ environment = guard_rail_environment
115
+ explicit_user = ::GuardRail.global_config[:username]
110
116
  return @shareable if @shareable_environment_key == [environment, explicit_user]
111
117
  @shareable_environment_key = [environment, explicit_user]
112
118
  if explicit_user
@@ -179,13 +185,18 @@ module Switchman
179
185
  shard = Shard.create!(:id => shard_id,
180
186
  :name => name,
181
187
  :database_server => self)
188
+ schema_already_existed = false
182
189
 
183
190
  begin
184
191
  self.class.creating_new_shard = true
185
192
  shard.activate(*Shard.categories) do
186
- ::Shackles.activate(:deploy) do
193
+ ::GuardRail.activate(:deploy) do
187
194
  begin
188
195
  if create_statement
196
+ if (::ActiveRecord::Base.connection.select_value("SELECT 1 FROM pg_namespace WHERE nspname=#{::ActiveRecord::Base.connection.quote(name)}"))
197
+ schema_already_existed = true
198
+ raise "This schema already exists; cannot overwrite"
199
+ end
189
200
  Array(create_statement.call).each do |stmt|
190
201
  ::ActiveRecord::Base.connection.execute(stmt)
191
202
  end
@@ -223,7 +234,9 @@ module Switchman
223
234
  shard
224
235
  rescue
225
236
  shard.destroy
226
- shard.drop_database rescue nil
237
+ unless schema_already_existed
238
+ shard.drop_database rescue nil
239
+ end
227
240
  reset_column_information unless create_schema == false rescue nil
228
241
  raise
229
242
  ensure
@@ -3,6 +3,7 @@ require 'switchman/database_server'
3
3
  module Switchman
4
4
  class DefaultShard
5
5
  def id; 'default'; end
6
+ alias cache_key id
6
7
  def activate(*categories); yield; end
7
8
  def activate!(*categories); end
8
9
  def default?; true; end
@@ -87,8 +87,8 @@ module Switchman
87
87
  require "switchman/arel"
88
88
  require "switchman/call_super"
89
89
  require "switchman/rails"
90
- require "switchman/shackles/relation"
91
- require_dependency "switchman/shard_internal"
90
+ require "switchman/guard_rail/relation"
91
+ require_dependency "switchman/shard"
92
92
  require "switchman/standard_error"
93
93
 
94
94
  ::StandardError.include(StandardError)
@@ -118,15 +118,11 @@ module Switchman
118
118
  ::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
119
119
  ::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
120
120
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
121
- # when we call super in Switchman::ActiveRecord::QueryCache#select_all,
122
- # we want it to find the definition from
123
- # ActiveRecord::ConnectionAdapters::DatabaseStatements, not
124
- # ActiveRecord::ConnectionAdapters::QueryCache
125
- ::ActiveRecord::ConnectionAdapters::QueryCache.send(:remove_method, :select_all) if ::Rails.version < '5.0.1'
126
121
 
127
122
  ::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
128
123
  ::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
129
124
  ::ActiveRecord::Migration::Compatibility::V5_0.prepend(ActiveRecord::Migration::Compatibility::V5_0)
125
+ ::ActiveRecord::MigrationContext.prepend(ActiveRecord::MigrationContext) if ::Rails.version >= '5.2'
130
126
  ::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
131
127
 
132
128
  ::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
@@ -137,7 +133,7 @@ module Switchman
137
133
  ::ActiveRecord::Relation.prepend(ActiveRecord::Calculations)
138
134
  ::ActiveRecord::Relation.include(ActiveRecord::FinderMethods)
139
135
  ::ActiveRecord::Relation.include(ActiveRecord::QueryMethods)
140
- ::ActiveRecord::Relation.prepend(Shackles::Relation)
136
+ ::ActiveRecord::Relation.prepend(GuardRail::Relation)
141
137
  ::ActiveRecord::Relation.prepend(ActiveRecord::Relation)
142
138
  ::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
143
139
  ::ActiveRecord::Relation.include(CallSuper)
@@ -154,8 +150,8 @@ module Switchman
154
150
  end
155
151
  end
156
152
 
157
- def self.foreign_key_check(name, type, options)
158
- 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
159
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`"
160
156
  end
161
157
  end
@@ -173,6 +169,12 @@ module Switchman
173
169
  require "switchman/active_record/postgresql_adapter"
174
170
  ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
175
171
  end
172
+
173
+ # If Switchman::Shard wasn't loaded as of when ActiveRecord::Base initialized
174
+ # establish a connection here instead
175
+ if !Shard.instance_variable_get(:@default)
176
+ ::ActiveRecord::Base.establish_connection
177
+ end
176
178
  end
177
179
  end
178
180
 
@@ -183,15 +185,15 @@ module Switchman
183
185
  end
184
186
  end
185
187
 
186
- initializer 'switchman.extend_shackles', :before => "switchman.extend_ar" do
188
+ initializer 'switchman.extend_guard_rail', :before => "switchman.extend_ar" do
187
189
  ::ActiveSupport.on_load(:active_record) do
188
- require "switchman/shackles"
190
+ require "switchman/guard_rail"
189
191
 
190
- ::Shackles.singleton_class.prepend(Shackles::ClassMethods)
192
+ ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
191
193
  end
192
194
  end
193
195
 
194
- initializer 'switchman.extend_controller', :after => "shackles.extend_ar" do
196
+ initializer 'switchman.extend_controller', :after => "guard_rail.extend_ar" do
195
197
  ::ActiveSupport.on_load(:action_controller) do
196
198
  require "switchman/action_controller/caching"
197
199
 
@@ -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
@@ -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