activerecord 7.2.2.1 → 8.1.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +564 -753
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -11
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +23 -11
  9. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  10. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  11. data/lib/active_record/associations/builder/has_one.rb +1 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  13. data/lib/active_record/associations/collection_association.rb +10 -8
  14. data/lib/active_record/associations/collection_proxy.rb +22 -4
  15. data/lib/active_record/associations/deprecation.rb +88 -0
  16. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  19. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -2
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/preloader/batch.rb +7 -1
  23. data/lib/active_record/associations/preloader/branch.rb +1 -0
  24. data/lib/active_record/associations/singular_association.rb +8 -3
  25. data/lib/active_record/associations.rb +192 -24
  26. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  27. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  28. data/lib/active_record/attribute_methods/query.rb +34 -0
  29. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  30. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  31. data/lib/active_record/attribute_methods.rb +24 -19
  32. data/lib/active_record/attributes.rb +40 -26
  33. data/lib/active_record/autosave_association.rb +91 -39
  34. data/lib/active_record/base.rb +3 -4
  35. data/lib/active_record/coders/json.rb +14 -5
  36. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  37. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  38. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  39. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
  40. data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
  41. data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
  42. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  43. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  45. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
  50. data/lib/active_record/connection_adapters/column.rb +17 -4
  51. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  52. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  53. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  54. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  55. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  56. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  57. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
  58. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  65. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  66. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  67. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
  68. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  69. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
  70. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
  71. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  72. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  73. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  74. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  75. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
  78. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  79. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  80. data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
  81. data/lib/active_record/connection_adapters.rb +1 -56
  82. data/lib/active_record/connection_handling.rb +37 -10
  83. data/lib/active_record/core.rb +61 -25
  84. data/lib/active_record/counter_cache.rb +34 -9
  85. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  86. data/lib/active_record/database_configurations/database_config.rb +9 -1
  87. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  88. data/lib/active_record/database_configurations/url_config.rb +13 -3
  89. data/lib/active_record/database_configurations.rb +7 -3
  90. data/lib/active_record/delegated_type.rb +19 -19
  91. data/lib/active_record/dynamic_matchers.rb +54 -69
  92. data/lib/active_record/encryption/config.rb +3 -1
  93. data/lib/active_record/encryption/encryptable_record.rb +9 -9
  94. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  95. data/lib/active_record/encryption/encryptor.rb +49 -28
  96. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  97. data/lib/active_record/encryption/scheme.rb +9 -2
  98. data/lib/active_record/enum.rb +46 -42
  99. data/lib/active_record/errors.rb +36 -12
  100. data/lib/active_record/explain.rb +1 -1
  101. data/lib/active_record/explain_registry.rb +51 -2
  102. data/lib/active_record/filter_attribute_handler.rb +73 -0
  103. data/lib/active_record/fixture_set/table_row.rb +19 -2
  104. data/lib/active_record/fixtures.rb +2 -4
  105. data/lib/active_record/future_result.rb +13 -9
  106. data/lib/active_record/gem_version.rb +3 -3
  107. data/lib/active_record/inheritance.rb +1 -1
  108. data/lib/active_record/insert_all.rb +12 -7
  109. data/lib/active_record/locking/optimistic.rb +8 -1
  110. data/lib/active_record/locking/pessimistic.rb +5 -0
  111. data/lib/active_record/log_subscriber.rb +3 -13
  112. data/lib/active_record/middleware/shard_selector.rb +34 -17
  113. data/lib/active_record/migration/command_recorder.rb +44 -11
  114. data/lib/active_record/migration/compatibility.rb +37 -24
  115. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  116. data/lib/active_record/migration.rb +50 -43
  117. data/lib/active_record/model_schema.rb +38 -13
  118. data/lib/active_record/nested_attributes.rb +6 -6
  119. data/lib/active_record/persistence.rb +162 -133
  120. data/lib/active_record/query_cache.rb +22 -15
  121. data/lib/active_record/query_logs.rb +104 -52
  122. data/lib/active_record/query_logs_formatter.rb +17 -28
  123. data/lib/active_record/querying.rb +12 -12
  124. data/lib/active_record/railtie.rb +37 -32
  125. data/lib/active_record/railties/controller_runtime.rb +11 -6
  126. data/lib/active_record/railties/databases.rake +26 -37
  127. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  128. data/lib/active_record/railties/job_runtime.rb +10 -11
  129. data/lib/active_record/reflection.rb +53 -21
  130. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  131. data/lib/active_record/relation/batches.rb +147 -73
  132. data/lib/active_record/relation/calculations.rb +80 -63
  133. data/lib/active_record/relation/delegation.rb +25 -15
  134. data/lib/active_record/relation/finder_methods.rb +54 -37
  135. data/lib/active_record/relation/merger.rb +8 -8
  136. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  137. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  138. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  139. data/lib/active_record/relation/predicate_builder.rb +22 -7
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +156 -95
  142. data/lib/active_record/relation/spawn_methods.rb +7 -7
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +122 -80
  145. data/lib/active_record/result.rb +109 -24
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +9 -6
  148. data/lib/active_record/schema_dumper.rb +47 -22
  149. data/lib/active_record/schema_migration.rb +2 -1
  150. data/lib/active_record/scoping/named.rb +5 -2
  151. data/lib/active_record/scoping.rb +0 -1
  152. data/lib/active_record/secure_token.rb +3 -3
  153. data/lib/active_record/signed_id.rb +47 -18
  154. data/lib/active_record/statement_cache.rb +24 -20
  155. data/lib/active_record/store.rb +51 -22
  156. data/lib/active_record/structured_event_subscriber.rb +85 -0
  157. data/lib/active_record/table_metadata.rb +6 -23
  158. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  159. data/lib/active_record/tasks/database_tasks.rb +85 -85
  160. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  161. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  162. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  163. data/lib/active_record/test_databases.rb +14 -4
  164. data/lib/active_record/test_fixtures.rb +39 -2
  165. data/lib/active_record/testing/query_assertions.rb +8 -2
  166. data/lib/active_record/timestamp.rb +4 -2
  167. data/lib/active_record/token_for.rb +1 -1
  168. data/lib/active_record/transaction.rb +2 -5
  169. data/lib/active_record/transactions.rb +39 -16
  170. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  171. data/lib/active_record/type/internal/timezone.rb +7 -0
  172. data/lib/active_record/type/json.rb +15 -2
  173. data/lib/active_record/type/serialized.rb +11 -4
  174. data/lib/active_record/type/type_map.rb +1 -1
  175. data/lib/active_record/type_caster/connection.rb +2 -1
  176. data/lib/active_record/validations/associated.rb +1 -1
  177. data/lib/active_record/validations/uniqueness.rb +8 -8
  178. data/lib/active_record.rb +85 -50
  179. data/lib/arel/alias_predication.rb +2 -0
  180. data/lib/arel/collectors/bind.rb +2 -2
  181. data/lib/arel/collectors/sql_string.rb +1 -1
  182. data/lib/arel/collectors/substitute_binds.rb +2 -2
  183. data/lib/arel/crud.rb +8 -11
  184. data/lib/arel/delete_manager.rb +5 -0
  185. data/lib/arel/nodes/binary.rb +1 -1
  186. data/lib/arel/nodes/count.rb +2 -2
  187. data/lib/arel/nodes/delete_statement.rb +4 -2
  188. data/lib/arel/nodes/function.rb +4 -10
  189. data/lib/arel/nodes/named_function.rb +2 -2
  190. data/lib/arel/nodes/node.rb +2 -2
  191. data/lib/arel/nodes/sql_literal.rb +1 -1
  192. data/lib/arel/nodes/update_statement.rb +4 -2
  193. data/lib/arel/nodes.rb +0 -2
  194. data/lib/arel/select_manager.rb +13 -4
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/update_manager.rb +5 -0
  197. data/lib/arel/visitors/dot.rb +2 -3
  198. data/lib/arel/visitors/postgresql.rb +55 -0
  199. data/lib/arel/visitors/sqlite.rb +55 -8
  200. data/lib/arel/visitors/to_sql.rb +6 -22
  201. data/lib/arel.rb +3 -1
  202. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  203. metadata +17 -17
  204. data/lib/active_record/explain_subscriber.rb +0 -34
  205. data/lib/active_record/normalization.rb +0 -163
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thread"
4
3
  require "concurrent/map"
