switchman 2.0.11 → 2.1.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: aa20d460683c12b9e6528f0956c83dec5fadcc4247d551fbd84361757d5452a0
4
- data.tar.gz: 79a6a917b940d6e0bc5b10288f757d002635526e083f3c123698976fb5e96483
3
+ metadata.gz: 53e4594468044606c5a63726359283b3ddedde69c01adbec55ed3ea66eaccaad
4
+ data.tar.gz: 28b2b151c9e22a954249e9f1116e382791a20453d075fafb139609242897345e
5
5
  SHA512:
6
- metadata.gz: 55aca398595c2fda0e32f4aa35e10f42ded64d3154d1dd9bb5cee8f0a0682d61317f8486b156e2722ed3c381dd6cc42710729e19d859b3ade543991469464835
7
- data.tar.gz: 4b5bfb169f36aa3a69f716195316941f648d8b06ae3c9a9f09c5b5835dd67005ddbc7fe7cbe864b278aefeb3abdeaa8f65292f00dcd29c4cf1011c4e852bec64
6
+ metadata.gz: b1e9930cd87320c1465d8296145ca9b390670bd71ff757873187a96ad8b2314aa621eba795ffc9e6aa74ce9ab9f4462dbcb44424d0dd1236d793d37ff0f8f78b
7
+ data.tar.gz: 8827e210a74e28a6d1ee3b40efa2a2514009f4c3d825928a5e7c17ab1630b0a711dc8bf20280126624cf6560799bd3658cd1080696ab9e196524d71917add6dd
@@ -18,7 +18,7 @@ module Switchman
18
18
  :unsharded => [Shard]
19
19
  }
20
20
  private_constant :CATEGORIES
21
- @connection_specification_name = @shard_category = :unsharded
21
+ @connection_specification_name = 'unsharded'
22
22
 
23
23
  if defined?(::ProtectedAttributes)
24
24
  attr_accessible :default, :name, :database_server
@@ -283,17 +283,28 @@ module Switchman
283
283
 
284
284
  with_each_shard(subscope, categories, options) { yield }
285
285
  exception_pipe.last.close
286
- rescue => e
286
+ rescue Exception => e
287
287
  begin
288
288
  dumped = Marshal.dump(e)
289
+ dumped = nil if dumped.length > 64 * 1024
289
290
  rescue
291
+ dumped = nil
292
+ end
293
+
294
+ if dumped.nil?
290
295
  # couldn't dump the exception; create a copy with just
291
296
  # the message and the backtrace
292
297
  e2 = e.class.new(e.message)
293
- e2.set_backtrace(e.backtrace)
298
+ backtrace = e.backtrace
299
+ # truncate excessively long backtraces
300
+ if backtrace.length > 50
301
+ backtrace = backtrace[0...25] + ['...'] + backtrace[-25..-1]
302
+ end
303
+ e2.set_backtrace(backtrace)
294
304
  e2.instance_variable_set(:@active_shards, e.instance_variable_get(:@active_shards))
295
305
  dumped = Marshal.dump(e2)
296
306
  end
307
+
297
308
  exception_pipe.last.set_encoding(dumped.encoding)
298
309
  exception_pipe.last.write(dumped)
299
310
  exception_pipe.last.flush
@@ -112,8 +112,20 @@ module Switchman
112
112
  end
113
113
 
114
114
  def remove_connection(spec_name)
115
+ # also remove pools based on the same spec name that are for shard category purposes
116
+ # can't just use delete_if, because it's a Concurrent::Map, not a Hash
117
+ owner_to_pool.keys.each do |k|
118
+ next if k == spec_name
119
+
120
+ v = owner_to_pool[k]
121
+ owner_to_pool.delete(k) if v.is_a?(ConnectionPoolProxy) && v.default_pool.spec.name == spec_name
122
+ end
123
+
124
+ # unwrap the pool from inside a ConnectionPoolProxy
115
125
  pool = owner_to_pool[spec_name]
116
126
  owner_to_pool[spec_name] = pool.default_pool if pool.is_a?(ConnectionPoolProxy)
127
+
128
+ # now let Rails do its thing with the data type it expects
117
129
  super
118
130
  end
119
131
 
@@ -128,15 +140,21 @@ module Switchman
128
140
  else
129
141
  ancestor_pool.spec
130
142
  end
131
- pool = establish_connection(spec.to_hash)
132
- pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
133
- pool
134
- elsif spec_name != "primary"
143
+ # avoid copying "duplicate" pools that implement shard categories.
144
+ # they'll have a spec.name of primary, but a spec_name of something else, like unsharded
145
+ if spec.name == spec_name
146
+ pool = establish_connection(spec.to_hash)
147
+ pool.instance_variable_set(:@schema_cache, ancestor_pool.schema_cache) if ancestor_pool.schema_cache
148
+ next pool
149
+ end
150
+ end
151
+
152
+ if spec_name != "primary"
135
153
  primary_pool = retrieve_connection_pool("primary")
136
154
  if primary_pool.is_a?(ConnectionPoolProxy)
137
155
  pool = ConnectionPoolProxy.new(spec_name.to_sym, primary_pool.default_pool, @shard_connection_pools)
138
156
  pool.schema_cache.copy_references(primary_pool.schema_cache)
139
- pool
157
+ owner_to_pool[spec_name] = pool
140
158
  else
141
159
  primary_pool
142
160
  end
@@ -15,7 +15,7 @@ module Switchman
15
15
  def convert_to_id(value)
16
16
  case value
17
17
  when ::ActiveRecord::Base
18
- value.send(primary_key)
18
+ value.id
19
19
  else
20
20
  super
21
21
  end
@@ -246,6 +246,18 @@ module Switchman
246
246
  binds: nil,
247
247
  dup_binds_on_mutation: false)
