activerecord 5.1.5 → 5.2.8.1
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 +655 -608
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +14 -5
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +32 -216
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +35 -19
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +15 -1
- data/lib/active_record/collection_cache_key.rb +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -112
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -95
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +51 -61
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +60 -15
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +30 -42
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +19 -24
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +198 -49
- data/lib/active_record/query_cache.rb +12 -14
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +80 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +46 -20
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +77 -78
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +129 -100
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +26 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +6 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +26 -40
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -114
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module CollectionCacheKey
|
3
5
|
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
|
4
|
-
query_signature = Digest
|
6
|
+
query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
|
5
7
|
key = "#{collection.model_name.cache_key}/query-#{query_signature}"
|
6
8
|
|
7
9
|
if collection.loaded? || collection.distinct_value
|
@@ -10,24 +12,26 @@ module ActiveRecord
|
|
10
12
|
timestamp = collection.max_by(×tamp_column)._read_attribute(timestamp_column)
|
11
13
|
end
|
12
14
|
else
|
13
|
-
|
14
|
-
|
15
|
+
if collection.eager_loading?
|
16
|
+
collection = collection.send(:apply_join_dependency)
|
17
|
+
end
|
18
|
+
column_type = type_for_attribute(timestamp_column)
|
19
|
+
column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
|
15
20
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
16
21
|
|
17
22
|
if collection.has_limit_or_offset?
|
18
|
-
query = collection.
|
19
|
-
query.select_values = [column]
|
23
|
+
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
20
24
|
subquery_alias = "subquery_for_cache_key"
|
21
|
-
subquery_column = "#{subquery_alias}
|
25
|
+
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
22
26
|
subquery = query.arel.as(subquery_alias)
|
23
|
-
arel = Arel::SelectManager.new(
|
27
|
+
arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
|
24
28
|
else
|
25
29
|
query = collection.unscope(:order)
|
26
30
|
query.select_values = [select_values % column]
|
27
31
|
arel = query.arel
|
28
32
|
end
|
29
33
|
|
30
|
-
result = connection.select_one(arel, nil
|
34
|
+
result = connection.select_one(arel, nil)
|
31
35
|
|
32
36
|
if result.blank?
|
33
37
|
size = 0
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "thread"
|
2
4
|
require "concurrent/map"
|
3
5
|
require "monitor"
|
@@ -61,15 +63,13 @@ module ActiveRecord
|
|
61
63
|
# There are several connection-pooling-related options that you can add to
|
62
64
|
# your database connection configuration:
|
63
65
|
#
|
64
|
-
# * +pool+: number
|
65
|
-
# * +
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# Regardless of this setting, the Reaper will be invoked before every
|
72
|
-
# blocking wait. (Default +nil+, which means don't schedule the Reaper).
|
66
|
+
# * +pool+: maximum number of connections the pool may manage (default 5).
|
67
|
+
# * +idle_timeout+: number of seconds that a connection will be kept
|
68
|
+
# unused in the pool before it is automatically disconnected (default
|
69
|
+
# 300 seconds). Set this to zero to keep connections forever.
|
70
|
+
# * +checkout_timeout+: number of seconds to wait for a connection to
|
71
|
+
# become available before giving up and raising a timeout error (default
|
72
|
+
# 5 seconds).
|
73
73
|
#
|
74
74
|
#--
|
75
75
|
# Synchronization policy:
|
@@ -80,11 +80,8 @@ module ActiveRecord
|
|
80
80
|
# * private methods that require being called in a +synchronize+ blocks
|
81
81
|
# are now explicitly documented
|
82
82
|
class ConnectionPool
|
83
|
-
# Threadsafe, fair,
|
84
|
-
# with which it shares a Monitor.
|
85
|
-
#
|
86
|
-
# The Queue in stdlib's 'thread' could replace this class except
|
87
|
-
# stdlib's doesn't support waiting with a timeout.
|
83
|
+
# Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
|
84
|
+
# with which it shares a Monitor.
|
88
85
|
class Queue
|
89
86
|
def initialize(lock = Monitor.new)
|
90
87
|
@lock = lock
|
@@ -173,7 +170,7 @@ module ActiveRecord
|
|
173
170
|
|
174
171
|
# Removes and returns the head of the queue if possible, or +nil+.
|
175
172
|
def remove
|
176
|
-
@queue.
|
173
|
+
@queue.pop
|
177
174
|
end
|
178
175
|
|
179
176
|
# Remove and return the head the queue if the number of
|
@@ -191,7 +188,9 @@ module ActiveRecord
|
|
191
188
|
t0 = Time.now
|
192
189
|
elapsed = 0
|
193
190
|
loop do
|
194
|
-
|
191
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
192
|
+
@cond.wait(timeout - elapsed)
|
193
|
+
end
|
195
194
|
|
196
195
|
return remove if any?
|
197
196
|
|
@@ -268,7 +267,7 @@ module ActiveRecord
|
|
268
267
|
# Connections must be leased while holding the main pool mutex. This is
|
269
268
|
# an internal subclass that also +.leases+ returned connections while
|
270
269
|
# still in queue's critical section (queue synchronizes with the same
|
271
|
-
#
|
270
|
+
# <tt>@lock</tt> as the main pool) so that a returned connection is already
|
272
271
|
# leased and there is no need to re-enter synchronized block.
|
273
272
|
class ConnectionLeasingQueue < Queue # :nodoc:
|
274
273
|
include BiasableQueue
|
@@ -281,12 +280,12 @@ module ActiveRecord
|
|
281
280
|
end
|
282
281
|
end
|
283
282
|
|
284
|
-
# Every +frequency+ seconds, the reaper will call +reap+
|
285
|
-
# A reaper instantiated with a
|
286
|
-
# connection pool.
|
283
|
+
# Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
|
284
|
+
# +pool+. A reaper instantiated with a zero frequency will never reap
|
285
|
+
# the connection pool.
|
287
286
|
#
|
288
|
-
# Configure the frequency by setting
|
289
|
-
#
|
287
|
+
# Configure the frequency by setting +reaping_frequency+ in your database
|
288
|
+
# yaml file (default 60 seconds).
|
290
289
|
class Reaper
|
291
290
|
attr_reader :pool, :frequency
|
292
291
|
|
@@ -296,11 +295,12 @@ module ActiveRecord
|
|
296
295
|
end
|
297
296
|
|
298
297
|
def run
|
299
|
-
return unless frequency
|
298
|
+
return unless frequency && frequency > 0
|
300
299
|
Thread.new(frequency, pool) { |t, p|
|
301
300
|
loop do
|
302
301
|
sleep t
|
303
302
|
p.reap
|
303
|
+
p.flush
|
304
304
|
end
|
305
305
|
}
|
306
306
|
end
|
@@ -310,7 +310,7 @@ module ActiveRecord
|
|
310
310
|
include QueryCache::ConnectionPoolConfiguration
|
311
311
|
|
312
312
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
313
|
-
attr_reader :spec, :
|
313
|
+
attr_reader :spec, :size, :reaper
|
314
314
|
|
315
315
|
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
|
316
316
|
# object which describes database connection information (e.g. adapter,
|
@@ -324,8 +324,10 @@ module ActiveRecord
|
|
324
324
|
@spec = spec
|
325
325
|
|
326
326
|
@checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
|
327
|
-
@
|
328
|
-
|
327
|
+
if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
|
328
|
+
@idle_timeout = @idle_timeout.to_f
|
329
|
+
@idle_timeout = nil if @idle_timeout <= 0
|
330
|
+
end
|
329
331
|
|
330
332
|
# default max pool size to 5
|
331
333
|
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
|
@@ -338,7 +340,7 @@ module ActiveRecord
|
|
338
340
|
# then that +thread+ does indeed own that +conn+. However, an absence of a such
|
339
341
|
# mapping does not mean that the +thread+ doesn't own the said connection. In
|
340
342
|
# that case +conn.owner+ attr should be consulted.
|
341
|
-
# Access and modification of
|
343
|
+
# Access and modification of <tt>@thread_cached_conns</tt> does not require
|
342
344
|
# synchronization.
|
343
345
|
@thread_cached_conns = Concurrent::Map.new(initial_capacity: @size)
|
344
346
|
|
@@ -355,6 +357,12 @@ module ActiveRecord
|
|
355
357
|
@available = ConnectionLeasingQueue.new self
|
356
358
|
|
357
359
|
@lock_thread = false
|
360
|
+
|
361
|
+
# +reaping_frequency+ is configurable mostly for historical reasons, but it could
|
362
|
+
# also be useful if someone wants a very low +idle_timeout+.
|
363
|
+
reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
|
364
|
+
@reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
|
365
|
+
@reaper.run
|
358
366
|
end
|
359
367
|
|
360
368
|
def lock_thread=(lock_thread)
|
@@ -371,7 +379,7 @@ module ActiveRecord
|
|
371
379
|
# #connection can be called any number of times; the connection is
|
372
380
|
# held in a cache keyed by a thread.
|
373
381
|
def connection
|
374
|
-
@thread_cached_conns[connection_cache_key(
|
382
|
+
@thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
|
375
383
|
end
|
376
384
|
|
377
385
|
# Returns true if there is an open connection being used for the current thread.
|
@@ -380,7 +388,7 @@ module ActiveRecord
|
|
380
388
|
# #connection or #with_connection methods. Connections obtained through
|
381
389
|
# #checkout will not be detected by #active_connection?
|
382
390
|
def active_connection?
|
383
|
-
@thread_cached_conns[connection_cache_key(
|
391
|
+
@thread_cached_conns[connection_cache_key(current_thread)]
|
384
392
|
end
|
385
393
|
|
386
394
|
# Signal that the thread is finished with the current connection.
|
@@ -415,6 +423,21 @@ module ActiveRecord
|
|
415
423
|
synchronize { @connections.any? }
|
416
424
|
end
|
417
425
|
|
426
|
+
# Returns an array containing the connections currently in the pool.
|
427
|
+
# Access to the array does not require synchronization on the pool because
|
428
|
+
# the array is newly created and not retained by the pool.
|
429
|
+
#
|
430
|
+
# However; this method bypasses the ConnectionPool's thread-safe connection
|
431
|
+
# access pattern. A returned connection may be owned by another thread,
|
432
|
+
# unowned, or by happen-stance owned by the calling thread.
|
433
|
+
#
|
434
|
+
# Calling methods on a connection without ownership is subject to the
|
435
|
+
# thread-safety guarantees of the underlying method. Many of the methods
|
436
|
+
# on connection adapter classes are inherently multi-thread unsafe.
|
437
|
+
def connections
|
438
|
+
synchronize { @connections.dup }
|
439
|
+
end
|
440
|
+
|
418
441
|
# Disconnects all connections in the pool, and clears the pool.
|
419
442
|
#
|
420
443
|
# Raises:
|
@@ -447,6 +470,21 @@ module ActiveRecord
|
|
447
470
|
disconnect(false)
|
448
471
|
end
|
449
472
|
|
473
|
+
# Discards all connections in the pool (even if they're currently
|
474
|
+
# leased!), along with the pool itself. Any further interaction with the
|
475
|
+
# pool (except #spec and #schema_cache) is undefined.
|
476
|
+
#
|
477
|
+
# See AbstractAdapter#discard!
|
478
|
+
def discard! # :nodoc:
|
479
|
+
synchronize do
|
480
|
+
return if @connections.nil? # already discarded
|
481
|
+
@connections.each do |conn|
|
482
|
+
conn.discard!
|
483
|
+
end
|
484
|
+
@connections = @available = @thread_cached_conns = nil
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
450
488
|
# Clears the cache which maps classes and re-connects connections that
|
451
489
|
# require reloading.
|
452
490
|
#
|
@@ -572,6 +610,35 @@ module ActiveRecord
|
|
572
610
|
end
|
573
611
|
end
|
574
612
|
|
613
|
+
# Disconnect all connections that have been idle for at least
|
614
|
+
# +minimum_idle+ seconds. Connections currently checked out, or that were
|
615
|
+
# checked in less than +minimum_idle+ seconds ago, are unaffected.
|
616
|
+
def flush(minimum_idle = @idle_timeout)
|
617
|
+
return if minimum_idle.nil?
|
618
|
+
|
619
|
+
idle_connections = synchronize do
|
620
|
+
@connections.select do |conn|
|
621
|
+
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
622
|
+
end.each do |conn|
|
623
|
+
conn.lease
|
624
|
+
|
625
|
+
@available.delete conn
|
626
|
+
@connections.delete conn
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
idle_connections.each do |conn|
|
631
|
+
conn.disconnect!
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
# Disconnect all currently idle connections. Connections currently checked
|
636
|
+
# out are unaffected.
|
637
|
+
def flush!
|
638
|
+
reap
|
639
|
+
flush(-1)
|
640
|
+
end
|
641
|
+
|
575
642
|
def num_waiting_in_queue # :nodoc:
|
576
643
|
@available.num_waiting
|
577
644
|
end
|
@@ -616,6 +683,10 @@ module ActiveRecord
|
|
616
683
|
thread
|
617
684
|
end
|
618
685
|
|
686
|
+
def current_thread
|
687
|
+
@lock_thread || Thread.current
|
688
|
+
end
|
689
|
+
|
619
690
|
# Take control of all existing connections so a "group" action such as
|
620
691
|
# reload/disconnect can be performed safely. It is no longer enough to
|
621
692
|
# wrap it in +synchronize+ because some pool's actions are allowed
|
@@ -679,7 +750,7 @@ module ActiveRecord
|
|
679
750
|
# this block can't be easily moved into attempt_to_checkout_all_existing_connections's
|
680
751
|
# rescue block, because doing so would put it outside of synchronize section, without
|
681
752
|
# being in a critical section thread_report might become inaccurate
|
682
|
-
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
753
|
+
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
|
683
754
|
|
684
755
|
thread_report = []
|
685
756
|
@connections.each do |conn|
|
@@ -734,10 +805,10 @@ module ActiveRecord
|
|
734
805
|
# Implementation detail: the connection returned by +acquire_connection+
|
735
806
|
# will already be "+connection.lease+ -ed" to the current thread.
|
736
807
|
def acquire_connection(checkout_timeout)
|
737
|
-
# NOTE: we rely on
|
808
|
+
# NOTE: we rely on <tt>@available.poll</tt> and +try_to_checkout_new_connection+ to
|
738
809
|
# +conn.lease+ the returned connection (and to do this in a +synchronized+
|
739
810
|
# section). This is not the cleanest implementation, as ideally we would
|
740
|
-
# <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to
|
811
|
+
# <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to <tt>@available.poll</tt>
|
741
812
|
# and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
|
742
813
|
# of the said methods and avoid an additional +synchronize+ overhead.
|
743
814
|
if conn = @available.poll || try_to_checkout_new_connection
|
@@ -761,7 +832,7 @@ module ActiveRecord
|
|
761
832
|
end
|
762
833
|
end
|
763
834
|
|
764
|
-
# If the pool is not at a
|
835
|
+
# If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
|
765
836
|
# to the DB is done outside main synchronized section.
|
766
837
|
#--
|
767
838
|
# Implementation constraint: a newly established connection returned by this
|
@@ -827,7 +898,7 @@ module ActiveRecord
|
|
827
898
|
# end
|
828
899
|
#
|
829
900
|
# class Book < ActiveRecord::Base
|
830
|
-
# establish_connection
|
901
|
+
# establish_connection :library_db
|
831
902
|
# end
|
832
903
|
#
|
833
904
|
# class ScaryBook < Book
|
@@ -859,17 +930,41 @@ module ActiveRecord
|
|
859
930
|
# All Active Record models use this handler to determine the connection pool that they
|
860
931
|
# should use.
|
861
932
|
#
|
862
|
-
# The ConnectionHandler class is not coupled with the Active models, as it has no
|
933
|
+
# The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
|
863
934
|
# about the model. The model needs to pass a specification name to the handler,
|
864
|
-
# in order to
|
935
|
+
# in order to look up the correct connection pool.
|
865
936
|
class ConnectionHandler
|
866
|
-
def
|
867
|
-
|
868
|
-
|
937
|
+
def self.create_owner_to_pool # :nodoc:
|
938
|
+
Concurrent::Map.new(initial_capacity: 2) do |h, k|
|
939
|
+
# Discard the parent's connection pools immediately; we have no need
|
940
|
+
# of them
|
941
|
+
discard_unowned_pools(h)
|
942
|
+
|
869
943
|
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
870
944
|
end
|
871
945
|
end
|
872
946
|
|
947
|
+
def self.unowned_pool_finalizer(pid_map) # :nodoc:
|
948
|
+
lambda do |_|
|
949
|
+
discard_unowned_pools(pid_map)
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def self.discard_unowned_pools(pid_map) # :nodoc:
|
954
|
+
pid_map.each do |pid, pools|
|
955
|
+
pools.values.compact.each(&:discard!) unless pid == Process.pid
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
959
|
+
def initialize
|
960
|
+
# These caches are keyed by spec.name (ConnectionSpecification#name).
|
961
|
+
@owner_to_pool = ConnectionHandler.create_owner_to_pool
|
962
|
+
|
963
|
+
# Backup finalizer: if the forked child never needed a pool, the above
|
964
|
+
# early discard has not occurred
|
965
|
+
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
966
|
+
end
|
967
|
+
|
873
968
|
def connection_pool_list
|
874
969
|
owner_to_pool.values.compact
|
875
970
|
end
|
@@ -921,6 +1016,13 @@ module ActiveRecord
|
|
921
1016
|
connection_pool_list.each(&:disconnect!)
|
922
1017
|
end
|
923
1018
|
|
1019
|
+
# Disconnects all currently idle connections.
|
1020
|
+
#
|
1021
|
+
# See ConnectionPool#flush! for details.
|
1022
|
+
def flush_idle_connections!
|
1023
|
+
connection_pool_list.each(&:flush!)
|
1024
|
+
end
|
1025
|
+
|
924
1026
|
# Locate the connection of the nearest super class. This can be an
|
925
1027
|
# active or defined connection: if it is the latter, it will be
|
926
1028
|
# opened and set as the active connection for the class it was defined
|
@@ -928,9 +1030,7 @@ module ActiveRecord
|
|
928
1030
|
def retrieve_connection(spec_name) #:nodoc:
|
929
1031
|
pool = retrieve_connection_pool(spec_name)
|
930
1032
|
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
|
931
|
-
|
932
|
-
raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn
|
933
|
-
conn
|
1033
|
+
pool.connection
|
934
1034
|
end
|
935
1035
|
|
936
1036
|
# Returns true if a connection that's accessible to this class has
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module DatabaseLimits
|
@@ -60,6 +62,11 @@ module ActiveRecord
|
|
60
62
|
def joins_per_query
|
61
63
|
256
|
62
64
|
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def bind_params_length
|
68
|
+
65535
|
69
|
+
end
|
63
70
|
end
|
64
71
|
end
|
65
72
|
end
|