Class: ActiveRecord::ConnectionAdapters::RactorConnectionHandler::ProxyConnectionPool
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Instance Chain:
self,
Proxy
|
|
| Inherits: | Object |
| Defined in: | activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb |
Class Method Summary
- .for_spec(spec)
- .new(spec) ⇒ ProxyConnectionPool constructor
Instance Attribute Summary
-
#active_connection
readonly
Alias for #active_connection?.
- #connected? ⇒ Boolean readonly
- #db_config readonly
- #key readonly
- #permanent_lease? ⇒ Boolean readonly
- #pool_transaction_isolation_level rw
- #pool_transaction_isolation_level=(isolation_level) rw
- #role readonly
- #shard readonly
Instance Method Summary
- #==(other) (also: #eql?)
- #active_connection? ⇒ Boolean (also: #active_connection) readonly
- #async_executor
- #build_async_executor
- #checkin(connection)
- #checkout(_checkout_timeout = nil)
- #clear_query_cache
-
#clear_reloadable_connections!
Alias for #disconnect!.
- #connection_descriptor
- #dirties_query_cache
- #disable_query_cache(dirties: true)
- #disable_query_cache!
- #disconnect! (also: #flush!, #clear_reloadable_connections!)
- #dispatch_to_main_schema_cache(method_name, args, kwargs)
- #enable_query_cache
- #enable_query_cache!
-
#eql?(other)
Alias for #==.
-
#flush!
Alias for #disconnect!.
- #hash
- #inspect
- #internal_metadata
- #lease_connection
- #migration_context
- #migrations_paths
-
#pin_connection!(lock_thread)
Mirrors ConnectionPool#pin_connection!: both pools are pinned so every checkout yields the same connection; worker-side transactions nest as savepoints.
- #query_cache
- #query_cache_enabled
- #query_cache_max_size
- #release_connection(existing_lease = nil)
- #remove(connection)
- #schedule_query(future_result)
- #schema_cache
- #schema_migration
- #schema_reflection
- #state
- #unpin_connection!
- #with_connection(prevent_permanent_checkout: false)
- #with_pool_transaction_isolation_level(isolation_level, transaction_open)
- #checkout_main_connection private
- #connection_lease private
- #main_pool_value(method_name) private
- #pin_main_connection!(lock_thread) private
- #pool_transaction_isolation_level_key private
- #release_lease(connection) private
-
#unpin_main_connection!
private
Nothing to unpin when the named pool was replaced or removed (pool token mismatch).
Proxy - Included
| #boundary_safe_bind | Attribute types may close over procs, so the database value is resolved locally. |
| #checkin_all_connections | For supervisors tearing down worker Ractors, which cannot release their own tokens when they die. |
| #checkin_token, #connection_pinned?, #discard_token, #dump_binds, #dump_column_types, #dump_object, | |
| #main_operation |
|
| #remove_token | |
Constructor Details
.new(spec) ⇒ ProxyConnectionPool
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 39
def initialize(spec) @db_config = spec.fetch(:db_config) @connection_name = spec.fetch(:connection_name).to_s.freeze @role = spec.fetch(:role) @shard = spec.fetch(:shard) @pool_token = spec.fetch(:pool_token) @key = [@connection_name, @role, @shard, @pool_token].freeze end
Class Method Details
.for_spec(spec)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 33
def self.for_spec(spec) pools = (ActiveSupport::Ractors[:active_record_ractor_pools] ||= Concurrent::Map.new) key = [spec.fetch(:connection_name), spec.fetch(:role), spec.fetch(:shard), spec.fetch(:pool_token)] pools.compute_if_absent(key) { new(spec) } end
Instance Attribute Details
#active_connection (readonly)
Alias for #active_connection?.
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 125
alias :active_connection :active_connection?
#connected? ⇒ Boolean (readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 225
def connected? main_pool_value(:connected?) end
#db_config (readonly)
[ GitHub ]#key (readonly)
[ GitHub ]
#permanent_lease? ⇒ Boolean (readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 118
def permanent_lease? connection_lease.sticky.nil? end
#pool_transaction_isolation_level (rw)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 283
def pool_transaction_isolation_level ActiveSupport::IsolatedExecutionState[pool_transaction_isolation_level_key] end
#pool_transaction_isolation_level=(isolation_level) (rw)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 287
def pool_transaction_isolation_level=(isolation_level) ActiveSupport::IsolatedExecutionState[pool_transaction_isolation_level_key] = isolation_level end
#role (readonly)
[ GitHub ]#shard (readonly)
[ GitHub ]Instance Method Details
#==(other) Also known as: #eql?
[ GitHub ]
#active_connection? ⇒ Boolean (readonly)
Also known as: #active_connection
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 122
def active_connection? connection_lease.connection end
#async_executor
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 309
def async_executor state.async_executor(self) end
#build_async_executor
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 313
def build_async_executor # :nodoc: case ActiveRecord.async_query_executor when :multi_thread_pool if db_config.max_threads > 0 Concurrent::ThreadPoolExecutor.new( name: "ActiveRecord-#{db_config.name}-ractor-async-query-executor", min_threads: db_config.min_threads, max_threads: db_config.max_threads, max_queue: db_config.max_queue, fallback_policy: :caller_runs ) end when :global_thread_pool ActiveRecord.global_thread_pool_async_query_executor end end
#checkin(connection)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 173
def checkin(connection) release_lease(connection) return if state.pinned_connection.equal?(connection) connection.expire if connection.in_use? connection.release_connection end
#checkout(_checkout_timeout = nil)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 161
def checkout(_checkout_timeout = nil) if pinned = state.pinned_connection return pinned end connection_token, profile = checkout_main_connection connection = profile[:proxy_class].new(self, connection_token, profile, db_config.configuration_hash) connection.lease connection.query_cache = query_cache connection end
#checkout_main_connection (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 402
def checkout_main_connection connection_name, role, shard = @connection_name, @role, @shard main_operation do connection = main_pool(connection_name, role, shard).checkout begin # A proxied connection is never verified by the query pipeline, so it must be usable up front. connection.connect! profile = connection.ractor_connection_profile token = register_connection(connection) rescue Exception connection.pool.checkin(connection) raise end ActiveSupport::Ractors.make_shareable([token, profile], copy: true) end end
#clear_query_cache
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 273
def clear_query_cache state.query_cache_version.increment if state.pinned_connection query_cache.clear end
#clear_reloadable_connections!
Alias for #disconnect!.
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 233
alias :clear_reloadable_connections! :disconnect!
#connection_descriptor
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 61
def connection_descriptor main_pool_value(:connection_descriptor) end
#connection_lease (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 380
def connection_lease leases = (ActiveSupport::IsolatedExecutionState[:active_record_ractor_connection_leases] ||= {}) lease = leases[key] ||= Lease.new(nil, nil) if (connection = lease.connection) && !connection.holds_main_connection? lease.connection = nil lease.sticky = nil end lease end
#dirties_query_cache
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 269
def dirties_query_cache query_cache.dirties end
#disable_query_cache(dirties: true)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 235
def disable_query_cache(dirties: true) cache = query_cache old_enabled, cache.enabled, old_dirties, cache.dirties = cache.enabled, false, cache.dirties, dirties begin yield ensure cache.enabled, cache.dirties = old_enabled, old_dirties end end
#disable_query_cache!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 260
def disable_query_cache! query_cache.enabled = false query_cache.dirties = true end
#disconnect! Also known as: #flush!, #clear_reloadable_connections!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 229
def disconnect! release_connection end
#dispatch_to_main_schema_cache(method_name, args, kwargs)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 73
def dispatch_to_main_schema_cache(method_name, args, kwargs) # :nodoc: connection_name, role, shard = @connection_name, @role, @shard connection_token = connection_lease.connection&.connection_token main_args = ActiveSupport::Ractors.make_shareable(args) main_kwargs = ActiveSupport::Ractors.make_shareable(kwargs) main_operation(connection_pool: self) do pool = main_pool(connection_name, role, shard) schema_cache = if connection_token # Bind to the pinned connection so the worker observes its own uncommitted DDL. connection = fetch_connection(connection_token) # Proxied connections don't connect on demand, so connect explicitly. connection.connect! unless connection.connected? BoundSchemaReflection.for_lone_connection(pool.schema_reflection, connection) else pool.schema_cache end schema_cache.public_send(method_name, *main_args, **main_kwargs) end end
#enable_query_cache
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 245
def enable_query_cache cache = query_cache old_enabled, cache.enabled, old_dirties, cache.dirties = cache.enabled, true, cache.dirties, true begin yield ensure cache.enabled, cache.dirties = old_enabled, old_dirties end end
#enable_query_cache!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 255
def enable_query_cache! query_cache.enabled = true query_cache.dirties = true end
#eql?(other)
Alias for #==.
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 55
alias :eql? :==
#flush!
Alias for #disconnect!.
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 232
alias :flush! :disconnect!
#hash
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 57
def hash [self.class, key].hash end
#inspect
[ GitHub ]#internal_metadata
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 107
def InternalMetadata.new(self) end
#lease_connection
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 111
def lease_connection lease = connection_lease lease.connection ||= checkout lease.sticky = true lease.connection end
#main_pool_value(method_name) (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 440
def main_pool_value(method_name) connection_name, role, shard = @connection_name, @role, @shard main_operation(connection_pool: self) do main_pool(connection_name, role, shard).public_send(method_name) end end
#migration_context
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 95
def migration_context MigrationContext.new(migrations_paths, schema_migration, ) end
#migrations_paths
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 99
def migrations_paths db_config.migrations_paths || Migrator.migrations_paths end
#pin_connection!(lock_thread)
Mirrors ConnectionPool#pin_connection!: both pools are pinned so every checkout yields the same connection; worker-side transactions nest as savepoints.
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 183
def pin_connection!(lock_thread) pin_main_connection!(lock_thread) state = self.state begin state.pinned_connection ||= (connection_lease.connection || checkout) state.pinned_depth += 1 connection = state.pinned_connection connection.lock_thread = ActiveSupport::IsolatedExecutionState.context if lock_thread connection.pinned = true rescue Exception unpin_main_connection! raise end end
#pin_main_connection!(lock_thread) (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 419
def pin_main_connection!(lock_thread) connection_name, role, shard = @connection_name, @role, @shard pin_lock_thread = !!lock_thread main_operation(connection_pool: self) do main_pool(connection_name, role, shard).pin_connection!(pin_lock_thread) nil end end
#pool_transaction_isolation_level_key (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 398
def pool_transaction_isolation_level_key "activerecord_pool_transaction_isolation_level_#{@db_config.name}" end
#query_cache
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 278
def query_cache caches = (ActiveSupport::IsolatedExecutionState[:active_record_ractor_query_caches] ||= {}) caches[key] ||= QueryCache::Store.new(state.query_cache_version, query_cache_max_size) end
#query_cache_enabled
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 265
def query_cache_enabled query_cache.enabled end
#query_cache_max_size
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 368
def query_cache_max_size # :nodoc: case size = db_config&.query_cache when 0, false nil when Integer size when nil QueryCache::DEFAULT_SIZE end end
#release_connection(existing_lease = nil)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 127
def release_connection(existing_lease = nil) lease = existing_lease || connection_lease if connection = lease.connection lease.connection = nil lease.sticky = nil checkin(connection) true else false end end
#release_lease(connection) (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 390
def release_lease(connection) lease = connection_lease if lease.connection.equal?(connection) lease.connection = nil lease.sticky = nil end end
#remove(connection)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 220
def remove(connection) release_lease(connection) connection.remove_connection end
#schedule_query(future_result)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 330
def schedule_query(future_result) if executor = async_executor executor.post { future_result.execute_or_skip } Thread.pass else future_result.execute_or_skip end end
#schema_cache
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 69
def schema_cache state.schema_cache ||= SchemaCacheProxy.new(self) end
#schema_migration
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 103
def schema_migration SchemaMigration.new(self) end
#schema_reflection
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 65
def schema_reflection main_pool_value(:schema_reflection) end
#state
[ GitHub ]#unpin_connection!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 199
def unpin_connection! state = self.state raise "There isn't a pinned connection #{object_id}" unless state.pinned_connection begin state.pinned_depth -= 1 if state.pinned_depth.zero? connection = state.pinned_connection state.pinned_connection = nil connection.pinned = false connection.lock_thread = nil release_lease(connection) connection.expire if connection.in_use? connection.release_connection end ensure unpin_main_connection! end end
#unpin_main_connection! (private)
Nothing to unpin when the named pool was replaced or removed (pool token mismatch).
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 429
def unpin_main_connection! connection_name, role, shard, pool_token = @connection_name, @role, @shard, @pool_token main_operation(connection_pool: self) do pool = main_connection_handler.retrieve_connection_pool( connection_name, role: role, shard: shard, strict: false ) pool.unpin_connection! if pool && pool.pool_config.pool_token == pool_token nil end end
#with_connection(prevent_permanent_checkout: false)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 139
def with_connection(prevent_permanent_checkout: false) lease = connection_lease sticky_was = lease.sticky lease.sticky = false if prevent_permanent_checkout if lease.connection begin yield lease.connection ensure lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was end else begin lease.connection = checkout yield lease.connection ensure lease.sticky = sticky_was if prevent_permanent_checkout && !sticky_was release_connection(lease) unless lease.sticky end end end
#with_pool_transaction_isolation_level(isolation_level, transaction_open)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy_connection_pool.rb', line 291
def with_pool_transaction_isolation_level(isolation_level, transaction_open) if !ActiveRecord.default_transaction_isolation_level.nil? begin if transaction_open && pool_transaction_isolation_level != ActiveRecord.default_transaction_isolation_level raise ActiveRecord::TransactionIsolationError, "cannot set default isolation level while transaction is open" end old_level = pool_transaction_isolation_level self.pool_transaction_isolation_level = isolation_level yield ensure self.pool_transaction_isolation_level = old_level end else yield end end