248
248
  result = predicates.map do |predicate|
249
+ if ::Rails.version >= '5.2' && predicate.is_a?(::Arel::Nodes::And)
250
+ new_predicates, _binds = transpose_predicates(predicate.children, source_shard, target_shard,
251
+ remove_nonlocal_primary_keys,
252
+ binds: binds,
253
+ dup_binds_on_mutation: dup_binds_on_mutation)
254
+ next (if new_predicates == predicate.children
255
+ predicate
256
+ else
257
+ ::Arel::Nodes::And.new(new_predicates)
258
+ end)
259
+ end
260
+
249
261
  next predicate unless predicate.is_a?(::Arel::Nodes::Binary)
250
262
  next predicate unless predicate.left.is_a?(::Arel::Attributes::Attribute)
251
263
  relation, column = relation_and_column(predicate.left)
@@ -28,15 +28,26 @@ module Switchman
28
28
  # this technically belongs on AssociationReflection, but we put it on
29
29
  # ThroughReflection as well, instead of delegating to its internal
30
30
  # HasManyAssociation, losing its proper `klass`
31
- def association_scope_cache(conn, owner, &block)
32
- key = conn.prepared_statements
33
- if polymorphic?
34
- key = [key, owner._read_attribute(@foreign_type)]
31
+ if ::Rails.version < '6.0.4'
32
+ def association_scope_cache(conn, owner, &block)
33
+ key = conn.prepared_statements
34
+ if polymorphic?
35
+ key = [key, owner._read_attribute(@foreign_type)]
36
+ end
37
+ key = [key, shard(owner).id].flatten
38
+ @association_scope_cache[key] ||= @scope_lock.synchronize {
39
+ @association_scope_cache[key] ||= (::Rails.version >= "5.2" ? ::ActiveRecord::StatementCache.create(conn, &block) : block.call)
40
+ }
41
+ end
42
+ else
43
+ def association_scope_cache(klass, owner, &block)
44
+ key = self
45
+ if polymorphic?
46
+ key = [key, owner._read_attribute(@foreign_type)]
47
+ end
48
+ key = [key, shard(owner).id].flatten
49
+ klass.cached_find_by_statement(key, &block)
35
50
  end
36
- key = [key, shard(owner).id].flatten
37
- @association_scope_cache[key] ||= @scope_lock.synchronize {
38
- @association_scope_cache[key] ||= (::Rails.version >= "5.2" ? ::ActiveRecord::StatementCache.create(conn, &block) : block.call)
39
- }
40
51
  end
41
52
  end
42
53
 
@@ -62,7 +62,7 @@ module Switchman
62
62
  %I{update_all delete_all}.each do |method|
63
63
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
64
64
  def #{method}(*args)
65
- result = self.activate { |relation| relation.call_super(#{method.inspect}, Relation, *args) }
65
+ result = self.activate(unordered: true) { |relation| relation.call_super(#{method.inspect}, Relation, *args) }
66
66
  result = result.sum if result.is_a?(Array)
67
67
  result
68
68
  end
@@ -97,7 +97,7 @@ module Switchman
97
97
  end
98
98
  end
99
99
 
100
- def activate(&block)
100
+ def activate(unordered: false, &block)
101
101
  shards = all_shards
102
102
  if (Array === shards && shards.length == 1)
103
103
  if shards.first == DefaultShard || shards.first == Shard.current(klass.shard_category)
@@ -118,7 +118,7 @@ module Switchman
118
118
 
119
119
  shard_results = relation.activate(&block)
120
120
 
121
- if shard_results.present?
121
+ if shard_results.present? && !unordered
122
122
  can_order ||= can_order_cross_shard_results? unless order_values.empty?
123
123
  raise OrderOnMultiShardQuery if !can_order && !order_values.empty? && result_count.positive?
124
124
 
@@ -142,7 +142,9 @@ module Switchman
142
142
  results.sort! do |l, r|
143
143
  result = 0
144
144
  order_values.each do |ov|
145
- if l.respond_to?(ov.expr.name)
145
+ if !l.is_a?(::ActiveRecord::Base)
146
+ a, b = l, r
147
+ elsif l.respond_to?(ov.expr.name)
146
148
  a = l.send(ov.expr.name)
147
149
  b = r.send(ov.expr.name)
148
150
  else
@@ -154,7 +154,7 @@ module Switchman
154
154
  end
155
155
  end
156
156
  spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(
157
- category,
157
+ default_pool.spec.name,
158
158
  config,
159
159
  "#{config[:adapter]}_connection"
160
160
  )
@@ -142,6 +142,7 @@ module Switchman
142
142
 
143
143
  ::ActiveRecord::Relation::WhereClauseFactory.prepend(ActiveRecord::WhereClauseFactory)
144
144
  ::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
145
+ ::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
145
146
  ::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
146
147
  ::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
147
148
 
@@ -17,13 +17,7 @@ module Switchman
17
17
  Shard.default(reload: true)
18
18
  end
19
19
 
20
- # can't auto-create a new shard on the default shard's db server if the
21
- # default shard is split across multiple db servers
22
- if ::ActiveRecord::Base.connection_handler.connection_pool_list.length > 1
23
- server1 = DatabaseServer.create(Shard.default.database_server.config)
24
- else
25
- server1 = Shard.default.database_server
26
- end
20
+ server1 = Shard.default.database_server
27
21
  server2 = DatabaseServer.create(Shard.default.database_server.config.merge(server2: true))
28
22
 
29
23
  if server1 == Shard.default.database_server && server1.config[:shard1] && server1.config[:shard2]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- VERSION = "2.0.11"
4
+ VERSION = "2.1.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.11
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-06-11 00:00:00.000000000 Z
13
+ date: 2021-07-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties