DBIO
view release on metacpan or search on metacpan
lib/DBIO/Storage/PoolBase.pm view on Meta::CPAN
ready immediately and behaviour is unchanged. For async transports whose
connection is not usable until a background connect completes, the seam is
the single place where the Future is held pending until the connection is
actually ready; see L</_connection_ready_future>.
=head2 _connection_ready_future
sub _connection_ready_future { my ($self, $conn) = @_; ... }
Readiness seam, chained by L</acquire> around every connection it hands out
â freshly spawned, reused-idle, or handed to a queued waiter. Returns a
Future that resolves to C<$conn> once the connection is actually ready to
run queries.
The default implementation is a safe no-op for synchronous pools:
sub _connection_ready_future { $_[0]->future_class->done($_[1]) }
A DBI / synchronous connection is usable the instant its constructor
returns, so an immediately-C<done> Future is correct and L</acquire> stays
ready-at-once. Behaviour for every existing synchronous pool is therefore
unchanged.
B<Async transports MUST override this.> A backend whose connection is not
usable when its constructor returns â every event-loop transport: EV::Pg,
EV::MariaDB, C<future_io>, ... â is still connecting in the background when
the handle first exists. If such a driver leaves this seam at its default,
L</acquire> hands out a live-looking but unconnected handle and the very
first bound query on a cold pool dies C<not connected>. This is not a
theoretical edge: C<dbio-mysql-ev> shipped exactly this bug â its
C<_create_connection> wired C<on_connect =E<gt> sub {}>, a pure no-op, with
no readiness tracking, and the symptom was papered over with test-harness
pre-warming rather than fixed in the driver (B<dbio-mysql-ev karr #20>).
The correct override returns a per-connection Future that resolves from the
transport's C<on_connect> callback and fails from its C<on_error>.
The default deliberately does NOT auto-detect the async case â it cannot
know whether a given transport's constructor connects synchronously â so
forgetting the override stays possible by design. What the base does
provide is that the responsibility now lives at ONE documented seam, and
the bookkeeping for the common "resolve a per-connection Future from a
connect callback" pattern is supplied by L</_register_connection_ready>,
L</_connection_ready_lookup> and L</_clear_connection_ready>, so an override
only has to wire C<on_connect> / C<on_error> onto a Future instead of
building the side table from scratch. A typical async override:
sub _connection_ready_future {
my ($self, $conn) = @_;
return $self->future_class->done($conn) if $conn->is_connected;
return $self->_connection_ready_lookup($conn)
|| $self->future_class->done($conn);
}
=head2 _register_connection_ready
$self->_register_connection_ready($conn, $ready_future);
Bookkeeping primitive for the L</_connection_ready_future> pattern. Stores a
per-connection readiness Future keyed by C<Scalar::Util::refaddr($conn)>, so
an async L</_create_connection> can hand the Future's C<done> / C<fail> to
the transport's C<on_connect> / C<on_error> callbacks and have
L</_connection_ready_future> find it again by connection. Returns the Future.
=head2 _connection_ready_lookup
my $ready = $self->_connection_ready_lookup($conn);
Return the readiness Future registered for C<$conn> via
L</_register_connection_ready>, or undef if none (e.g. a synchronous pool
that never registered one). An async L</_connection_ready_future> override
typically returns
C<< $self->_connection_ready_lookup($conn) || $self->future_class->done($conn) >>.
=head2 _clear_connection_ready
$self->_clear_connection_ready($conn);
Drop C<$conn>'s readiness Future from the side table. Called for you by
L</shutdown> for every pooled connection, so an async L</_shutdown_connection>
override never has to clean the table up itself; also exposed for drivers
that retire a single connection outside shutdown. A no-op when no readiness
table exists.
=head2 acquire_txn
Acquire a connection pinned for exclusive transaction use.
Same as L</acquire> but the connection will not be released
back to the idle pool until explicitly released.
=head2 release
$pool->release($conn);
Return a connection to the idle pool. If waiters are queued, hands the
connection straight to the oldest waiter instead.
=head2 size
Total connections (active + idle).
=head2 available
Number of idle connections.
=head2 max_size
Configured maximum pool size.
=head2 shutdown
Close all connections via L</_shutdown_connection> and clear the pool.
=head2 _create_connection
sub _create_connection { my ($self, $conninfo) = @_; ... }
Required driver hook: build and return one connection from the
(already transformed) connect info. The pool tracks the connection;
do not push it anywhere yourself.
=head2 _shutdown_connection
( run in 1.350 second using v1.01-cache-2.11-cpan-6aa56a78535 )