switchman 1.6.1 → 2.0.9

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 (56) hide show
  1. checksums.yaml +5 -5
  2. data/app/models/switchman/shard.rb +746 -11
  3. data/db/migrate/20130328212039_create_switchman_shards.rb +3 -1
  4. data/db/migrate/20130328224244_create_default_shard.rb +4 -2
  5. data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +13 -0
  6. data/db/migrate/20180828183945_add_default_shard_index.rb +15 -0
  7. data/db/migrate/20180828192111_add_timestamps_to_shards.rb +17 -0
  8. data/db/migrate/20190114212900_add_unique_name_indexes.rb +9 -0
  9. data/lib/switchman/action_controller/caching.rb +2 -0
  10. data/lib/switchman/active_record/abstract_adapter.rb +14 -4
  11. data/lib/switchman/active_record/association.rb +64 -37
  12. data/lib/switchman/active_record/attribute_methods.rb +16 -5
  13. data/lib/switchman/active_record/base.rb +67 -22
  14. data/lib/switchman/active_record/batches.rb +3 -1
  15. data/lib/switchman/active_record/calculations.rb +16 -21
  16. data/lib/switchman/active_record/connection_handler.rb +71 -79
  17. data/lib/switchman/active_record/connection_pool.rb +28 -23
  18. data/lib/switchman/active_record/finder_methods.rb +20 -29
  19. data/lib/switchman/active_record/log_subscriber.rb +14 -19
  20. data/lib/switchman/active_record/migration.rb +80 -0
  21. data/lib/switchman/active_record/model_schema.rb +3 -1
  22. data/lib/switchman/active_record/persistence.rb +9 -1
  23. data/lib/switchman/active_record/postgresql_adapter.rb +166 -126
  24. data/lib/switchman/active_record/predicate_builder.rb +2 -0
  25. data/lib/switchman/active_record/query_cache.rb +22 -87
  26. data/lib/switchman/active_record/query_methods.rb +122 -126
  27. data/lib/switchman/active_record/reflection.rb +37 -20
  28. data/lib/switchman/active_record/relation.rb +50 -29
  29. data/lib/switchman/active_record/spawn_methods.rb +2 -0
  30. data/lib/switchman/active_record/statement_cache.rb +44 -52
  31. data/lib/switchman/active_record/table_definition.rb +4 -2
  32. data/lib/switchman/active_record/type_caster.rb +2 -0
  33. data/lib/switchman/active_record/where_clause_factory.rb +5 -2
  34. data/lib/switchman/active_support/cache.rb +18 -0
  35. data/lib/switchman/arel.rb +8 -25
  36. data/lib/switchman/call_super.rb +19 -0
  37. data/lib/switchman/connection_pool_proxy.rb +70 -24
  38. data/lib/switchman/database_server.rb +69 -59
  39. data/lib/switchman/default_shard.rb +3 -0
  40. data/lib/switchman/engine.rb +42 -40
  41. data/lib/switchman/environment.rb +2 -0
  42. data/lib/switchman/errors.rb +2 -0
  43. data/lib/switchman/{shackles → guard_rail}/relation.rb +7 -5
  44. data/lib/switchman/{shackles.rb → guard_rail.rb} +6 -4
  45. data/lib/switchman/open4.rb +2 -0
  46. data/lib/switchman/r_spec_helper.rb +14 -8
  47. data/lib/switchman/rails.rb +2 -0
  48. data/lib/switchman/schema_cache.rb +17 -0
  49. data/lib/switchman/sharded_instrumenter.rb +4 -2
  50. data/lib/switchman/standard_error.rb +4 -2
  51. data/lib/switchman/test_helper.rb +6 -3
  52. data/lib/switchman/version.rb +3 -1
  53. data/lib/switchman.rb +3 -1
  54. data/lib/tasks/switchman.rake +46 -72
  55. metadata +87 -41
  56. data/app/models/switchman/shard_internal.rb +0 -692
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Switchman
2
- VERSION = "1.6.1"
4
+ VERSION = "2.0.9"
3
5
  end
data/lib/switchman.rb CHANGED
@@ -1,4 +1,6 @@
1
- require "shackles"
1
+ # frozen_string_literal: true
2
+
3
+ require "guard_rail"
2
4
  require "switchman/open4"
3
5
  require "switchman/engine"
4
6
 
@@ -20,13 +20,18 @@ module Switchman
20
20
  open = servers.delete('open')
21
21
 
