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
  require "monitor"
6
5
 
@@ -9,18 +8,13 @@ require "active_record/connection_adapters/abstract/connection_pool/reaper"
9
8
 
10
9
  module ActiveRecord
11
10
  module ConnectionAdapters
12
- module AbstractPool # :nodoc:
13
- end
14
-
15
11
  class NullPool # :nodoc:
16
- include ConnectionAdapters::AbstractPool
17
-
18
- class NullConfig # :nodoc:
12
+ class NullConfig
19
13
  def method_missing(...)
20
14
  nil
21
15
  end
22
16
  end
23
- NULL_CONFIG = NullConfig.new # :nodoc:
17
+ NULL_CONFIG = NullConfig.new
24
18
 
25
19
  def initialize
26
20
  super()
@@ -37,7 +31,8 @@ module ActiveRecord
37
31
  end
38
32
 
39
33
  def schema_cache; end
40
- def connection_class; end
34
+ def query_cache; end
35
+ def connection_descriptor; end
41
36
  def checkin(_); end
42
37
  def remove(_); end
43
38
  def async_executor; end
@@ -49,6 +44,11 @@ module ActiveRecord
49
44
  def dirties_query_cache
50
45
  true
51
46
  end
47
+
48
+ def pool_transaction_isolation_level; end
49
+ def pool_transaction_isolation_level=(isolation_level)
50
+ raise NotImplementedError, "This method should never be called"
51
+ end
52
52
  end
53
53
 
54
54
  # = Active Record Connection Pool
@@ -101,13 +101,21 @@ module ActiveRecord
101
101
  # There are several connection-pooling-related options that you can add to
102
102
  # your database connection configuration:
103
103
  #
104
- # * +pool+: maximum number of connections the pool may manage (default 5).
105
- # * +idle_timeout+: number of seconds that a connection will be kept
106
- # unused in the pool before it is automatically disconnected (default
107
- # 300 seconds). Set this to zero to keep connections forever.
108
104
  # * +checkout_timeout+: number of seconds to wait for a connection to
109
105
  # become available before giving up and raising a timeout error (default
110
106
  # 5 seconds).
107
+ # * +idle_timeout+: number of seconds that a connection will be kept
108
+ # unused in the pool before it is automatically disconnected (default
109
+ # 300 seconds). Set this to zero to keep connections forever.
110
+ # * +keepalive+: number of seconds between keepalive checks if the
111
+ # connection has been idle (default 600 seconds).
112
+ # * +max_age+: number of seconds the pool will allow the connection to
113
+ # exist before retiring it at next checkin. (default Float::INFINITY).
114
+ # * +max_connections+: maximum number of connections the pool may manage (default 5).
115
+ # Set to +nil+ or -1 for unlimited connections.
116
+ # * +min_connections+: minimum number of connections the pool will open and maintain (default 0).
117
+ # * +pool_jitter+: maximum reduction factor to apply to +max_age+ and
118
+ # +keepalive+ intervals (default 0.2; range 0.0-1.0).
111
119
  #
112
120
  #--
113
121
  # Synchronization policy:
@@ -115,27 +123,34 @@ module ActiveRecord
115
123
  # * access to these instance variables needs to be in +synchronize+:
116
124
  # * @connections
117
125
  # * @now_connecting
126
+ # * @maintaining
118
127
  # * private methods that require being called in a +synchronize+ blocks
119
128
  # are now explicitly documented
120
129
  class ConnectionPool
121
- class WeakThreadKeyMap # :nodoc:
122
- # FIXME: On 3.3 we could use ObjectSpace::WeakKeyMap
123
- # but it currently cause GC crashes: https://github.com/byroot/rails/pull/3
124
- def initialize
125
- @map = {}
126
- end
130
+ # Prior to 3.3.5, WeakKeyMap had a use after free bug
131
+ # https://bugs.ruby-lang.org/issues/20688
132
+ if ObjectSpace.const_defined?(:WeakKeyMap) && RUBY_VERSION >= "3.3.5"
133
+ WeakThreadKeyMap = ObjectSpace::WeakKeyMap
134
+ else
135
+ class WeakThreadKeyMap # :nodoc:
136
+ # FIXME: On 3.3 we could use ObjectSpace::WeakKeyMap
137
+ # but it currently causes GC crashes: https://github.com/byroot/rails/pull/3
138
+ def initialize
139
+ @map = {}
140
+ end
127
141
 
128
- def clear
129
- @map.clear
130
- end
142
+ def clear
143
+ @map.clear
144
+ end
131
145
 
