switchman 3.0.5 → 4.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.
- checksums.yaml +4 -4
- data/Rakefile +16 -15
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -2
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +1 -1
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +6 -15
- data/lib/switchman/active_record/associations.rb +331 -0
- data/lib/switchman/active_record/attribute_methods.rb +182 -77
- data/lib/switchman/active_record/base.rb +249 -46
- data/lib/switchman/active_record/calculations.rb +98 -44
- data/lib/switchman/active_record/connection_handler.rb +18 -0
- data/lib/switchman/active_record/connection_pool.rb +27 -28
- data/lib/switchman/active_record/database_configurations.rb +44 -6
- data/lib/switchman/active_record/finder_methods.rb +46 -16
- data/lib/switchman/active_record/log_subscriber.rb +11 -5
- data/lib/switchman/active_record/migration.rb +52 -5
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/pending_migration_connection.rb +17 -0
- data/lib/switchman/active_record/persistence.rb +37 -2
- data/lib/switchman/active_record/postgresql_adapter.rb +12 -11
- data/lib/switchman/active_record/predicate_builder.rb +2 -2
- data/lib/switchman/active_record/query_cache.rb +49 -20
- data/lib/switchman/active_record/query_methods.rb +202 -136
- data/lib/switchman/active_record/reflection.rb +1 -1
- data/lib/switchman/active_record/relation.rb +40 -28
- data/lib/switchman/active_record/spawn_methods.rb +2 -2
- data/lib/switchman/active_record/statement_cache.rb +11 -7
- data/lib/switchman/active_record/table_definition.rb +1 -1
- data/lib/switchman/active_record/tasks/database_tasks.rb +6 -1
- data/lib/switchman/active_record/test_fixtures.rb +53 -0
- data/lib/switchman/active_support/cache.rb +25 -4
- data/lib/switchman/arel.rb +45 -7
- data/lib/switchman/call_super.rb +2 -2
- data/lib/switchman/database_server.rb +123 -79
- data/lib/switchman/default_shard.rb +14 -5
- data/lib/switchman/engine.rb +79 -131
- data/lib/switchman/environment.rb +2 -2
- data/lib/switchman/errors.rb +17 -2
- data/lib/switchman/guard_rail/relation.rb +7 -10
- data/lib/switchman/guard_rail.rb +5 -0
- data/lib/switchman/parallel.rb +68 -0
- data/lib/switchman/r_spec_helper.rb +17 -28
- data/lib/switchman/rails.rb +1 -4
- data/{app/models → lib}/switchman/shard.rb +226 -241
- data/lib/switchman/sharded_instrumenter.rb +3 -3
- data/lib/switchman/shared_schema_cache.rb +11 -0
- data/lib/switchman/standard_error.rb +15 -12
- data/lib/switchman/test_helper.rb +2 -2
- data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +44 -12
- data/lib/tasks/switchman.rake +101 -54
- metadata +50 -58
- data/lib/switchman/active_record/association.rb +0 -206
- data/lib/switchman/open4.rb +0 -80
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:
|
|
4
|
+
version: 4.0.0
|
|
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:
|
|
13
|
+
date: 2025-02-12 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activerecord
|
|
@@ -18,96 +18,82 @@ dependencies:
|
|
|
18
18
|
requirements:
|
|
19
19
|
- - ">="
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: '
|
|
21
|
+
version: '7.0'
|
|
22
22
|
- - "<"
|
|
23
23
|
- !ruby/object:Gem::Version
|
|
24
|
-
version: '
|
|
24
|
+
version: '7.2'
|
|
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: '
|
|
31
|
+
version: '7.0'
|
|
32
32
|
- - "<"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '
|
|
34
|
+
version: '7.2'
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
36
|
name: guardrail
|
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
39
|
- - "~>"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 3.0.
|
|
41
|
+
version: 3.0.1
|
|
42
42
|
type: :runtime
|
|
43
43
|
prerelease: false
|
|
44
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
46
|
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: 3.0.
|
|
48
|
+
version: 3.0.1
|
|
49
49
|
- !ruby/object:Gem::Dependency
|
|
50
|
-
name:
|
|
50
|
+
name: parallel
|
|
51
51
|
requirement: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
53
|
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
|
-
version: 1.
|
|
55
|
+
version: '1.22'
|
|
56
56
|
type: :runtime
|
|
57
57
|
prerelease: false
|
|
58
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
60
|
- - "~>"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: 1.
|
|
62
|
+
version: '1.22'
|
|
63
63
|
- !ruby/object:Gem::Dependency
|
|
64
64
|
name: railties
|
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
|
66
66
|
requirements:
|
|
67
67
|
- - ">="
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '
|
|
69
|
+
version: '7.0'
|
|
70
70
|
- - "<"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '
|
|
72
|
+
version: '7.2'
|
|
73
73
|
type: :runtime
|
|
74
74
|
prerelease: false
|
|
75
75
|
version_requirements: !ruby/object:Gem::Requirement
|
|
76
76
|
requirements:
|
|
77
77
|
- - ">="
|
|
78
78
|
- !ruby/object:Gem::Version
|
|
79
|
-
version: '
|
|
79
|
+
version: '7.0'
|
|
80
80
|
- - "<"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '7.2'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: debug
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
89
|
+
version: '1.8'
|
|
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: '
|
|
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'
|
|
96
|
+
version: '1.8'
|
|
111
97
|
- !ruby/object:Gem::Dependency
|
|
112
98
|
name: pg
|
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -122,20 +108,6 @@ dependencies:
|
|
|
122
108
|
- - "~>"
|
|
123
109
|
- !ruby/object:Gem::Version
|
|
124
110
|
version: '1.2'
|
|
125
|
-
- !ruby/object:Gem::Dependency
|
|
126
|
-
name: pry
|
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
|
128
|
-
requirements:
|
|
129
|
-
- - ">="
|
|
130
|
-
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0'
|
|
132
|
-
type: :development
|
|
133
|
-
prerelease: false
|
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
-
requirements:
|
|
136
|
-
- - ">="
|
|
137
|
-
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0'
|
|
139
111
|
- !ruby/object:Gem::Dependency
|
|
140
112
|
name: rake
|
|
141
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,14 +142,14 @@ dependencies:
|
|
|
170
142
|
requirements:
|
|
171
143
|
- - "~>"
|
|
172
144
|
- !ruby/object:Gem::Version
|
|
173
|
-
version: '
|
|
145
|
+
version: '6.0'
|
|
174
146
|
type: :development
|
|
175
147
|
prerelease: false
|
|
176
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
149
|
requirements:
|
|
178
150
|
- - "~>"
|
|
179
151
|
- !ruby/object:Gem::Version
|
|
180
|
-
version: '
|
|
152
|
+
version: '6.0'
|
|
181
153
|
- !ruby/object:Gem::Dependency
|
|
182
154
|
name: rubocop
|
|
183
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -192,6 +164,20 @@ dependencies:
|
|
|
192
164
|
- - "~>"
|
|
193
165
|
- !ruby/object:Gem::Version
|
|
194
166
|
version: '1.10'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: rubocop-inst
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '1'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '1'
|
|
195
181
|
- !ruby/object:Gem::Dependency
|
|
196
182
|
name: rubocop-rake
|
|
197
183
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -242,8 +228,6 @@ extensions: []
|
|
|
242
228
|
extra_rdoc_files: []
|
|
243
229
|
files:
|
|
244
230
|
- Rakefile
|
|
245
|
-
- app/models/switchman/shard.rb
|
|
246
|
-
- app/models/switchman/unsharded_record.rb
|
|
247
231
|
- db/migrate/20130328212039_create_switchman_shards.rb
|
|
248
232
|
- db/migrate/20130328224244_create_default_shard.rb
|
|
249
233
|
- db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
|
|
@@ -253,10 +237,11 @@ files:
|
|
|
253
237
|
- lib/switchman.rb
|
|
254
238
|
- lib/switchman/action_controller/caching.rb
|
|
255
239
|
- lib/switchman/active_record/abstract_adapter.rb
|
|
256
|
-
- lib/switchman/active_record/
|
|
240
|
+
- lib/switchman/active_record/associations.rb
|
|
257
241
|
- lib/switchman/active_record/attribute_methods.rb
|
|
258
242
|
- lib/switchman/active_record/base.rb
|
|
259
243
|
- lib/switchman/active_record/calculations.rb
|
|
244
|
+
- lib/switchman/active_record/connection_handler.rb
|
|
260
245
|
- lib/switchman/active_record/connection_pool.rb
|
|
261
246
|
- lib/switchman/active_record/database_configurations.rb
|
|
262
247
|
- lib/switchman/active_record/database_configurations/database_config.rb
|
|
@@ -264,6 +249,7 @@ files:
|
|
|
264
249
|
- lib/switchman/active_record/log_subscriber.rb
|
|
265
250
|
- lib/switchman/active_record/migration.rb
|
|
266
251
|
- lib/switchman/active_record/model_schema.rb
|
|
252
|
+
- lib/switchman/active_record/pending_migration_connection.rb
|
|
267
253
|
- lib/switchman/active_record/persistence.rb
|
|
268
254
|
- lib/switchman/active_record/postgresql_adapter.rb
|
|
269
255
|
- lib/switchman/active_record/predicate_builder.rb
|
|
@@ -275,6 +261,7 @@ files:
|
|
|
275
261
|
- lib/switchman/active_record/statement_cache.rb
|
|
276
262
|
- lib/switchman/active_record/table_definition.rb
|
|
277
263
|
- lib/switchman/active_record/tasks/database_tasks.rb
|
|
264
|
+
- lib/switchman/active_record/test_fixtures.rb
|
|
278
265
|
- lib/switchman/active_record/type_caster.rb
|
|
279
266
|
- lib/switchman/active_support/cache.rb
|
|
280
267
|
- lib/switchman/arel.rb
|
|
@@ -286,19 +273,24 @@ files:
|
|
|
286
273
|
- lib/switchman/errors.rb
|
|
287
274
|
- lib/switchman/guard_rail.rb
|
|
288
275
|
- lib/switchman/guard_rail/relation.rb
|
|
289
|
-
- lib/switchman/
|
|
276
|
+
- lib/switchman/parallel.rb
|
|
290
277
|
- lib/switchman/r_spec_helper.rb
|
|
291
278
|
- lib/switchman/rails.rb
|
|
279
|
+
- lib/switchman/shard.rb
|
|
292
280
|
- lib/switchman/sharded_instrumenter.rb
|
|
281
|
+
- lib/switchman/shared_schema_cache.rb
|
|
293
282
|
- lib/switchman/standard_error.rb
|
|
294
283
|
- lib/switchman/test_helper.rb
|
|
284
|
+
- lib/switchman/unsharded_record.rb
|
|
295
285
|
- lib/switchman/version.rb
|
|
296
286
|
- lib/tasks/switchman.rake
|
|
297
287
|
homepage: http://www.instructure.com/
|
|
298
288
|
licenses:
|
|
299
289
|
- MIT
|
|
300
|
-
metadata:
|
|
301
|
-
|
|
290
|
+
metadata:
|
|
291
|
+
rubygems_mfa_required: 'true'
|
|
292
|
+
source_code_uri: https://github.com/instructure/switchman
|
|
293
|
+
post_install_message:
|
|
302
294
|
rdoc_options: []
|
|
303
295
|
require_paths:
|
|
304
296
|
- lib
|
|
@@ -306,15 +298,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
306
298
|
requirements:
|
|
307
299
|
- - ">="
|
|
308
300
|
- !ruby/object:Gem::Version
|
|
309
|
-
version: '
|
|
301
|
+
version: '3.0'
|
|
310
302
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
311
303
|
requirements:
|
|
312
304
|
- - ">="
|
|
313
305
|
- !ruby/object:Gem::Version
|
|
314
306
|
version: '0'
|
|
315
307
|
requirements: []
|
|
316
|
-
rubygems_version: 3.2.
|
|
317
|
-
signing_key:
|
|
308
|
+
rubygems_version: 3.2.33
|
|
309
|
+
signing_key:
|
|
318
310
|
specification_version: 4
|
|
319
311
|
summary: Rails sharding magic
|
|
320
312
|
test_files: []
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Switchman
|
|
4
|
-
module ActiveRecord
|
|
5
|
-
module Association
|
|
6
|
-
def shard
|
|
7
|
-
reflection.shard(owner)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def build_record(*args)
|
|
11
|
-
shard.activate { super }
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def load_target
|
|
15
|
-
shard.activate { super }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def scope
|
|
19
|
-
shard_value = @reflection.options[:multishard] ? @owner : shard
|
|
20
|
-
@owner.shard.activate { super.shard(shard_value, :association) }
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
module CollectionAssociation
|
|
25
|
-
def find_target
|
|
26
|
-
shards = reflection.options[:multishard] && owner.respond_to?(:associated_shards) ? owner.associated_shards : [shard]
|
|
27
|
-
# activate both the owner and the target's shard category, so that Reflection#join_id_for,
|
|
28
|
-
# when called for the owner, will be returned relative to shard the query will execute on
|
|
29
|
-
Shard.with_each_shard(shards, [klass.connection_classes, owner.class.connection_classes].uniq) do
|
|
30
|
-
super
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def _create_record(*)
|
|
35
|
-
shard.activate { super }
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
module BelongsToAssociation
|
|
40
|
-
def replace_keys(record, force: false)
|
|
41
|
-
if record&.class&.sharded_column?(reflection.association_primary_key(record.class))
|
|
42
|
-
foreign_id = record[reflection.association_primary_key(record.class)]
|
|
43
|
-
owner[reflection.foreign_key] = Shard.relative_id_for(foreign_id, record.shard, owner.shard)
|
|
44
|
-
else
|
|
45
|
-
super
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def shard
|
|
50
|
-
if @owner.class.sharded_column?(@reflection.foreign_key) &&
|
|
51
|
-
(foreign_id = @owner[@reflection.foreign_key])
|
|
52
|
-
Shard.shard_for(foreign_id, @owner.shard)
|
|
53
|
-
else
|
|
54
|
-
super
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
module ForeignAssociation
|
|
60
|
-
# significant change:
|
|
61
|
-
# * transpose the key to the correct shard
|
|
62
|
-
def set_owner_attributes(record) # rubocop:disable Naming/AccessorMethodName
|
|
63
|
-
return if options[:through]
|
|
64
|
-
|
|
65
|
-
key = owner._read_attribute(reflection.join_foreign_key)
|
|
66
|
-
key = Shard.relative_id_for(key, owner.shard, shard)
|
|
67
|
-
record._write_attribute(reflection.join_primary_key, key)
|
|
68
|
-
|
|
69
|
-
record._write_attribute(reflection.type, owner.class.polymorphic_name) if reflection.type
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
module Extension
|
|
74
|
-
def self.build(_model, _reflection); end
|
|
75
|
-
|
|
76
|
-
def self.valid_options
|
|
77
|
-
[:multishard]
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
::ActiveRecord::Associations::Builder::Association.extensions << Extension
|
|
82
|
-
|
|
83
|
-
module Preloader
|
|
84
|
-
module Association
|
|
85
|
-
# Copypasta from Activerecord but with added global_id_for goodness.
|
|
86
|
-
def records_for(ids)
|
|
87
|
-
scope.where(association_key_name => ids).load do |record|
|
|
88
|
-
global_key = if model.connection_classes == UnshardedRecord
|
|
89
|
-
convert_key(record[association_key_name])
|
|
90
|
-
else
|
|
91
|
-
Shard.global_id_for(record[association_key_name], record.shard)
|
|
92
|
-
end
|
|
93
|
-
owner = owners_by_key[convert_key(global_key)].first
|
|
94
|
-
association = owner.association(reflection.name)
|
|
95
|
-
association.set_inverse_instance(record)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# significant changes:
|
|
100
|
-
# * partition_by_shard the records_for call
|
|
101
|
-
# * re-globalize the fetched owner id before looking up in the map
|
|
102
|
-
def load_records
|
|
103
|
-
# owners can be duplicated when a relation has a collection association join
|
|
104
|
-
# #compare_by_identity makes such owners different hash keys
|
|
105
|
-
@records_by_owner = {}.compare_by_identity
|
|
106
|
-
|
|
107
|
-
if owner_keys.empty?
|
|
108
|
-
raw_records = []
|
|
109
|
-
else
|
|
110
|
-
# determine the shard to search for each owner
|
|
111
|
-
if reflection.macro == :belongs_to
|
|
112
|
-
# for belongs_to, it's the shard of the foreign_key
|
|
113
|
-
partition_proc = lambda do |owner|
|
|
114
|
-
if owner.class.sharded_column?(owner_key_name)
|
|
115
|
-
Shard.shard_for(owner[owner_key_name], owner.shard)
|
|
116
|
-
else
|
|
117
|
-
Shard.current
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
elsif !reflection.options[:multishard]
|
|
121
|
-
# for non-multishard associations, it's *just* the owner's shard
|
|
122
|
-
partition_proc = ->(owner) { owner.shard }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
raw_records = Shard.partition_by_shard(owners, partition_proc) do |partitioned_owners|
|
|
126
|
-
relative_owner_keys = partitioned_owners.map do |owner|
|
|
127
|
-
key = owner[owner_key_name]
|
|
128
|
-
if key && owner.class.sharded_column?(owner_key_name)
|
|
129
|
-
key = Shard.relative_id_for(key, owner.shard,
|
|
130
|
-
Shard.current(klass.connection_classes))
|
|
131
|
-
end
|
|
132
|
-
convert_key(key)
|
|
133
|
-
end
|
|
134
|
-
relative_owner_keys.compact!
|
|
135
|
-
relative_owner_keys.uniq!
|
|
136
|
-
records_for(relative_owner_keys)
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
@preloaded_records = raw_records.select do |record|
|
|
141
|
-
assignments = false
|
|
142
|
-
|
|
143
|
-
owner_key = record[association_key_name]
|
|
144
|
-
if owner_key && record.class.sharded_column?(association_key_name)
|
|
145
|
-
owner_key = Shard.global_id_for(owner_key,
|
|
146
|
-
record.shard)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
owners_by_key[convert_key(owner_key)].each do |owner|
|
|
150
|
-
entries = (@records_by_owner[owner] ||= [])
|
|
151
|
-
|
|
152
|
-
if reflection.collection? || entries.empty?
|
|
153
|
-
entries << record
|
|
154
|
-
assignments = true
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
assignments
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# significant change: globalize keys on sharded columns
|
|
163
|
-
def owners_by_key
|
|
164
|
-
@owners_by_key ||= owners.each_with_object({}) do |owner, result|
|
|
165
|
-
key = owner[owner_key_name]
|
|
166
|
-
key = Shard.global_id_for(key, owner.shard) if key && owner.class.sharded_column?(owner_key_name)
|
|
167
|
-
key = convert_key(key)
|
|
168
|
-
(result[key] ||= []) << owner if key
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# significant change: don't cache scope (since it could be for different shards)
|
|
173
|
-
def scope
|
|
174
|
-
build_scope
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
module CollectionProxy
|
|
180
|
-
def initialize(*args)
|
|
181
|
-
super
|
|
182
|
-
self.shard_value = scope.shard_value
|
|
183
|
-
self.shard_source_value = :association
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def shard(*args)
|
|
187
|
-
scope.shard(*args)
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
module AutosaveAssociation
|
|
192
|
-
def record_changed?(reflection, record, key)
|
|
193
|
-
record.new_record? ||
|
|
194
|
-
(record.has_attribute?(reflection.foreign_key) && record.send(reflection.foreign_key) != key) || # have to use send instead of [] because sharding
|
|
195
|
-
record.attribute_changed?(reflection.foreign_key)
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def save_belongs_to_association(reflection)
|
|
199
|
-
# this seems counter-intuitive, but the autosave code will assign to attribute bypassing switchman,
|
|
200
|
-
# after reading the id attribute _without_ bypassing switchman. So we need Shard.current for the
|
|
201
|
-
# category of the associated record to match Shard.current for the category of self
|
|
202
|
-
shard.activate(connection_classes_for_reflection(reflection)) { super }
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
data/lib/switchman/open4.rb
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'open4'
|
|
4
|
-
|
|
5
|
-
# This fixes a bug with exception handling,
|
|
6
|
-
# see https://github.com/ahoward/open4/pull/30
|
|
7
|
-
module Open4
|
|
8
|
-
def self.do_popen(b = nil, exception_propagation_at = nil, closefds=false, &cmd)
|
|
9
|
-
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
|
10
|
-
|
|
11
|
-
verbose = $VERBOSE
|
|
12
|
-
begin
|
|
13
|
-
$VERBOSE = nil
|
|
14
|
-
|
|
15
|
-
cid = fork {
|
|
16
|
-
if closefds
|
|
17
|
-
exlist = [0, 1, 2] | [pw,pr,pe,ps].map{|p| [p.first.fileno, p.last.fileno] }.flatten
|
|
18
|
-
ObjectSpace.each_object(IO){|io|
|
|
19
|
-
io.close if (not io.closed?) and (not exlist.include? io.fileno) rescue nil
|
|
20
|
-
}
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
pw.last.close
|
|
24
|
-
STDIN.reopen pw.first
|
|
25
|
-
pw.first.close
|
|
26
|
-
|
|
27
|
-
pr.first.close
|
|
28
|
-
STDOUT.reopen pr.last
|
|
29
|
-
pr.last.close
|
|
30
|
-
|
|
31
|
-
pe.first.close
|
|
32
|
-
STDERR.reopen pe.last
|
|
33
|
-
pe.last.close
|
|
34
|
-
|
|
35
|
-
STDOUT.sync = STDERR.sync = true
|
|
36
|
-
|
|
37
|
-
begin
|
|
38
|
-
cmd.call(ps)
|
|
39
|
-
rescue Exception => e
|
|
40
|
-
begin
|
|
41
|
-
Marshal.dump(e, ps.last)
|
|
42
|
-
ps.last.flush
|
|
43
|
-
rescue Errno::EPIPE
|
|
44
|
-
raise e
|
|
45
|
-
end
|
|
46
|
-
ensure
|
|
47
|
-
ps.last.close unless ps.last.closed?
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
exit!
|
|
51
|
-
}
|
|
52
|
-
ensure
|
|
53
|
-
$VERBOSE = verbose
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
[ pw.first, pr.last, pe.last, ps.last ].each { |fd| fd.close }
|
|
57
|
-
|
|
58
|
-
Open4.propagate_exception cid, ps.first if exception_propagation_at == :init
|
|
59
|
-
|
|
60
|
-
pw.last.sync = true
|
|
61
|
-
|
|
62
|
-
pi = [ pw.last, pr.first, pe.first ]
|
|
63
|
-
|
|
64
|
-
begin
|
|
65
|
-
return [cid, *pi] unless b
|
|
66
|
-
|
|
67
|
-
begin
|
|
68
|
-
b.call(cid, *pi)
|
|
69
|
-
ensure
|
|
70
|
-
pi.each { |fd| fd.close unless fd.closed? }
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
Open4.propagate_exception cid, ps.first if exception_propagation_at == :block
|
|
74
|
-
|
|
75
|
-
Process.waitpid2(cid).last
|
|
76
|
-
ensure
|
|
77
|
-
ps.first.close unless ps.first.closed?
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|