activerecord 6.0.6 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -6,37 +6,26 @@ require "monitor"
|
|
6
6
|
require "weakref"
|
7
7
|
|
8
8
|
module ActiveRecord
|
9
|
-
# Raised when a connection could not be obtained within the connection
|
10
|
-
# acquisition timeout period: because max connections in pool
|
11
|
-
# are in use.
|
12
|
-
class ConnectionTimeoutError < ConnectionNotEstablished
|
13
|
-
end
|
14
|
-
|
15
|
-
# Raised when a pool was unable to get ahold of all its connections
|
16
|
-
# to perform a "group" action such as
|
17
|
-
# {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
|
18
|
-
# or {ActiveRecord::Base.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
|
19
|
-
class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
|
20
|
-
end
|
21
|
-
|
22
9
|
module ConnectionAdapters
|
23
10
|
module AbstractPool # :nodoc:
|
24
11
|
def get_schema_cache(connection)
|
25
|
-
|
26
|
-
|
27
|
-
|
12
|
+
self.schema_cache ||= SchemaCache.new(connection)
|
13
|
+
schema_cache.connection = connection
|
14
|
+
schema_cache
|
28
15
|
end
|
29
16
|
|
30
17
|
def set_schema_cache(cache)
|
31
|
-
|
18
|
+
self.schema_cache = cache
|
32
19
|
end
|
33
20
|
end
|
34
21
|
|
35
22
|
class NullPool # :nodoc:
|
36
23
|
include ConnectionAdapters::AbstractPool
|
37
24
|
|
38
|
-
|
39
|
-
|
25
|
+
attr_accessor :schema_cache
|
26
|
+
|
27
|
+
def owner_name
|
28
|
+
nil
|
40
29
|
end
|
41
30
|
end
|
42
31
|
|
@@ -150,7 +139,7 @@ module ActiveRecord
|
|
150
139
|
|
151
140
|
# Remove the head of the queue.
|
152
141
|
#
|
153
|
-
# If +timeout+ is not given, remove and return the head the
|
142
|
+
# If +timeout+ is not given, remove and return the head of the
|
154
143
|
# queue if the number of available elements is strictly
|
155
144
|
# greater than the number of threads currently waiting (that
|
156
145
|
# is, don't jump ahead in line). Otherwise, return +nil+.
|
@@ -193,7 +182,7 @@ module ActiveRecord
|
|
193
182
|
@queue.pop
|
194
183
|
end
|
195
184
|
|
196
|
-
# Remove and return the head the queue if the number of
|
185
|
+
# Remove and return the head of the queue if the number of
|
197
186
|
# available elements is strictly greater than the number of
|
198
187
|
# threads currently waiting. Otherwise, return +nil+.
|
199
188
|
def no_wait_poll
|
@@ -332,11 +321,17 @@ module ActiveRecord
|
|
332
321
|
private
|
333
322
|
def spawn_thread(frequency)
|
334
323
|
Thread.new(frequency) do |t|
|
324
|
+
# Advise multi-threaded app servers to ignore this thread for
|
325
|
+
# the purposes of fork safety warnings
|
326
|
+
Thread.current.thread_variable_set(:fork_safe, true)
|
335
327
|
running = true
|
336
328
|
while running
|
337
329
|
sleep t
|
338
330
|
@mutex.synchronize do
|
339
|
-
@pools[frequency].select!
|
331
|
+
@pools[frequency].select! do |pool|
|
332
|
+
pool.weakref_alive? && !pool.discarded?
|
333
|
+
end
|
334
|
+
|
340
335
|
@pools[frequency].each do |p|
|
341
336
|
p.reap
|
342
337
|
p.flush
|
@@ -364,35 +359,34 @@ module ActiveRecord
|
|
364
359
|
include QueryCache::ConnectionPoolConfiguration
|
365
360
|
include ConnectionAdapters::AbstractPool
|
366
361
|
|
367
|
-
attr_accessor :automatic_reconnect, :checkout_timeout
|
368
|
-
attr_reader :
|
362
|
+
attr_accessor :automatic_reconnect, :checkout_timeout
|
363
|
+
attr_reader :db_config, :size, :reaper, :pool_config, :owner_name
|
369
364
|
|
370
|
-
|
365
|
+
delegate :schema_cache, :schema_cache=, to: :pool_config
|
366
|
+
|
367
|
+
# Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
|
371
368
|
# object which describes database connection information (e.g. adapter,
|
372
369
|
# host name, username, password, etc), as well as the maximum size for
|
373
370
|
# this ConnectionPool.
|
374
371
|
#
|
375
372
|
# The default ConnectionPool maximum size is 5.
|
376
|
-
def initialize(
|
373
|
+
def initialize(pool_config)
|
377
374
|
super()
|
378
375
|
|
379
|
-
@
|
380
|
-
|
381
|
-
@
|
382
|
-
if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
|
383
|
-
@idle_timeout = @idle_timeout.to_f
|
384
|
-
@idle_timeout = nil if @idle_timeout <= 0
|
385
|
-
end
|
376
|
+
@pool_config = pool_config
|
377
|
+
@db_config = pool_config.db_config
|
378
|
+
@owner_name = pool_config.connection_specification_name
|
386
379
|
|
387
|
-
|
388
|
-
@
|
380
|
+
@checkout_timeout = db_config.checkout_timeout
|
381
|
+
@idle_timeout = db_config.idle_timeout
|
382
|
+
@size = db_config.pool
|
389
383
|
|
390
384
|
# This variable tracks the cache of threads mapped to reserved connections, with the
|
391
385
|
# sole purpose of speeding up the +connection+ method. It is not the authoritative
|
392
386
|
# registry of which thread owns which connection. Connection ownership is tracked by
|
393
387
|
# the +connection.owner+ attr on each +connection+ instance.
|
394
388
|
# The invariant works like this: if there is mapping of <tt>thread => conn</tt>,
|
395
|
-
# then that +thread+ does indeed own that +conn+. However, an absence of
|
389
|
+
# then that +thread+ does indeed own that +conn+. However, an absence of such
|
396
390
|
# mapping does not mean that the +thread+ doesn't own the said connection. In
|
397
391
|
# that case +conn.owner+ attr should be consulted.
|
398
392
|
# Access and modification of <tt>@thread_cached_conns</tt> does not require
|
@@ -413,10 +407,7 @@ module ActiveRecord
|
|
413
407
|
|
414
408
|
@lock_thread = false
|
415
409
|
|
416
|
-
|
417
|
-
# also be useful if someone wants a very low +idle_timeout+.
|
418
|
-
reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
|
419
|
-
@reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
|
410
|
+
@reaper = Reaper.new(self, db_config.reaping_frequency)
|
420
411
|
@reaper.run
|
421
412
|
end
|
422
413
|
|
@@ -498,7 +489,7 @@ module ActiveRecord
|
|
498
489
|
# Raises:
|
499
490
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
500
491
|
# connections in the pool within a timeout interval (default duration is
|
501
|
-
# <tt>spec.
|
492
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
502
493
|
def disconnect(raise_on_acquisition_timeout = true)
|
503
494
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
504
495
|
synchronize do
|
@@ -519,7 +510,7 @@ module ActiveRecord
|
|
519
510
|
#
|
520
511
|
# The pool first tries to gain ownership of all connections. If unable to
|
521
512
|
# do so within a timeout interval (default duration is
|
522
|
-
# <tt>spec.
|
513
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
|
523
514
|
# disconnected without any regard for other connection owning threads.
|
524
515
|
def disconnect!
|
525
516
|
disconnect(false)
|
@@ -532,7 +523,7 @@ module ActiveRecord
|
|
532
523
|
# See AbstractAdapter#discard!
|
533
524
|
def discard! # :nodoc:
|
534
525
|
synchronize do
|
535
|
-
return if
|
526
|
+
return if self.discarded?
|
536
527
|
@connections.each do |conn|
|
537
528
|
conn.discard!
|
538
529
|
end
|
@@ -540,13 +531,17 @@ module ActiveRecord
|
|
540
531
|
end
|
541
532
|
end
|
542
533
|
|
534
|
+
def discarded? # :nodoc:
|
535
|
+
@connections.nil?
|
536
|
+
end
|
537
|
+
|
543
538
|
# Clears the cache which maps classes and re-connects connections that
|
544
539
|
# require reloading.
|
545
540
|
#
|
546
541
|
# Raises:
|
547
542
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
548
543
|
# connections in the pool within a timeout interval (default duration is
|
549
|
-
# <tt>spec.
|
544
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
550
545
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
551
546
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
552
547
|
synchronize do
|
@@ -568,7 +563,7 @@ module ActiveRecord
|
|
568
563
|
#
|
569
564
|
# The pool first tries to gain ownership of all connections. If unable to
|
570
565
|
# do so within a timeout interval (default duration is
|
571
|
-
# <tt>spec.
|
566
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
|
572
567
|
# clears the cache and reloads connections without any regard for other
|
573
568
|
# connection owning threads.
|
574
569
|
def clear_reloadable_connections!
|
@@ -648,7 +643,7 @@ module ActiveRecord
|
|
648
643
|
# or a thread dies unexpectedly.
|
649
644
|
def reap
|
650
645
|
stale_connections = synchronize do
|
651
|
-
return
|
646
|
+
return if self.discarded?
|
652
647
|
@connections.select do |conn|
|
653
648
|
conn.in_use? && !conn.owner.alive?
|
654
649
|
end.each do |conn|
|
@@ -673,7 +668,7 @@ module ActiveRecord
|
|
673
668
|
return if minimum_idle.nil?
|
674
669
|
|
675
670
|
idle_connections = synchronize do
|
676
|
-
return
|
671
|
+
return if self.discarded?
|
677
672
|
@connections.select do |conn|
|
678
673
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
679
674
|
end.each do |conn|
|
@@ -884,7 +879,7 @@ module ActiveRecord
|
|
884
879
|
alias_method :release, :remove_connection_from_thread_cache
|
885
880
|
|
886
881
|
def new_connection
|
887
|
-
Base.
|
882
|
+
Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
|
888
883
|
conn.check_version
|
889
884
|
end
|
890
885
|
end
|
@@ -988,38 +983,18 @@ module ActiveRecord
|
|
988
983
|
# should use.
|
989
984
|
#
|
990
985
|
# The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
|
991
|
-
# about the model. The model needs to pass a specification name to the handler,
|
986
|
+
# about the model. The model needs to pass a connection specification name to the handler,
|
992
987
|
# in order to look up the correct connection pool.
|
993
988
|
class ConnectionHandler
|
994
|
-
|
995
|
-
|
996
|
-
# Discard the parent's connection pools immediately; we have no need
|
997
|
-
# of them
|
998
|
-
discard_unowned_pools(h)
|
999
|
-
|
1000
|
-
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
1001
|
-
end
|
1002
|
-
end
|
1003
|
-
|
1004
|
-
def self.unowned_pool_finalizer(pid_map) # :nodoc:
|
1005
|
-
lambda do |_|
|
1006
|
-
discard_unowned_pools(pid_map)
|
1007
|
-
end
|
1008
|
-
end
|
1009
|
-
|
1010
|
-
def self.discard_unowned_pools(pid_map) # :nodoc:
|
1011
|
-
pid_map.each do |pid, pools|
|
1012
|
-
pools.values.compact.each(&:discard!) unless pid == Process.pid
|
1013
|
-
end
|
1014
|
-
end
|
989
|
+
FINALIZER = lambda { |_| ActiveSupport::ForkTracker.check! }
|
990
|
+
private_constant :FINALIZER
|
1015
991
|
|
1016
992
|
def initialize
|
1017
|
-
# These caches are keyed by
|
1018
|
-
@
|
993
|
+
# These caches are keyed by pool_config.connection_specification_name (PoolConfig#connection_specification_name).
|
994
|
+
@owner_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
|
1019
995
|
|
1020
|
-
# Backup finalizer: if the forked child
|
1021
|
-
|
1022
|
-
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
996
|
+
# Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
|
997
|
+
ObjectSpace.define_finalizer self, FINALIZER
|
1023
998
|
end
|
1024
999
|
|
1025
1000
|
def prevent_writes # :nodoc:
|
@@ -1042,84 +1017,112 @@ module ActiveRecord
|
|
1042
1017
|
# See `READ_QUERY` for the queries that are blocked by this
|
1043
1018
|
# method.
|
1044
1019
|
def while_preventing_writes(enabled = true)
|
1020
|
+
unless ActiveRecord::Base.legacy_connection_handling
|
1021
|
+
raise NotImplementedError, "`while_preventing_writes` is only available on the connection_handler with legacy_connection_handling"
|
1022
|
+
end
|
1023
|
+
|
1045
1024
|
original, self.prevent_writes = self.prevent_writes, enabled
|
1046
1025
|
yield
|
1047
1026
|
ensure
|
1048
1027
|
self.prevent_writes = original
|
1049
1028
|
end
|
1050
1029
|
|
1051
|
-
def
|
1052
|
-
|
1030
|
+
def connection_pool_names # :nodoc:
|
1031
|
+
owner_to_pool_manager.keys
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def all_connection_pools
|
1035
|
+
owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def connection_pool_list(role = ActiveRecord::Base.current_role)
|
1039
|
+
owner_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
|
1053
1040
|
end
|
1054
1041
|
alias :connection_pools :connection_pool_list
|
1055
1042
|
|
1056
|
-
def establish_connection(config)
|
1057
|
-
|
1058
|
-
spec = resolver.spec(config)
|
1043
|
+
def establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
|
1044
|
+
owner_name = config.to_s if config.is_a?(Symbol)
|
1059
1045
|
|
1060
|
-
|
1046
|
+
pool_config = resolve_pool_config(config, owner_name)
|
1047
|
+
db_config = pool_config.db_config
|
1048
|
+
|
1049
|
+
# Protects the connection named `ActiveRecord::Base` from being removed
|
1050
|
+
# if the user calls `establish_connection :primary`.
|
1051
|
+
if owner_to_pool_manager.key?(pool_config.connection_specification_name)
|
1052
|
+
remove_connection_pool(pool_config.connection_specification_name, role: role, shard: shard)
|
1053
|
+
end
|
1061
1054
|
|
1062
1055
|
message_bus = ActiveSupport::Notifications.instrumenter
|
1063
|
-
payload = {
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
payload[:
|
1068
|
-
payload[:config] = spec.config
|
1056
|
+
payload = {}
|
1057
|
+
if pool_config
|
1058
|
+
payload[:spec_name] = pool_config.connection_specification_name
|
1059
|
+
payload[:shard] = shard
|
1060
|
+
payload[:config] = db_config.configuration_hash
|
1069
1061
|
end
|
1070
1062
|
|
1071
|
-
|
1072
|
-
|
1063
|
+
if ActiveRecord::Base.legacy_connection_handling
|
1064
|
+
owner_to_pool_manager[pool_config.connection_specification_name] ||= LegacyPoolManager.new
|
1065
|
+
else
|
1066
|
+
owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
|
1073
1067
|
end
|
1068
|
+
pool_manager = get_pool_manager(pool_config.connection_specification_name)
|
1069
|
+
pool_manager.set_pool_config(role, shard, pool_config)
|
1074
1070
|
|
1075
|
-
|
1071
|
+
message_bus.instrument("!connection.active_record", payload) do
|
1072
|
+
pool_config.pool
|
1073
|
+
end
|
1076
1074
|
end
|
1077
1075
|
|
1078
1076
|
# Returns true if there are any active connections among the connection
|
1079
1077
|
# pools that the ConnectionHandler is managing.
|
1080
|
-
def active_connections?
|
1081
|
-
connection_pool_list.any?(&:active_connection?)
|
1078
|
+
def active_connections?(role = ActiveRecord::Base.current_role)
|
1079
|
+
connection_pool_list(role).any?(&:active_connection?)
|
1082
1080
|
end
|
1083
1081
|
|
1084
1082
|
# Returns any connections in use by the current thread back to the pool,
|
1085
1083
|
# and also returns connections to the pool cached by threads that are no
|
1086
1084
|
# longer alive.
|
1087
|
-
def clear_active_connections!
|
1088
|
-
connection_pool_list.each(&:release_connection)
|
1085
|
+
def clear_active_connections!(role = ActiveRecord::Base.current_role)
|
1086
|
+
connection_pool_list(role).each(&:release_connection)
|
1089
1087
|
end
|
1090
1088
|
|
1091
1089
|
# Clears the cache which maps classes.
|
1092
1090
|
#
|
1093
1091
|
# See ConnectionPool#clear_reloadable_connections! for details.
|
1094
|
-
def clear_reloadable_connections!
|
1095
|
-
connection_pool_list.each(&:clear_reloadable_connections!)
|
1092
|
+
def clear_reloadable_connections!(role = ActiveRecord::Base.current_role)
|
1093
|
+
connection_pool_list(role).each(&:clear_reloadable_connections!)
|
1096
1094
|
end
|
1097
1095
|
|
1098
|
-
def clear_all_connections!
|
1099
|
-
connection_pool_list.each(&:disconnect!)
|
1096
|
+
def clear_all_connections!(role = ActiveRecord::Base.current_role)
|
1097
|
+
connection_pool_list(role).each(&:disconnect!)
|
1100
1098
|
end
|
1101
1099
|
|
1102
1100
|
# Disconnects all currently idle connections.
|
1103
1101
|
#
|
1104
1102
|
# See ConnectionPool#flush! for details.
|
1105
|
-
def flush_idle_connections!
|
1106
|
-
connection_pool_list.each(&:flush!)
|
1103
|
+
def flush_idle_connections!(role = ActiveRecord::Base.current_role)
|
1104
|
+
connection_pool_list(role).each(&:flush!)
|
1107
1105
|
end
|
1108
1106
|
|
1109
1107
|
# Locate the connection of the nearest super class. This can be an
|
1110
1108
|
# active or defined connection: if it is the latter, it will be
|
1111
1109
|
# opened and set as the active connection for the class it was defined
|
1112
1110
|
# for (not necessarily the current class).
|
1113
|
-
def retrieve_connection(spec_name)
|
1114
|
-
pool = retrieve_connection_pool(spec_name)
|
1111
|
+
def retrieve_connection(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
|
1112
|
+
pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
|
1115
1113
|
|
1116
1114
|
unless pool
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1115
|
+
if shard != ActiveRecord::Base.default_shard
|
1116
|
+
message = "No connection pool for '#{spec_name}' found for the '#{shard}' shard."
|
1117
|
+
elsif ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
|
1118
|
+
message = "No connection pool for '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
|
1119
|
+
elsif role != ActiveRecord::Base.default_role
|
1120
|
+
message = "No connection pool for '#{spec_name}' found for the '#{role}' role."
|
1120
1121
|
else
|
1121
|
-
|
1122
|
+
message = "No connection pool for '#{spec_name}' found."
|
1122
1123
|
end
|
1124
|
+
|
1125
|
+
raise ConnectionNotEstablished, message
|
1123
1126
|
end
|
1124
1127
|
|
1125
1128
|
pool.connection
|
@@ -1127,8 +1130,8 @@ module ActiveRecord
|
|
1127
1130
|
|
1128
1131
|
# Returns true if a connection that's accessible to this class has
|
1129
1132
|
# already been opened.
|
1130
|
-
def connected?(spec_name)
|
1131
|
-
pool = retrieve_connection_pool(spec_name)
|
1133
|
+
def connected?(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1134
|
+
pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
|
1132
1135
|
pool && pool.connected?
|
1133
1136
|
end
|
1134
1137
|
|
@@ -1136,42 +1139,90 @@ module ActiveRecord
|
|
1136
1139
|
# connection and the defined connection (if they exist). The result
|
1137
1140
|
# can be used as an argument for #establish_connection, for easily
|
1138
1141
|
# re-establishing the connection.
|
1139
|
-
def remove_connection(
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1142
|
+
def remove_connection(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1143
|
+
remove_connection_pool(owner, role: role, shard: shard)&.configuration_hash
|
1144
|
+
end
|
1145
|
+
deprecate remove_connection: "Use #remove_connection_pool, which now returns a DatabaseConfig object instead of a Hash"
|
1146
|
+
|
1147
|
+
def remove_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1148
|
+
if pool_manager = get_pool_manager(owner)
|
1149
|
+
pool_config = pool_manager.remove_pool_config(role, shard)
|
1150
|
+
|
1151
|
+
if pool_config
|
1152
|
+
pool_config.disconnect!
|
1153
|
+
pool_config.db_config
|
1154
|
+
end
|
1144
1155
|
end
|
1145
1156
|
end
|
1146
1157
|
|
1147
|
-
# Retrieving the connection pool happens a lot, so we cache it in @
|
1158
|
+
# Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool_manager.
|
1148
1159
|
# This makes retrieving the connection pool O(1) once the process is warm.
|
1149
1160
|
# When a connection is established or removed, we invalidate the cache.
|
1150
|
-
def retrieve_connection_pool(
|
1151
|
-
|
1152
|
-
|
1153
|
-
# which may have been forked.
|
1154
|
-
if ancestor_pool = pool_from_any_process_for(spec_name)
|
1155
|
-
# A connection was established in an ancestor process that must have
|
1156
|
-
# subsequently forked. We can't reuse the connection, but we can copy
|
1157
|
-
# the specification and establish a new connection with it.
|
1158
|
-
establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
|
1159
|
-
pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
|
1160
|
-
end
|
1161
|
-
else
|
1162
|
-
owner_to_pool[spec_name] = nil
|
1163
|
-
end
|
1164
|
-
end
|
1161
|
+
def retrieve_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1162
|
+
pool_config = get_pool_manager(owner)&.get_pool_config(role, shard)
|
1163
|
+
pool_config&.pool
|
1165
1164
|
end
|
1166
1165
|
|
1167
1166
|
private
|
1168
|
-
|
1169
|
-
|
1167
|
+
attr_reader :owner_to_pool_manager
|
1168
|
+
|
1169
|
+
# Returns the pool manager for an owner.
|
1170
|
+
#
|
1171
|
+
# Using `"primary"` to look up the pool manager for `ActiveRecord::Base` is
|
1172
|
+
# deprecated in favor of looking it up by `"ActiveRecord::Base"`.
|
1173
|
+
#
|
1174
|
+
# During the deprecation period, if `"primary"` is passed, the pool manager
|
1175
|
+
# for `ActiveRecord::Base` will still be returned.
|
1176
|
+
def get_pool_manager(owner)
|
1177
|
+
return owner_to_pool_manager[owner] if owner_to_pool_manager.key?(owner)
|
1178
|
+
|
1179
|
+
if owner == "primary"
|
1180
|
+
ActiveSupport::Deprecation.warn("Using `\"primary\"` as a `connection_specification_name` is deprecated and will be removed in Rails 6.2.0. Please use `ActiveRecord::Base`.")
|
1181
|
+
owner_to_pool_manager[Base.name]
|
1182
|
+
end
|
1170
1183
|
end
|
1171
1184
|
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1185
|
+
# Returns an instance of PoolConfig for a given adapter.
|
1186
|
+
# Accepts a hash one layer deep that contains all connection information.
|
1187
|
+
#
|
1188
|
+
# == Example
|
1189
|
+
#
|
1190
|
+
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
1191
|
+
# pool_config = Base.configurations.resolve_pool_config(:production)
|
1192
|
+
# pool_config.db_config.configuration_hash
|
1193
|
+
# # => { host: "localhost", database: "foo", adapter: "sqlite3" }
|
1194
|
+
#
|
1195
|
+
def resolve_pool_config(config, owner_name)
|
1196
|
+
db_config = Base.configurations.resolve(config)
|
1197
|
+
|
1198
|
+
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
|
1199
|
+
|
1200
|
+
# Require the adapter itself and give useful feedback about
|
1201
|
+
# 1. Missing adapter gems and
|
1202
|
+
# 2. Adapter gems' missing dependencies.
|
1203
|
+
path_to_adapter = "active_record/connection_adapters/#{db_config.adapter}_adapter"
|
1204
|
+
begin
|
1205
|
+
require path_to_adapter
|
1206
|
+
rescue LoadError => e
|
1207
|
+
# We couldn't require the adapter itself. Raise an exception that
|
1208
|
+
# points out config typos and missing gems.
|
1209
|
+
if e.path == path_to_adapter
|
1210
|
+
# We can assume that a non-builtin adapter was specified, so it's
|
1211
|
+
# either misspelled or missing from Gemfile.
|
1212
|
+
raise LoadError, "Could not load the '#{db_config.adapter}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
|
1213
|
+
|
1214
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
1215
|
+
# with some guidance about how to address it and reraise.
|
1216
|
+
else
|
1217
|
+
raise LoadError, "Error loading the '#{db_config.adapter}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
1218
|
+
end
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
|
1222
|
+
raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
ConnectionAdapters::PoolConfig.new(owner_name, db_config)
|
1175
1226
|
end
|
1176
1227
|
end
|
1177
1228
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/deprecation"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module ConnectionAdapters # :nodoc:
|
7
5
|
module DatabaseLimits
|
@@ -14,18 +12,6 @@ module ActiveRecord
|
|
14
12
|
max_identifier_length
|
15
13
|
end
|
16
14
|
|
17
|
-
# Returns the maximum length of a column name.
|
18
|
-
def column_name_length
|
19
|
-
max_identifier_length
|
20
|
-
end
|
21
|
-
deprecate :column_name_length
|
22
|
-
|
23
|
-
# Returns the maximum length of a table name.
|
24
|
-
def table_name_length
|
25
|
-
max_identifier_length
|
26
|
-
end
|
27
|
-
deprecate :table_name_length
|
28
|
-
|
29
15
|
# Returns the maximum allowed length for an index name. This
|
30
16
|
# limit is enforced by \Rails and is less than or equal to
|
31
17
|
# #index_name_length. The gap between
|
@@ -34,47 +20,19 @@ module ActiveRecord
|
|
34
20
|
def allowed_index_name_length
|
35
21
|
index_name_length
|
36
22
|
end
|
23
|
+
deprecate :allowed_index_name_length
|
37
24
|
|
38
25
|
# Returns the maximum length of an index name.
|
39
26
|
def index_name_length
|
40
27
|
max_identifier_length
|
41
28
|
end
|
42
29
|
|
43
|
-
# Returns the maximum number of columns per table.
|
44
|
-
def columns_per_table
|
45
|
-
1024
|
46
|
-
end
|
47
|
-
deprecate :columns_per_table
|
48
|
-
|
49
|
-
# Returns the maximum number of indexes per table.
|
50
|
-
def indexes_per_table
|
51
|
-
16
|
52
|
-
end
|
53
|
-
deprecate :indexes_per_table
|
54
|
-
|
55
|
-
# Returns the maximum number of columns in a multicolumn index.
|
56
|
-
def columns_per_multicolumn_index
|
57
|
-
16
|
58
|
-
end
|
59
|
-
deprecate :columns_per_multicolumn_index
|
60
|
-
|
61
30
|
# Returns the maximum number of elements in an IN (x,y,z) clause.
|
62
31
|
# +nil+ means no limit.
|
63
32
|
def in_clause_length
|
64
33
|
nil
|
65
34
|
end
|
66
|
-
|
67
|
-
# Returns the maximum length of an SQL query.
|
68
|
-
def sql_query_length
|
69
|
-
1048575
|
70
|
-
end
|
71
|
-
deprecate :sql_query_length
|
72
|
-
|
73
|
-
# Returns maximum number of joins in a single query.
|
74
|
-
def joins_per_query
|
75
|
-
256
|
76
|
-
end
|
77
|
-
deprecate :joins_per_query
|
35
|
+
deprecate :in_clause_length
|
78
36
|
|
79
37
|
private
|
80
38
|
def bind_params_length
|