132
- def [](key)
133
- @map[key]
134
- end
146
+ def [](key)
147
+ @map[key]
148
+ end
135
149
 
136
- def []=(key, value)
137
- @map.select! { |c, _| c.alive? }
138
- @map[key] = value
150
+ def []=(key, value)
151
+ @map.select! { |c, _| c&.alive? }
152
+ @map[key] = value
153
+ end
139
154
  end
140
155
  end
141
156
 
@@ -165,21 +180,30 @@ module ActiveRecord
165
180
  end
166
181
  end
167
182
 
168
- class LeaseRegistry # :nodoc:
169
- def initialize
170
- @mutex = Mutex.new
171
- @map = WeakThreadKeyMap.new
183
+ if RUBY_ENGINE == "ruby"
184
+ # Thanks to the GVL, the LeaseRegistry doesn't need to be synchronized on MRI
185
+ class LeaseRegistry < WeakThreadKeyMap # :nodoc:
186
+ def [](context)
187
+ super || (self[context] = Lease.new)
188
+ end
172
189
  end
190
+ else
191
+ class LeaseRegistry # :nodoc:
192
+ def initialize
193
+ @mutex = Mutex.new
194
+ @map = WeakThreadKeyMap.new
195
+ end
173
196
 
174
- def [](context)
175
- @mutex.synchronize do
176
- @map[context] ||= Lease.new
197
+ def [](context)
198
+ @mutex.synchronize do
199
+ @map[context] ||= Lease.new
200
+ end
177
201
  end
178
- end
179
202
 
180
- def clear
181
- @mutex.synchronize do
182
- @map.clear
203
+ def clear
204
+ @mutex.synchronize do
205
+ @map.clear
206
+ end
183
207
  end
184
208
  end
185
209
  end
@@ -211,10 +235,10 @@ module ActiveRecord
211
235
 
212
236
  include MonitorMixin
213
237
  prepend QueryCache::ConnectionPoolConfiguration
214
- include ConnectionAdapters::AbstractPool
215
238
 
216
239
  attr_accessor :automatic_reconnect, :checkout_timeout
217
- attr_reader :db_config, :size, :reaper, :pool_config, :async_executor, :role, :shard
240
+ attr_reader :db_config, :max_connections, :min_connections, :max_age, :keepalive, :reaper, :pool_config, :async_executor, :role, :shard
241
+ alias :size :max_connections
218
242
 
219
243
  delegate :schema_reflection, :server_version, to: :pool_config
220
244
 
@@ -234,7 +258,10 @@ module ActiveRecord
234
258
 
235
259
  @checkout_timeout = db_config.checkout_timeout
236
260
  @idle_timeout = db_config.idle_timeout
237
- @size = db_config.pool
261
+ @max_connections = db_config.max_connections
262
+ @min_connections = db_config.min_connections
263
+ @max_age = db_config.max_age
264
+ @keepalive = db_config.keepalive
238
265
 
239
266
  # This variable tracks the cache of threads mapped to reserved connections, with the
240
267
  # sole purpose of speeding up the +connection+ method. It is not the authoritative
@@ -256,6 +283,12 @@ module ActiveRecord
256
283
  # currently in the process of independently establishing connections to the DB.
257
284
  @now_connecting = 0
258
285
 
286
+ # Sometimes otherwise-idle connections are temporarily held by the Reaper for
287
+ # maintenance. This variable tracks the number of connections currently in that
288
+ # state -- if a thread requests a connection and there are none available, it
289
+ # will await any in-maintenance connections in preference to creating a new one.
290
+ @maintaining = 0
291
+
259
292
  @threads_blocking_new_connections = 0
260
293
 
261
294
  @available = ConnectionLeasingQueue.new self
@@ -266,13 +299,17 @@ module ActiveRecord
266
299
 
267
300
  @schema_cache = nil
268
301
 
302
+ @activated = false
303
+ @original_context = ActiveSupport::IsolatedExecutionState.context
304
+
305
+ @reaper_lock = Monitor.new
269
306
  @reaper = Reaper.new(self, db_config.reaping_frequency)
270
307
  @reaper.run
271
308
  end
272
309
 
273
310
  def inspect # :nodoc:
274
- name_field = " name=#{db_config.name.inspect}" unless db_config.name == "primary"
275
- shard_field = " shard=#{@shard.inspect}" unless @shard == :default
311
+ name_field = " name=#{name_inspect}" if name_inspect
312
+ shard_field = " shard=#{shard_inspect}" if shard_inspect
276
313
 
