# Somewhere very visible...
my @autosubs;
BEGIN {
@autosubs = qw(blacklist floodcheck viruscheck spamcheck headers subject body sender recievers);
}
# At the end of the package...
BEGIN {
# READ THIS CAREFULLY
#
# Auto-magically generate a number of similar plugin register functions without
# actually writing them down one-by-one. This makes consistent changes much easier,
# but you need Perl wizardry level +12 to understand how it works.
#
# Since *you* don't actually exist at the time of writing (me, cavac, being the only
# team member), it is *your* fault for not showing up and writing a better solution ;-)
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
# -- Deep magic begins here...
for my $a (@autosubs){
*{__PACKAGE__ . "::add_$a"} =
sub {
my %conf = (
Module => $_[1],
Function=> $_[2],
);
push @{$_[0]->{plugins}->{$a}}, \%conf;
};
}
# ... and ends here
}
####
BEGIN {
my @stdFuncs = qw(prepare prepare_cached do quote);
my @simpleFuncs = qw(commit rollback errstr);
my @varSetFuncs = qw(AutoCommit RaiseError);
my @varGetFuncs = qw();
for my $a (@simpleFuncs){
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
*{__PACKAGE__ . "::$a"} = sub { $_[0]->checkDBH(); return $_[0]->{mdbh}->$a(); };
}
for my $a (@stdFuncs){
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
*{__PACKAGE__ . "::$a"} = sub { $_[0]->checkDBH(); return $_[0]->{mdbh}->$a($_[1]); };
}
for my $a (@varSetFuncs){
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
*{__PACKAGE__ . "::$a"} = sub { $_[0]->checkDBH(); return $_[0]->{mdbh}->{$a} = $_[1]; };
}
for my $a (@varGetFuncs){
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
*{__PACKAGE__ . "::$a"} = sub { $_[0]->checkDBH(); return $_[0]->{mdbh}->{$a}; };
}
### BLOB handling primitives ###
my @blobFuncs = qw(write read lseek tell close unlink import export);
{
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
*{__PACKAGE__ . "::pg_lo_creat"} = sub {
$_[0]->checkDBH();
return $_[0]->{mdbh}->pg_lo_creat($BLOBMODE);
};
*{__PACKAGE__ . "::pg_lo_open"} = sub {
$_[0]->checkDBH();
return $_[0]->{mdbh}->pg_lo_open($_[1], $BLOBMODE);
};
}
for my $a (@blobFuncs){
no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNoStrict)
$a = "pg_lo_$a";
*{__PACKAGE__ . "::$a"} = sub {
my ($self, @args) = @_;
$self->checkDBH();
return $self->{mdbh}->$a(@args);
};
}
}
##
##
sub get {
my ($self, $key) = @_;
$key = $self->sanitize_key($key);
my $dbh = $self->{server}->{modules}->{$self->{db}};
my $memh = $self->{server}->{modules}->{$self->{memcache}};
# Try memcached first
my $dataref = $memh->get($key);
if(defined($dataref)) {
return Maplat::Helpers::DBSerialize::dbthaw($dataref);
}
# Ok, try DB
my $sth = $dbh->prepare_cached("SELECT yamldata FROM memcachedb WHERE mckey = ?")
or croak($dbh->errstr);
$sth->execute($key) or croak($dbh->errstr);
while((my @line = $sth->fetchrow_array)) {
$dataref = $line[0];
last;
}
$sth->finish;
$dbh->rollback;
# Ok, now also store data in memcached
if(defined($dataref)) {
$memh->set($key, $dataref);
return Maplat::Helpers::DBSerialize::dbthaw($dataref);
}
return;
}
sub set { ## no critic (NamingConventions::ProhibitAmbiguousNames)
my ($self, $key, $data) = @_;
$key = $self->sanitize_key($key);
my $dbh = $self->{server}->{modules}->{$self->{db}};
my $memh = $self->{server}->{modules}->{$self->{memcache}};
my $yamldata = Maplat::Helpers::DBSerialize::dbfreeze($data);
# Check if it already matches the key we have
my $olddata = $memh->get($key);
if(defined($olddata) && $olddata eq $yamldata) {
return 1;
}
$memh->set($key, $yamldata);
my $sth = $dbh->prepare_cached("SELECT merge_memcachedb(?, ?)")
or return;
my $count = 0;
my $ok = 0;
while($count < $RETRY_COUNT) {
# print STDERR "WORKER: Merge $key\n";
if($sth->execute($key, $yamldata)) {
$ok = 1;
$sth->finish;
$dbh->commit;
last;
} else {
$count++;
$sth->finish;
$dbh->rollback;
if($count < $RETRY_COUNT) {
sleep($RETRY_WAIT); # try again in a short time
}
}
}
if(!$ok) {
croak($dbh->errstr);
}
return 1;
}