22
22
  servers = servers.map { |server| DatabaseServer.find(server) }.compact
23
- servers.concat(DatabaseServer.all.select { |server| server.config[:open] }) if open
23
+ if open
24
+ open_servers = DatabaseServer.all.select { |server| server.config[:open] }
25
+ servers.concat(open_servers)
26
+ servers << DatabaseServer.find(nil) if open_servers.empty?
27
+ servers.uniq!
28
+ end
24
29
  servers = DatabaseServer.all - servers if negative
25
30
  end
26
31
 
27
32
  servers = filter_database_servers_chain.call(servers)
28
33
 
29
- scope = base_scope.order("database_server_id IS NOT NULL, database_server_id, id")
34
+ scope = base_scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
30
35
  if servers != DatabaseServer.all
31
36
  conditions = ["database_server_id IN (?)", servers.map(&:id)]
32
37
  conditions.first << " OR database_server_id IS NULL" if servers.include?(Shard.default.database_server)
@@ -48,7 +53,7 @@ module Switchman
48
53
  # task. tasks which modify the schema may want to pass all categories in
49
54
  # so that schema updates for non-default tables happen against all shards.
50
55
  # this is handled automatically for the default migration tasks, below.
51
- def self.shardify_task(task_name, categories: [:default])
56
+ def self.shardify_task(task_name, categories: [:primary])
52
57
  old_task = ::Rake::Task[task_name]
53
58
  old_actions = old_task.actions.dup
54
59
  old_task.actions.clear
@@ -59,22 +64,34 @@ module Switchman
59
64
  TestHelper.recreate_persistent_test_shards(dont_create: true)
60
65
  end
61
66
 
62
- ::Shackles.activate(:deploy) do
63
- begin
64
- categories = categories.call if categories.respond_to?(:call)
65
- Shard.with_each_shard(scope, categories, options) do
66
- shard = Shard.current
67
- puts "#{shard.id}: #{shard.description}"
68
- ::ActiveRecord::Base.connection_pool.spec.config[:shard_name] = Shard.current.name
69
- ::ActiveRecord::Base.configurations[::Rails.env] = ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys
70
- shard.database_server.unshackle do
71
- old_actions.each { |action| action.call(*task_args) }
67
+ ::GuardRail.activate(:deploy) do
68
+ Shard.default.database_server.unguard do
69
+ begin
70
+ categories = categories.call if categories.respond_to?(:call)
71
+ Shard.with_each_shard(scope, categories, options) do
72
+ shard = Shard.current
73
+ puts "#{shard.id}: #{shard.description}"
74
+ ::ActiveRecord::Base.connection_pool.spec.config[:shard_name] = Shard.current.name
75
+ if ::Rails.version < '6.0'
76
+ ::ActiveRecord::Base.configurations[::Rails.env] = ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys
77
+ else
78
+ # Adopted from the deprecated code that currently lives in rails proper
79
+ remaining_configs = ::ActiveRecord::Base.configurations.configurations.reject { |db_config| db_config.env_name == ::Rails.env }
80
+ new_config = ::ActiveRecord::DatabaseConfigurations.new(::Rails.env =>
81
+ ::ActiveRecord::Base.connection_pool.spec.config.stringify_keys).configurations
82
+ new_configs = remaining_configs + new_config
83
+
84
+ ::ActiveRecord::Base.configurations = new_configs
85
+ end
86
+ shard.database_server.unguard do
87
+ old_actions.each { |action| action.call(*task_args) }
88
+ end
89
+ nil
72
90
  end
73
- nil
91
+ rescue => e
92
+ puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
93
+ raise
74
94
  end
75
- rescue => e
76
- puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
77
- raise
78
95
  end
79
96
  end
80
97
  end
@@ -193,64 +210,21 @@ module Switchman
193
210
  @filter_database_servers_chain ||= ->(servers) { servers }
194
211
  end
195
212
  end
196
- end
197
213
 
198
- module Switchman
199
214
  module ActiveRecord
200
215
  module PostgreSQLDatabaseTasks