5
4
 
6
5
  module ActiveRecord
@@ -55,19 +54,22 @@ module ActiveRecord
55
54
  # about the model. The model needs to pass a connection specification name to the handler,
56
55
  # in order to look up the correct connection pool.
57
56
  class ConnectionHandler
58
- class StringConnectionName # :nodoc:
59
- attr_reader :name
60
-
61
- def initialize(name)
57
+ class ConnectionDescriptor # :nodoc:
58
+ def initialize(name, primary = false)
62
59
  @name = name
60
+ @primary = primary
61
+ end
62
+
63
+ def name
64
+ primary_class? ? "ActiveRecord::Base" : @name
63
65
  end
64
66
 
65
67
  def primary_class?
66
- false
68
+ @primary
67
69
  end
68
70
 
69
71
  def current_preventing_writes
70
- false
72
+ ActiveRecord::Base.preventing_writes?(@name)
71
73
  end
72
74
  end
73
75
 
@@ -116,7 +118,7 @@ module ActiveRecord
116
118
  pool_config = resolve_pool_config(config, owner_name, role, shard)
117
119
  db_config = pool_config.db_config
118
120
 
119
- pool_manager = set_pool_manager(pool_config.connection_name)
121
+ pool_manager = set_pool_manager(pool_config.connection_descriptor)
120
122
 
