activerecord 5.2.8 → 7.0.2
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 +1393 -587
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +10 -9
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +122 -47
- data/lib/active_record/associations/association_scope.rb +24 -24
- data/lib/active_record/associations/belongs_to_association.rb +67 -49
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
- data/lib/active_record/associations/builder/association.rb +52 -23
- data/lib/active_record/associations/builder/belongs_to.rb +44 -61
- data/lib/active_record/associations/builder/collection_association.rb +17 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +10 -3
- data/lib/active_record/associations/builder/has_one.rb +35 -3
- data/lib/active_record/associations/builder/singular_association.rb +5 -3
- data/lib/active_record/associations/collection_association.rb +59 -50
- data/lib/active_record/associations/collection_proxy.rb +32 -23
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +27 -14
- data/lib/active_record/associations/has_many_through_association.rb +26 -19
- data/lib/active_record/associations/has_one_association.rb +52 -37
- data/lib/active_record/associations/has_one_through_association.rb +6 -6
- 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 +97 -62
- data/lib/active_record/associations/preloader/association.rb +220 -60
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +85 -40
- data/lib/active_record/associations/preloader.rb +44 -105
- data/lib/active_record/associations/singular_association.rb +9 -17
- data/lib/active_record/associations/through_association.rb +4 -4
- data/lib/active_record/associations.rb +207 -66
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
- data/lib/active_record/attribute_methods/dirty.rb +141 -47
- data/lib/active_record/attribute_methods/primary_key.rb +22 -27
- data/lib/active_record/attribute_methods/query.rb +6 -10
- data/lib/active_record/attribute_methods/read.rb +15 -55
- data/lib/active_record/attribute_methods/serialization.rb +77 -18
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
- data/lib/active_record/attribute_methods/write.rb +18 -37
- data/lib/active_record/attribute_methods.rb +90 -153
- data/lib/active_record/attributes.rb +38 -12
- data/lib/active_record/autosave_association.rb +50 -50
- data/lib/active_record/base.rb +23 -18
- data/lib/active_record/callbacks.rb +159 -44
- data/lib/active_record/coders/yaml_column.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
- data/lib/active_record/connection_adapters/column.rb +33 -11
- 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 +113 -45
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
- 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 +25 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
- 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 +53 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
- 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 +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
- 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/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
- 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 +386 -182
- data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +53 -0
- data/lib/active_record/connection_handling.rb +292 -38
- data/lib/active_record/core.rb +385 -158
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
- data/lib/active_record/database_configurations/database_config.rb +83 -0
- data/lib/active_record/database_configurations/hash_config.rb +154 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +256 -0
- data/lib/active_record/delegated_type.rb +250 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +4 -5
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +130 -51
- data/lib/active_record/errors.rb +129 -23
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +22 -15
- 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 +187 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +206 -490
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +104 -37
- data/lib/active_record/insert_all.rb +278 -0
- data/lib/active_record/integration.rb +69 -18
- data/lib/active_record/internal_metadata.rb +24 -9
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +41 -26
- data/lib/active_record/locking/pessimistic.rb +18 -8
- data/lib/active_record/log_subscriber.rb +46 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector.rb +82 -0
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +246 -64
- data/lib/active_record/migration/join_table.rb +1 -2
- data/lib/active_record/migration.rb +266 -187
- data/lib/active_record/model_schema.rb +165 -52
- data/lib/active_record/nested_attributes.rb +17 -19
- data/lib/active_record/no_touching.rb +11 -4
- data/lib/active_record/null_relation.rb +2 -7
- data/lib/active_record/persistence.rb +467 -92
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +51 -24
- data/lib/active_record/railtie.rb +224 -57
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +31 -36
- data/lib/active_record/railties/databases.rake +369 -101
- data/lib/active_record/readonly_attributes.rb +15 -0
- data/lib/active_record/reflection.rb +170 -137
- data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
- data/lib/active_record/relation/batches.rb +46 -37
- data/lib/active_record/relation/calculations.rb +168 -96
- data/lib/active_record/relation/delegation.rb +37 -52
- data/lib/active_record/relation/finder_methods.rb +79 -58
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +50 -51
- 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 +58 -46
- data/lib/active_record/relation/query_attribute.rb +9 -10
- data/lib/active_record/relation/query_methods.rb +685 -208
- data/lib/active_record/relation/record_fetch_warning.rb +9 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -10
- data/lib/active_record/relation/where_clause.rb +108 -64
- data/lib/active_record/relation.rb +515 -151
- data/lib/active_record/result.rb +78 -42
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +29 -44
- data/lib/active_record/schema.rb +37 -31
- data/lib/active_record/schema_dumper.rb +74 -23
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +62 -17
- data/lib/active_record/scoping/named.rb +17 -32
- data/lib/active_record/scoping.rb +70 -41
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +6 -4
- 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 +13 -17
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +352 -94
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
- 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 +44 -34
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +67 -128
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +34 -19
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +7 -4
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +9 -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 +2 -3
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +39 -31
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +209 -32
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +33 -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 +48 -0
- data/lib/arel/delete_manager.rb +32 -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/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +48 -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 +44 -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/filter.rb +10 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +45 -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 +46 -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 +71 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +258 -0
- data/lib/arel/select_manager.rb +276 -0
- data/lib/arel/table.rb +117 -0
- data/lib/arel/tree_manager.rb +60 -0
- data/lib/arel/update_manager.rb +48 -0
- data/lib/arel/visitors/dot.rb +298 -0
- data/lib/arel/visitors/mysql.rb +99 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +955 -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 +55 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -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
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +162 -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
@@ -4,21 +4,41 @@ require "thread"
|
|
4
4
|
require "concurrent/map"
|
5
5
|
require "monitor"
|
6
6
|
|
7
|
+
require "active_record/connection_adapters/abstract/connection_pool/queue"
|
8
|
+
require "active_record/connection_adapters/abstract/connection_pool/reaper"
|
9
|
+
|
7
10
|
module ActiveRecord
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
module ConnectionAdapters
|
12
|
+
module AbstractPool # :nodoc:
|
13
|
+
def get_schema_cache(connection)
|
14
|
+
self.schema_cache ||= SchemaCache.new(connection)
|
15
|
+
schema_cache.connection = connection
|
16
|
+
schema_cache
|
17
|
+
end
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
def set_schema_cache(cache)
|
20
|
+
self.schema_cache = cache
|
21
|
+
end
|
22
|
+
|
23
|
+
def lazily_set_schema_cache
|
24
|
+
return unless ActiveRecord.lazily_load_schema_cache
|
25
|
+
|
26
|
+
cache = SchemaCache.load_from(db_config.lazy_schema_cache_path)
|
27
|
+
set_schema_cache(cache)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class NullPool # :nodoc:
|
32
|
+
include ConnectionAdapters::AbstractPool
|
33
|
+
|
34
|
+
attr_accessor :schema_cache
|
35
|
+
|
36
|
+
def connection_class; end
|
37
|
+
def checkin(_); end
|
38
|
+
def remove(_); end
|
39
|
+
def async_executor; end
|
40
|
+
end
|
20
41
|
|
21
|
-
module ConnectionAdapters
|
22
42
|
# Connection pool base class for managing Active Record database
|
23
43
|
# connections.
|
24
44
|
#
|
@@ -80,264 +100,42 @@ module ActiveRecord
|
|
80
100
|
# * private methods that require being called in a +synchronize+ blocks
|
81
101
|
# are now explicitly documented
|
82
102
|
class ConnectionPool
|
83
|
-
# Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
|
84
|
-
# with which it shares a Monitor.
|
85
|
-
class Queue
|
86
|
-
def initialize(lock = Monitor.new)
|
87
|
-
@lock = lock
|
88
|
-
@cond = @lock.new_cond
|
89
|
-
@num_waiting = 0
|
90
|
-
@queue = []
|
91
|
-
end
|
92
|
-
|
93
|
-
# Test if any threads are currently waiting on the queue.
|
94
|
-
def any_waiting?
|
95
|
-
synchronize do
|
96
|
-
@num_waiting > 0
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns the number of threads currently waiting on this
|
101
|
-
# queue.
|
102
|
-
def num_waiting
|
103
|
-
synchronize do
|
104
|
-
@num_waiting
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Add +element+ to the queue. Never blocks.
|
109
|
-
def add(element)
|
110
|
-
synchronize do
|
111
|
-
@queue.push element
|
112
|
-
@cond.signal
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# If +element+ is in the queue, remove and return it, or +nil+.
|
117
|
-
def delete(element)
|
118
|
-
synchronize do
|
119
|
-
@queue.delete(element)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# Remove all elements from the queue.
|
124
|
-
def clear
|
125
|
-
synchronize do
|
126
|
-
@queue.clear
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# Remove the head of the queue.
|
131
|
-
#
|
132
|
-
# If +timeout+ is not given, remove and return the head the
|
133
|
-
# queue if the number of available elements is strictly
|
134
|
-
# greater than the number of threads currently waiting (that
|
135
|
-
# is, don't jump ahead in line). Otherwise, return +nil+.
|
136
|
-
#
|
137
|
-
# If +timeout+ is given, block if there is no element
|
138
|
-
# available, waiting up to +timeout+ seconds for an element to
|
139
|
-
# become available.
|
140
|
-
#
|
141
|
-
# Raises:
|
142
|
-
# - ActiveRecord::ConnectionTimeoutError if +timeout+ is given and no element
|
143
|
-
# becomes available within +timeout+ seconds,
|
144
|
-
def poll(timeout = nil)
|
145
|
-
synchronize { internal_poll(timeout) }
|
146
|
-
end
|
147
|
-
|
148
|
-
private
|
149
|
-
|
150
|
-
def internal_poll(timeout)
|
151
|
-
no_wait_poll || (timeout && wait_poll(timeout))
|
152
|
-
end
|
153
|
-
|
154
|
-
def synchronize(&block)
|
155
|
-
@lock.synchronize(&block)
|
156
|
-
end
|
157
|
-
|
158
|
-
# Test if the queue currently contains any elements.
|
159
|
-
def any?
|
160
|
-
!@queue.empty?
|
161
|
-
end
|
162
|
-
|
163
|
-
# A thread can remove an element from the queue without
|
164
|
-
# waiting if and only if the number of currently available
|
165
|
-
# connections is strictly greater than the number of waiting
|
166
|
-
# threads.
|
167
|
-
def can_remove_no_wait?
|
168
|
-
@queue.size > @num_waiting
|
169
|
-
end
|
170
|
-
|
171
|
-
# Removes and returns the head of the queue if possible, or +nil+.
|
172
|
-
def remove
|
173
|
-
@queue.pop
|
174
|
-
end
|
175
|
-
|
176
|
-
# Remove and return the head the queue if the number of
|
177
|
-
# available elements is strictly greater than the number of
|
178
|
-
# threads currently waiting. Otherwise, return +nil+.
|
179
|
-
def no_wait_poll
|
180
|
-
remove if can_remove_no_wait?
|
181
|
-
end
|
182
|
-
|
183
|
-
# Waits on the queue up to +timeout+ seconds, then removes and
|
184
|
-
# returns the head of the queue.
|
185
|
-
def wait_poll(timeout)
|
186
|
-
@num_waiting += 1
|
187
|
-
|
188
|
-
t0 = Time.now
|
189
|
-
elapsed = 0
|
190
|
-
loop do
|
191
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
192
|
-
@cond.wait(timeout - elapsed)
|
193
|
-
end
|
194
|
-
|
195
|
-
return remove if any?
|
196
|
-
|
197
|
-
elapsed = Time.now - t0
|
198
|
-
if elapsed >= timeout
|
199
|
-
msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
|
200
|
-
[timeout, elapsed]
|
201
|
-
raise ConnectionTimeoutError, msg
|
202
|
-
end
|
203
|
-
end
|
204
|
-
ensure
|
205
|
-
@num_waiting -= 1
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Adds the ability to turn a basic fair FIFO queue into one
|
210
|
-
# biased to some thread.
|
211
|
-
module BiasableQueue # :nodoc:
|
212
|
-
class BiasedConditionVariable # :nodoc:
|
213
|
-
# semantics of condition variables guarantee that +broadcast+, +broadcast_on_biased+,
|
214
|
-
# +signal+ and +wait+ methods are only called while holding a lock
|
215
|
-
def initialize(lock, other_cond, preferred_thread)
|
216
|
-
@real_cond = lock.new_cond
|
217
|
-
@other_cond = other_cond
|
218
|
-
@preferred_thread = preferred_thread
|
219
|
-
@num_waiting_on_real_cond = 0
|
220
|
-
end
|
221
|
-
|
222
|
-
def broadcast
|
223
|
-
broadcast_on_biased
|
224
|
-
@other_cond.broadcast
|
225
|
-
end
|
226
|
-
|
227
|
-
def broadcast_on_biased
|
228
|
-
@num_waiting_on_real_cond = 0
|
229
|
-
@real_cond.broadcast
|
230
|
-
end
|
231
|
-
|
232
|
-
def signal
|
233
|
-
if @num_waiting_on_real_cond > 0
|
234
|
-
@num_waiting_on_real_cond -= 1
|
235
|
-
@real_cond
|
236
|
-
else
|
237
|
-
@other_cond
|
238
|
-
end.signal
|
239
|
-
end
|
240
|
-
|
241
|
-
def wait(timeout)
|
242
|
-
if Thread.current == @preferred_thread
|
243
|
-
@num_waiting_on_real_cond += 1
|
244
|
-
@real_cond
|
245
|
-
else
|
246
|
-
@other_cond
|
247
|
-
end.wait(timeout)
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
def with_a_bias_for(thread)
|
252
|
-
previous_cond = nil
|
253
|
-
new_cond = nil
|
254
|
-
synchronize do
|
255
|
-
previous_cond = @cond
|
256
|
-
@cond = new_cond = BiasedConditionVariable.new(@lock, @cond, thread)
|
257
|
-
end
|
258
|
-
yield
|
259
|
-
ensure
|
260
|
-
synchronize do
|
261
|
-
@cond = previous_cond if previous_cond
|
262
|
-
new_cond.broadcast_on_biased if new_cond # wake up any remaining sleepers
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
# Connections must be leased while holding the main pool mutex. This is
|
268
|
-
# an internal subclass that also +.leases+ returned connections while
|
269
|
-
# still in queue's critical section (queue synchronizes with the same
|
270
|
-
# <tt>@lock</tt> as the main pool) so that a returned connection is already
|
271
|
-
# leased and there is no need to re-enter synchronized block.
|
272
|
-
class ConnectionLeasingQueue < Queue # :nodoc:
|
273
|
-
include BiasableQueue
|
274
|
-
|
275
|
-
private
|
276
|
-
def internal_poll(timeout)
|
277
|
-
conn = super
|
278
|
-
conn.lease if conn
|
279
|
-
conn
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
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.
|
286
|
-
#
|
287
|
-
# Configure the frequency by setting +reaping_frequency+ in your database
|
288
|
-
# yaml file (default 60 seconds).
|
289
|
-
class Reaper
|
290
|
-
attr_reader :pool, :frequency
|
291
|
-
|
292
|
-
def initialize(pool, frequency)
|
293
|
-
@pool = pool
|
294
|
-
@frequency = frequency
|
295
|
-
end
|
296
|
-
|
297
|
-
def run
|
298
|
-
return unless frequency && frequency > 0
|
299
|
-
Thread.new(frequency, pool) { |t, p|
|
300
|
-
loop do
|
301
|
-
sleep t
|
302
|
-
p.reap
|
303
|
-
p.flush
|
304
|
-
end
|
305
|
-
}
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
103
|
include MonitorMixin
|
310
104
|
include QueryCache::ConnectionPoolConfiguration
|
105
|
+
include ConnectionAdapters::AbstractPool
|
311
106
|
|
312
|
-
attr_accessor :automatic_reconnect, :checkout_timeout
|
313
|
-
attr_reader :
|
107
|
+
attr_accessor :automatic_reconnect, :checkout_timeout
|
108
|
+
attr_reader :db_config, :size, :reaper, :pool_config, :connection_class, :async_executor, :role, :shard
|
314
109
|
|
315
|
-
|
110
|
+
alias_method :connection_klass, :connection_class
|
111
|
+
deprecate :connection_klass
|
112
|
+
delegate :schema_cache, :schema_cache=, to: :pool_config
|
113
|
+
|
114
|
+
# Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
|
316
115
|
# object which describes database connection information (e.g. adapter,
|
317
116
|
# host name, username, password, etc), as well as the maximum size for
|
318
117
|
# this ConnectionPool.
|
319
118
|
#
|
320
119
|
# The default ConnectionPool maximum size is 5.
|
321
|
-
def initialize(
|
120
|
+
def initialize(pool_config)
|
322
121
|
super()
|
323
122
|
|
324
|
-
@
|
325
|
-
|
326
|
-
@
|
327
|
-
|
328
|
-
|
329
|
-
@idle_timeout = nil if @idle_timeout <= 0
|
330
|
-
end
|
123
|
+
@pool_config = pool_config
|
124
|
+
@db_config = pool_config.db_config
|
125
|
+
@connection_class = pool_config.connection_class
|
126
|
+
@role = pool_config.role
|
127
|
+
@shard = pool_config.shard
|
331
128
|
|
332
|
-
|
333
|
-
@
|
129
|
+
@checkout_timeout = db_config.checkout_timeout
|
130
|
+
@idle_timeout = db_config.idle_timeout
|
131
|
+
@size = db_config.pool
|
334
132
|
|
335
133
|
# This variable tracks the cache of threads mapped to reserved connections, with the
|
336
134
|
# sole purpose of speeding up the +connection+ method. It is not the authoritative
|
337
135
|
# registry of which thread owns which connection. Connection ownership is tracked by
|
338
136
|
# the +connection.owner+ attr on each +connection+ instance.
|
339
137
|
# 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
|
138
|
+
# then that +thread+ does indeed own that +conn+. However, an absence of such
|
341
139
|
# mapping does not mean that the +thread+ doesn't own the said connection. In
|
342
140
|
# that case +conn.owner+ attr should be consulted.
|
343
141
|
# Access and modification of <tt>@thread_cached_conns</tt> does not require
|
@@ -358,10 +156,11 @@ module ActiveRecord
|
|
358
156
|
|
359
157
|
@lock_thread = false
|
360
158
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
159
|
+
@async_executor = build_async_executor
|
160
|
+
|
161
|
+
lazily_set_schema_cache
|
162
|
+
|
163
|
+
@reaper = Reaper.new(self, db_config.reaping_frequency)
|
365
164
|
@reaper.run
|
366
165
|
end
|
367
166
|
|
@@ -443,7 +242,7 @@ module ActiveRecord
|
|
443
242
|
# Raises:
|
444
243
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
445
244
|
# connections in the pool within a timeout interval (default duration is
|
446
|
-
# <tt>spec.
|
245
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
447
246
|
def disconnect(raise_on_acquisition_timeout = true)
|
448
247
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
449
248
|
synchronize do
|
@@ -464,7 +263,7 @@ module ActiveRecord
|
|
464
263
|
#
|
465
264
|
# The pool first tries to gain ownership of all connections. If unable to
|
466
265
|
# do so within a timeout interval (default duration is
|
467
|
-
# <tt>spec.
|
266
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
|
468
267
|
# disconnected without any regard for other connection owning threads.
|
469
268
|
def disconnect!
|
470
269
|
disconnect(false)
|
@@ -477,7 +276,7 @@ module ActiveRecord
|
|
477
276
|
# See AbstractAdapter#discard!
|
478
277
|
def discard! # :nodoc:
|
479
278
|
synchronize do
|
480
|
-
return if
|
279
|
+
return if self.discarded?
|
481
280
|
@connections.each do |conn|
|
482
281
|
conn.discard!
|
483
282
|
end
|
@@ -485,13 +284,17 @@ module ActiveRecord
|
|
485
284
|
end
|
486
285
|
end
|
487
286
|
|
287
|
+
def discarded? # :nodoc:
|
288
|
+
@connections.nil?
|
289
|
+
end
|
290
|
+
|
488
291
|
# Clears the cache which maps classes and re-connects connections that
|
489
292
|
# require reloading.
|
490
293
|
#
|
491
294
|
# Raises:
|
492
295
|
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
493
296
|
# connections in the pool within a timeout interval (default duration is
|
494
|
-
# <tt>spec.
|
297
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
|
495
298
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
496
299
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
497
300
|
synchronize do
|
@@ -513,7 +316,7 @@ module ActiveRecord
|
|
513
316
|
#
|
514
317
|
# The pool first tries to gain ownership of all connections. If unable to
|
515
318
|
# do so within a timeout interval (default duration is
|
516
|
-
# <tt>spec.
|
319
|
+
# <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
|
517
320
|
# clears the cache and reloads connections without any regard for other
|
518
321
|
# connection owning threads.
|
519
322
|
def clear_reloadable_connections!
|
@@ -593,6 +396,7 @@ module ActiveRecord
|
|
593
396
|
# or a thread dies unexpectedly.
|
594
397
|
def reap
|
595
398
|
stale_connections = synchronize do
|
399
|
+
return if self.discarded?
|
596
400
|
@connections.select do |conn|
|
597
401
|
conn.in_use? && !conn.owner.alive?
|
598
402
|
end.each do |conn|
|
@@ -617,6 +421,7 @@ module ActiveRecord
|
|
617
421
|
return if minimum_idle.nil?
|
618
422
|
|
619
423
|
idle_connections = synchronize do
|
424
|
+
return if self.discarded?
|
620
425
|
@connections.select do |conn|
|
621
426
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
622
427
|
end.each do |conn|
|
@@ -661,7 +466,28 @@ module ActiveRecord
|
|
661
466
|
end
|
662
467
|
end
|
663
468
|
|
469
|
+
def schedule_query(future_result) # :nodoc:
|
470
|
+
@async_executor.post { future_result.execute_or_skip }
|
471
|
+
Thread.pass
|
472
|
+
end
|
473
|
+
|
664
474
|
private
|
475
|
+
def build_async_executor
|
476
|
+
case ActiveRecord.async_query_executor
|
477
|
+
when :multi_thread_pool
|
478
|
+
if @db_config.max_threads > 0
|
479
|
+
Concurrent::ThreadPoolExecutor.new(
|
480
|
+
min_threads: @db_config.min_threads,
|
481
|
+
max_threads: @db_config.max_threads,
|
482
|
+
max_queue: @db_config.max_queue,
|
483
|
+
fallback_policy: :caller_runs
|
484
|
+
)
|
485
|
+
end
|
486
|
+
when :global_thread_pool
|
487
|
+
ActiveRecord.global_thread_pool_async_query_executor
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
665
491
|
#--
|
666
492
|
# this is unfortunately not concurrent
|
667
493
|
def bulk_make_new_connections(num_new_conns_needed)
|
@@ -705,13 +531,13 @@ module ActiveRecord
|
|
705
531
|
end
|
706
532
|
|
707
533
|
newly_checked_out = []
|
708
|
-
timeout_time =
|
534
|
+
timeout_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + (@checkout_timeout * 2)
|
709
535
|
|
710
536
|
@available.with_a_bias_for(Thread.current) do
|
711
537
|
loop do
|
712
538
|
synchronize do
|
713
539
|
return if collected_conns.size == @connections.size && @now_connecting == 0
|
714
|
-
remaining_timeout = timeout_time -
|
540
|
+
remaining_timeout = timeout_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
715
541
|
remaining_timeout = 0 if remaining_timeout < 0
|
716
542
|
conn = checkout_for_exclusive_access(remaining_timeout)
|
717
543
|
collected_conns << conn
|
@@ -750,7 +576,7 @@ module ActiveRecord
|
|
750
576
|
# this block can't be easily moved into attempt_to_checkout_all_existing_connections's
|
751
577
|
# rescue block, because doing so would put it outside of synchronize section, without
|
752
578
|
# being in a critical section thread_report might become inaccurate
|
753
|
-
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
579
|
+
msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
754
580
|
|
755
581
|
thread_report = []
|
756
582
|
@connections.each do |conn|
|
@@ -827,8 +653,8 @@ module ActiveRecord
|
|
827
653
|
alias_method :release, :remove_connection_from_thread_cache
|
828
654
|
|
829
655
|
def new_connection
|
830
|
-
Base.
|
831
|
-
conn.
|
656
|
+
Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
|
657
|
+
conn.check_version
|
832
658
|
end
|
833
659
|
end
|
834
660
|
|
@@ -885,203 +711,5 @@ module ActiveRecord
|
|
885
711
|
raise
|
886
712
|
end
|
887
713
|
end
|
888
|
-
|
889
|
-
# ConnectionHandler is a collection of ConnectionPool objects. It is used
|
890
|
-
# for keeping separate connection pools that connect to different databases.
|
891
|
-
#
|
892
|
-
# For example, suppose that you have 5 models, with the following hierarchy:
|
893
|
-
#
|
894
|
-
# class Author < ActiveRecord::Base
|
895
|
-
# end
|
896
|
-
#
|
897
|
-
# class BankAccount < ActiveRecord::Base
|
898
|
-
# end
|
899
|
-
#
|
900
|
-
# class Book < ActiveRecord::Base
|
901
|
-
# establish_connection :library_db
|
902
|
-
# end
|
903
|
-
#
|
904
|
-
# class ScaryBook < Book
|
905
|
-
# end
|
906
|
-
#
|
907
|
-
# class GoodBook < Book
|
908
|
-
# end
|
909
|
-
#
|
910
|
-
# And a database.yml that looked like this:
|
911
|
-
#
|
912
|
-
# development:
|
913
|
-
# database: my_application
|
914
|
-
# host: localhost
|
915
|
-
#
|
916
|
-
# library_db:
|
917
|
-
# database: library
|
918
|
-
# host: some.library.org
|
919
|
-
#
|
920
|
-
# Your primary database in the development environment is "my_application"
|
921
|
-
# but the Book model connects to a separate database called "library_db"
|
922
|
-
# (this can even be a database on a different machine).
|
923
|
-
#
|
924
|
-
# Book, ScaryBook and GoodBook will all use the same connection pool to
|
925
|
-
# "library_db" while Author, BankAccount, and any other models you create
|
926
|
-
# will use the default connection pool to "my_application".
|
927
|
-
#
|
928
|
-
# The various connection pools are managed by a single instance of
|
929
|
-
# ConnectionHandler accessible via ActiveRecord::Base.connection_handler.
|
930
|
-
# All Active Record models use this handler to determine the connection pool that they
|
931
|
-
# should use.
|
932
|
-
#
|
933
|
-
# 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,
|
935
|
-
# in order to look up the correct connection pool.
|
936
|
-
class ConnectionHandler
|
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
|
-
|
943
|
-
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
944
|
-
end
|
945
|
-
end
|
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
|
-
|
968
|
-
def connection_pool_list
|
969
|
-
owner_to_pool.values.compact
|
970
|
-
end
|
971
|
-
alias :connection_pools :connection_pool_list
|
972
|
-
|
973
|
-
def establish_connection(config)
|
974
|
-
resolver = ConnectionSpecification::Resolver.new(Base.configurations)
|
975
|
-
spec = resolver.spec(config)
|
976
|
-
|
977
|
-
remove_connection(spec.name)
|
978
|
-
|
979
|
-
message_bus = ActiveSupport::Notifications.instrumenter
|
980
|
-
payload = {
|
981
|
-
connection_id: object_id
|
982
|
-
}
|
983
|
-
if spec
|
984
|
-
payload[:spec_name] = spec.name
|
985
|
-
payload[:config] = spec.config
|
986
|
-
end
|
987
|
-
|
988
|
-
message_bus.instrument("!connection.active_record", payload) do
|
989
|
-
owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec)
|
990
|
-
end
|
991
|
-
|
992
|
-
owner_to_pool[spec.name]
|
993
|
-
end
|
994
|
-
|
995
|
-
# Returns true if there are any active connections among the connection
|
996
|
-
# pools that the ConnectionHandler is managing.
|
997
|
-
def active_connections?
|
998
|
-
connection_pool_list.any?(&:active_connection?)
|
999
|
-
end
|
1000
|
-
|
1001
|
-
# Returns any connections in use by the current thread back to the pool,
|
1002
|
-
# and also returns connections to the pool cached by threads that are no
|
1003
|
-
# longer alive.
|
1004
|
-
def clear_active_connections!
|
1005
|
-
connection_pool_list.each(&:release_connection)
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
# Clears the cache which maps classes.
|
1009
|
-
#
|
1010
|
-
# See ConnectionPool#clear_reloadable_connections! for details.
|
1011
|
-
def clear_reloadable_connections!
|
1012
|
-
connection_pool_list.each(&:clear_reloadable_connections!)
|
1013
|
-
end
|
1014
|
-
|
1015
|
-
def clear_all_connections!
|
1016
|
-
connection_pool_list.each(&:disconnect!)
|
1017
|
-
end
|
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
|
-
|
1026
|
-
# Locate the connection of the nearest super class. This can be an
|
1027
|
-
# active or defined connection: if it is the latter, it will be
|
1028
|
-
# opened and set as the active connection for the class it was defined
|
1029
|
-
# for (not necessarily the current class).
|
1030
|
-
def retrieve_connection(spec_name) #:nodoc:
|
1031
|
-
pool = retrieve_connection_pool(spec_name)
|
1032
|
-
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
|
1033
|
-
pool.connection
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
# Returns true if a connection that's accessible to this class has
|
1037
|
-
# already been opened.
|
1038
|
-
def connected?(spec_name)
|
1039
|
-
conn = retrieve_connection_pool(spec_name)
|
1040
|
-
conn && conn.connected?
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
# Remove the connection for this class. This will close the active
|
1044
|
-
# connection and the defined connection (if they exist). The result
|
1045
|
-
# can be used as an argument for #establish_connection, for easily
|
1046
|
-
# re-establishing the connection.
|
1047
|
-
def remove_connection(spec_name)
|
1048
|
-
if pool = owner_to_pool.delete(spec_name)
|
1049
|
-
pool.automatic_reconnect = false
|
1050
|
-
pool.disconnect!
|
1051
|
-
pool.spec.config
|
1052
|
-
end
|
1053
|
-
end
|
1054
|
-
|
1055
|
-
# Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool.
|
1056
|
-
# This makes retrieving the connection pool O(1) once the process is warm.
|
1057
|
-
# When a connection is established or removed, we invalidate the cache.
|
1058
|
-
def retrieve_connection_pool(spec_name)
|
1059
|
-
owner_to_pool.fetch(spec_name) do
|
1060
|
-
# Check if a connection was previously established in an ancestor process,
|
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
|
1073
|
-
end
|
1074
|
-
|
1075
|
-
private
|
1076
|
-
|
1077
|
-
def owner_to_pool
|
1078
|
-
@owner_to_pool[Process.pid]
|
1079
|
-
end
|
1080
|
-
|
1081
|
-
def pool_from_any_process_for(spec_name)
|
1082
|
-
owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[spec_name] }
|
1083
|
-
owner_to_pool && owner_to_pool[spec_name]
|
1084
|
-
end
|
1085
|
-
end
|
1086
714
|
end
|
1087
715
|
end
|