in lib/Mail/SpamAssassin/Plugin/Redirectors.pm [471:622]
sub initialise_url_redirector_cache {
my ($self, $conf) = @_;
return if $self->{dbh};
return if !$conf->{url_redirector_cache_type};
if (!$conf->{url_redirector_cache_dsn}) {
warn "Redirectors: invalid cache configuration\n";
return;
}
##
## SQLite
##
if ($conf->{url_redirector_cache_type} =~ /^(?:dbi|sqlite)$/i
&& $conf->{url_redirector_cache_dsn} =~ /^dbi:SQLite/)
{
eval {
local $SIG{'__DIE__'};
require DBI;
require DBD::SQLite;
DBD::SQLite->VERSION(1.59_01); # Required for ON CONFLICT
$self->{dbh} = DBI->connect_cached(
$conf->{url_redirector_cache_dsn}, '', '',
{RaiseError => 1, PrintError => 0, InactiveDestroy => 1, AutoCommit => 1}
);
$self->{dbh}->do("
CREATE TABLE IF NOT EXISTS redir_url_cache (
redir_url TEXT PRIMARY KEY NOT NULL,
target_url TEXT NOT NULL,
hits INTEGER NOT NULL DEFAULT 1,
created INTEGER NOT NULL,
modified INTEGER NOT NULL
)
");
# Maintaining index for cleaning is likely more expensive than occasional full table scan
#$self->{dbh}->do("
# CREATE INDEX IF NOT EXISTS redir_url_modified
# ON redir_url_cache(created)
#");
$self->{sth_insert} = $self->{dbh}->prepare("
INSERT INTO redir_url_cache (redir_url, target_url, created, modified)
VALUES (?,?,strftime('%s','now'),strftime('%s','now'))
ON CONFLICT(redir_url) DO UPDATE
SET target_url = excluded.target_url,
modified = excluded.modified,
hits = hits + 1
");
$self->{sth_select} = $self->{dbh}->prepare("
SELECT target_url FROM redir_url_cache
WHERE redir_url = ?
");
$self->{sth_delete} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE redir_url = ? AND created < strftime('%s','now') - $conf->{url_redirector_cache_ttl}
");
$self->{sth_clean} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE created < strftime('%s','now') - $conf->{url_redirector_cache_ttl}
");
};
}
##
## MySQL/MariaDB
##
elsif (lc $conf->{url_redirector_cache_type} eq 'dbi'
&& $conf->{url_redirector_cache_dsn} =~ /^dbi:(?:mysql|MariaDB)/i)
{
eval {
local $SIG{'__DIE__'};
require DBI;
$self->{dbh} = DBI->connect_cached(
$conf->{url_redirector_cache_dsn},
$conf->{url_redirector_cache_username},
$conf->{url_redirector_cache_password},
{RaiseError => 1, PrintError => 0, InactiveDestroy => 1, AutoCommit => 1}
);
$self->{sth_insert} = $self->{dbh}->prepare("
INSERT INTO redir_url_cache (redir_url, target_url, created, modified)
VALUES (?,?,UNIX_TIMESTAMP(),UNIX_TIMESTAMP())
ON DUPLICATE KEY UPDATE
target_url = VALUES(target_url),
modified = VALUES(modified),
hits = hits + 1
");
$self->{sth_select} = $self->{dbh}->prepare("
SELECT target_url FROM redir_url_cache
WHERE redir_url = ?
");
$self->{sth_delete} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE redir_url = ? AND created < UNIX_TIMESTAMP() - $conf->{url_redirector_cache_ttl}
");
$self->{sth_clean} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE created < UNIX_TIMESTAMP() - $conf->{url_redirector_cache_ttl}
");
};
}
##
## PostgreSQL
##
elsif (lc $conf->{url_redirector_cache_type} eq 'dbi'
&& $conf->{url_redirector_cache_dsn} =~ /^dbi:Pg/i)
{
eval {
local $SIG{'__DIE__'};
require DBI;
$self->{dbh} = DBI->connect_cached(
$conf->{url_redirector_cache_dsn},
$conf->{url_redirector_cache_username},
$conf->{url_redirector_cache_password},
{RaiseError => 1, PrintError => 0, InactiveDestroy => 1, AutoCommit => 1}
);
$self->{sth_insert} = $self->{dbh}->prepare("
INSERT INTO redir_url_cache (redir_url, target_url, created, modified)
VALUES (?,?,CAST(EXTRACT(epoch FROM NOW()) AS INT),CAST(EXTRACT(epoch FROM NOW()) AS INT))
ON CONFLICT (redir_url) DO UPDATE SET
target_url = EXCLUDED.target_url,
modified = EXCLUDED.modified,
hits = redir_url_cache.hits + 1
");
$self->{sth_select} = $self->{dbh}->prepare("
SELECT target_url FROM redir_url_cache
WHERE redir_url = ?
");
$self->{sth_delete} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE redir_url = ? AND created < CAST(EXTRACT(epoch FROM NOW()) AS INT) - $conf->{url_redirector_cache_ttl}
");
$self->{sth_clean} = $self->{dbh}->prepare("
DELETE FROM redir_url_cache
WHERE created < CAST(EXTRACT(epoch FROM NOW()) AS INT) - $conf->{url_redirector_cache_ttl}
");
};
##
## ...
##
} else {
warn "Redirectors: invalid cache configuration\n";
return;
}
if ($@ || !$self->{sth_clean}) {
warn "Redirectors: cache connect failed: $@\n";
undef $self->{dbh};
undef $self->{sth_insert};
undef $self->{sth_select};
undef $self->{sth_delete};
undef $self->{sth_clean};
}
}