121
123
  # If there is an existing pool with the same values as the pool_config
122
124
  # don't remove the connection. Connections should only be removed if we are
@@ -128,8 +130,8 @@ module ActiveRecord
128
130
  # Update the pool_config's connection class if it differs. This is used
129
131
  # for ensuring that ActiveRecord::Base and the primary_abstract_class use
130
132
  # the same pool. Without this granular swapping will not work correctly.
131
- if owner_name.primary_class? && (existing_pool_config.connection_class != owner_name)
132
- existing_pool_config.connection_class = owner_name
133
+ if owner_name.primary_class? && (existing_pool_config.connection_descriptor != owner_name)
134
+ existing_pool_config.connection_descriptor = owner_name
133
135
  end
134
136
 
135
137
  existing_pool_config.pool
@@ -138,7 +140,7 @@ module ActiveRecord
138
140
  pool_manager.set_pool_config(role, shard, pool_config)
139
141
 
140
142
  payload = {
141
- connection_name: pool_config.connection_name,
143
+ connection_name: pool_config.connection_descriptor.name,
142
144
  role: role,
143
145
  shard: shard,
144
146
  config: db_config.configuration_hash
@@ -156,9 +158,7 @@ module ActiveRecord
156
158
  each_connection_pool(role).any?(&:active_connection?)
157
159
  end
158
160
 
159
- # Returns any connections in use by the current thread back to the pool,
160
- # and also returns connections to the pool cached by threads that are no
161
- # longer alive.
161
+ # Returns any connections in use by the current thread back to the pool.
162
162
  def clear_active_connections!(role = nil)
163
163
  each_connection_pool(role).each do |pool|
164
164
  pool.release_connection
@@ -166,7 +166,7 @@ module ActiveRecord
166
166
  end
167
167
  end
168
168
 
169
- # Clears the cache which maps classes.
169
+ # Clears reloadable connection caches in all connection pools.
170
170
  #
171
171
  # See ConnectionPool#clear_reloadable_connections! for details.
172
172
  def clear_reloadable_connections!(role = nil)
@@ -210,18 +210,25 @@ module ActiveRecord
210
210
  # This makes retrieving the connection pool O(1) once the process is warm.
211
211
  # When a connection is established or removed, we invalidate the cache.
212
212
  def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
213
- pool = get_pool_manager(connection_name)&.get_pool_config(role, shard)&.pool
213
+ pool_manager = get_pool_manager(connection_name)
214
+ pool = pool_manager&.get_pool_config(role, shard)&.pool
214
215
 
215
216
  if strict && !pool
216
- if shard != ActiveRecord::Base.default_shard
217
- message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
218
- elsif role != ActiveRecord::Base.default_role
219
- message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
220
- else
221
- message = "No connection pool for '#{connection_name}' found."
222
- end
217
+ selector = [
218
+ ("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard),
219
+ ("'#{role}' role" unless role == ActiveRecord::Base.default_role),
220
+ ].compact.join(" and ")
221
+
222
+ selector = [
223
+ (connection_name unless connection_name == "ActiveRecord::Base"),
224
+ selector.presence,
225
+ ].compact.join(" with ")
226
+
227
+ selector = " for #{selector}" if selector.present?
228
+
229
+ message = "No database connection defined#{selector}."
223
230
 
224
- raise ConnectionNotEstablished, message
231
+ raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role)
225
232
  end
226
233
 
227
234
  pool
@@ -236,8 +243,8 @@ module ActiveRecord
236
243
  end
237
244
 
238
245
  # Get the existing pool manager or initialize and assign a new one.
239
- def set_pool_manager(connection_name)
240
- connection_name_to_pool_manager[connection_name] ||= PoolManager.new
246
+ def set_pool_manager(connection_descriptor)
247
+ connection_name_to_pool_manager[connection_descriptor.name] ||= PoolManager.new
241
248
  end
242
249
 
243
250
  def pool_managers
@@ -272,9 +279,9 @@ module ActiveRecord
272
279
 
273
280
  def determine_owner_name(owner_name, config)
274
281
  if owner_name.is_a?(String) || owner_name.is_a?(Symbol)
275
- StringConnectionName.new(owner_name.to_s)
282
+ ConnectionDescriptor.new(owner_name.to_s)
276
283
  elsif config.is_a?(Symbol)
277
- StringConnectionName.new(config.to_s)
284
+ ConnectionDescriptor.new(config.to_s)
278
285
  else
279
286
  owner_name
280
287
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thread"
4
3
  require "monitor"
5
4
 
6
5
  module ActiveRecord
@@ -41,6 +40,14 @@ module ActiveRecord
41
40
  end
42
41
  end
43
42
 
43
+ # Add +element+ to the back of the queue. Never blocks.
44
+ def add_back(element)
45
+ synchronize do
46
+ @queue.unshift element
47
+ @cond.signal
48
+ end
49
+ end
50
+
44
51
  # If +element+ is in the queue, remove and return it, or +nil+.
45
52
  def delete(element)
46
53
  synchronize do
@@ -55,6 +62,13 @@ module ActiveRecord
55
62
  end
56
63
  end
57
64
 
65
+ # Number of elements in the queue.
66
+ def size
67
+ synchronize do
68
+ @queue.size
69
+ end
70
+ end
71
+
58
72
  # Remove the head of the queue.
59
73
  #
60
74
  # If +timeout+ is not given, remove and return the head of the
@@ -115,9 +129,7 @@ module ActiveRecord
115
129
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
116
130
  elapsed = 0
117
131
  loop do
118
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
119
- @cond.wait(timeout - elapsed)
120
- end
132
+ @cond.wait(timeout - elapsed)
121
133
 
122
134
  return remove if any?
123
135
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thread"
4
3
  require "weakref"
5
4
 
6
5
  module ActiveRecord
@@ -8,12 +7,29 @@ module ActiveRecord
8
7
  class ConnectionPool
9
8
  # = Active Record Connection Pool \Reaper
10
9
  #
11
- # Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
12
- # +pool+. A reaper instantiated with a zero frequency will never reap
13
- # the connection pool.
10
+ # The reaper is a singleton that exists in the background of the process
11
+ # and is responsible for general maintenance of all the connection pools.
14
12
  #
15
- # Configure the frequency by setting +reaping_frequency+ in your database
16
- # YAML file (default 60 seconds).
13
+ # It will reclaim connections that are leased to now-dead threads,
14
+ # ensuring that a bad thread can't leak a pool slot forever. By definition,
15
+ # this involves touching currently-leased connections, but that is safe
16
+ # because the owning thread is known to be dead.
17
+ #
18
+ # Beyond that, it manages the health of available / unleased connections:
19
+ # * retiring connections that have been idle[1] for too long
20
+ # * creating occasional activity on inactive[1] connections
21
+ # * keeping the pool prepopulated up to its minimum size
22
+ # * proactively connecting to the target database from any pooled
23
+ # connections that had lazily deferred that step
24
+ # * resetting or replacing connections that are known to be broken
25
+ #
26
+ #
27
+ # [1]: "idle" and "inactive" here distinguish between connections that
28
+ # have not been requested by the application in a while (idle) and those
29
+ # that have not spoken to their remote server in a while (inactive). The
30
+ # former is a desirable opportunity to reduce our connection count
31
+ # (`idle_timeout`); the latter is a risk that the server or a firewall may
32
+ # drop a connection we still anticipate using (avoided by `keepalive`).
17
33
  class Reaper
18
34
  attr_reader :pool, :frequency
19
35
 
@@ -37,6 +53,15 @@ module ActiveRecord
37
53
  end
38
54
  end
39
55
 
56
+ def pools(refs = nil) # :nodoc:
57
+ refs ||= @mutex.synchronize { @pools.values.flatten(1) }
58
+
59
+ refs.filter_map do |ref|
60
+ ref.__getobj__ if ref.weakref_alive?
61
+ rescue WeakRef::RefError
62
+ end.select(&:maintainable?)
63
+ end
64
+
40
65
  private
41
66
  def spawn_thread(frequency)
42
67
  Thread.new(frequency) do |t|
@@ -47,23 +72,36 @@ module ActiveRecord
47
72
  running = true
48
73
  while running
49
74
  sleep t
75
+
76
+ refs = nil
77
+
50
78
  @mutex.synchronize do
51
- @pools[frequency].select! do |pool|
52
- pool.weakref_alive? && !pool.discarded?
53
- end
79
+ refs = @pools[frequency]
54
80
 
55
- @pools[frequency].each do |p|
56
- p.reap
57
- p.flush
81
+ refs.select! do |pool|
82
+ pool.weakref_alive? && !pool.discarded?
58
83
  rescue WeakRef::RefError
59
84
  end
60
85
 
61
- if @pools[frequency].empty?
86
+ if refs.empty?
62
87
  @pools.delete(frequency)
63
88
  @threads.delete(frequency)
64
89
  running = false
65
90
  end
66
91
  end
92
+
93
+ if running
94
+ pools(refs).each do |pool|
95
+ pool.reaper_lock do
96
+ pool.reap
97
+ pool.flush
98
+ pool.prepopulate
99
+ pool.retire_old_connections
100
+ pool.keep_alive
101
+ pool.preconnect
102
+ end
103
+ end
104
+ end
67
105
  end
68
106
  end
69
107
  end