activerecord 6.0.6.1 → 6.1.0.rc1
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 +764 -942
- 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 +39 -27
- 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 +4 -4
- 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 +52 -48
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -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 +35 -44
- 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 +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- 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 +33 -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 -10
- 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 +214 -58
- 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 +33 -23
- 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 +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- 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 -42
- 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 +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -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 +2 -2
- 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 +319 -198
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- 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 +0 -4
- 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 +36 -52
- 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 +30 -32
- 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,38 +6,23 @@ 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
|
-
@schema_cache = nil
|
40
|
-
end
|
25
|
+
attr_accessor :schema_cache
|
41
26
|
end
|
42
27
|
|
43
28
|
# Connection pool base class for managing Active Record database
|
@@ -150,7 +135,7 @@ module ActiveRecord
|
|
150
135
|
|
151
136
|
# Remove the head of the queue.
|
152
137
|
#
|
153
|
-
# If +timeout+ is not given, remove and return the head the
|
138
|
+
# If +timeout+ is not given, remove and return the head of the
|
154
139
|
# queue if the number of available elements is strictly
|
155
140
|
# greater than the number of threads currently waiting (that
|
156
141
|
# is, don't jump ahead in line). Otherwise, return +nil+.
|
@@ -193,7 +178,7 @@ module ActiveRecord
|
|
193
178
|
@queue.pop
|
194
179
|
end
|
195
180
|
|
196
|
-
# Remove and return the head the queue if the number of
|
181
|
+
# Remove and return the head of the queue if the number of
|
197
182
|
# available elements is strictly greater than the number of
|
198
183
|
# threads currently waiting. Otherwise, return +nil+.
|
199
184
|
def no_wait_poll
|
@@ -332,11 +317,17 @@ module ActiveRecord
|
|
332
317
|
private
|
333
318
|
def spawn_thread(frequency)
|
334
319
|
Thread.new(frequency) do |t|
|
320
|
+
# Advise multi-threaded app servers to ignore this thread for
|
321
|
+
# the purposes of fork safety warnings
|
322
|
+
Thread.current.thread_variable_set(:fork_safe, true)
|
335
323
|
running = true
|
336
324
|
while running
|
337
325
|
sleep t
|
338
326
|
@mutex.synchronize do
|
339
|
-
@pools[frequency].select!
|
327
|
+
@pools[frequency].select! do |pool|
|
328
|
+
pool.weakref_alive? && !pool.discarded?
|
329
|
+
end
|
330
|
+
|
340
331
|
@pools[frequency].each do |p|
|
341
332
|
p.reap
|
342
333
|
p.flush
|
@@ -364,28 +355,26 @@ module ActiveRecord
|
|
364
355
|
include QueryCache::ConnectionPoolConfiguration
|
365
356
|
include ConnectionAdapters::AbstractPool
|
366
357
|
|
367
|
-
attr_accessor :automatic_reconnect, :checkout_timeout
|
368
|
-
attr_reader :
|
358
|
+
attr_accessor :automatic_reconnect, :checkout_timeout
|
359
|
+
attr_reader :db_config, :size, :reaper, :pool_config
|
369
360
|
|
370
|
-
|
361
|
+
delegate :schema_cache, :schema_cache=, to: :pool_config
|
362
|
+
|
363
|
+
# Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
|
371
364
|
# object which describes database connection information (e.g. adapter,
|
372
365
|
# host name, username, password, etc), as well as the maximum size for
|
373
366
|
# this ConnectionPool.
|
374
367
|
#
|
375
368
|
# The default ConnectionPool maximum size is 5.
|
376
|
-
def initialize(
|
369
|
+
def initialize(pool_config)
|
377
370
|
super()
|
378
371
|
|
379
|
-
@
|
380
|
-
|
381
|
-
@checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
|
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
|
372
|
+
@pool_config = pool_config
|
373
|
+
@db_config = pool_config.db_config
|
386
374
|
|
387
|
-
|
388
|
-
@
|
375
|
+
@checkout_timeout = db_config.checkout_timeout
|
376
|
+
@idle_timeout = db_config.idle_timeout
|
377
|
+
@size = db_config.pool
|
389
378
|
|
390
379
|
# This variable tracks the cache of threads mapped to reserved connections, with the
|
391
380
|
# sole purpose of speeding up the +connection+ method. It is not the authoritative
|
@@ -413,10 +402,7 @@ module ActiveRecord
|
|
413
402
|
|
414
403
|
@lock_thread = false
|
415
404
|
|
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)
|
405
|
+
@reaper = Reaper.new(self, db_config.reaping_frequency)
|
420
406
|
@reaper.run
|
421
407
|
end
|
422
408
|
|
@@ -498,7 +484,7 @@ module ActiveRecord
|
|
498
484
|
# Raises:
|
499
485
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
500
486
|
# connections in the pool within a timeout interval (default duration is
|
501
|
-
# <tt>spec.
|
487
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
502
488
|
def disconnect(raise_on_acquisition_timeout = true)
|
503
489
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
504
490
|
synchronize do
|
@@ -519,7 +505,7 @@ module ActiveRecord
|
|
519
505
|
#
|
520
506
|
# The pool first tries to gain ownership of all connections. If unable to
|
521
507
|
# do so within a timeout interval (default duration is
|
522
|
-
# <tt>spec.
|
508
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
|
523
509
|
# disconnected without any regard for other connection owning threads.
|
524
510
|
def disconnect!
|
525
511
|
disconnect(false)
|
@@ -532,7 +518,7 @@ module ActiveRecord
|
|
532
518
|
# See AbstractAdapter#discard!
|
533
519
|
def discard! # :nodoc:
|
534
520
|
synchronize do
|
535
|
-
return if
|
521
|
+
return if self.discarded?
|
536
522
|
@connections.each do |conn|
|
537
523
|
conn.discard!
|
538
524
|
end
|
@@ -540,13 +526,17 @@ module ActiveRecord
|
|
540
526
|
end
|
541
527
|
end
|
542
528
|
|
529
|
+
def discarded? # :nodoc:
|
530
|
+
@connections.nil?
|
531
|
+
end
|
532
|
+
|
543
533
|
# Clears the cache which maps classes and re-connects connections that
|
544
534
|
# require reloading.
|
545
535
|
#
|
546
536
|
# Raises:
|
547
537
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
548
538
|
# connections in the pool within a timeout interval (default duration is
|
549
|
-
# <tt>spec.
|
539
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
550
540
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
551
541
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
552
542
|
synchronize do
|
@@ -568,7 +558,7 @@ module ActiveRecord
|
|
568
558
|
#
|
569
559
|
# The pool first tries to gain ownership of all connections. If unable to
|
570
560
|
# do so within a timeout interval (default duration is
|
571
|
-
# <tt>spec.
|
561
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
|
572
562
|
# clears the cache and reloads connections without any regard for other
|
573
563
|
# connection owning threads.
|
574
564
|
def clear_reloadable_connections!
|
@@ -648,7 +638,7 @@ module ActiveRecord
|
|
648
638
|
# or a thread dies unexpectedly.
|
649
639
|
def reap
|
650
640
|
stale_connections = synchronize do
|
651
|
-
return
|
641
|
+
return if self.discarded?
|
652
642
|
@connections.select do |conn|
|
653
643
|
conn.in_use? && !conn.owner.alive?
|
654
644
|
end.each do |conn|
|
@@ -673,7 +663,7 @@ module ActiveRecord
|
|
673
663
|
return if minimum_idle.nil?
|
674
664
|
|
675
665
|
idle_connections = synchronize do
|
676
|
-
return
|
666
|
+
return if self.discarded?
|
677
667
|
@connections.select do |conn|
|
678
668
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
679
669
|
end.each do |conn|
|
@@ -884,7 +874,7 @@ module ActiveRecord
|
|
884
874
|
alias_method :release, :remove_connection_from_thread_cache
|
885
875
|
|
886
876
|
def new_connection
|
887
|
-
Base.
|
877
|
+
Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
|
888
878
|
conn.check_version
|
889
879
|
end
|
890
880
|
end
|
@@ -988,38 +978,18 @@ module ActiveRecord
|
|
988
978
|
# should use.
|
989
979
|
#
|
990
980
|
# 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,
|
981
|
+
# about the model. The model needs to pass a connection specification name to the handler,
|
992
982
|
# in order to look up the correct connection pool.
|
993
983
|
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
|
984
|
+
FINALIZER = lambda { |_| ActiveSupport::ForkTracker.check! }
|
985
|
+
private_constant :FINALIZER
|
1015
986
|
|
1016
987
|
def initialize
|
1017
|
-
# These caches are keyed by
|
1018
|
-
@
|
988
|
+
# These caches are keyed by pool_config.connection_specification_name (PoolConfig#connection_specification_name).
|
989
|
+
@owner_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
|
1019
990
|
|
1020
|
-
# Backup finalizer: if the forked child
|
1021
|
-
|
1022
|
-
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
991
|
+
# Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
|
992
|
+
ObjectSpace.define_finalizer self, FINALIZER
|
1023
993
|
end
|
1024
994
|
|
1025
995
|
def prevent_writes # :nodoc:
|
@@ -1042,84 +1012,112 @@ module ActiveRecord
|
|
1042
1012
|
# See `READ_QUERY` for the queries that are blocked by this
|
1043
1013
|
# method.
|
1044
1014
|
def while_preventing_writes(enabled = true)
|
1015
|
+
unless ActiveRecord::Base.legacy_connection_handling
|
1016
|
+
raise NotImplementedError, "`while_preventing_writes` is only available on the connection_handler with legacy_connection_handling"
|
1017
|
+
end
|
1018
|
+
|
1045
1019
|
original, self.prevent_writes = self.prevent_writes, enabled
|
1046
1020
|
yield
|
1047
1021
|
ensure
|
1048
1022
|
self.prevent_writes = original
|
1049
1023
|
end
|
1050
1024
|
|
1051
|
-
def
|
1052
|
-
|
1025
|
+
def connection_pool_names # :nodoc:
|
1026
|
+
owner_to_pool_manager.keys
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
def all_connection_pools
|
1030
|
+
owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def connection_pool_list(role = ActiveRecord::Base.current_role)
|
1034
|
+
owner_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
|
1053
1035
|
end
|
1054
1036
|
alias :connection_pools :connection_pool_list
|
1055
1037
|
|
1056
|
-
def establish_connection(config)
|
1057
|
-
|
1058
|
-
spec = resolver.spec(config)
|
1038
|
+
def establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
|
1039
|
+
owner_name = config.to_s if config.is_a?(Symbol)
|
1059
1040
|
|
1060
|
-
|
1041
|
+
pool_config = resolve_pool_config(config, owner_name)
|
1042
|
+
db_config = pool_config.db_config
|
1043
|
+
|
1044
|
+
# Protects the connection named `ActiveRecord::Base` from being removed
|
1045
|
+
# if the user calls `establish_connection :primary`.
|
1046
|
+
if owner_to_pool_manager.key?(pool_config.connection_specification_name)
|
1047
|
+
remove_connection_pool(pool_config.connection_specification_name, role: role, shard: shard)
|
1048
|
+
end
|
1061
1049
|
|
1062
1050
|
message_bus = ActiveSupport::Notifications.instrumenter
|
1063
|
-
payload = {
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
payload[:
|
1068
|
-
payload[:config] = spec.config
|
1051
|
+
payload = {}
|
1052
|
+
if pool_config
|
1053
|
+
payload[:spec_name] = pool_config.connection_specification_name
|
1054
|
+
payload[:shard] = shard
|
1055
|
+
payload[:config] = db_config.configuration_hash
|
1069
1056
|
end
|
1070
1057
|
|
1071
|
-
|
1072
|
-
|
1058
|
+
if ActiveRecord::Base.legacy_connection_handling
|
1059
|
+
owner_to_pool_manager[pool_config.connection_specification_name] ||= LegacyPoolManager.new
|
1060
|
+
else
|
1061
|
+
owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
|
1073
1062
|
end
|
1063
|
+
pool_manager = get_pool_manager(pool_config.connection_specification_name)
|
1064
|
+
pool_manager.set_pool_config(role, shard, pool_config)
|
1074
1065
|
|
1075
|
-
|
1066
|
+
message_bus.instrument("!connection.active_record", payload) do
|
1067
|
+
pool_config.pool
|
1068
|
+
end
|
1076
1069
|
end
|
1077
1070
|
|
1078
1071
|
# Returns true if there are any active connections among the connection
|
1079
1072
|
# pools that the ConnectionHandler is managing.
|
1080
|
-
def active_connections?
|
1081
|
-
connection_pool_list.any?(&:active_connection?)
|
1073
|
+
def active_connections?(role = ActiveRecord::Base.current_role)
|
1074
|
+
connection_pool_list(role).any?(&:active_connection?)
|
1082
1075
|
end
|
1083
1076
|
|
1084
1077
|
# Returns any connections in use by the current thread back to the pool,
|
1085
1078
|
# and also returns connections to the pool cached by threads that are no
|
1086
1079
|
# longer alive.
|
1087
|
-
def clear_active_connections!
|
1088
|
-
connection_pool_list.each(&:release_connection)
|
1080
|
+
def clear_active_connections!(role = ActiveRecord::Base.current_role)
|
1081
|
+
connection_pool_list(role).each(&:release_connection)
|
1089
1082
|
end
|
1090
1083
|
|
1091
1084
|
# Clears the cache which maps classes.
|
1092
1085
|
#
|
1093
1086
|
# See ConnectionPool#clear_reloadable_connections! for details.
|
1094
|
-
def clear_reloadable_connections!
|
1095
|
-
connection_pool_list.each(&:clear_reloadable_connections!)
|
1087
|
+
def clear_reloadable_connections!(role = ActiveRecord::Base.current_role)
|
1088
|
+
connection_pool_list(role).each(&:clear_reloadable_connections!)
|
1096
1089
|
end
|
1097
1090
|
|
1098
|
-
def clear_all_connections!
|
1099
|
-
connection_pool_list.each(&:disconnect!)
|
1091
|
+
def clear_all_connections!(role = ActiveRecord::Base.current_role)
|
1092
|
+
connection_pool_list(role).each(&:disconnect!)
|
1100
1093
|
end
|
1101
1094
|
|
1102
1095
|
# Disconnects all currently idle connections.
|
1103
1096
|
#
|
1104
1097
|
# See ConnectionPool#flush! for details.
|
1105
|
-
def flush_idle_connections!
|
1106
|
-
connection_pool_list.each(&:flush!)
|
1098
|
+
def flush_idle_connections!(role = ActiveRecord::Base.current_role)
|
1099
|
+
connection_pool_list(role).each(&:flush!)
|
1107
1100
|
end
|
1108
1101
|
|
1109
1102
|
# Locate the connection of the nearest super class. This can be an
|
1110
1103
|
# active or defined connection: if it is the latter, it will be
|
1111
1104
|
# opened and set as the active connection for the class it was defined
|
1112
1105
|
# for (not necessarily the current class).
|
1113
|
-
def retrieve_connection(spec_name)
|
1114
|
-
pool = retrieve_connection_pool(spec_name)
|
1106
|
+
def retrieve_connection(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
|
1107
|
+
pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
|
1115
1108
|
|
1116
1109
|
unless pool
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1110
|
+
if shard != ActiveRecord::Base.default_shard
|
1111
|
+
message = "No connection pool for '#{spec_name}' found for the '#{shard}' shard."
|
1112
|
+
elsif ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
|
1113
|
+
message = "No connection pool for '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
|
1114
|
+
elsif role != ActiveRecord::Base.default_role
|
1115
|
+
message = "No connection pool for '#{spec_name}' found for the '#{role}' role."
|
1120
1116
|
else
|
1121
|
-
|
1117
|
+
message = "No connection pool for '#{spec_name}' found."
|
1122
1118
|
end
|
1119
|
+
|
1120
|
+
raise ConnectionNotEstablished, message
|
1123
1121
|
end
|
1124
1122
|
|
1125
1123
|
pool.connection
|
@@ -1127,8 +1125,8 @@ module ActiveRecord
|
|
1127
1125
|
|
1128
1126
|
# Returns true if a connection that's accessible to this class has
|
1129
1127
|
# already been opened.
|
1130
|
-
def connected?(spec_name)
|
1131
|
-
pool = retrieve_connection_pool(spec_name)
|
1128
|
+
def connected?(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1129
|
+
pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
|
1132
1130
|
pool && pool.connected?
|
1133
1131
|
end
|
1134
1132
|
|
@@ -1136,42 +1134,90 @@ module ActiveRecord
|
|
1136
1134
|
# connection and the defined connection (if they exist). The result
|
1137
1135
|
# can be used as an argument for #establish_connection, for easily
|
1138
1136
|
# re-establishing the connection.
|
1139
|
-
def remove_connection(
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1137
|
+
def remove_connection(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1138
|
+
remove_connection_pool(owner, role: role, shard: shard)&.configuration_hash
|
1139
|
+
end
|
1140
|
+
deprecate remove_connection: "Use #remove_connection_pool, which now returns a DatabaseConfig object instead of a Hash"
|
1141
|
+
|
1142
|
+
def remove_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1143
|
+
if pool_manager = get_pool_manager(owner)
|
1144
|
+
pool_config = pool_manager.remove_pool_config(role, shard)
|
1145
|
+
|
1146
|
+
if pool_config
|
1147
|
+
pool_config.disconnect!
|
1148
|
+
pool_config.db_config
|
1149
|
+
end
|
1144
1150
|
end
|
1145
1151
|
end
|
1146
1152
|
|
1147
|
-
# Retrieving the connection pool happens a lot, so we cache it in @
|
1153
|
+
# Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool_manager.
|
1148
1154
|
# This makes retrieving the connection pool O(1) once the process is warm.
|
1149
1155
|
# 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
|
1156
|
+
def retrieve_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
|
1157
|
+
pool_config = get_pool_manager(owner)&.get_pool_config(role, shard)
|
1158
|
+
pool_config&.pool
|
1165
1159
|
end
|
1166
1160
|
|
1167
1161
|
private
|
1168
|
-
|
1169
|
-
|
1162
|
+
attr_reader :owner_to_pool_manager
|
1163
|
+
|
1164
|
+
# Returns the pool manager for an owner.
|
1165
|
+
#
|
1166
|
+
# Using `"primary"` to look up the pool manager for `ActiveRecord::Base` is
|
1167
|
+
# deprecated in favor of looking it up by `"ActiveRecord::Base"`.
|
1168
|
+
#
|
1169
|
+
# During the deprecation period, if `"primary"` is passed, the pool manager
|
1170
|
+
# for `ActiveRecord::Base` will still be returned.
|
1171
|
+
def get_pool_manager(owner)
|
1172
|
+
return owner_to_pool_manager[owner] if owner_to_pool_manager.key?(owner)
|
1173
|
+
|
1174
|
+
if owner == "primary"
|
1175
|
+
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`.")
|
1176
|
+
owner_to_pool_manager[Base.name]
|
1177
|
+
end
|
1170
1178
|
end
|
1171
1179
|
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1180
|
+
# Returns an instance of PoolConfig for a given adapter.
|
1181
|
+
# Accepts a hash one layer deep that contains all connection information.
|
1182
|
+
#
|
1183
|
+
# == Example
|
1184
|
+
#
|
1185
|
+
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
1186
|
+
# pool_config = Base.configurations.resolve_pool_config(:production)
|
1187
|
+
# pool_config.db_config.configuration_hash
|
1188
|
+
# # => { host: "localhost", database: "foo", adapter: "sqlite3" }
|
1189
|
+
#
|
1190
|
+
def resolve_pool_config(config, owner_name)
|
1191
|
+
db_config = Base.configurations.resolve(config)
|
1192
|
+
|
1193
|
+
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
|
1194
|
+
|
1195
|
+
# Require the adapter itself and give useful feedback about
|
1196
|
+
# 1. Missing adapter gems and
|
1197
|
+
# 2. Adapter gems' missing dependencies.
|
1198
|
+
path_to_adapter = "active_record/connection_adapters/#{db_config.adapter}_adapter"
|
1199
|
+
begin
|
1200
|
+
require path_to_adapter
|
1201
|
+
rescue LoadError => e
|
1202
|
+
# We couldn't require the adapter itself. Raise an exception that
|
1203
|
+
# points out config typos and missing gems.
|
1204
|
+
if e.path == path_to_adapter
|
1205
|
+
# We can assume that a non-builtin adapter was specified, so it's
|
1206
|
+
# either misspelled or missing from Gemfile.
|
1207
|
+
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
|
1208
|
+
|
1209
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
1210
|
+
# with some guidance about how to address it and reraise.
|
1211
|
+
else
|
1212
|
+
raise LoadError, "Error loading the '#{db_config.adapter}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
1213
|
+
end
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
|
1217
|
+
raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
ConnectionAdapters::PoolConfig.new(owner_name, db_config)
|
1175
1221
|
end
|
1176
1222
|
end
|
1177
1223
|
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
|