201
- if ::Rails.version < '4.2'
202
- def structure_dump(filename)
203
- set_psql_env
204
- search_path = configuration['schema_search_path']
205
- unless search_path.blank?
206
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
207
- serialized_search_path = ::ActiveRecord::Base.connection.schema_search_path
208
- end
209
- if configuration['use_qualified_names']
210
- shard = Shard.current.name
211
- serialized_search_path = shard
212
- search_path = "--schema=#{Shellwords.escape(shard)}"
213
- end
214
-
215
- command = "pg_dump -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
216
- raise 'Error dumping database' unless Kernel.system(command)
217
-
218
- File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
219
- end
220
- else
221
- def structure_dump(filename)
222
- set_psql_env
223
- args = ['-s', '-x', '-O', '-f', filename]
224
- search_path = configuration['schema_search_path']
225
- if configuration['use_qualified_names']
226
- shard = Shard.current.name
227
- serialized_search_path = shard
228
- args << "--schema=#{Shellwords.escape(shard)}"
229
- elsif !search_path.blank?
230
- args << search_path.split(',').map do |part|
231
- "--schema=#{part.strip}"
232
- end.join(' ')
233
- serialized_search_path = connection.schema_search_path
234
- end
235
-
236
- args << configuration['database']
237
- run_cmd('pg_dump', args, 'dumping')
238
- File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
239
- end
240
-
241
- if ::Rails.version < '4.2.5'
242
- # These methods are backported from rails 4.2.5 to work with the above
243
- def run_cmd(cmd, args, action)
244
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
245
- end
246
-
247
- def run_cmd_error(cmd, args, action)
248
- msg = "failed to execute:\n"
249
- msg << "#{cmd} #{args.join(' ')}\n\n"
250
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
251
- msg
252
- end
253
- end
216
+ def structure_dump(filename, extra_flags=nil)
217
+ set_psql_env
218
+ args = ['-s', '-x', '-O', '-f', filename]
219
+ args.concat(Array(extra_flags)) if extra_flags
220
+ search_path = configuration['schema_search_path']
221
+ shard = Shard.current.name
222
+ serialized_search_path = shard
223
+ args << "--schema=#{Shellwords.escape(shard)}"
224
+
225
+ args << configuration['database']
226
+ run_cmd('pg_dump', args, 'dumping')
227
+ File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
254
228
  end
255
229
  end
256
230
  end
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.6.1
4
+ version: 2.0.9
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: 2016-09-20 00:00:00.000000000 Z
13
+ date: 2021-04-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
@@ -18,82 +18,110 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: '4.0'
22
- - - "<="
21
+ version: '5.1'
22
+ - - "<"
23
23
  - !ruby/object:Gem::Version
24
- version: 5.0.0.beta3
24
+ version: '6.1'
25
25
  type: :runtime
26
26
  prerelease: false
27
27
  version_requirements: !ruby/object:Gem::Requirement
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: '4.0'
32
- - - "<="
31
+ version: '5.1'
32
+ - - "<"
33
33
  - !ruby/object:Gem::Version
34
- version: 5.0.0.beta3
34
+ version: '6.1'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: activerecord
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '4.0'
42
- - - "<="
41
+ version: '5.1'
42
+ - - "<"
43
43
  - !ruby/object:Gem::Version
44
- version: 5.0.0.beta3
44
+ version: '6.1'
45
45
  type: :runtime
46
46
  prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: '4.0'
52
- - - "<="
51
+ version: '5.1'
52
+ - - "<"
53
53
  - !ruby/object:Gem::Version
54
- version: 5.0.0.beta3
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.1.0
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.1.0
68
+ version: 2.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: open4
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 1.3.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.3.0
83
83
  - !ruby/object:Gem::Dependency
84
- name: mysql2
84
+ name: appraisal
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.3'
89
+ version: '2.1'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.3'
96
+ version: '2.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
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'
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: pg
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -112,44 +140,58 @@ dependencies:
112
140
  name: rspec-rails
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
- - - '='
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec-mocks
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
116
158
  - !ruby/object:Gem::Version
117
- version: 3.1.0
159
+ version: '3.5'
118
160
  type: :development
119
161
  prerelease: false
120
162
  version_requirements: !ruby/object:Gem::Requirement
121
163
  requirements:
122
- - - '='
164
+ - - "~>"
123
165
  - !ruby/object:Gem::Version
124
- version: 3.1.0
166
+ version: '3.5'
125
167
  - !ruby/object:Gem::Dependency
126
- name: sqlite3
168
+ name: simplecov
127
169
  requirement: !ruby/object:Gem::Requirement
128
170
  requirements:
129
171
  - - "~>"
130
172
  - !ruby/object:Gem::Version
131
- version: '1.3'
173
+ version: '0.15'
132
174
  type: :development
