Forking from Mailzu 0.8RC3

This commit is contained in:
Mikko Husari
2008-12-10 15:33:43 +02:00
commit 2572b1814b
184 changed files with 79039 additions and 0 deletions

266
scripts/mz_db_clean.pl Executable file
View File

@@ -0,0 +1,266 @@
#!/usr/local/bin/perl -w
use strict;
use Getopt::Long;
##### PLEASE CONFIGURE THIS SECTION ######
# Globals
# Set this array for database authentication
my(@storage_sql_dsn) = (
'DBI:Pg:database=dbname;host=host.example.org',
'user','password'
);
# Set this to 1 if you are using the new database schema
# introduced with amavisd 2.4.0. Only do this if you also
# have the foreign key references between the tables and use
# time_iso as a real date type instead of a string.
my($new_dd) = 1; # 1 or undef
# Purge old messages - One Week
my($interval) = time - 7*24*60*60;
# Purge incomplete messages - 1 hour
my($partial_interval) = time - 60*60;
# These variables only matter if $new_dd is set to 1
# The values for these variables must be syntactically
# correct for your database. This value is passed to
# the 'interval' keyword. Please check your database
# documentation
# PostgreSQL
my($new_interval) = '1 week';
my($new_partial_interval) = '1 hour';
# MySQL
#my($new_interval) = '7 day';
#my($new_partial_interval) = '1 hour';
# PostgreSQL specific options
# Should we VACUUM ANALYZE the database after the purge?
# Default is undef because we should be using autovacuum
my($postop_vacuum) = undef; # 1 or undef
##### END OF CONFIGURATION SECTION ######
# Options array
my(%opt);
my(@modules);
my(@missing);
my(@dsn) = split(/:/,$storage_sql_dsn[0],-1);
push(@modules, 'DBD::'.$dsn[1]) if uc($dsn[0]) eq 'DBI';
for my $m (@modules) {
local($_) = $m;
$_ .= /^auto::/ ? '.al' : '.pm' if !/\.(pm|pl|al)\z/;
s[::][/]g;
eval { require $_ } or push(@missing, $m);
}
die "ERROR: MISSING module(s):\n" . join('', map { " $_\n" } @missing) if @missing;
sub build_queries($) {
my($dbtype) = shift;
# Return a hash of queries to be run
my(%query) = (
# Old schema queries
'del_d_flag' =>
'DELETE FROM msgrcpt ' .
'WHERE rs=\'D\'',
'del_partial_msg' =>
'DELETE FROM msgs ' .
"WHERE time_num < $partial_interval " .
'AND content IS NULL',
'del_old_mail_ids' =>
'DELETE FROM msgs ' .
"WHERE time_num < $interval",
'del_msgs_mail_ids' =>
'DELETE FROM msgs ' .
'WHERE NOT EXISTS ' .
' (SELECT 1 FROM msgrcpt ' .
' WHERE msgrcpt.mail_id=msgs.mail_id)',
'del_quarantine' =>
'DELETE FROM quarantine ' .
'WHERE NOT EXISTS '.
' (SELECT 1 FROM msgs ' .
' WHERE msgs.mail_id=quarantine.mail_id)',
'del_msgrcpt' =>
'DELETE FROM msgrcpt ' .
'WHERE NOT EXISTS ' .
' (SELECT 1 FROM msgs ' .
' WHERE msgs.mail_id=msgrcpt.mail_id)',
# New schema queries
'del_d_flag_new' =>
'DELETE FROM msgs ' .
'WHERE mail_id IN ' .
' (SELECT DISTINCT mail_id ' .
' FROM msgrcpt WHERE rs=\'D\')',
# Generic queries
'del_maddr' =>
'DELETE FROM maddr ' .
'WHERE NOT EXISTS ' .
' (SELECT sid FROM msgs WHERE sid=id) ' .
' AND NOT EXISTS' .
' (SELECT rid FROM msgrcpt WHERE rid=id)'
);
if ($dbtype eq 'pgsql') {
$query{'vacuum_analyze'} = 'VACUUM ANALYZE';
# New schema queries
$query{'del_old_mail_ids_new'} = 'DELETE FROM msgs ' .
'WHERE time_iso < now() ' .
"- interval '$new_interval'";
$query{'del_partial_msg_new'} = 'DELETE FROM msgs ' .
'WHERE time_iso < now() ' .
"- interval '$new_partial_interval' " .
' AND content IS NULL';
}
if ($dbtype eq 'mysql') {
# New schema queries
$query{'del_old_mail_ids_new'} = 'DELETE FROM msgs ' .
'WHERE time_iso < UTC_TIMESTAMP() ' .
"- interval $new_interval";
$query{'del_partial_msg_new'} = 'DELETE FROM msgs ' .
'WHERE time_iso < UTC_TIMESTAMP() ' .
"- interval $new_partial_interval " .
' AND content IS NULL';
# Old schema queries
$query{'del_msgs_mail_ids'} = 'DELETE msgs FROM msgs ' .
'LEFT JOIN msgrcpt USING(mail_id) ' .
'WHERE msgrcpt.mail_id IS NULL';
$query{'del_quarantine'} = 'DELETE quarantine FROM quarantine ' .
'LEFT JOIN msgs USING(mail_id) '.
'WHERE msgs.mail_id IS NULL';
$query{'del_msgrcpt'} = 'DELETE msgrcpt FROM msgrcpt ' .
'LEFT JOIN msgs USING(mail_id) ' .
'WHERE msgs.mail_id IS NULL';
}
my(%post_query) = (
'vacuum_analyze' => 'VACUUM ANALYZE'
);
# Order of execution IS IMPORTANT!
my(@query_order) = qw (del_d_flag del_partial_msg del_msgs_mail_ids
del_old_mail_ids del_quarantine del_msgrcpt
del_maddr
);
@query_order = qw (del_d_flag_new del_partial_msg_new
del_old_mail_ids_new del_maddr
) if $new_dd;
my(@post_query_order);
push(@post_query_order, 'vacuum_analyze') if $dbtype eq 'pgsql' && $postop_vacuum;
return (\%query,\@query_order,\%post_query,\@post_query_order);
}
sub usage {
print "Usage:\n";
print "\tmz_db_clean.pl [--verbose|-v] [--database|-db <dbtype>]\n";
print "\tmz_db_clean.pl --help|-h \n\n";
print "\tThe database configuration parameter is REQUIRED!\n\n";
print "\tPossible parameters for the \'--database\' option is \'mysql\'\n" .
"\tand 'pgsql'.\n";
exit;
}
sub main {
Getopt::Long::Configure('no_ignore_case');
GetOptions(\%opt, 'help|h', 'database|db=s', 'verbose|v',
) or exit(1);
usage if $opt{help};
usage if not $opt{database};
my($dbh) = connect_to_sql(@storage_sql_dsn);
my($query,$query_order,$p_query,$p_query_order) = build_queries($opt{database});
my($sth_ref) = prepare_queries($dbh,$query,$p_query);
my($result) = exec_queries($dbh,$sth_ref,$query,$p_query,
$query_order,$p_query_order
);
print "Database cleanup successful\n" if $result;
$dbh->disconnect;
}
sub exec_queries($$$$$) {
my($dbh,$sth_ref,$query,$p_query,$query_o,$p_query_o) = @_;
my($affected);
$dbh->begin_work;
eval {
foreach (@$query_o) {
if ($opt{verbose}) {
print "Executing... " . localtime() . "\n";
print $query->{$_} . "\n";
}
$affected = $sth_ref->{$_}->execute or die "Query '$_' did not execute";
print "$affected rows affected\n" if $opt{verbose};
}
};
if ($@ ne '') {
$dbh->rollback;
print "There was an error executing a query! $@\n" .
"No records modified by database maintenance\n" .
"Rollback complete.\n";
return undef
} else {
$dbh->commit;
}
eval {
foreach (@$p_query_o) {
if ($opt{verbose}) {
print "Executing... " . localtime() . "\n";
print $p_query->{$_} . "\n";
}
$affected = $sth_ref->{$_}->execute or die "Query '$_' did not execute";
print "$affected rows affected\n" if $opt{verbose};
}
};
if ($@ ne '') {
print "There was an error executing an optional query! $@\n" .
return undef
}
return 1;
}
sub connect_to_sql(@) {
my(@sql_dsn) = @_;
my($dsn, $username, $password) = @sql_dsn;
print "Connecting to SQL database server\n" if $opt{verbose};
print "Trying dsn '$dsn'\n" if $opt{verbose};
my($dbh) = DBI->connect($dsn, $username, $password,
# {PrintError => 1, RaiseError => 0, Taint => 1, AutoCommit => 0} );
{PrintError => 1, RaiseError => 0, Taint => 1} );
if ($dbh) {
print "Connection to '$dsn' succeeded\n" if $opt{verbose};
} else {
die "Unable to connect to '$dsn'!\n";
}
$dbh;
}
sub prepare_queries($$$) {
my($dbh) = shift;
my($query) = shift;
my($p_query) = shift;
my(%sths);
foreach my $query_set ($query, $p_query) {
foreach (keys %$query) {
$sths{$_} = $dbh->prepare($query->{$_});
}
}
\%sths
}
main;