line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
############################################################################### |
2
|
|
|
|
|
|
|
# Purpose : Cache data structures against a file (serialised in files using Storable) |
3
|
|
|
|
|
|
|
# Author : John Alden |
4
|
|
|
|
|
|
|
# Created : 22 Apr 2005 (based on IFL::FileCache) |
5
|
|
|
|
|
|
|
# CVS : $Id: Storable.pm,v 1.22 2006/05/09 09:02:32 mattheww Exp $ |
6
|
|
|
|
|
|
|
############################################################################### |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Cache::AgainstFile::Storable; |
9
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
885
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
55
|
|
11
|
2
|
|
|
2
|
|
40
|
use Carp; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
116
|
|
12
|
2
|
|
|
2
|
|
983
|
use Cache::AgainstFile::Base; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
62
|
|
13
|
2
|
|
|
2
|
|
1958
|
use Storable qw(store retrieve retrieve_fd lock_store lock_retrieve); |
|
2
|
|
|
|
|
7125
|
|
|
2
|
|
|
|
|
216
|
|
14
|
2
|
|
|
2
|
|
1676
|
use File::Spec::Functions qw(canonpath catfile rel2abs); |
|
2
|
|
|
|
|
1492
|
|
|
2
|
|
|
|
|
163
|
|
15
|
2
|
|
|
2
|
|
2095
|
use FileHandle; |
|
2
|
|
|
|
|
25684
|
|
|
2
|
|
|
|
|
14
|
|
16
|
|
|
|
|
|
|
|
17
|
2
|
50
|
|
2
|
|
1347
|
use constant IS_WINDOWS => ($^O eq 'MSWin32' ? 1 : 0); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
228
|
|
18
|
|
|
|
|
|
|
if (IS_WINDOWS) { require Win32 } |
19
|
|
|
|
|
|
|
|
20
|
2
|
|
|
|
|
3
|
use constant HAVE_FILE_POLICY => eval { |
21
|
2
|
|
|
|
|
862
|
require File::Policy; |
22
|
0
|
|
|
|
|
0
|
import File::Policy qw(check_safe); |
23
|
0
|
|
|
|
|
0
|
1; |
24
|
2
|
|
|
2
|
|
16
|
}; |
|
2
|
|
|
|
|
5
|
|
25
|
|
|
|
|
|
|
|
26
|
2
|
|
|
2
|
|
9
|
use vars qw($VERSION @ISA); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
4424
|
|
27
|
|
|
|
|
|
|
$VERSION = sprintf"%d.%03d", q$Revision: 1.22 $ =~ /: (\d+)\.(\d+)/; |
28
|
|
|
|
|
|
|
@ISA = qw(Cache::AgainstFile::Base); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# |
31
|
|
|
|
|
|
|
# Public interface |
32
|
|
|
|
|
|
|
# |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub new { |
35
|
9
|
|
|
9
|
1
|
247
|
my $class = shift; |
36
|
9
|
|
|
|
|
17
|
my ($loader, $options) = @_; |
37
|
9
|
|
|
|
|
55
|
my $self = $class->SUPER::new(@_); |
38
|
|
|
|
|
|
|
|
39
|
9
|
|
66
|
|
|
383
|
my $dir = $self->{options}->{CacheDir} || croak("You must supply a cache directory for caching with Storable"); |
40
|
8
|
50
|
|
|
|
39
|
check_safe($dir,"w") if(HAVE_FILE_POLICY); |
41
|
8
|
|
|
|
|
16
|
_create_dir_if_required($dir); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
#Select locking implementation |
44
|
8
|
|
100
|
|
|
39
|
my $locking = $options->{Locking} || 'AtomicWrite'; |
45
|
8
|
100
|
|
|
|
45
|
if($locking eq 'Flock') { |
|
|
100
|
|
|
|
|
|
46
|
1
|
|
|
|
|
3
|
$self->{write} = \&_write_locked; |
47
|
1
|
|
|
|
|
4
|
$self->{read} = \&_read_locked; |
48
|
|
|
|
|
|
|
} elsif ($locking eq 'AtomicWrite') { |
49
|
6
|
|
|
|
|
23
|
$self->{write} = \&_write_atomic; |
50
|
6
|
|
|
|
|
19
|
$self->{read} = \&_read; |
51
|
|
|
|
|
|
|
} else { |
52
|
1
|
|
|
|
|
227
|
croak("Unrecognised locking model '$locking'"); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
7
|
|
|
|
|
32
|
return $self; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub get |
59
|
|
|
|
|
|
|
{ |
60
|
36
|
|
|
36
|
1
|
127
|
my ($self, $filename, @opts) = @_; |
61
|
|
|
|
|
|
|
|
62
|
36
|
50
|
|
|
|
198
|
check_safe($filename,"r") if(HAVE_FILE_POLICY); |
63
|
|
|
|
|
|
|
|
64
|
36
|
|
|
|
|
208
|
my $cache_dir = $self->{options}{CacheDir}; |
65
|
36
|
|
|
|
|
148
|
my $cache_filename = catfile($cache_dir, $self->_filename2cache($filename)); |
66
|
36
|
|
|
|
|
212
|
TRACE("cache get - cache filename is '$cache_filename'"); |
67
|
36
|
|
|
|
|
56
|
my $stale = 0; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# In some (as yet undetermined) circumstances the cachefile directory |
70
|
|
|
|
|
|
|
# can disappear, which causes application errors |
71
|
36
|
|
|
|
|
112
|
_create_dir_if_required($cache_dir); |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# If cachefile doesn't exist, it won't open, implying staleness. |
74
|
36
|
|
|
|
|
324
|
my $cache_fh = new FileHandle; |
75
|
36
|
50
|
|
|
|
2283
|
check_safe($cache_filename,"r") if(HAVE_FILE_POLICY); |
76
|
36
|
100
|
|
|
|
160
|
unless ($cache_fh->open($cache_filename)) { |
77
|
25
|
|
|
|
|
1973
|
undef $cache_fh; |
78
|
25
|
|
|
|
|
113
|
$stale = 1; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Compare file mtimes to check staleness |
82
|
36
|
|
|
|
|
584
|
my $file_mtime; |
83
|
36
|
100
|
100
|
|
|
202
|
unless ($self->{options}->{NoStat} && !$stale) { |
84
|
34
|
|
|
|
|
763
|
$file_mtime = (stat($filename))[9]; |
85
|
34
|
100
|
|
|
|
129
|
my $cache_mtime = ($cache_fh->stat)[9] if $cache_fh; |
86
|
34
|
|
100
|
|
|
630
|
$stale = (!defined $file_mtime) || (!defined $cache_mtime) || ($file_mtime != $cache_mtime); |
87
|
|
|
|
|
|
|
} |
88
|
36
|
100
|
|
|
|
184
|
TRACE("Cache " . ($stale?"is":"is not") . " stale"); |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
#Read from cache |
91
|
36
|
|
|
|
|
63
|
my $data; |
92
|
36
|
100
|
|
|
|
101
|
if (!$stale) { |
93
|
8
|
|
|
|
|
14
|
$data = eval { $self->{read}->($cache_filename, $cache_fh) }; |
|
8
|
|
|
|
|
28
|
|
94
|
8
|
50
|
|
|
|
25
|
if ($@) { |
95
|
0
|
|
|
|
|
0
|
warn "Storable couldn't retrieve $cache_filename: $@"; |
96
|
0
|
|
|
|
|
0
|
$stale = 1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
36
|
100
|
|
|
|
131
|
$cache_fh->close if $cache_fh; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
#Write to cache |
102
|
36
|
100
|
|
|
|
222
|
if ($stale) { |
103
|
28
|
|
|
|
|
84
|
TRACE("writing cache"); |
104
|
28
|
|
|
|
|
159
|
$data = $self->{loader}->($filename, @opts); |
105
|
28
|
50
|
|
|
|
10001177
|
$file_mtime = (stat($filename))[9] unless(defined $file_mtime); #Need mtime now |
106
|
28
|
|
|
|
|
114
|
$self->{write}->($cache_filename, $data, $file_mtime); |
107
|
|
|
|
|
|
|
} |
108
|
36
|
|
|
|
|
206
|
return $data; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub count { |
113
|
8
|
|
|
8
|
1
|
15
|
my ($self) = shift; |
114
|
8
|
|
|
|
|
25
|
my $files_in_cache = $self->_cache_files; |
115
|
7
|
|
|
|
|
43
|
return scalar @$files_in_cache; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub size { |
119
|
5
|
|
|
5
|
1
|
36
|
my ($self) = shift; |
120
|
5
|
|
|
|
|
11
|
my $cache_dir = $self->{options}{CacheDir}; |
121
|
5
|
|
|
|
|
9
|
my $files_in_cache = $self->_cache_files; |
122
|
5
|
|
|
|
|
7
|
my $sum = 0; |
123
|
5
|
|
|
|
|
11
|
foreach(@$files_in_cache) {$sum += -s catfile($cache_dir, $_)} |
|
3
|
|
|
|
|
51
|
|
124
|
5
|
|
|
|
|
22
|
return $sum; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# |
128
|
|
|
|
|
|
|
# Protected methods referenced from Base class |
129
|
|
|
|
|
|
|
# |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub _remove { |
132
|
7
|
|
|
7
|
|
13
|
my($self, $keys) = @_; |
133
|
7
|
|
|
|
|
15
|
my $cache_dir = $self->{options}{CacheDir}; |
134
|
7
|
|
|
|
|
22
|
foreach(@$keys) |
135
|
|
|
|
|
|
|
{ |
136
|
12
|
|
|
|
|
42
|
my $filename = $self->_filename2cache($_); |
137
|
12
|
|
|
|
|
50
|
TRACE("Deleting cache for $_ ($filename)"); |
138
|
12
|
|
|
|
|
1325
|
unlink catfile($cache_dir, $filename); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _accessed { |
143
|
11
|
|
|
11
|
|
19
|
my($self) = @_; |
144
|
11
|
|
|
|
|
32
|
my $cache_dir = $self->{options}{CacheDir}; |
145
|
11
|
|
|
|
|
31
|
my $files_in_cache = $self->_cache_files; |
146
|
17
|
|
|
|
|
104
|
my %accessed = map |
147
|
|
|
|
|
|
|
{ |
148
|
11
|
|
|
|
|
111
|
my $cache_file = catfile($cache_dir, $_); |
149
|
17
|
|
|
|
|
60
|
$self->_cache2filename($_) => (stat($cache_file))[8] |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
@$files_in_cache; |
152
|
11
|
|
|
|
|
49
|
return \%accessed; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _stale { |
156
|
1
|
|
|
1
|
|
2
|
my($self) = @_; |
157
|
1
|
|
|
|
|
11
|
my $cache_dir = $self->{options}{CacheDir}; |
158
|
1
|
|
|
|
|
3
|
my $files_in_cache = $self->_cache_files; |
159
|
1
|
|
|
|
|
3
|
my @out = |
160
|
|
|
|
|
|
|
map |
161
|
|
|
|
|
|
|
{ |
162
|
1
|
|
|
|
|
7
|
$self->_cache2filename($_) |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
grep |
165
|
|
|
|
|
|
|
{ |
166
|
1
|
|
|
|
|
2
|
my $cache_file = catfile($cache_dir, $_); |
167
|
1
|
|
|
|
|
4
|
my $src_mt = (stat ($self->_cache2filename($_)))[9]; |
168
|
1
|
|
|
|
|
13
|
my $cache_mt = (stat ($cache_file))[9]; |
169
|
1
|
50
|
33
|
|
|
16
|
(!defined $src_mt) || (!defined $cache_mt) || ($src_mt != $cache_mt) |
170
|
|
|
|
|
|
|
} @$files_in_cache; |
171
|
1
|
|
|
|
|
5
|
@out; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# |
175
|
|
|
|
|
|
|
# Private methods |
176
|
|
|
|
|
|
|
# |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub _cache_files { |
179
|
25
|
|
|
25
|
|
31
|
my($self) = @_; |
180
|
25
|
|
|
|
|
44
|
my $cache_dir = $self->{options}{CacheDir}; |
181
|
25
|
|
|
|
|
60
|
local *FH; |
182
|
25
|
50
|
|
|
|
82
|
check_safe($cache_dir,"r") if(HAVE_FILE_POLICY); |
183
|
25
|
100
|
|
|
|
684
|
opendir (FH, $cache_dir) or die("unable to open directory $cache_dir - $!"); |
184
|
24
|
|
|
|
|
508
|
my @files = grep {$_ !~ /^\./} readdir(FH); |
|
72
|
|
|
|
|
280
|
|
185
|
24
|
|
|
|
|
244
|
closedir FH; |
186
|
24
|
|
|
|
|
72
|
DUMP("cache files", \@files); |
187
|
24
|
|
|
|
|
82
|
return \@files; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# |
191
|
|
|
|
|
|
|
# Subroutines |
192
|
|
|
|
|
|
|
# |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub _read_locked { |
195
|
2
|
|
|
2
|
|
5
|
my($cache_filename, $fh) = @_; |
196
|
|
|
|
|
|
|
# we don't want the filehandle. Suppose it might need to be closed |
197
|
|
|
|
|
|
|
# under Win32? Close it anyway |
198
|
2
|
50
|
|
|
|
16
|
$fh->close if $fh; |
199
|
2
|
50
|
|
|
|
101
|
check_safe($cache_filename,"r") if(HAVE_FILE_POLICY); |
200
|
2
|
|
|
|
|
10
|
my $ref_data = lock_retrieve($cache_filename); |
201
|
2
|
|
|
|
|
192
|
TRACE("Fetched from cache file: $cache_filename"); |
202
|
2
|
|
|
|
|
6
|
return $$ref_data; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub _write_locked { |
206
|
2
|
|
|
2
|
|
4
|
my ($cache_filename, $data, $mtime) = @_; |
207
|
2
|
50
|
|
|
|
9
|
check_safe($cache_filename,"w") if(HAVE_FILE_POLICY); |
208
|
2
|
|
|
|
|
8
|
lock_store(\$data, $cache_filename); |
209
|
2
|
|
|
|
|
4307
|
TRACE("wrote cache file: $cache_filename"); |
210
|
2
|
|
|
|
|
7
|
_backtouch($cache_filename, $mtime); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub _write_atomic { |
214
|
26
|
|
|
26
|
|
53
|
my ($cache_filename, $data, $mtime) = @_; |
215
|
26
|
50
|
|
|
|
185
|
check_safe($cache_filename,"w") if(HAVE_FILE_POLICY); |
216
|
26
|
|
|
|
|
153
|
my $temp_filename = $cache_filename . ".tmp$$"; |
217
|
26
|
|
|
|
|
138
|
store(\$data, $temp_filename); |
218
|
26
|
|
|
|
|
2296393
|
TRACE("wrote temp file: $temp_filename"); |
219
|
26
|
50
|
|
|
|
100
|
(_backtouch($temp_filename, $mtime)) or die "couldn't set utime on $temp_filename: $!"; |
220
|
26
|
50
|
|
|
|
1764
|
rename($temp_filename, $cache_filename) or die("Unable to rename temporary file '$temp_filename' to cache file '$cache_filename'"); |
221
|
26
|
|
|
|
|
115
|
TRACE("moved to cache file: $cache_filename"); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub _backtouch { |
225
|
28
|
|
|
28
|
|
197
|
my ($file, $utime) = @_; |
226
|
28
|
50
|
|
|
|
82
|
(defined $utime) or confess "need utime"; |
227
|
|
|
|
|
|
|
# Might not work in race condition? Exception NOT thrown, returns false on failure. |
228
|
28
|
50
|
|
|
|
102
|
check_safe($file,"w") if(HAVE_FILE_POLICY); |
229
|
28
|
|
|
|
|
895
|
return utime (time(), $utime, $file); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub _read { |
233
|
6
|
|
|
6
|
|
10
|
my($cache_filename, $fh) = @_; |
234
|
6
|
|
|
|
|
5
|
my $ref_data; |
235
|
6
|
50
|
|
|
|
20
|
check_safe($cache_filename,"r") if(HAVE_FILE_POLICY); |
236
|
6
|
50
|
|
|
|
27
|
if (!$fh) { |
237
|
0
|
|
|
|
|
0
|
TRACE("Reading $cache_filename..."); |
238
|
0
|
|
|
|
|
0
|
$ref_data = retrieve($cache_filename); |
239
|
|
|
|
|
|
|
} else { |
240
|
6
|
|
|
|
|
21
|
TRACE("Reading $cache_filename (from filehandle)..."); |
241
|
6
|
|
|
|
|
21
|
$ref_data = retrieve_fd($$fh); |
242
|
|
|
|
|
|
|
} |
243
|
6
|
|
|
|
|
618
|
return $$ref_data; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub _create_dir_if_required { |
248
|
44
|
|
|
44
|
|
93
|
my ($dir) = @_; |
249
|
44
|
100
|
|
|
|
917
|
if(! -d $dir) { |
250
|
4
|
|
|
|
|
9
|
eval { |
251
|
4
|
|
|
|
|
26
|
require File::Path; |
252
|
4
|
|
|
|
|
24190
|
File::Path::mkpath($dir); |
253
|
|
|
|
|
|
|
}; |
254
|
4
|
50
|
|
|
|
24
|
croak "Unable to create directory $dir: $@" if $@; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# escape and normalise filename |
260
|
|
|
|
|
|
|
sub _filename2cache { |
261
|
61
|
|
|
61
|
|
463
|
my ($self, $filename) = @_; |
262
|
61
|
|
|
|
|
787
|
TRACE({Level => 2}, "filename = $filename"); |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
#Remove redundant slashes |
265
|
61
|
|
|
|
|
363
|
$filename = canonpath($filename); |
266
|
61
|
|
|
|
|
457
|
TRACE({Level => 2}, " - canonpath => $filename"); |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
#Make absolute |
269
|
61
|
|
|
|
|
310
|
my $cache_file = rel2abs($filename); |
270
|
61
|
|
|
|
|
2567
|
TRACE({Level => 2}, " - rel2abs => $cache_file"); |
271
|
|
|
|
|
|
|
|
272
|
61
|
|
|
|
|
197
|
if (IS_WINDOWS) { |
273
|
|
|
|
|
|
|
# resolve C:/LONGNA~1 to C:/LongName |
274
|
|
|
|
|
|
|
$cache_file = Win32::GetFullPathName($cache_file); |
275
|
|
|
|
|
|
|
TRACE({Level => 2}, " - fullpathname => $cache_file"); |
276
|
|
|
|
|
|
|
# normalise path separator |
277
|
|
|
|
|
|
|
$cache_file =~ tr:\\:/:; |
278
|
|
|
|
|
|
|
TRACE({Level => 2}, " - normalise slashes => $cache_file"); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# escape control chars, special characters, etc e.g. '/' -> '%2F' |
282
|
61
|
|
|
|
|
633
|
$cache_file =~ s|([^\w\.\-])| sprintf("%%%02X", ord($1)) |eg; |
|
360
|
|
|
|
|
1813
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# normalise case on case-insensitive filesystems |
285
|
61
|
50
|
|
|
|
555
|
$cache_file = lc $cache_file if File::Spec->case_tolerant; |
286
|
|
|
|
|
|
|
|
287
|
61
|
|
|
|
|
414
|
TRACE({Level => 2}," => cache filename = $cache_file"); |
288
|
61
|
|
|
|
|
492
|
TRACE("filename2cache $filename -> $cache_file"); |
289
|
61
|
|
|
|
|
326
|
return $cache_file; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# unescape filename |
293
|
|
|
|
|
|
|
sub _cache2filename { |
294
|
32
|
|
|
32
|
|
243
|
my $self = shift; |
295
|
32
|
|
|
|
|
39
|
my $cache_file = shift; |
296
|
32
|
|
|
|
|
559
|
(my $filename = $cache_file) =~ s|%([0-9A-Fa-f]{2})| chr(hex($1)) |eg; |
|
186
|
|
|
|
|
627
|
|
297
|
32
|
|
|
|
|
135
|
TRACE("cache2filename $cache_file -> $filename"); |
298
|
32
|
|
|
|
|
640
|
return $filename; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# |
302
|
|
|
|
|
|
|
# Log::Trace stubs |
303
|
|
|
|
|
|
|
# |
304
|
|
|
|
|
|
|
|
305
|
48
|
|
|
48
|
0
|
57
|
sub TRACE {} |
306
|
0
|
|
|
0
|
0
|
|
sub DUMP {} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
1; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head1 NAME |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Cache::AgainstFile::Storable - cache data structures parsed from files in Storable files |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head1 SYNOPSIS |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
use Cache::AgainstFile; |
317
|
|
|
|
|
|
|
my $cache = new Cache::AgainstFile( |
318
|
|
|
|
|
|
|
\&loader, |
319
|
|
|
|
|
|
|
{ |
320
|
|
|
|
|
|
|
Method => 'Storable', |
321
|
|
|
|
|
|
|
CacheDir => '/var/tmp/cache/myapp', |
322
|
|
|
|
|
|
|
# ... |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
$data = $cache->get($filename); |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=head1 DESCRIPTION |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Data structures parsed from files are cached in "shadow" storable files. |
331
|
|
|
|
|
|
|
If parsing is significantly more expensive than file I/O (e.g. with XML files), |
332
|
|
|
|
|
|
|
then this will offer some benefit. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
This backend is suitable for non-persistent environments (e.g. CGI scripts) |
335
|
|
|
|
|
|
|
where you want the cache to outlive the process. For persistent environments, |
336
|
|
|
|
|
|
|
the Memory backend may be more suitable as it saves on file I/O. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
count() and size() are relatively expensive operations involving scanning the cache directory. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head1 OPTIONS |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=over 4 |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item CacheDir |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Directory in which to store cache files. This is mandatory. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=item MaxATime |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Purge items older than this. |
351
|
|
|
|
|
|
|
Value is in seconds (default=undefined=infinity) |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item MaxItems |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Purge oldest items from the cache to reduce the number of items in the cache to be at most this number. |
356
|
|
|
|
|
|
|
Value should be an integer (default=undefined=infinity) |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=item NoStat |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Don't stat files to validate the cache - items are served from the cache until they are purged. |
361
|
|
|
|
|
|
|
Valid values are 0|1 (default=0, i.e. files are statted) |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=item Locking |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Valid values are Flock and AtomicWrite (default is AtomicWrite). |
366
|
|
|
|
|
|
|
If neither of these are to your taste, consider using Cache::AgainstFile::CacheModule with another caching module. |
367
|
|
|
|
|
|
|
Some other file caching modules on CPAN are: |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=over 4 |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=item Cache::FileCache |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
This uses atomic writes. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=item Cache::File |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
This uses File::NFSLock for locking (no locking is also an option) |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=back |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=back |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 VERSION |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
$Revision: 1.22 $ on $Date: 2006/05/09 09:02:32 $ by $Author: mattheww $ |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 AUTHOR |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
John Alden & Piers Kent |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head1 COPYRIGHT |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
(c) BBC 2005. This program is free software; you can redistribute it and/or modify it under the GNU GPL. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
See the file COPYING in this distribution, or http://www.gnu.org/licenses/gpl.txt |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=cut |