Mail-SpamAssassin
view release on metacpan or search on metacpan
lib/Mail/SpamAssassin/AICache.pm view on Meta::CPAN
$self->{prefix},
File::Spec->rel2abs($split[1]),
join('_', '.spamassassin_cache', $self->{type}, $split[2]));
my @stat = stat($self->{cache_file});
@stat or dbg("AIcache: no access to %s: %s", $self->{cache_file}, $!);
$self->{cache_mtime} = $stat[9] || 0;
# for mbox and mbx, verify whether mtime on cache file is >= mtime of
# messages file. if it is, use it, otherwise don't.
@stat = stat($self->{path});
@stat or dbg("AIcache: no access to %s: %s", $self->{path}, $!);
if ($stat[9] > $self->{cache_mtime}) {
$use_cache = 0;
}
}
$self->{cache_file} = File::Spec->canonpath($self->{cache_file});
# go ahead and read in the cache information
local *CACHE;
if (!$use_cache) {
# not in use
} elsif (!open(CACHE, $self->{cache_file})) {
dbg("AIcache: cannot open AI cache file (%s): %s", $self->{cache_file},$!);
} else {
for ($!=0; defined($_=<CACHE>); $!=0) {
my($k,$v) = split(/\t/, $_);
next unless (defined $k && defined $v);
$self->{cache}->{$k} = $v;
}
defined $_ || $!==0 or
$!==EBADF ? dbg("AIcache: error reading from AI cache file: $!")
: warn "error reading from AI cache file: $!";
close CACHE
or die "error closing AI cache file (".$self->{cache_file}."): $!";
}
bless($self,$class);
$self;
}
sub count {
my ($self) = @_;
return keys %{$self->{cache}};
}
sub check {
my ($self, $name) = @_;
return $self->{cache} unless $name;
# for dir collections: just use the info on a file, if an entry
# exists for that file. it's very unlikely that a file will be
# changed to contain a different Date header, and it's slow to check.
# return if ($self->{type} eq 'dir' && (stat($name))[9] > $self->{cache_mtime});
$name = $self->canon($name);
return $self->{cache}->{$name};
}
sub update {
my ($self, $name, $date) = @_;
return unless $name;
$name = $self->canon($name);
# if information is different than cached version, set dirty and update
if (!exists $self->{cache}->{$name} || $self->{cache}->{$name} != $date) {
$self->{cache}->{$name} = $date;
$self->{dirty} = 1;
}
}
sub finish {
my ($self) = @_;
return unless $self->{dirty};
# Cache is dirty, so write out new file
# create enclosing dir tree, if required
eval {
mkpath(dirname($self->{cache_file}));
1;
} or do {
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
warn "cannot mkpath for AI cache file ($self->{cache_file}): $eval_stat\n";
};
my $towrite = '';
while(my($k,$v) = each %{$self->{cache}}) {
$towrite .= "$k\t$v\n";
}
{
# ignore signals while we're writing this file
local $SIG{'INT'} = 'IGNORE';
local $SIG{'TERM'} = 'IGNORE';
if (!open(CACHE, ">".$self->{cache_file}))
{
warn "creating AI cache file failed (".$self->{cache_file}."): $!";
# TODO: should we delete it/clean it up?
}
else {
print CACHE $towrite
or warn "error writing to AI cache file: $!";
close CACHE
or warn "error closing AI cache file (".$self->{cache_file}."): $!";
}
}
return;
}
sub canon {
my ($self, $name) = @_;
if ($self->{type} eq 'dir') {
# strip off dirs, just look at filename
$name = (File::Spec->splitpath($name))[2];
( run in 0.718 second using v1.01-cache-2.11-cpan-39bf76dae61 )