DBIO-PostgreSQL-EV
view release on metacpan or search on metacpan
(Storage.pm 1109 -> 938 lines). It inherits the shared machinery â
select/insert/update/delete_async, _run_crud, txn_do_async, the
insert-RETURNING overlay, pipeline, the sync fallbacks and SQL
generation â and keeps only the EV/libpq wire seams plus EV value-add
(listen/notify, copy_in, deploy_async). (karr #22, core #70)
- Async is opt-in per connection via { async => 'ev' } (ADR 0030):
loading the PostgreSQL::EV component is an inert marker, and the EV
backend is reached explicitly through
MyApp::Schema->connect($dsn, $u, $p, { async => 'ev' }). The async
storage is embedded as the async backend of the sync storage rather
than hijacking storage_type; it weakens its schema ref to break the
embed cycle and accepts the sync driver's DBI-form connect_info. The
legacy async_backend() instance method and async_fallback chain are
gone â a *_async call on a sync instance now croaks explicitly rather
than silently degrading. (ADR 0028, ADR 0030, karr #59)
- insert_async resolves with a returned-columns HASHREF, not a positional
row (ADR 0031 §3): _run_crud appends RETURNING * to the INSERT and folds
the returned row onto the source's declared column order, so
create_async / Row::insert_async see the autoinc PK on the row.
select_async resolves with row arrayrefs (cursor ->all shape),
select_single_async with a single row arrayref / undef; documented in
t/05-bind-release.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use Scalar::Util 'weaken';
use Future;
# OFFLINE regression test for karr #11 / CurtisPoe review #5 N1:
# "async bind-value leak". No EV::Pg, no real DB.
#
# WHAT THE TICKET FEARED (ported from the sync DBI driver's contract):
# bind values issued through the async pool are retained on an in-flight
# future / per-pool cache, so (1) a re-issued query could see stale binds
# and (2) memory grows with total binds ever issued, not with outstanding
# queries.
t/05-bind-release.t view on Meta::CPAN
}
# --- 1. single pooled query: bind released once the future completes -------
{
my ($storage, $pg) = new_storage;
my $weak;
my $f;
{
my $bind = [ 'payload' x 64 ]; # a large-ish bind, like the repro
weaken($weak = $bind);
$f = $storage->_query_async('SELECT $1', $bind);
} # the issuing-scope strong lexical dies here
$pg->complete_one;
$f->get;
ok !defined $weak,
'pooled query: bind arrayref is freed after the future completes '
. '(completion closure does not retain it)';
}
# --- 2. pinned (transaction) query: same release contract ------------------
{
my ($storage, $pg) = new_storage;
my $weak;
my $f;
{
my $bind = [ 'txn-payload' x 64 ];
weaken($weak = $bind);
$f = $storage->_query_async_pinned($pg, 'SELECT $1', $bind);
}
$pg->complete_one;
$f->get;
ok !defined $weak,
'pinned (txn) query: bind arrayref is freed after completion too';
}
t/05-bind-release.t view on Meta::CPAN
{
my ($storage, $pg) = new_storage;
my $N = 8;
my @weak;
my @f;
for my $i (1 .. $N) {
my $w;
{
my $bind = [ "row$i" x 32 ];
weaken($w = $bind);
push @f, $storage->_query_async("SELECT \$1 -- $i", $bind);
}
push @weak, $w;
}
is $pg->pending_count, $N, "all $N queries are in-flight at once";
my $held_inflight = grep { defined } @weak;
is $held_inflight, 0,
"no bind arrayref is retained while $N queries are in-flight "
( run in 0.631 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )