# 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; }