Apache-Sybase-ConPool
view release on metacpan or search on metacpan
# -*-Perl-*-
# $Id: ConPool.pm,v 1.1.1.1 2001/10/31 22:03:22 mpeppler Exp $
# Copyright (c) 2001 Michael Peppler
#
# You may distribute under the terms of either the GNU General Public
# License or the Artistic License, as specified in the Perl README file,
# with the exception that it cannot be placed on a CD-ROM or similar media
# for commercial distribution without the prior approval of the author.
package Apache::Sybase::ConPool;
use strict;
use Sybase::CTlib;
use IPC::SysV qw(IPC_CREAT S_IRWXU SEM_UNDO IPC_NOWAIT);
use IPC::Semaphore;
use Carp;
use Sys::Hostname;
use vars qw($VERSION $Revision);
$VERSION = '1.00';
$Revision = substr(q$Revision: 1.1.1.1 $, 10);
my %config;
my %share;
my %handles;
my $verbose;
sub import {
my $package = shift;
my (%args) = @_;
return if(%share);
if(!$args{config}) {
croak("Usage: use Apache::Sybase::ConPool (config => <config file>)");
}
# loadConfig($args{config});
initialize($args{config});
}
sub initialize {
my $file = shift;
loadConfig($file);
my $verbose = $config{'DbVerbose'};
my $hostname = hostname;
($hostname) = split(/\./, $hostname);
my $timeout = $config{'DbTimeout'} || 30;
if(ct_config(CS_SET, CS_TIMEOUT, $timeout, CS_INT_TYPE) != CS_SUCCEED) {
warn "[ConPool] ct_config(CS_TIMEOUT) failed\n";
}
my $max_connect = $config{'DbNumConnect'} || 40;
ct_config(CS_SET, CS_MAX_CONNECT, $max_connect, CS_INT_TYPE);
for(my $i = 1; $i <= $config{DbNumPools} || 1; ++$i) {
my $data = $config{"ConPool$i"};
if(!$data) {
warn("[ConTool] Nothing found for ConPool$i\n") if $verbose;
last;
}
my ($srv, $usr, $pwd, $count, $key) = split(/,\s*/, $data);
warn "[ConPool] Connecting to $srv ($count connections)\n" if $verbose;
$share{$srv}->{COUNT} = $count;
$share{$srv}->{KEY} = unpack('N', $key);
for (1 .. $count) {
my $dbh =
Sybase::CTlib->new($usr, $pwd, $srv, "(ConPool)",
{ CON_PROPS => { CS_HOSTNAME => $hostname },
SRV => $srv});
warn "[ConPool] Can't connect to $srv\n" unless $dbh;
$share{$srv}->{DBH}->{$_} = $dbh;
}
$key = $share{$srv}->{KEY};
my $sem;
if($sem = new IPC::Semaphore($key, 0, 0666)) {
warn "[ConPool] Removing existing semaphore ", $sem->id(), "\n" if $verbose;
$sem->remove;
}
$sem = new IPC::Semaphore($key, $count + 1, 0666 | IPC_CREAT);
$sem->setall ( $count, (0) x $count );
}
}
sub loadConfig {
my $file = shift;
# warn "Reading $file\n";
open(IN, $file) || croak("Can't open $file: $!");
while(<IN>) {
chomp;
# warn "read $_\n";
next if /^\s*$/;
next if /^\s*\#/;
my ($key, $val) = split(/\s*=\s*/, $_);
$config{$key} = $val;
}
close(IN);
}
sub getDbh {
my $srv = shift;
print STDERR "[ConPool] getting handle for $srv\n" if $verbose;
if(!exists($share{$srv})) {
warn "[ConPool] No connection defined for $srv!\n";
return undef;
}
my $key = $share{$srv}->{KEY};
my $count = $share{$srv}->{COUNT};
my $sem = new IPC::Semaphore($key, 0, 0666);
my $r;
my $used = 0;
my $sleep = 0;
my %ignore;
my $sleepTime = $config{'DbSleepTime'} || 0.25;
my $semTimeout = $config{'SemTimeout'} || 30;
my $now = time;
eval {
my $h = Sys::Signal->set(ALRM => sub { die "Timeout\n"; } );
alarm($semTimeout);
$r = $sem->op(0, -1, 0);
alarm(0);
};
if($@ && $@ =~ /Timeout/) {
warn "[ConPool] semaphore timed out for $srv\n";
return undef;
}
my $diff = time - $now;
if($diff) {
warn "[ConPool] Semaphore acquisition for $srv: $diff seconds\n";
}
RETRY:;
for my $i (1 .. $count) {
next if $ignore{$i};
$r = $sem->op(
$i, 0, IPC_NOWAIT,
$i, 1, IPC_NOWAIT
);
print STDERR "semop(get $$) (lock $i) returned $r: $!\n" if $verbose;
if($r == 1) {
$used = $i;
last;
}
}
# If the connection's been marked DEAD, just skip this one...
if($used && $share{$srv}->{DBH}->{$used}->DBDEAD()) {
warn "[ConPool] Connection $used ($srv) is dead - ignored\n";
$ignore{$used}++;
goto RETRY;
}
if(!$used) {
print STDERR "[ConPool] No handle available for $srv - sleeping\n";
#sleep(1);
++$sleep;
select(undef, undef, undef, $sleepTime);
goto RETRY;
}
if($sleep) {
print STDERR "[ConPool] Slept for $srv for ", $sleep * $sleepTime, " seconds\n";
}
# print STDERR "[ConPool] ($$): got handle $used\n" if $verbose;
warn "[ConPool] ($$): got handle $used\n" if $verbose;
$handles{$share{$srv}->{DBH}->{$used}} = $share{$srv}->{DBH}->{$used};
$share{$srv}->{DBH}->{$used};
}
sub freeDbh {
my $dbh = shift;
my $force = shift || 0;
# print STDERR "$dbh\n";
my $srv = $dbh->{SRV};
print STDERR "[ConPool] Freeing handle for $srv (force = $force)\n" if $verbose;
( run in 0.752 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )