Cache-Static
view release on metacpan or search on metacpan
}
set:
my $FH = $cache::static::_curr_locked_FH || open(...);
...
close($FH);
an optimization idea stolen from the lighthttpd folks:
(http://www.lighttpd.net/documentation/performance.html)
stat() cache
A stat(2) can be expensive; caching it saves time and context switches.
Instead of using stat() every time to check for the existence of a file
you can stat() it once and monitor the directory the file is in for
modifications. As long as the directory doesn't change, the files in it
must all still be the same.
With the help of FAM or gamin you can use kernel events to assure that
your stat cache is up to date.
server.stat-cache-engine = "fam" # either fam, simple or disabled
granted, they are talking about the context of httpd serving static
pages, but it could still cut down on our number of stat calls by a
large factor in the common case...
-- documentation:
null $deps in set()... two usage modes, one where we care,
one where we don't. be more explicit about this...
this is not even the tip of the iceberg...
---- STUFF FOR LATER ----
-- the one second wait bug:
you have to wait one second or else you will always regenerate
this is a limitation of stat() and/or what's stored in most filesystems
solution:
- if $have_fcntl, lock writes to lessen dependency expiration bursts
(only regen once)
since we have a WORM model, writes can be expensive. therefore,
- when you call set, also save a file called $cachefile.microseconds
- if timestamps are equal, THEN read $cachefile.microseconds.
use this to determine if we need a refresh or not
to do this we require Time::HiRes, but that's ok b/c this whole
functionality will be optional
bin/cache-static-cleanup.pl view on Meta::CPAN
prune_older($ROOT);
sub prune_older {
my $dir = shift;
opendir(DIR, $dir);
foreach my $f (map { "$dir/$_" } grep(!/(\.|\.\.)/, readdir(DIR))) {
if(-f $f) {
#don't delete files named config or log* (log, log.1.gz, etc.)
#note: config files can be 0 or 1 levels down dir tree
next if ($f eq 'config' || $f =~ /^log/);
my @t = stat($f);
my $modtime = @t ? $t[9] : $MAX_TIME;
if($modtime < ($NOW - $THRESH)) {
my $file = $f;
$file =~ s/^$ROOT//;
my $size = $t[7];
print "deleting old file: $file ($size bytes)\n" if($VERBOSE);
if(unlink($f)) {
$bytes_deleted += $size;
$files_deleted++;
} else {
lib/Cache/Static.pm view on Meta::CPAN
unless($depsref) {
open(F, "$ROOT/$ns/cache/$key.dep");
my $deps_str = <F>;
close(F);
my @deps = split(/\0/, $deps_str);
$depsref = \@deps;
_log(4, "Cache::Static::_is_same: got ".($#deps+1)." deps for $key");
}
#get last modified time of the cached version, or 0 if it doesn't exist
my @t = stat("$ROOT/$ns/cache/$key");
my $request_modtime = @t ? $t[9] : 0;
return (0, "(not yet cached)") unless($request_modtime);
# give a chance to add any module specific extra deps
my %extra_deps;
### TODO: this is too slow, at least for XML::Comma (0.02 sec on p4@3GHz)
# foreach my $dep (@$depsref) {
# my ($type, $spec) = split(/\|/, $dep, 2);
# my $dep_modtime;
# if($type =~ /^_/) {
lib/Cache/Static.pm view on Meta::CPAN
_log(4, "here we are, extension, module: $module, type: $type spec: $spec");
$dep_modtime = eval "Cache::Static::${module}_Util::modtime(\"$type\", \"$spec\")";
if($@) {
_log(3, "error calling Cache::Static::${module}_Util::modtime(\"$type\", \"$spec\"): $@");
} elsif(!$dep_modtime) {
_log(4, "got non-true value from Cache::Static::${module}_Util::modtime(\"$type\", \"$spec\"): $@ $!");
}
} elsif ($type eq 'file') {
_log(4, "here we are, file spec: $spec");
my @t = stat($spec);
$dep_modtime = $t[9];
} elsif ($type eq 'time') {
my $spec_regex = '([0-9]*[hmdsw])+([0-9]*)?';
if ($spec =~ /^[0-9]{10}$/) {
#one-time timestamp expiration
$dep_modtime = $spec;
} elsif ($spec =~ /^$spec_regex$/) {
#5w4d3h2m1s, e.g. 5 weeks, 4 days, ...
#this is a bit backwards: now - spec > time of modification
my $sex = get_seconds_from_timespec($spec);
lib/Cache/Static/DBI_Util.pm view on Meta::CPAN
sub _get_timestamp_file {
my ($type, $spec) = @_;
Cache::Static::_log(4, "DBI_Util: in get_timestamp_file for $type $spec");
return $Cache::Static::ROOT.'/timestamps/'
.Cache::Static::md5_path("DBI|$type|$spec").'.ts';
}
sub modtime {
my $file = _get_timestamp_file(@_);
my @t = stat($file);
die "DBI_Util couldn't get modtime for $file (@_): $!" unless(@t);
return @t ? $t[9] : 0;
}
sub get_extra_deps {
return ( );
}
1;
lib/Cache/Static/XML_Comma_Util.pm view on Meta::CPAN
sub _get_timestamp_file {
my ($type, $spec) = @_;
Cache::Static::_log(4, "XML_Comma_Util: in get_timestamp_file for $type $spec");
return $Cache::Static::ROOT.'/timestamps/'.
Cache::Static::md5_path("XML::Comma|$type|$spec").'.ts';
}
sub modtime {
my $file = _get_timestamp_file(@_);
my @t = stat($file);
die "XML_Comma_Util couldn't get modtime for $file (@_): $!" unless(@t);
return @t ? $t[9] : 0;
}
#bummer, this takes 0.02 seconds... too slow...
# we could cache the spec lookup...
sub get_extra_deps {
my ($type, $spec) = @_;
my @t = split(/\|/, $spec, 1);
( run in 1.511 second using v1.01-cache-2.11-cpan-49f99fa48dc )