133
175
  prerelease: false
134
176
  version_requirements: !ruby/object:Gem::Requirement
135
177
  requirements:
136
178
  - - "~>"
137
179
  - !ruby/object:Gem::Version
138
- version: '1.3'
180
+ version: '0.15'
139
181
  - !ruby/object:Gem::Dependency
140
182
  name: rake
141
183
  requirement: !ruby/object:Gem::Requirement
142
184
  requirements:
143
185
  - - "~>"
144
186
  - !ruby/object:Gem::Version
145
- version: '10.0'
187
+ version: '12.0'
146
188
  type: :development
147
189
  prerelease: false
148
190
  version_requirements: !ruby/object:Gem::Requirement
149
191
  requirements:
150
192
  - - "~>"
151
193
  - !ruby/object:Gem::Version
152
- version: '10.0'
194
+ version: '12.0'
153
195
  description: Sharding
154
196
  email:
155
197
  - cody@instructure.com
@@ -159,9 +201,12 @@ extra_rdoc_files: []
159
201
  files:
160
202
  - Rakefile
161
203
  - app/models/switchman/shard.rb
162
- - app/models/switchman/shard_internal.rb
163
204
  - db/migrate/20130328212039_create_switchman_shards.rb
164
205
  - db/migrate/20130328224244_create_default_shard.rb
206
+ - db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
207
+ - db/migrate/20180828183945_add_default_shard_index.rb
208
+ - db/migrate/20180828192111_add_timestamps_to_shards.rb
209
+ - db/migrate/20190114212900_add_unique_name_indexes.rb
165
210
  - lib/switchman.rb
166
211
  - lib/switchman/action_controller/caching.rb
167
212
  - lib/switchman/active_record/abstract_adapter.rb
@@ -174,6 +219,7 @@ files:
174
219
  - lib/switchman/active_record/connection_pool.rb
175
220
  - lib/switchman/active_record/finder_methods.rb
176
221
  - lib/switchman/active_record/log_subscriber.rb
222
+ - lib/switchman/active_record/migration.rb
177
223
  - lib/switchman/active_record/model_schema.rb
178
224
  - lib/switchman/active_record/persistence.rb
179
225
  - lib/switchman/active_record/postgresql_adapter.rb
@@ -189,18 +235,19 @@ files:
189
235
  - lib/switchman/active_record/where_clause_factory.rb
190
236
  - lib/switchman/active_support/cache.rb
191
237
  - lib/switchman/arel.rb
238
+ - lib/switchman/call_super.rb
192
239
  - lib/switchman/connection_pool_proxy.rb
193
240
  - lib/switchman/database_server.rb
194
241
  - lib/switchman/default_shard.rb
195
242
  - lib/switchman/engine.rb
196
243
  - lib/switchman/environment.rb
197
244
  - lib/switchman/errors.rb
245
+ - lib/switchman/guard_rail.rb
246
+ - lib/switchman/guard_rail/relation.rb
198
247
  - lib/switchman/open4.rb
199
248
  - lib/switchman/r_spec_helper.rb
200
249
  - lib/switchman/rails.rb
201
250
  - lib/switchman/schema_cache.rb
202
- - lib/switchman/shackles.rb
203
- - lib/switchman/shackles/relation.rb
204
251
  - lib/switchman/sharded_instrumenter.rb
205
252
  - lib/switchman/standard_error.rb
206
253
  - lib/switchman/test_helper.rb
@@ -210,7 +257,7 @@ homepage: http://www.instructure.com/
210
257
  licenses:
211
258
  - MIT
212
259
  metadata: {}
213
- post_install_message:
260
+ post_install_message:
214
261
  rdoc_options: []
215
262
  require_paths:
216
263
  - lib
@@ -218,16 +265,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
265
  requirements:
219
266
  - - ">="
220
267
  - !ruby/object:Gem::Version
221
- version: '2.0'
268
+ version: '2.5'
222
269
  required_rubygems_version: !ruby/object:Gem::Requirement
223
270
  requirements:
224
271
  - - ">="
225
272
  - !ruby/object:Gem::Version
226
273
  version: '0'
227
274
  requirements: []
228
- rubyforge_project:
229
- rubygems_version: 2.6.4
230
- signing_key:
275
+ rubygems_version: 3.2.15
276
+ signing_key:
231
277
  specification_version: 4
232
- summary: Rails 4 sharding magic
278
+ summary: Rails sharding magic
233
279
  test_files: []