277
314
  "#<#{self.class.name} env_name=#{db_config.env_name.inspect}#{name_field} role=#{role.inspect}#{shard_field}>"
278
315
  end
@@ -302,6 +339,14 @@ module ActiveRecord
302
339
  InternalMetadata.new(self)
303
340
  end
304
341
 
342
+ def activate
343
+ @activated = true
344
+ end
345
+
346
+ def activated?
347
+ @activated
348
+ end
349
+
305
350
  # Retrieve the connection associated with the current thread, or call
306
351
  # #checkout to obtain one if necessary.
307
352
  #
@@ -309,22 +354,15 @@ module ActiveRecord
309
354
  # held in a cache keyed by a thread.
310
355
  def lease_connection
311
356
  lease = connection_lease
312
- lease.sticky = true
313
357
  lease.connection ||= checkout
358
+ lease.sticky = true
359
+ lease.connection
314
360
  end
315
361
 
316
362
  def permanent_lease? # :nodoc:
317
363
  connection_lease.sticky.nil?
318
364
  end
319
365
 
320
- def connection
321
- ActiveRecord.deprecator.warn(<<~MSG)
322
- ActiveRecord::ConnectionAdapters::ConnectionPool#connection is deprecated
323
- and will be removed in Rails 8.0. Use #lease_connection instead.
324
- MSG
325
- lease_connection
326
- end
327
-
328
366
  def pin_connection!(lock_thread) # :nodoc:
329
367
  @pinned_connection ||= (connection_lease&.connection || checkout)
330
368
  @pinned_connections_depth += 1
@@ -336,6 +374,7 @@ module ActiveRecord
336
374
  end
337
375
 
338
376
  @pinned_connection.lock_thread = ActiveSupport::IsolatedExecutionState.context if lock_thread
377
+ @pinned_connection.pinned = true
339
378
  @pinned_connection.verify! # eagerly validate the connection
340
379
  @pinned_connection.begin_transaction joinable: false, _lazy: false
341
380
  end
@@ -358,6 +397,7 @@ module ActiveRecord
358
397
  end
359
398
 
360
399
  if @pinned_connection.nil?
400
+ connection.pinned = false
361
401
  connection.steal!
362
402
  connection.lock_thread = nil
363
403
  checkin(connection)
@@ -367,8 +407,8 @@ module ActiveRecord
367
407
  clean
368
408
  end
369
409
 
370
- def connection_class # :nodoc:
371
- pool_config.connection_class
410
+ def connection_descriptor # :nodoc:
411
+ pool_config.connection_descriptor
372
412
  end
373
413
 
374
414
  # Returns true if there is an open connection being used for the current thread.
@@ -389,6 +429,8 @@ module ActiveRecord
389
429
  # #lease_connection or #with_connection methods, connections obtained through
390
430
  # #checkout will not be automatically released.
391
431
  def release_connection(existing_lease = nil)
432
+ return if self.discarded?
433
+
392
434
  if conn = connection_lease.release
393
435
  checkin conn
394
436
  return true
@@ -426,6 +468,24 @@ module ActiveRecord
426
468
  end
427
469
  end
428
470
 
471
+ def with_pool_transaction_isolation_level(isolation_level, transaction_open, &block) # :nodoc:
472
+ if !ActiveRecord.default_transaction_isolation_level.nil?
473
+ begin
474
+ if transaction_open && self.pool_transaction_isolation_level != ActiveRecord.default_transaction_isolation_level
475
+ raise ActiveRecord::TransactionIsolationError, "cannot set default isolation level while transaction is open"
476
+ end
477
+
478
+ old_level = self.pool_transaction_isolation_level
479
+ self.pool_transaction_isolation_level = isolation_level
480
+ yield
481
+ ensure
482
+ self.pool_transaction_isolation_level = old_level
483
+ end
484
+ else
485
+ yield
486
+ end
487
+ end
488
+
429
489
  # Returns true if a connection has already been opened.
430
490
  def connected?
431
491
  synchronize { @connections.any?(&:connected?) }
@@ -453,18 +513,26 @@ module ActiveRecord
453
513
  # connections in the pool within a timeout interval (default duration is
454
514
  # <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
455
515
  def disconnect(raise_on_acquisition_timeout = true)
