activerecord 5.2.7.1 → 6.1.4.6
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 +1145 -575
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +100 -41
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +55 -48
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- 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 +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +135 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +334 -97
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +108 -36
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- 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 +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +200 -481
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +142 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +411 -80
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +476 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +115 -62
- data/lib/active_record/relation.rb +379 -115
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +4 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- 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 +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- 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
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +117 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -3,22 +3,32 @@
|
|
3
3
|
require "thread"
|
4
4
|
require "concurrent/map"
|
5
5
|
require "monitor"
|
6
|
+
require "weakref"
|
6
7
|
|
7
8
|
module ActiveRecord
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
module ConnectionAdapters
|
10
|
+
module AbstractPool # :nodoc:
|
11
|
+
def get_schema_cache(connection)
|
12
|
+
self.schema_cache ||= SchemaCache.new(connection)
|
13
|
+
schema_cache.connection = connection
|
14
|
+
schema_cache
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def set_schema_cache(cache)
|
18
|
+
self.schema_cache = cache
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class NullPool # :nodoc:
|
23
|
+
include ConnectionAdapters::AbstractPool
|
24
|
+
|
25
|
+
attr_accessor :schema_cache
|
26
|
+
|
27
|
+
def connection_klass
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
20
31
|
|
21
|
-
module ConnectionAdapters
|
22
32
|
# Connection pool base class for managing Active Record database
|
23
33
|
# connections.
|
24
34
|
#
|
@@ -129,7 +139,7 @@ module ActiveRecord
|
|
129
139
|
|
130
140
|
# Remove the head of the queue.
|
131
141
|
#
|
132
|
-
# If +timeout+ is not given, remove and return the head the
|
142
|
+
# If +timeout+ is not given, remove and return the head of the
|
133
143
|
# queue if the number of available elements is strictly
|
134
144
|
# greater than the number of threads currently waiting (that
|
135
145
|
# is, don't jump ahead in line). Otherwise, return +nil+.
|
@@ -146,7 +156,6 @@ module ActiveRecord
|
|
146
156
|
end
|
147
157
|
|
148
158
|
private
|
149
|
-
|
150
159
|
def internal_poll(timeout)
|
151
160
|
no_wait_poll || (timeout && wait_poll(timeout))
|
152
161
|
end
|
@@ -173,7 +182,7 @@ module ActiveRecord
|
|
173
182
|
@queue.pop
|
174
183
|
end
|
175
184
|
|
176
|
-
# Remove and return the head the queue if the number of
|
185
|
+
# Remove and return the head of the queue if the number of
|
177
186
|
# available elements is strictly greater than the number of
|
178
187
|
# threads currently waiting. Otherwise, return +nil+.
|
179
188
|
def no_wait_poll
|
@@ -185,7 +194,7 @@ module ActiveRecord
|
|
185
194
|
def wait_poll(timeout)
|
186
195
|
@num_waiting += 1
|
187
196
|
|
188
|
-
t0 =
|
197
|
+
t0 = Concurrent.monotonic_time
|
189
198
|
elapsed = 0
|
190
199
|
loop do
|
191
200
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -194,7 +203,7 @@ module ActiveRecord
|
|
194
203
|
|
195
204
|
return remove if any?
|
196
205
|
|
197
|
-
elapsed =
|
206
|
+
elapsed = Concurrent.monotonic_time - t0
|
198
207
|
if elapsed >= timeout
|
199
208
|
msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
|
200
209
|
[timeout, elapsed]
|
@@ -294,50 +303,90 @@ module ActiveRecord
|
|
294
303
|
@frequency = frequency
|
295
304
|
end
|
296
305
|
|
306
|
+
@mutex = Mutex.new
|
307
|
+
@pools = {}
|
308
|
+
@threads = {}
|
309
|
+
|
310
|
+
class << self
|
311
|
+
def register_pool(pool, frequency) # :nodoc:
|
312
|
+
@mutex.synchronize do
|
313
|
+
unless @threads[frequency]&.alive?
|
314
|
+
@threads[frequency] = spawn_thread(frequency)
|
315
|
+
end
|
316
|
+
@pools[frequency] ||= []
|
317
|
+
@pools[frequency] << WeakRef.new(pool)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
private
|
322
|
+
def spawn_thread(frequency)
|
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)
|
327
|
+
running = true
|
328
|
+
while running
|
329
|
+
sleep t
|
330
|
+
@mutex.synchronize do
|
331
|
+
@pools[frequency].select! do |pool|
|
332
|
+
pool.weakref_alive? && !pool.discarded?
|
333
|
+
end
|
334
|
+
|
335
|
+
@pools[frequency].each do |p|
|
336
|
+
p.reap
|
337
|
+
p.flush
|
338
|
+
rescue WeakRef::RefError
|
339
|
+
end
|
340
|
+
|
341
|
+
if @pools[frequency].empty?
|
342
|
+
@pools.delete(frequency)
|
343
|
+
@threads.delete(frequency)
|
344
|
+
running = false
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
297
352
|
def run
|
298
353
|
return unless frequency && frequency > 0
|
299
|
-
|
300
|
-
loop do
|
301
|
-
sleep t
|
302
|
-
p.reap
|
303
|
-
p.flush
|
304
|
-
end
|
305
|
-
}
|
354
|
+
self.class.register_pool(pool, frequency)
|
306
355
|
end
|
307
356
|
end
|
308
357
|
|
309
358
|
include MonitorMixin
|
310
359
|
include QueryCache::ConnectionPoolConfiguration
|
360
|
+
include ConnectionAdapters::AbstractPool
|
361
|
+
|
362
|
+
attr_accessor :automatic_reconnect, :checkout_timeout
|
363
|
+
attr_reader :db_config, :size, :reaper, :pool_config, :connection_klass
|
311
364
|
|
312
|
-
|
313
|
-
attr_reader :spec, :size, :reaper
|
365
|
+
delegate :schema_cache, :schema_cache=, to: :pool_config
|
314
366
|
|
315
|
-
# Creates a new ConnectionPool object. +
|
367
|
+
# Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
|
316
368
|
# object which describes database connection information (e.g. adapter,
|
317
369
|
# host name, username, password, etc), as well as the maximum size for
|
318
370
|
# this ConnectionPool.
|
319
371
|
#
|
320
372
|
# The default ConnectionPool maximum size is 5.
|
321
|
-
def initialize(
|
373
|
+
def initialize(pool_config)
|
322
374
|
super()
|
323
375
|
|
324
|
-
@
|
325
|
-
|
326
|
-
@
|
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
|
376
|
+
@pool_config = pool_config
|
377
|
+
@db_config = pool_config.db_config
|
378
|
+
@connection_klass = pool_config.connection_klass
|
331
379
|
|
332
|
-
|
333
|
-
@
|
380
|
+
@checkout_timeout = db_config.checkout_timeout
|
381
|
+
@idle_timeout = db_config.idle_timeout
|
382
|
+
@size = db_config.pool
|
334
383
|
|
335
384
|
# This variable tracks the cache of threads mapped to reserved connections, with the
|
336
385
|
# sole purpose of speeding up the +connection+ method. It is not the authoritative
|
337
386
|
# registry of which thread owns which connection. Connection ownership is tracked by
|
338
387
|
# the +connection.owner+ attr on each +connection+ instance.
|
339
388
|
# The invariant works like this: if there is mapping of <tt>thread => conn</tt>,
|
340
|
-
# 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
|
341
390
|
# mapping does not mean that the +thread+ doesn't own the said connection. In
|
342
391
|
# that case +conn.owner+ attr should be consulted.
|
343
392
|
# Access and modification of <tt>@thread_cached_conns</tt> does not require
|
@@ -358,10 +407,7 @@ module ActiveRecord
|
|
358
407
|
|
359
408
|
@lock_thread = false
|
360
409
|
|
361
|
-
|
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)
|
410
|
+
@reaper = Reaper.new(self, db_config.reaping_frequency)
|
365
411
|
@reaper.run
|
366
412
|
end
|
367
413
|
|
@@ -443,7 +489,7 @@ module ActiveRecord
|
|
443
489
|
# Raises:
|
444
490
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
445
491
|
# connections in the pool within a timeout interval (default duration is
|
446
|
-
# <tt>spec.
|
492
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
447
493
|
def disconnect(raise_on_acquisition_timeout = true)
|
448
494
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
449
495
|
synchronize do
|
@@ -464,7 +510,7 @@ module ActiveRecord
|
|
464
510
|
#
|
465
511
|
# The pool first tries to gain ownership of all connections. If unable to
|
466
512
|
# do so within a timeout interval (default duration is
|
467
|
-
# <tt>spec.
|
513
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
|
468
514
|
# disconnected without any regard for other connection owning threads.
|
469
515
|
def disconnect!
|
470
516
|
disconnect(false)
|
@@ -477,7 +523,7 @@ module ActiveRecord
|
|
477
523
|
# See AbstractAdapter#discard!
|
478
524
|
def discard! # :nodoc:
|
479
525
|
synchronize do
|
480
|
-
return if
|
526
|
+
return if self.discarded?
|
481
527
|
@connections.each do |conn|
|
482
528
|
conn.discard!
|
483
529
|
end
|
@@ -485,13 +531,17 @@ module ActiveRecord
|
|
485
531
|
end
|
486
532
|
end
|
487
533
|
|
534
|
+
def discarded? # :nodoc:
|
535
|
+
@connections.nil?
|
536
|
+
end
|
537
|
+
|
488
538
|
# Clears the cache which maps classes and re-connects connections that
|
489
539
|
# require reloading.
|
490
540
|
#
|
491
541
|
# Raises:
|
492
542
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
493
543
|
# connections in the pool within a timeout interval (default duration is
|
494
|
-
# <tt>spec.
|
544
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
495
545
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
496
546
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
497
547
|
synchronize do
|
@@ -513,7 +563,7 @@ module ActiveRecord
|
|
513
563
|
#
|
514
564
|
# The pool first tries to gain ownership of all connections. If unable to
|
515
565
|
# do so within a timeout interval (default duration is
|
516
|
-
# <tt>spec.
|
566
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
|
517
567
|
# clears the cache and reloads connections without any regard for other
|
518
568
|
# connection owning threads.
|
519
569
|
def clear_reloadable_connections!
|
@@ -593,6 +643,7 @@ module ActiveRecord
|
|
593
643
|
# or a thread dies unexpectedly.
|
594
644
|
def reap
|
595
645
|
stale_connections = synchronize do
|
646
|
+
return if self.discarded?
|
596
647
|
@connections.select do |conn|
|
597
648
|
conn.in_use? && !conn.owner.alive?
|
598
649
|
end.each do |conn|
|
@@ -617,6 +668,7 @@ module ActiveRecord
|
|
617
668
|
return if minimum_idle.nil?
|
618
669
|
|
619
670
|
idle_connections = synchronize do
|
671
|
+
return if self.discarded?
|
620
672
|
@connections.select do |conn|
|
621
673
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
622
674
|
end.each do |conn|
|
@@ -705,13 +757,13 @@ module ActiveRecord
|
|
705
757
|
end
|
706
758
|
|
707
759
|
newly_checked_out = []
|
708
|
-
timeout_time =
|
760
|
+
timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
|
709
761
|
|
710
762
|
@available.with_a_bias_for(Thread.current) do
|
711
763
|
loop do
|
712
764
|
synchronize do
|
713
765
|
return if collected_conns.size == @connections.size && @now_connecting == 0
|
714
|
-
remaining_timeout = timeout_time -
|
766
|
+
remaining_timeout = timeout_time - Concurrent.monotonic_time
|
715
767
|
remaining_timeout = 0 if remaining_timeout < 0
|
716
768
|
conn = checkout_for_exclusive_access(remaining_timeout)
|
717
769
|
collected_conns << conn
|
@@ -750,7 +802,7 @@ module ActiveRecord
|
|
750
802
|
# this block can't be easily moved into attempt_to_checkout_all_existing_connections's
|
751
803
|
# rescue block, because doing so would put it outside of synchronize section, without
|
752
804
|
# being in a critical section thread_report might become inaccurate
|
753
|
-
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
805
|
+
msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
754
806
|
|
755
807
|
thread_report = []
|
756
808
|
@connections.each do |conn|
|
@@ -827,8 +879,8 @@ module ActiveRecord
|
|
827
879
|
alias_method :release, :remove_connection_from_thread_cache
|
828
880
|
|
829
881
|
def new_connection
|
830
|
-
Base.
|
831
|
-
conn.
|
882
|
+
Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
|
883
|
+
conn.check_version
|
832
884
|
end
|
833
885
|
end
|
834
886
|
|
@@ -931,156 +983,246 @@ module ActiveRecord
|
|
931
983
|
# should use.
|
932
984
|
#
|
933
985
|
# The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
|
934
|
-
# 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,
|
935
987
|
# in order to look up the correct connection pool.
|
936
988
|
class ConnectionHandler
|
937
|
-
|
938
|
-
|
939
|
-
# Discard the parent's connection pools immediately; we have no need
|
940
|
-
# of them
|
941
|
-
discard_unowned_pools(h)
|
989
|
+
FINALIZER = lambda { |_| ActiveSupport::ForkTracker.check! }
|
990
|
+
private_constant :FINALIZER
|
942
991
|
|
943
|
-
|
944
|
-
|
992
|
+
def initialize
|
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)
|
995
|
+
|
996
|
+
# Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
|
997
|
+
ObjectSpace.define_finalizer self, FINALIZER
|
945
998
|
end
|
946
999
|
|
947
|
-
def
|
948
|
-
|
949
|
-
|
950
|
-
|
1000
|
+
def prevent_writes # :nodoc:
|
1001
|
+
Thread.current[:prevent_writes]
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def prevent_writes=(prevent_writes) # :nodoc:
|
1005
|
+
Thread.current[:prevent_writes] = prevent_writes
|
951
1006
|
end
|
952
1007
|
|
953
|
-
|
954
|
-
|
955
|
-
|
1008
|
+
# Prevent writing to the database regardless of role.
|
1009
|
+
#
|
1010
|
+
# In some cases you may want to prevent writes to the database
|
1011
|
+
# even if you are on a database that can write. `while_preventing_writes`
|
1012
|
+
# will prevent writes to the database for the duration of the block.
|
1013
|
+
#
|
1014
|
+
# This method does not provide the same protection as a readonly
|
1015
|
+
# user and is meant to be a safeguard against accidental writes.
|
1016
|
+
#
|
1017
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
1018
|
+
# method.
|
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"
|
956
1022
|
end
|
1023
|
+
|
1024
|
+
original, self.prevent_writes = self.prevent_writes, enabled
|
1025
|
+
yield
|
1026
|
+
ensure
|
1027
|
+
self.prevent_writes = original
|
957
1028
|
end
|
958
1029
|
|
959
|
-
def
|
960
|
-
|
961
|
-
|
1030
|
+
def connection_pool_names # :nodoc:
|
1031
|
+
owner_to_pool_manager.keys
|
1032
|
+
end
|
962
1033
|
|
963
|
-
|
964
|
-
|
965
|
-
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
1034
|
+
def all_connection_pools
|
1035
|
+
owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
|
966
1036
|
end
|
967
1037
|
|
968
|
-
def connection_pool_list
|
969
|
-
|
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) }
|
970
1040
|
end
|
971
1041
|
alias :connection_pools :connection_pool_list
|
972
1042
|
|
973
|
-
def establish_connection(config)
|
974
|
-
|
975
|
-
|
1043
|
+
def establish_connection(config, owner_name: Base, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
|
1044
|
+
owner_name = config.to_s if config.is_a?(Symbol)
|
1045
|
+
|
1046
|
+
pool_config = resolve_pool_config(config, owner_name)
|
1047
|
+
db_config = pool_config.db_config
|
976
1048
|
|
977
|
-
|
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
|
978
1054
|
|
979
1055
|
message_bus = ActiveSupport::Notifications.instrumenter
|
980
|
-
payload = {
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
payload[:
|
985
|
-
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
|
986
1061
|
end
|
987
1062
|
|
988
|
-
|
989
|
-
|
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
|
990
1067
|
end
|
1068
|
+
pool_manager = get_pool_manager(pool_config.connection_specification_name)
|
1069
|
+
pool_manager.set_pool_config(role, shard, pool_config)
|
991
1070
|
|
992
|
-
|
1071
|
+
message_bus.instrument("!connection.active_record", payload) do
|
1072
|
+
pool_config.pool
|
1073
|
+
end
|
993
1074
|
end
|
994
1075
|
|
995
1076
|
# Returns true if there are any active connections among the connection
|
996
1077
|
# pools that the ConnectionHandler is managing.
|
997
|
-
def active_connections?
|
998
|
-
connection_pool_list.any?(&:active_connection?)
|
1078
|
+
def active_connections?(role = ActiveRecord::Base.current_role)
|
1079
|
+
connection_pool_list(role).any?(&:active_connection?)
|
999
1080
|
end
|
1000
1081
|
|
1001
1082
|
# Returns any connections in use by the current thread back to the pool,
|
1002
1083
|
# and also returns connections to the pool cached by threads that are no
|
1003
1084
|
# longer alive.
|
1004
|
-
def clear_active_connections!
|
1005
|
-
connection_pool_list.each(&:release_connection)
|
1085
|
+
def clear_active_connections!(role = ActiveRecord::Base.current_role)
|
1086
|
+
connection_pool_list(role).each(&:release_connection)
|
1006
1087
|
end
|
1007
1088
|
|
1008
1089
|
# Clears the cache which maps classes.
|
1009
1090
|
#
|
1010
1091
|
# See ConnectionPool#clear_reloadable_connections! for details.
|
1011
|
-
def clear_reloadable_connections!
|
1012
|
-
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!)
|
1013
1094
|
end
|
1014
1095
|
|
1015
|
-
def clear_all_connections!
|
1016
|
-
connection_pool_list.each(&:disconnect!)
|
1096
|
+
def clear_all_connections!(role = ActiveRecord::Base.current_role)
|
1097
|
+
connection_pool_list(role).each(&:disconnect!)
|
1017
1098
|
end
|
1018
1099
|
|
1019
1100
|
# Disconnects all currently idle connections.
|
1020
1101
|
#
|
1021
1102
|
# See ConnectionPool#flush! for details.
|
1022
|
-
def flush_idle_connections!
|
1023
|
-
connection_pool_list.each(&:flush!)
|
1103
|
+
def flush_idle_connections!(role = ActiveRecord::Base.current_role)
|
1104
|
+
connection_pool_list(role).each(&:flush!)
|
1024
1105
|
end
|
1025
1106
|
|
1026
1107
|
# Locate the connection of the nearest super class. This can be an
|
1027
1108
|
# active or defined connection: if it is the latter, it will be
|
1028
1109
|
# opened and set as the active connection for the class it was defined
|
1029
1110
|
# for (not necessarily the current class).
|
1030
|
-
def retrieve_connection(spec_name)
|
1031
|
-
pool = retrieve_connection_pool(spec_name)
|
1032
|
-
|
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)
|
1113
|
+
|
1114
|
+
unless pool
|
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."
|
1121
|
+
else
|
1122
|
+
message = "No connection pool for '#{spec_name}' found."
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
raise ConnectionNotEstablished, message
|
1126
|
+
end
|
1127
|
+
|
1033
1128
|
pool.connection
|
1034
1129
|
end
|
1035
1130
|
|
1036
1131
|
# Returns true if a connection that's accessible to this class has
|
1037
1132
|
# already been opened.
|
1038
|
-
def connected?(spec_name)
|
1039
|
-
|
1040
|
-
|
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)
|
1135
|
+
pool && pool.connected?
|
1041
1136
|
end
|
1042
1137
|
|
1043
1138
|
# Remove the connection for this class. This will close the active
|
1044
1139
|
# connection and the defined connection (if they exist). The result
|
1045
1140
|
# can be used as an argument for #establish_connection, for easily
|
1046
1141
|
# re-establishing the connection.
|
1047
|
-
def remove_connection(
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
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
|
1052
1155
|
end
|
1053
1156
|
end
|
1054
1157
|
|
1055
|
-
# 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.
|
1056
1159
|
# This makes retrieving the connection pool O(1) once the process is warm.
|
1057
1160
|
# When a connection is established or removed, we invalidate the cache.
|
1058
|
-
def retrieve_connection_pool(
|
1059
|
-
|
1060
|
-
|
1061
|
-
# which may have been forked.
|
1062
|
-
if ancestor_pool = pool_from_any_process_for(spec_name)
|
1063
|
-
# A connection was established in an ancestor process that must have
|
1064
|
-
# subsequently forked. We can't reuse the connection, but we can copy
|
1065
|
-
# the specification and establish a new connection with it.
|
1066
|
-
establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
|
1067
|
-
pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
|
1068
|
-
end
|
1069
|
-
else
|
1070
|
-
owner_to_pool[spec_name] = nil
|
1071
|
-
end
|
1072
|
-
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
|
1073
1164
|
end
|
1074
1165
|
|
1075
1166
|
private
|
1167
|
+
attr_reader :owner_to_pool_manager
|
1076
1168
|
|
1077
|
-
|
1078
|
-
|
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
|
1079
1183
|
end
|
1080
1184
|
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
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)
|
1084
1226
|
end
|
1085
1227
|
end
|
1086
1228
|
end
|