DBIx-Poggy

 view release on metacpan or  search on metacpan

lib/DBIx/Poggy.pm  view on Meta::CPAN

queuing and support of transactions.

=head2 Why pool?

DBD::Pg is not async, it's non blocking. Every connection can execute only one query
at a moment, so to execute several queries in parallel you need several connections.
What you get is you can do something in Perl side while postgres crunches data for
you.

=head2 Queue

Usually if you attempt to run two queries on the same connection then DBI throws an
error about active query. Poggy takes care of that by queuing up queries you run on
one connection. Handy for transactions and pool doesn't grow too much.

=head2 What is async here then?

Only a queries on multiple connections, so if you need to execute many parallel
queries then you need many connections. pg_bouncer and haproxy are your friends.

=head2 Pool management

In auto mode (default) you just "loose" reference to database handle and it gets
released back into the pool after all queries are done:

    {
        my $cv = AnyEvent->condvar;
        $pool->take->do(...)->finally($cv);
        $cv->recv;
    }
    # released

Or:
    {
        my $cv = AnyEvent->condvar;
        my $dbh = $pool->take;
        $dbh->do(...)
        ->then(sub { $dbh->do(...) })
        ->then(sub { ... })
        ->finally($cv);
        $cv->recv;
    }
    # $dbh goes out of scope and all queries are done (cuz of condvar)
    # released

=cut

use DBIx::Poggy::DBI;
use DBIx::Poggy::Error;

=head1 METHODS

=head2 new

Named arguments:

=over 4

=item pool_size

number of connections to create, creates one more in case all are busy

=back

Returns a new pool object.

=cut

sub new {
    my $proto = shift;
    my $self = bless { @_ }, ref($proto) || $proto;
    return $self->init;
}

sub init {
    my $self = shift;
    $self->{pool_size} ||= 10;
    $self->{ping_on_take} ||= 30;
    return $self;
}

=head2 connect

Takes the same arguments as L<DBI/connect>, opens "pool_size" connections.
Saves connection settings for reuse when pool is exhausted.

=cut

sub connect {
    my $self = shift;
    my ($dsn, $user, $password, $opts) = @_;

    $opts ||= {};
    $opts->{RaiseError} //= 1;

    $self->{free} ||= [];

    $self->{connection_settings} = [ $dsn, $user, $password, $opts ];

    $self->_connect for 1 .. $self->{pool_size};
    return $self;
}

sub _connect {
    my $self = shift;

    my $dbh = DBIx::Poggy::DBI->connect(
        @{ $self->{connection_settings} }
    ) or die DBIx::Poggy::Error->new( 'DBIx::Poggy::DBI' );
    push @{$self->{free}}, $dbh;
    $self->{last_used}{ refaddr $dbh } = time;

    return;
}

=head2 take

Gives one connection from the pool. Takes arguments:

=over 4



( run in 2.538 seconds using v1.01-cache-2.11-cpan-364913b4093 )