456
- with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
457
- synchronize do
458
- @connections.each do |conn|
459
- if conn.in_use?
460
- conn.steal!
461
- checkin conn
516
+ @reaper_lock.synchronize do
517
+ return if self.discarded?
518
+
519
+ with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
520
+ synchronize do
521
+ return if self.discarded?
522
+ @connections.each do |conn|
523
+ if conn.in_use?
524
+ conn.steal!
525
+ checkin conn
526
+ end
527
+ conn.disconnect!
462
528
  end
463
- conn.disconnect!
529
+ @connections = []
530
+ @leases.clear
531
+ @available.clear
532
+
533
+ # Stop maintaining the minimum size until reactivated
534
+ @activated = false
464
535
  end
465
- @connections = []
466
- @leases.clear
467
- @available.clear
468
536
  end
469
537
  end
470
538
  end
@@ -485,12 +553,14 @@ module ActiveRecord
485
553
  #
486
554
  # See AbstractAdapter#discard!
487
555
  def discard! # :nodoc:
488
- synchronize do
489
- return if self.discarded?
490
- @connections.each do |conn|
491
- conn.discard!
556
+ @reaper_lock.synchronize do
557
+ synchronize do
558
+ return if self.discarded?
559
+ @connections.each do |conn|
560
+ conn.discard!
561
+ end
562
+ @connections = @available = @leases = nil
492
563
  end
493
- @connections = @available = @leases = nil
494
564
  end
495
565
  end
496
566
 
@@ -498,7 +568,17 @@ module ActiveRecord
498
568
  @connections.nil?
499
569
  end
500
570
 
501
- # Clears the cache which maps classes and re-connects connections that
571
+ def maintainable? # :nodoc:
572
+ synchronize do
573
+ @connections&.size&.> 0 || (activated? && @min_connections > 0)
574
+ end
575
+ end
576
+
577
+ def reaper_lock(&block) # :nodoc:
578
+ @reaper_lock.synchronize(&block)
579
+ end
580
+
581
+ # Clears reloadable connections from the pool and re-connects connections that
502
582
  # require reloading.
503
583
  #
504
584
  # Raises:
@@ -521,7 +601,7 @@ module ActiveRecord
521
601
  end
522
602
  end
523
603
 
524
- # Clears the cache which maps classes and re-connects connections that
604
+ # Clears reloadable connections from the pool and re-connects connections that
525
605
  # require reloading.
526
606
  #
527
607
  # The pool first tries to gain ownership of all connections. If unable to
@@ -548,20 +628,25 @@ module ActiveRecord
548
628
  # Raises:
549
629
  # - ActiveRecord::ConnectionTimeoutError no connection can be obtained from the pool.
550
630
  def checkout(checkout_timeout = @checkout_timeout)
551
- if @pinned_connection
552
- @pinned_connection.lock.synchronize do
553
- synchronize do
631
+ return checkout_and_verify(acquire_connection(checkout_timeout)) unless @pinned_connection
632
+
633
+ @pinned_connection.lock.synchronize do
634
+ synchronize do
635
+ # The pinned connection may have been cleaned up before we synchronized, so check if it is still present
636
+ if @pinned_connection
554
637
  @pinned_connection.verify!
638
+
555
639
  # Any leased connection must be in @connections otherwise
556
640
  # some methods like #connected? won't behave correctly
557
641
  unless @connections.include?(@pinned_connection)
558
642
  @connections << @pinned_connection
559
643
  end
644
+
645
+ @pinned_connection
646
+ else
647
+ checkout_and_verify(acquire_connection(checkout_timeout))
560
648
  end
561
649
  end
562
- @pinned_connection
563
- else
564
- checkout_and_verify(acquire_connection(checkout_timeout))
565
650
  end
566
651
  end
567
652
 
@@ -576,11 +661,7 @@ module ActiveRecord
576
661
  conn.lock.synchronize do
577
662
  synchronize do
578
663
  connection_lease.clear(conn)
579
-
580
- conn._run_checkin_callbacks do
581
- conn.expire
582
- end
583
-
664
+ conn.expire
584
665
  @available.add conn
585
666
  end
586
667
  end
@@ -598,7 +679,7 @@ module ActiveRecord
598
679
  @available.delete conn
599
680
 
600
681
  # @available.any_waiting? => true means that prior to removing this
601
- # conn, the pool was at its max size (@connections.size == @size).
682
+ # conn, the pool was at its max size (@connections.size == @max_connections).
602
683
  # This would mean that any threads stuck waiting in the queue wouldn't
603
684
  # know they could checkout_new_connection, so let's do it for them.
604
685
  # Because condition-wait loop is encapsulated in the Queue class
@@ -606,14 +687,14 @@ module ActiveRecord
606
687
  # that are "stuck" there are helpless. They have no way of creating
607
688
  # new connections and are completely reliant on us feeding available
608
689
  # connections into the Queue.
609
- needs_new_connection = @available.any_waiting?
690
+ needs_new_connection = @available.num_waiting > @maintaining
610
691
  end
611
692
 
612
693
  # This is intentionally done outside of the synchronized section as we
613
694
  # would like not to hold the main mutex while checking out new connections.
614
695
  # Thus there is some chance that needs_new_connection information is now
615
696
  # stale, we can live with that (bulk_make_new_connections will make
616
- # sure not to exceed the pool's @size limit).
697
+ # sure not to exceed the pool's @max_connections limit).
617
698
  bulk_make_new_connections(1) if needs_new_connection
618
699
  end
619
700
 
@@ -646,11 +727,27 @@ module ActiveRecord
646
727
  def flush(minimum_idle = @idle_timeout)
647
728
  return if minimum_idle.nil?
648
729
 
649
- idle_connections = synchronize do
730
+ removed_connections = synchronize do
650
731
  return if self.discarded?
651
- @connections.select do |conn|
732
+
733
+ idle_connections = @connections.select do |conn|
652
734
  !conn.in_use? && conn.seconds_idle >= minimum_idle
653
- end.each do |conn|
735
+ end.sort_by { |conn| -conn.seconds_idle } # sort longest idle first
736
+
737
+ # Don't go below our configured pool minimum unless we're flushing
738
+ # everything
739
+ idles_to_retain =
740
+ if minimum_idle > 0
741
+ @min_connections - (@connections.size - idle_connections.size)
742
+ else
743
+ 0
744
+ end
745
+
746
+ if idles_to_retain > 0
747
+ idle_connections.pop idles_to_retain
748
+ end
749
+
750
+ idle_connections.each do |conn|
654
751
  conn.lease
655
752
 
656
753
  @available.delete conn
@@ -658,22 +755,109 @@ module ActiveRecord
658
755
  end
659
756
  end
660
757
 
661
- idle_connections.each do |conn|
758
+ removed_connections.each do |conn|
662
759
  conn.disconnect!
663
760
  end
664
761
  end
665
762
 
666
763
  # Disconnect all currently idle connections. Connections currently checked
667
- # out are unaffected.
764
+ # out are unaffected. The pool will stop maintaining its minimum size until
765
+ # it is reactivated (such as by a subsequent checkout).
668
766
  def flush!
669
767
  reap
670
768
  flush(-1)
769
+
770
+ # Stop maintaining the minimum size until reactivated
771
+ @activated = false
772
+ end
773
+
774
+ # Ensure that the pool contains at least the configured minimum number of
775
+ # connections.
776
+ def prepopulate
777
+ need_new_connections = nil
778
+
779
+ synchronize do
780
+ return if self.discarded?
781
+
782
+ # We don't want to start prepopulating until we know the pool is wanted,
783
+ # so we can avoid maintaining full pools in one-off scripts etc.
784
+ return unless @activated
785
+
786
+ need_new_connections = @connections.size < @min_connections
787
+ end
788
+
789
+ if need_new_connections
790
+ while new_conn = try_to_checkout_new_connection { @connections.size < @min_connections }
791
+ new_conn.allow_preconnect = true
792
+ checkin(new_conn)
793
+ end
794
+ end
795
+ end
796
+
797
+ def retire_old_connections(max_age = @max_age)
798
+ max_age ||= Float::INFINITY
799
+
800
+ sequential_maintenance -> c { c.connection_age&.>= c.pool_jitter(max_age) } do |conn|
801
+ # Disconnect, then return the adapter to the pool. Preconnect will
802
+ # handle the rest.
803
+ conn.disconnect!
804
+ end
805
+ end
806
+
807
+ # Preconnect all connections in the pool. This saves pool users from
808
+ # having to wait for a connection to be established when first using it
809
+ # after checkout.
810
+ def preconnect
811
+ sequential_maintenance -> c { (!c.connected? || !c.verified?) && c.allow_preconnect } do |conn|
812
+ conn.connect!
813
+ rescue
814
+ # Wholesale rescue: there's nothing we can do but move on. The
815
+ # connection will go back to the pool, and the next consumer will
816
+ # presumably try to connect again -- which will either work, or
817
+ # fail and they'll be able to report the exception.
818
+ end
819
+ end
820
+
821
+ # Prod any connections that have been idle for longer than the configured
822
+ # keepalive time. This will incidentally verify the connection is still
823
+ # alive, but the main purpose is to show the server (and any intermediate
824
+ # network hops) that we're still here and using the connection.
825
+ def keep_alive(threshold = @keepalive)
826
+ return if threshold.nil?
827
+
828
+ sequential_maintenance -> c { (c.seconds_since_last_activity || 0) > c.pool_jitter(threshold) } do |conn|
829
+ # conn.active? will cause some amount of network activity, which is all
830
+ # we need to provide a keepalive signal.
831
+ #
832
+ # If it returns false, the connection is already broken; disconnect,
833
+ # so it can be found and repaired.
834
+ conn.disconnect! unless conn.active?
835
+ end
836
+ end
837
+
838
+ # Immediately mark all current connections as due for replacement,
839
+ # equivalent to them having reached +max_age+ -- even if there is
840
+ # no +max_age+ configured.
841
+ def recycle!
842
+ synchronize do
843
+ return if self.discarded?
844
+
845
+ @connections.each do |conn|
846
+ conn.force_retirement
847
+ end
848
+ end
849
+
850
+ retire_old_connections
671
851
  end
672
852
 
673
853
  def num_waiting_in_queue # :nodoc:
674
854
  @available.num_waiting
675
855
  end
676
856
 
857
+ def num_available_in_queue # :nodoc:
858
+ @available.size
859
+ end
860
+
677
861
  # Returns the connection pool's usage statistic.
678
862
  #
679
863
  # ActiveRecord::Base.connection_pool.stat # => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }
@@ -696,6 +880,24 @@ module ActiveRecord
696
880
  Thread.pass
697
881
  end
698
882
 
883
+ def new_connection # :nodoc:
884
+ connection = db_config.new_connection
885
+ connection.pool = self
886
+ connection
887
+ rescue ConnectionNotEstablished => ex
888
+ raise ex.set_pool(self)
889
+ end
890
+
891
+ def pool_transaction_isolation_level
892
+ isolation_level_key = "activerecord_pool_transaction_isolation_level_#{db_config.name}"
893
+ ActiveSupport::IsolatedExecutionState[isolation_level_key]
894
+ end
895
+
896
+ def pool_transaction_isolation_level=(isolation_level)
897
+ isolation_level_key = "activerecord_pool_transaction_isolation_level_#{db_config.name}"
898
+ ActiveSupport::IsolatedExecutionState[isolation_level_key] = isolation_level
899
+ end
900
+
699
901
  private
700
902
  def connection_lease
701
903
  @leases[ActiveSupport::IsolatedExecutionState.context]
@@ -705,7 +907,9 @@ module ActiveRecord
705
907
  case ActiveRecord.async_query_executor
706
908
  when :multi_thread_pool
707
909
  if @db_config.max_threads > 0
910
+ name_with_shard = [name_inspect, shard_inspect].join("-").tr("_", "-")
708
911
  Concurrent::ThreadPoolExecutor.new(
912
+ name: "ActiveRecord-#{name_with_shard}-async-query-executor",
709
913
  min_threads: @db_config.min_threads,
710
914
  max_threads: @db_config.max_threads,
711
915
  max_queue: @db_config.max_queue,
@@ -717,11 +921,109 @@ module ActiveRecord
717
921
  end
718
922
  end
719
923
 
924
+ # Perform maintenance work on pool connections. This method will
925
+ # select a connection to work on by calling the +candidate_selector+
926
+ # proc while holding the pool lock. If a connection is selected, it
927
+ # will be checked out for maintenance and passed to the
928
+ # +maintenance_work+ proc. The connection will always be returned to
929
+ # the pool after the proc completes.
930
+ #
931
+ # If the pool has async threads, all work will be scheduled there.
932
+ # Otherwise, this method will block until all work is complete.
933
+ #
934
+ # Each connection will only be processed once per call to this method,
935
+ # but (particularly in the async case) there is no protection against
936
+ # a second call to this method starting to work through the list
937
+ # before the first call has completed. (Though regular pool behavior
938
+ # will prevent two instances from working on the same specific
939
+ # connection at the same time.)
940
+ def sequential_maintenance(candidate_selector, &maintenance_work)
941
+ # This hash doesn't need to be synchronized, because it's only
942
+ # used by one thread at a time: the +perform_work+ block gives
943
+ # up its right to +connections_visited+ when it schedules the
944
+ # next iteration.
945
+ connections_visited = Hash.new(false)
946
+ connections_visited.compare_by_identity
947
+
948
+ perform_work = lambda do
949
+ connection_to_maintain = nil
950
+
951
+ synchronize do
952
+ unless self.discarded?
953
+ if connection_to_maintain = @connections.select { |conn| !conn.in_use? }.select(&candidate_selector).sort_by(&:seconds_idle).find { |conn| !connections_visited[conn] }
954
+ checkout_for_maintenance connection_to_maintain
955
+ end
956
+ end
957
+ end
958
+
959
+ if connection_to_maintain
960
+ connections_visited[connection_to_maintain] = true
961
+
962
+ # If we're running async, we can schedule the next round of work
963
+ # as soon as we've grabbed a connection to work on.
964
+ @async_executor&.post(&perform_work)
965
+
966
+ begin
967
+ maintenance_work.call connection_to_maintain
968
+ ensure
969
+ return_from_maintenance connection_to_maintain
970
+ end
971
+
972
+ true
973
+ end
974
+ end
975
+
976
+ if @async_executor
977
+ @async_executor.post(&perform_work)
978
+ else
979
+ nil while perform_work.call
980
+ end
981
+ end
982
+
983
+ # Directly check a specific connection out of the pool. Skips callbacks.
984
+ #
985
+ # The connection must later either #return_from_maintenance or
986
+ # #remove_from_maintenance, or the pool will hang.
987
+ def checkout_for_maintenance(conn)
988
+ synchronize do
989
+ @maintaining += 1
990
+ @available.delete(conn)
991
+ conn.lease
992
+ conn
993
+ end
994
+ end
995
+
996
+ # Return a connection to the pool after it has been checked out for
997
+ # maintenance. Does not update the connection's idle time, and skips
998
+ # callbacks.
999
+ #--
1000
+ # We assume that a connection that has required maintenance is less
1001
+ # desirable (either it's been idle for a long time, or it was just
1002
+ # created and hasn't been used yet). We'll put it at the back of the
1003
+ # queue.
1004
+ def return_from_maintenance(conn)
1005
+ synchronize do
1006
+ conn.expire(false)
1007
+ @available.add_back(conn)
1008
+ @maintaining -= 1
1009
+ end
1010
+ end
1011
+
1012
+ # Remove a connection from the pool after it has been checked out for
1013
+ # maintenance. It will be automatically replaced with a new connection if
1014
+ # necessary.
1015
+ def remove_from_maintenance(conn)
1016
+ synchronize do
1017
+ @maintaining -= 1
1018
+ remove conn
1019
+ end
1020
+ end
1021
+
720
1022
  #--
721
1023
  # this is unfortunately not concurrent
722
1024
  def bulk_make_new_connections(num_new_conns_needed)
723
1025
  num_new_conns_needed.times do
724
- # try_to_checkout_new_connection will not exceed pool's @size limit
1026
+ # try_to_checkout_new_connection will not exceed pool's @max_connections limit
725
1027
  if new_conn = try_to_checkout_new_connection
726
1028
  # make the new_conn available to the starving threads stuck @available Queue
727
1029
  checkin(new_conn)
@@ -734,9 +1036,11 @@ module ActiveRecord
734
1036
  # wrap it in +synchronize+ because some pool's actions are allowed
735
1037
  # to be performed outside of the main +synchronize+ block.
736
1038
  def with_exclusively_acquired_all_connections(raise_on_acquisition_timeout = true)
737
- with_new_connections_blocked do
738
- attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout)
739
- yield
1039
+ @reaper_lock.synchronize do
1040
+ with_new_connections_blocked do
1041
+ attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout)
1042
+ yield
1043
+ end
740
1044
  end
741
1045
  end
742
1046
 
@@ -856,13 +1160,13 @@ module ActiveRecord
856
1160
  # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to <tt>@available.poll</tt>
857
1161
  # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
858
1162
  # of the said methods and avoid an additional +synchronize+ overhead.
859
- if conn = @available.poll || try_to_checkout_new_connection
1163
+ if conn = @available.poll || try_to_queue_for_background_connection(checkout_timeout) || try_to_checkout_new_connection
860
1164
  conn
861
1165
  else
862
1166
  reap
863
1167
  # Retry after reaping, which may return an available connection,
864
1168
  # remove an inactive connection, or both
865
- if conn = @available.poll || try_to_checkout_new_connection
1169
+ if conn = @available.poll || try_to_queue_for_background_connection(checkout_timeout) || try_to_checkout_new_connection
866
1170
  conn
867
1171
  else
868
1172
  @available.poll(checkout_timeout)
@@ -872,32 +1176,60 @@ module ActiveRecord
872
1176
  raise ex.set_pool(self)
873
1177
  end
874
1178
 
1179
+ #--
1180
+ # If new connections are already being established in the background,
1181
+ # and there are fewer threads already waiting than the number of
1182
+ # upcoming connections, we can just get in queue and wait to be handed a
1183
+ # connection. This avoids us overshooting the required connection count
1184
+ # by starting a new connection ourselves, and is likely to be faster
1185
+ # too (because at least some of the time it takes to establish a new
1186
+ # connection must have already passed).
1187
+ #
1188
+ # If background connections are available, this method will block and
1189
+ # return a connection. If no background connections are available, it
1190
+ # will immediately return +nil+.
1191
+ def try_to_queue_for_background_connection(checkout_timeout)
1192
+ return unless @maintaining > 0
1193
+
1194
+ synchronize do
1195
+ return unless @maintaining > @available.num_waiting
1196
+
1197
+ # We are guaranteed the "maintaining" thread will return its promised
1198
+ # connection within one maintenance-unit of time. Thus we can safely
1199
+ # do a blocking wait with (functionally) no timeout.
1200
+ @available.poll(100)
1201
+ end
1202
+ end
1203
+
875
1204
  #--
876
1205
  # if owner_thread param is omitted, this must be called in synchronize block
877
1206
  def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
878
- @leases[owner_thread].clear(conn)
1207
+ if owner_thread
1208
+ @leases[owner_thread].clear(conn)
1209
+ end
879
1210
  end
880
1211
  alias_method :release, :remove_connection_from_thread_cache
881
1212
 
882
- def new_connection
883
- connection = db_config.new_connection
884
- connection.pool = self
885
- connection
886
- rescue ConnectionNotEstablished => ex
887
- raise ex.set_pool(self)
888
- end
889
-
890
- # If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
1213
+ # If the pool is not at a <tt>@max_connections</tt> limit, establish new connection. Connecting
891
1214
  # to the DB is done outside main synchronized section.
1215
+ #
1216
+ # If a block is supplied, it is an additional constraint (checked while holding the
1217
+ # pool lock) on whether a new connection should be established.
892
1218
  #--
893
1219
  # Implementation constraint: a newly established connection returned by this
894
1220
  # method must be in the +.leased+ state.
895
1221
  def try_to_checkout_new_connection
896
1222
  # first in synchronized section check if establishing new conns is allowed
897
- # and increment @now_connecting, to prevent overstepping this pool's @size
1223
+ # and increment @now_connecting, to prevent overstepping this pool's @max_connections
898
1224
  # constraint
899
1225
  do_checkout = synchronize do
900
- if @threads_blocking_new_connections.zero? && (@connections.size + @now_connecting) < @size
1226
+ return if self.discarded?
1227
+
1228
+ if @threads_blocking_new_connections.zero? && (@max_connections.nil? || (@connections.size + @now_connecting) < @max_connections) && (!block_given? || yield)
1229
+ if @connections.size > 0 || @original_context != ActiveSupport::IsolatedExecutionState.context
1230
+ @activated = true
1231
+ end
1232
+
901
1233
  @now_connecting += 1
902
1234
  end
903
1235
  end
@@ -908,12 +1240,16 @@ module ActiveRecord
908
1240
  conn = checkout_new_connection
909
1241
  ensure
910
1242
  synchronize do
1243
+ @now_connecting -= 1
911
1244
  if conn
912
- adopt_connection(conn)
913
- # returned conn needs to be already leased
914
- conn.lease
1245
+ if self.discarded?
1246
+ conn.discard!
1247
+ else
1248
+ adopt_connection(conn)
1249
+ # returned conn needs to be already leased
1250
+ conn.lease
1251
+ end
915
1252
  end
916
- @now_connecting -= 1
917
1253
  end
918
1254
  end
919
1255
  end
@@ -936,15 +1272,20 @@ module ActiveRecord
936
1272
  end
937
1273
 
938
1274
  def checkout_and_verify(c)
939
- c._run_checkout_callbacks do
940
- c.clean!
941
- end
942
- c
1275
+ c.clean!
943
1276
  rescue Exception
944
1277
  remove c
945
1278
  c.disconnect!
946
1279
  raise
947
1280
  end
1281
+
1282
+ def name_inspect
1283
+ db_config.name.inspect unless db_config.name == "primary"
1284
+ end
1285
+
1286
+ def shard_inspect
1287
+ shard.inspect unless shard == :default
1288
+ end
948
1289
  end
949
1290
  end
950
1291
  end