| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Tie::FileLRUCache; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
77327
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
48
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
1606
|
use Class::ParmList qw (simple_parms parse_parms); |
|
|
1
|
|
|
|
|
3320
|
|
|
|
1
|
|
|
|
|
93
|
|
|
6
|
1
|
|
|
1
|
|
3147
|
use Digest::SHA1 qw(sha1_hex); |
|
|
1
|
|
|
|
|
4433
|
|
|
|
1
|
|
|
|
|
76
|
|
|
7
|
1
|
|
|
1
|
|
7
|
use Fcntl qw (:flock); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
145
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use File::Spec; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
21
|
|
|
9
|
1
|
|
|
1
|
|
1532
|
use Storable qw (nstore nfreeze retrieve); |
|
|
1
|
|
|
|
|
4817
|
|
|
|
1
|
|
|
|
|
85
|
|
|
10
|
1
|
|
|
1
|
|
9
|
use Symbol qw (gensym); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
54
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
6
|
use vars qw ($VERSION); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
47
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
BEGIN { |
|
15
|
1
|
|
|
1
|
|
5291
|
$VERSION = "1.05"; |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
########################################################################### |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Tie::FileLRUCache - A lightweight but robust filesystem based persistent LRU cache |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 CHANGES |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
1.05 2005.09.14 - Changes to pod tests to make them more CPANTS friendly. |
|
27
|
|
|
|
|
|
|
No functional changes. |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
1.04 2005.09.13 - Removed use of 'warnings' to fix compatibility with Perl 5.005. |
|
30
|
|
|
|
|
|
|
Fixed minor typographical errors in documentation. |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
1.03 2005.09.10 - Changed build test to handle difference in treatment of hashes |
|
33
|
|
|
|
|
|
|
in scalar contect between 5.6.x and 5.8.x versions of Perl that |
|
34
|
|
|
|
|
|
|
caused a test failure under Perl 5.6.x. |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
1.02 2005.09.08 - Added build tests. Major code cleanup. Improved platform portability. |
|
37
|
|
|
|
|
|
|
Added and documented 'cache_dir', 'keep_last' and 'number_of_entries' |
|
38
|
|
|
|
|
|
|
methods. Added Module::Build support. |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
1.01 1999.12.09 - Added 'detainting' to cache management code. |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head2 OBJECT INTERFACE |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
use Tie::FileLRUCache; |
|
47
|
|
|
|
|
|
|
my $cache = Tie::FileLRUCache->new({ -cache_dir => $directory, -keep_last => 100 }); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Inserting value into LRU cache using '-key' |
|
50
|
|
|
|
|
|
|
$cache->update({ -key => $key, -value => $value }); |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Inserting value into LRU cache using '-cache_key' |
|
54
|
|
|
|
|
|
|
my $cache_key = $cache->make_cache_key({ -key => $key }); |
|
55
|
|
|
|
|
|
|
$cache->update({ -cache_key => $cache_key, -value => $value }); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# Checking LRU cache |
|
59
|
|
|
|
|
|
|
my ($in_cache,$value) = $cache->check({ -key => $key }); |
|
60
|
|
|
|
|
|
|
if ($in_cache) { |
|
61
|
|
|
|
|
|
|
return $value; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
# Not in cache - do something else |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Checking LRU cache with speed up hack for objects, hashes, arrays etc used as keys |
|
67
|
|
|
|
|
|
|
my $cache_key = $cache->make_cache_key({ -key => $something }); |
|
68
|
|
|
|
|
|
|
my ($in_cache,$value) = $cache->check({ -cache_key => $cache_key }); |
|
69
|
|
|
|
|
|
|
if ($in_cache) { |
|
70
|
|
|
|
|
|
|
return $value; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
# Not in cache - do something else |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Deleting a key and its value from the cache |
|
76
|
|
|
|
|
|
|
$cache->delete({ -key => $key }); |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Clearing LRU cache |
|
80
|
|
|
|
|
|
|
$cache->clear; |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head2 TIED INTERFACE |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
use Tie::FileLRUCache; |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
[$X =] tie %hash, 'Tie::FileLRUCache', $cache_dir, $keep_last_n; |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Adding a key/value to the cache |
|
89
|
|
|
|
|
|
|
$hash{$key} = $value; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Checking the cache |
|
92
|
|
|
|
|
|
|
if (not exists $hash{$key}) {; |
|
93
|
|
|
|
|
|
|
# No match |
|
94
|
|
|
|
|
|
|
. |
|
95
|
|
|
|
|
|
|
. |
|
96
|
|
|
|
|
|
|
. |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
} else { |
|
99
|
|
|
|
|
|
|
my $value = $hash{$key}; |
|
100
|
|
|
|
|
|
|
. |
|
101
|
|
|
|
|
|
|
. |
|
102
|
|
|
|
|
|
|
. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Removing a value from the cache; |
|
107
|
|
|
|
|
|
|
delete $hash{$key}; |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Clearing the cache |
|
110
|
|
|
|
|
|
|
%hash = (); |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Note: Iteration over the cache (each, keys, values) is _NOT_ supported. |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=cut |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Provides a lightweight persistent filesystem based LRU cache. |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
It uses the 'last accessed' timestamp generated by the file system |
|
121
|
|
|
|
|
|
|
to determine the 'oldest' cache entry and discards the oldest |
|
122
|
|
|
|
|
|
|
cache entries when needed to stay under the -keep_last limit. |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
If you store thing very fast (such that many entries receive the |
|
125
|
|
|
|
|
|
|
same time stamp), it is essentially a coin toss which entry |
|
126
|
|
|
|
|
|
|
within a single timestamped second gets purged from the cache |
|
127
|
|
|
|
|
|
|
to make room for new ones. |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
It is not designed to handle huge numbers of cached items. It is probably |
|
130
|
|
|
|
|
|
|
unwise to set the 'keep_last' higher than around 100. |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head1 OBJECT METHODS |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=cut |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
####################################################################### |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=over 4 |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=item new({[ -cache_dir => $cache_directory] [, -keep_last => $keep_last_n ] }); |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
Creates and optionally initializes a Tie::FileLRUCache object: |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Example: |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
my $cache = Tie::FileLRUCache->new({ |
|
149
|
|
|
|
|
|
|
-cache_dir => '/tmp/testing', |
|
150
|
|
|
|
|
|
|
-keep_last => 100, |
|
151
|
|
|
|
|
|
|
}); |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
The default cache size is 100 entries unless specified. |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=back |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=cut |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub new { |
|
160
|
13
|
|
|
13
|
1
|
4692
|
my $proto = shift; |
|
161
|
13
|
|
|
|
|
168
|
my $package = __PACKAGE__; |
|
162
|
13
|
|
66
|
|
|
73
|
my $class = ref ($proto) || $proto || $package; |
|
163
|
13
|
|
|
|
|
27
|
my $self = bless {}, $class; |
|
164
|
|
|
|
|
|
|
|
|
165
|
13
|
|
|
|
|
125
|
my $parms = parse_parms({ -parms => \@_, |
|
166
|
|
|
|
|
|
|
-legal => [-cache_dir, -keep_last], |
|
167
|
|
|
|
|
|
|
-required => [], |
|
168
|
|
|
|
|
|
|
-defaults => { -keep_last => 100, |
|
169
|
|
|
|
|
|
|
-cache_dir => undef, |
|
170
|
|
|
|
|
|
|
}, |
|
171
|
|
|
|
|
|
|
}); |
|
172
|
13
|
100
|
|
|
|
1184
|
if (not defined $parms) { |
|
173
|
1
|
|
|
|
|
6
|
my $error_message = Class::ParmList->error; |
|
174
|
1
|
|
|
|
|
9
|
require Carp; |
|
175
|
1
|
|
|
|
|
147
|
Carp::croak ($package . "::new() - Parameter error '$error_message'\n"); |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Save settings |
|
179
|
12
|
|
|
|
|
50
|
my ($cache_dir,$keep_last) = $parms->get(-cache_dir,-keep_last); |
|
180
|
12
|
|
|
|
|
282
|
$self->cache_dir($cache_dir); |
|
181
|
12
|
|
|
|
|
25
|
$self->keep_last($keep_last); |
|
182
|
|
|
|
|
|
|
|
|
183
|
12
|
|
|
|
|
63
|
$self; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
####################################################################### |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=over 4 |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item check({ -key => $key }); |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Reads the cache for the key. |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
Returns two values: $cache_hit (true if a hit was found, false if not) |
|
195
|
|
|
|
|
|
|
$value (the cached value, undef if no hit) |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Examples: |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
my ($cache_hit,$value) = $cache->check({ -key => $key }); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my ($cache_hit,$value) = $cache->check({ -cache_key => $cache_key }); |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
The '-key' form is used when you just want to use a raw key. It can use |
|
204
|
|
|
|
|
|
|
blessed objects, hash refs, scalars, or array refs as keys. The more complex |
|
205
|
|
|
|
|
|
|
structures take a speed penalty for computing a canonical form. |
|
206
|
|
|
|
|
|
|
You can minimize this penalty by using the '-cache_key' form instead. |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
The '-cache_key' form is used for performance reasons when using keys |
|
209
|
|
|
|
|
|
|
such as complex blessed objects or hashes as a key. The -cache_key |
|
210
|
|
|
|
|
|
|
is obtained with a call to 'make_cache_key'. It is legal to mix |
|
211
|
|
|
|
|
|
|
-cache_key and -key based calls - they are cross-compatible. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=back |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=cut |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub check { |
|
218
|
48
|
|
|
48
|
1
|
554
|
my $self = shift; |
|
219
|
48
|
|
|
|
|
80
|
my $package = __PACKAGE__; |
|
220
|
|
|
|
|
|
|
|
|
221
|
48
|
100
|
|
|
|
122
|
if (not wantarray) { |
|
222
|
1
|
|
|
|
|
4
|
require Carp; |
|
223
|
1
|
|
|
|
|
75
|
Carp::croak ($package . "::check() - Called in a scalar context\n"); |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
47
|
|
|
|
|
507
|
my $parms = parse_parms({ -parms => \@_, |
|
227
|
|
|
|
|
|
|
-legal => [-cache_key, -key], |
|
228
|
|
|
|
|
|
|
-required => [], |
|
229
|
|
|
|
|
|
|
-defaults => {}, |
|
230
|
|
|
|
|
|
|
}); |
|
231
|
46
|
100
|
|
|
|
8398
|
if (not defined $parms) { |
|
232
|
1
|
|
|
|
|
4
|
my $error_message = Class::ParmList->error; |
|
233
|
1
|
|
|
|
|
7
|
require Carp; |
|
234
|
1
|
|
|
|
|
97
|
Carp::croak ($package . "::check() - $error_message\n"); |
|
235
|
|
|
|
|
|
|
} |
|
236
|
45
|
|
|
|
|
7387
|
my ($key,$cache_key) = $parms->get(-key,-cache_key); |
|
237
|
45
|
100
|
100
|
|
|
1538
|
if (not (defined ($key) or defined ($cache_key))) { |
|
238
|
1
|
|
|
|
|
3
|
require Carp; |
|
239
|
1
|
|
|
|
|
79
|
Carp::croak ($package . "::check() - Called without either a -key or -cache_key\n"); |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
44
|
|
|
|
|
147
|
my $cache_dir = $self->cache_dir; |
|
243
|
44
|
100
|
|
|
|
117
|
unless (defined $cache_dir) { |
|
244
|
1
|
|
|
|
|
4
|
require Carp; |
|
245
|
1
|
|
|
|
|
80
|
Carp::croak ($package . "::check - No cache directory set.\n"); |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Ok. Set our lock on the cache |
|
249
|
43
|
|
|
|
|
115
|
$self->_lock_cache; |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# Generate the cache_key (done by making a cannonical |
|
252
|
|
|
|
|
|
|
# network order Storable string out of the key) if we |
|
253
|
|
|
|
|
|
|
# don't already have it |
|
254
|
43
|
100
|
|
|
|
163
|
unless (defined $cache_key) { |
|
255
|
5
|
|
|
|
|
25
|
$cache_key = $self->make_cache_key({ -key => $key }); |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Generate a unique cache file name by taking a SHA1 hash of $cache_key |
|
259
|
43
|
|
|
|
|
416
|
my $cache_hash = lc(sha1_hex($cache_key)); |
|
260
|
43
|
|
|
|
|
189
|
$cache_hash =~ s/\s//gs; |
|
261
|
43
|
|
|
|
|
459
|
my ($untainted_cache_hash) = $cache_hash =~ m/^([a-f0-9]+)$/s; |
|
262
|
43
|
|
|
|
|
674
|
my $cache_file = File::Spec->catfile($cache_dir, "cl_$untainted_cache_hash"); |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# Check if there is a cache entry for this key |
|
265
|
43
|
100
|
|
|
|
1580
|
unless (-e $cache_file) { |
|
266
|
22
|
|
|
|
|
86
|
$self->_unlock_cache; |
|
267
|
22
|
|
|
|
|
308
|
return (0,undef); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Yes. Get it. And update the last modified and last accessed dates. |
|
271
|
21
|
|
|
|
|
31
|
my $entry; |
|
272
|
21
|
|
|
|
|
51
|
eval { |
|
273
|
21
|
|
|
|
|
91
|
$entry = retrieve($cache_file); |
|
274
|
21
|
|
|
|
|
2073
|
my $now = time; |
|
275
|
21
|
|
|
|
|
1346
|
utime ($now, $now, $cache_file); |
|
276
|
|
|
|
|
|
|
}; |
|
277
|
21
|
50
|
|
|
|
69
|
if ($@) { |
|
278
|
0
|
|
|
|
|
0
|
my $error = $@; |
|
279
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
280
|
0
|
|
|
|
|
0
|
require Carp; |
|
281
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::check - Error while retrieving cache entry file '$cache_file': $error\n"); |
|
282
|
|
|
|
|
|
|
} |
|
283
|
21
|
50
|
|
|
|
51
|
unless (defined $entry) { |
|
284
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
285
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
286
|
0
|
|
|
|
|
0
|
require Carp; |
|
287
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::update - Failed to retrieve cache entry file '$cache_file': $error\n"); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Release the lock. |
|
291
|
21
|
|
|
|
|
69
|
$self->_unlock_cache; |
|
292
|
|
|
|
|
|
|
|
|
293
|
21
|
|
|
|
|
56
|
my $cache_value = $entry->{'-value'}; |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Give them their cupie doll |
|
296
|
21
|
|
|
|
|
320
|
return (1, $cache_value); |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
####################################################################### |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=over 4 |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=item make_cache_key({ -key => $key }); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Generates a cache key by canonicalizing a passed |
|
306
|
|
|
|
|
|
|
key as a network ordered canonical Storable string. |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Example: |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
my $cache_key = $cache->make_cache_key({ -key => $key }); |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=back |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=cut |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub make_cache_key { |
|
317
|
11
|
|
|
11
|
1
|
28
|
my $self = shift; |
|
318
|
11
|
|
|
|
|
21
|
my $package = __PACKAGE__; |
|
319
|
11
|
|
|
|
|
81
|
my $parms = parse_parms({ -parms => \@_, |
|
320
|
|
|
|
|
|
|
-legal => [], |
|
321
|
|
|
|
|
|
|
-required => ['-key'], |
|
322
|
|
|
|
|
|
|
-defaults => {}, |
|
323
|
|
|
|
|
|
|
}); |
|
324
|
11
|
100
|
|
|
|
933
|
unless (defined $parms) { |
|
325
|
1
|
|
|
|
|
8
|
my $error_message = Class::ParmList->error; |
|
326
|
1
|
|
|
|
|
9
|
require Carp; |
|
327
|
1
|
|
|
|
|
130
|
Carp::croak ($package . "::make_cache_key() - $error_message\n"); |
|
328
|
|
|
|
|
|
|
} |
|
329
|
10
|
|
|
|
|
37
|
my ($key) = $parms->get(-key); |
|
330
|
|
|
|
|
|
|
|
|
331
|
10
|
|
|
|
|
260
|
my $temp = $Storable::canonical; |
|
332
|
10
|
|
|
|
|
35
|
my $result = nfreeze(\$key); |
|
333
|
10
|
|
|
|
|
397
|
$Storable::canonical = $temp; |
|
334
|
|
|
|
|
|
|
|
|
335
|
10
|
50
|
|
|
|
25
|
if (not $result) { |
|
336
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
337
|
0
|
|
|
|
|
0
|
require Carp; |
|
338
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::check() - Unable to serialize passed -key value: $error"); |
|
339
|
|
|
|
|
|
|
} |
|
340
|
10
|
|
|
|
|
54
|
return $result; |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
####################################################################### |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=over 4 |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=item clear; |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Completely clears the cache of all cache entries. |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=back |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=cut |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
sub clear { |
|
356
|
4
|
|
|
4
|
1
|
28
|
my $self = shift; |
|
357
|
4
|
|
|
|
|
9
|
my $package = __PACKAGE__; |
|
358
|
4
|
|
|
|
|
13
|
my $cache_dir = $self->cache_dir; |
|
359
|
|
|
|
|
|
|
|
|
360
|
4
|
100
|
|
|
|
15
|
unless (defined $cache_dir) { |
|
361
|
1
|
|
|
|
|
12
|
require Carp; |
|
362
|
1
|
|
|
|
|
163
|
Carp::croak ($package . "::clear - No cache directory set.\n"); |
|
363
|
|
|
|
|
|
|
} |
|
364
|
3
|
100
|
|
|
|
9
|
if ($cache_dir eq '') { |
|
365
|
1
|
|
|
|
|
5
|
require Carp; |
|
366
|
1
|
|
|
|
|
80
|
Carp::croak ($package . "::clear - Cannot use root directory as cache directory.\n"); |
|
367
|
|
|
|
|
|
|
} |
|
368
|
2
|
50
|
33
|
|
|
58
|
if ((-e $cache_dir) and (not -d _)) { |
|
369
|
0
|
|
|
|
|
0
|
require Carp; |
|
370
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::clear - '$cache_dir' already exists and is not a directory.\n"); |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
2
|
|
|
|
|
8
|
$self->_lock_cache; |
|
374
|
|
|
|
|
|
|
|
|
375
|
2
|
|
|
|
|
11
|
my $cache_dir_fh = gensym; |
|
376
|
2
|
50
|
|
|
|
135
|
if (not opendir ($cache_dir_fh, $cache_dir)) { |
|
377
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
378
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
379
|
0
|
|
|
|
|
0
|
require Carp; |
|
380
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::clear - Failed to open directory '$cache_dir' for reading: $error\n"); |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
|
|
383
|
2
|
|
|
|
|
48
|
my @raw_directory_list = readdir($cache_dir_fh); |
|
384
|
2
|
50
|
|
|
|
38
|
unless (closedir ($cache_dir_fh)) { |
|
385
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
386
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
387
|
0
|
|
|
|
|
0
|
require Carp; |
|
388
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::clear - Failed to close directory '$cache_dir': $error\n"); |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Untaint the filenames, convert them to absolute file paths and unlink them. |
|
392
|
2
|
|
|
|
|
41
|
my @raw_files_list = grep(/^(cacheline_[a-zA-Z0-9]{1,50}|cl_[a-zA-Z0-9]{1,50})$/s, @raw_directory_list); |
|
393
|
2
|
|
|
|
|
4
|
my @file_list = (); |
|
394
|
2
|
|
|
|
|
6
|
foreach my $item (@raw_files_list) { |
|
395
|
10
|
|
|
|
|
73
|
my ($filename) = $item =~ m/^(.*)$/s; |
|
396
|
10
|
|
|
|
|
138
|
my $file_path = File::Spec->catfile($cache_dir, $filename); |
|
397
|
10
|
50
|
|
|
|
5379
|
unless (unlink $file_path) { |
|
398
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
399
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
400
|
0
|
|
|
|
|
0
|
require Carp; |
|
401
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::clear - Failed to unlink file '$file_path': $error"); |
|
402
|
|
|
|
|
|
|
} |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
|
|
405
|
2
|
|
|
|
|
16
|
$self->_unlock_cache; |
|
406
|
|
|
|
|
|
|
|
|
407
|
2
|
|
|
|
|
26
|
return; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
####################################################################### |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=over 4 |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=item update({ [-key => $key,] [-cache_key => $cache_key, ], -value => $value [, -keep_last => $keep_last_n ] }); |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Updates the Least Recently Used (LRU) cache for the specified |
|
417
|
|
|
|
|
|
|
key with the passed value. '-keep_last' is optional after the first access |
|
418
|
|
|
|
|
|
|
to a dataset. It will use the I 'keep_last' used |
|
419
|
|
|
|
|
|
|
if not specified. |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
It is legal to use ordinary scalars, hash references, or array references |
|
422
|
|
|
|
|
|
|
as keys as well as objects as -keys or -values. Basically, anything that |
|
423
|
|
|
|
|
|
|
Storable can reproducibly serialize can be used. |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Examples: |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
$cache->update({ -key => $key, -value => $value }); |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
$cache->update({ -key => $key, -value => $value, -keep_last => 100}); |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
my $cache_key = $cache->make_cache_key({ -key => $key }); |
|
432
|
|
|
|
|
|
|
$cache->update({ -cache_key => $cache_key, -value => $value }); |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
my $cache_key = $cache->make_cache_key({ -key => $key }); |
|
435
|
|
|
|
|
|
|
$cache->update({ -cache_key => $cache_key, -value => $value, -keep_last => 50 }); |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
-cache_key is assumed to be a simple scalar value for use as a key. |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
-key can be pretty much anything Storable can successfully and reproducibly serialize. |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
One or the other I be passed. |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=back |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=cut |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub update { |
|
448
|
21
|
|
|
21
|
1
|
6001245
|
my $self = shift; |
|
449
|
21
|
|
|
|
|
37
|
my $package = __PACKAGE__; |
|
450
|
|
|
|
|
|
|
|
|
451
|
21
|
|
|
|
|
242
|
my $parms = parse_parms({ -parms => \@_, |
|
452
|
|
|
|
|
|
|
-legal => ['-keep_last', '-key', '-cache_key'], |
|
453
|
|
|
|
|
|
|
-required => ['-value'], |
|
454
|
|
|
|
|
|
|
-defaults => {'-keep_last' => $self->keep_last}, |
|
455
|
|
|
|
|
|
|
}); |
|
456
|
21
|
100
|
|
|
|
3259
|
unless (defined $parms) { |
|
457
|
1
|
|
|
|
|
5
|
my $error_message = Class::ParmList->error; |
|
458
|
1
|
|
|
|
|
7
|
require Carp; |
|
459
|
1
|
|
|
|
|
110
|
Carp::croak ($package . "::update() - $error_message\n"); |
|
460
|
|
|
|
|
|
|
} |
|
461
|
20
|
|
|
|
|
138
|
my ($key,$cache_key,$value,$keep_last) = $parms->get('-key', '-cache_key', '-value', '-keep_last'); |
|
462
|
20
|
100
|
100
|
|
|
1792
|
unless (defined ($key) or defined ($cache_key)) { |
|
463
|
1
|
|
|
|
|
4
|
require Carp; |
|
464
|
1
|
|
|
|
|
106
|
Carp::croak ($package . "::update() - Called without either a -key or -cache_key. At least one of them must be passed.\n"); |
|
465
|
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
|
|
467
|
19
|
|
|
|
|
241
|
my ($cache_dir) = $self->cache_dir; |
|
468
|
19
|
100
|
|
|
|
67
|
unless (defined $cache_dir) { |
|
469
|
1
|
|
|
|
|
4
|
require Carp; |
|
470
|
1
|
|
|
|
|
90
|
Carp::croak ($package . "::update - No cache directory set.\n"); |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# Generate the cache_key (done by making a cannonical |
|
474
|
|
|
|
|
|
|
# network order Storable string out of the key) if we |
|
475
|
|
|
|
|
|
|
# don't already have one. |
|
476
|
18
|
100
|
|
|
|
60
|
unless (defined $cache_key) { |
|
477
|
2
|
|
|
|
|
9
|
$cache_key = $self->make_cache_key({ -key => $key }); |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# Generate a unique cache file |
|
481
|
|
|
|
|
|
|
# name by taking a SHA1 hash of |
|
482
|
|
|
|
|
|
|
# $cache_key and dumping it as hex |
|
483
|
18
|
|
|
|
|
203
|
my $cache_hash = lc(sha1_hex($cache_key)); |
|
484
|
18
|
|
|
|
|
2798
|
$cache_hash =~ s/\s//gs; |
|
485
|
18
|
|
|
|
|
165
|
my ($untainted_cache_hash) = $cache_hash =~ m/^([a-f0-9]+)$/s; |
|
486
|
18
|
|
|
|
|
382
|
my $cache_file = File::Spec->catfile($cache_dir, "cl_$untainted_cache_hash"); |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# Serialize the $value for storage |
|
489
|
18
|
|
|
|
|
81
|
my $entry = { -value => $value }; |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
# Set our lock on the cache directory |
|
492
|
18
|
|
|
|
|
1560
|
$self->_lock_cache; |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
########## |
|
495
|
|
|
|
|
|
|
# Store the cache entry. |
|
496
|
18
|
|
|
|
|
27
|
my $result; |
|
497
|
18
|
|
|
|
|
56
|
eval { $result = nstore($entry,$cache_file); }; |
|
|
18
|
|
|
|
|
115
|
|
|
498
|
18
|
50
|
|
|
|
7207
|
if ($@) { |
|
499
|
0
|
|
|
|
|
0
|
my $error = $@; |
|
500
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
501
|
0
|
|
|
|
|
0
|
require Carp; |
|
502
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::update - Error while saving cache entry file '$cache_file': $error"); |
|
503
|
|
|
|
|
|
|
} |
|
504
|
18
|
50
|
|
|
|
66
|
unless (defined $result) { |
|
505
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
506
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
507
|
0
|
|
|
|
|
0
|
require Carp; |
|
508
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::update - Error while saving cache entry file '$cache_file': $error\n"); |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
######################################## |
|
512
|
|
|
|
|
|
|
# Check if we need to purge old entries |
|
513
|
18
|
|
|
|
|
74
|
my $cache_dir_fh = gensym; |
|
514
|
18
|
50
|
|
|
|
1349
|
unless (opendir ($cache_dir_fh, $cache_dir)) { |
|
515
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
516
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
517
|
0
|
|
|
|
|
0
|
require Carp; |
|
518
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::update - Failed to open directory '$cache_dir' for reading: $error\n"); |
|
519
|
|
|
|
|
|
|
} |
|
520
|
18
|
|
|
|
|
2149
|
my @raw_file_list = grep(/^(cacheline_[a-fA-F0-9]{1,50}|cl_[a-fA-F0-9]{1,50})$/s,readdir($cache_dir_fh)); |
|
521
|
18
|
50
|
|
|
|
427
|
unless (closedir ($cache_dir_fh)) { |
|
522
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
523
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
524
|
0
|
|
|
|
|
0
|
require Carp; |
|
525
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::update - Failed to close directory '$cache_dir': $error\n"); |
|
526
|
|
|
|
|
|
|
} |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# Untainting the filenames and converting them to absolute file paths. |
|
529
|
18
|
|
|
|
|
44
|
my @file_list = (); |
|
530
|
18
|
|
|
|
|
56
|
foreach my $item (@raw_file_list) { |
|
531
|
58
|
|
|
|
|
222
|
my ($filename) = $item =~ m/^(.*)$/s; |
|
532
|
58
|
|
|
|
|
625
|
my $file_path = File::Spec->catfile($cache_dir, $filename); |
|
533
|
58
|
|
|
|
|
182
|
push (@file_list,$file_path); |
|
534
|
|
|
|
|
|
|
} |
|
535
|
18
|
|
|
|
|
55
|
my $n_files = $#file_list + 1; |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
# No problems. All done. |
|
538
|
18
|
100
|
|
|
|
51
|
if ($n_files <= $keep_last) { |
|
539
|
14
|
|
|
|
|
57
|
$self->_unlock_cache; |
|
540
|
14
|
|
|
|
|
687
|
return; |
|
541
|
|
|
|
|
|
|
} |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# Too many entries. Delete the excess entries (usually only one) |
|
544
|
4
|
|
|
|
|
15
|
my %file_last_access = (); |
|
545
|
4
|
|
|
|
|
11
|
foreach my $file (@file_list) { |
|
546
|
24
|
|
|
|
|
493
|
my $last_accessed = (stat($file))[9]; |
|
547
|
24
|
|
|
|
|
89
|
$file_last_access{$file} = $last_accessed; |
|
548
|
|
|
|
|
|
|
} |
|
549
|
4
|
|
|
|
|
36
|
my @sorted_file_list = sort { $file_last_access{$b} <=> $file_last_access{$a} } @file_list; |
|
|
40
|
|
|
|
|
96
|
|
|
550
|
4
|
|
66
|
|
|
34
|
while (($n_files > $keep_last) and ($n_files > 0)) { |
|
551
|
4
|
|
|
|
|
7
|
$n_files--; |
|
552
|
4
|
|
|
|
|
9
|
my $pruned_file = $sorted_file_list[$n_files]; |
|
553
|
4
|
50
|
|
|
|
126818
|
unless (unlink $pruned_file) { |
|
554
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
555
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
556
|
0
|
|
|
|
|
0
|
require Carp; |
|
557
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::update - Failed to unlink file '$pruned_file': $error"); |
|
558
|
|
|
|
|
|
|
} |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# Release our lock and return |
|
562
|
4
|
|
|
|
|
169
|
$self->_unlock_cache; |
|
563
|
4
|
|
|
|
|
111
|
return; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
####################################################################### |
|
567
|
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=over 4 |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=item delete({ -key => $key }); |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Forces the deletion of a specific key from the cache. |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
Example: |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
$cache->delete({ -key => $key }); |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=back |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=cut |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub delete { |
|
583
|
8
|
|
|
8
|
1
|
86
|
my $self = shift; |
|
584
|
8
|
|
|
|
|
10
|
my $package = __PACKAGE__; |
|
585
|
|
|
|
|
|
|
|
|
586
|
8
|
|
|
|
|
60
|
my $parms = parse_parms({ -parms => \@_, |
|
587
|
|
|
|
|
|
|
-legal => [-key, -cache_key], |
|
588
|
|
|
|
|
|
|
-required => [], |
|
589
|
|
|
|
|
|
|
-defaults => {}, |
|
590
|
|
|
|
|
|
|
}); |
|
591
|
7
|
100
|
|
|
|
529
|
if (not defined $parms) { |
|
592
|
1
|
|
|
|
|
4
|
my $error_message = Class::ParmList->error; |
|
593
|
1
|
|
|
|
|
6
|
require Carp; |
|
594
|
1
|
|
|
|
|
97
|
Carp::croak ($package . "::delete() - $error_message\n"); |
|
595
|
|
|
|
|
|
|
} |
|
596
|
6
|
|
|
|
|
28
|
my ($key,$cache_key) = $parms->get(-key, -cache_key); |
|
597
|
6
|
100
|
100
|
|
|
149
|
if (not (defined ($key) or defined ($cache_key))) { |
|
598
|
1
|
|
|
|
|
4
|
require Carp; |
|
599
|
1
|
|
|
|
|
75
|
Carp::croak ($package . "::delete() - Called without either a -key or -cache_key\n"); |
|
600
|
|
|
|
|
|
|
} |
|
601
|
|
|
|
|
|
|
|
|
602
|
5
|
|
|
|
|
12
|
my $cache_dir = $self->cache_dir; |
|
603
|
5
|
100
|
|
|
|
13
|
unless (defined $cache_dir) { |
|
604
|
1
|
|
|
|
|
25
|
require Carp; |
|
605
|
1
|
|
|
|
|
82
|
Carp::croak ($package . "::delete - No cache directory set.\n"); |
|
606
|
|
|
|
|
|
|
} |
|
607
|
4
|
50
|
|
|
|
12
|
if ($cache_dir eq '') { |
|
608
|
0
|
|
|
|
|
0
|
require Carp; |
|
609
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::delete - Cannot use root directory as cache directory.\n"); |
|
610
|
|
|
|
|
|
|
} |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
# Generate the cache_key (done by making a cannonical |
|
613
|
|
|
|
|
|
|
# network order Storable string out of the key) if we |
|
614
|
|
|
|
|
|
|
# don't already have it |
|
615
|
4
|
100
|
|
|
|
11
|
if (not defined $cache_key) { |
|
616
|
2
|
|
|
|
|
8
|
$cache_key = $self->make_cache_key({ -key => $key }); |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# Generate a unique cache file |
|
620
|
|
|
|
|
|
|
# name by taking a SHA1 hash of |
|
621
|
|
|
|
|
|
|
# $cache_key |
|
622
|
4
|
|
|
|
|
21
|
my $cache_hash = lc(sha1_hex($cache_key)); |
|
623
|
4
|
|
|
|
|
11
|
$cache_hash =~ s/\s//gs; |
|
624
|
4
|
|
|
|
|
19
|
my ($untainted_cache_hash) = $cache_hash =~ m/^([a-f0-9]+)$/s; |
|
625
|
4
|
|
|
|
|
52
|
my $cache_file = File::Spec->catfile($cache_dir, "cl_$untainted_cache_hash"); |
|
626
|
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
# Ok. Set our lock on the cache directory |
|
628
|
4
|
|
|
|
|
14
|
$self->_lock_cache; |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
# If it is in the cache, remove it |
|
631
|
4
|
50
|
33
|
|
|
446
|
if ((-e $cache_file) and (not unlink $cache_file)) { |
|
632
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
633
|
0
|
|
|
|
|
0
|
$self->_unlock_cache; |
|
634
|
0
|
|
|
|
|
0
|
require Carp; |
|
635
|
0
|
|
|
|
|
0
|
Carp::croak($package . "::delete - Failed to unlink file '$cache_file': $error"); |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# Release our lock and return |
|
639
|
4
|
|
|
|
|
14
|
$self->_unlock_cache; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
####################################################################### |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=over 4 |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
=item cache_dir([$cache_directory_path]); |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
Get/Set accessor for the cache directory path. |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
Ex. |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
my $cache_directory = $cache->cache_dir; |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
$cache->cache_dir($cache_directory); |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=back |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=cut |
|
659
|
|
|
|
|
|
|
|
|
660
|
163
|
|
|
163
|
1
|
12950
|
sub cache_dir { return shift->_property('cache_dir', @_); } |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
####################################################################### |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=over 4 |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=item keep_last([$keep_last_n]); |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
Get/Set accessor for the keep last N setting. |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
Ex. |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
my $n_last = $cache->keep_last; |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
$cache->keep_last(20); |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=back |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=cut |
|
679
|
|
|
|
|
|
|
|
|
680
|
37
|
|
|
37
|
1
|
124
|
sub keep_last { return shift->_property('keep_last', @_); } |
|
681
|
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
####################################################################### |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=over 4 |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
=item number_of_entries; |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
Returns the current number of entries in the cache. |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=back |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=cut |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
sub number_of_entries { |
|
696
|
2
|
|
|
2
|
1
|
2000337
|
my $self = shift; |
|
697
|
2
|
|
|
|
|
8
|
my $package = __PACKAGE__; |
|
698
|
|
|
|
|
|
|
|
|
699
|
2
|
|
|
|
|
23
|
my $cache_dir_fh = gensym; |
|
700
|
2
|
|
|
|
|
64
|
my $cache_dir = $self->cache_dir; |
|
701
|
2
|
50
|
|
|
|
15
|
unless (defined $cache_dir) { |
|
702
|
0
|
|
|
|
|
0
|
require Carp; |
|
703
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::delete - No cache directory set.\n"); |
|
704
|
|
|
|
|
|
|
} |
|
705
|
2
|
50
|
|
|
|
12
|
if ($cache_dir eq '') { |
|
706
|
0
|
|
|
|
|
0
|
require Carp; |
|
707
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::delete - Cannot use root directory as cache directory.\n"); |
|
708
|
|
|
|
|
|
|
} |
|
709
|
|
|
|
|
|
|
|
|
710
|
2
|
50
|
|
|
|
156
|
unless (opendir ($cache_dir_fh, $cache_dir)) { |
|
711
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
712
|
0
|
|
|
|
|
0
|
require Carp; |
|
713
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::update - Failed to open directory '$cache_dir' for reading: $error\n"); |
|
714
|
|
|
|
|
|
|
} |
|
715
|
2
|
|
|
|
|
171
|
my @raw_file_list = grep(/^(cacheline_[a-fA-F0-9]{1,50}|cl_[a-fA-F0-9]{1,50})$/s,readdir($cache_dir_fh)); |
|
716
|
2
|
50
|
|
|
|
134
|
unless (closedir ($cache_dir_fh)) { |
|
717
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
718
|
0
|
|
|
|
|
0
|
require Carp; |
|
719
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::update - Failed to close directory '$cache_dir': $error\n"); |
|
720
|
|
|
|
|
|
|
} |
|
721
|
2
|
|
|
|
|
8
|
my $n_entries = $#raw_file_list + 1; |
|
722
|
2
|
|
|
|
|
21
|
return $n_entries; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
####################################################################### |
|
726
|
|
|
|
|
|
|
# # |
|
727
|
|
|
|
|
|
|
# PRIVATE METHODS # |
|
728
|
|
|
|
|
|
|
# # |
|
729
|
|
|
|
|
|
|
# Internals. Documented for maintainance reasons only. # |
|
730
|
|
|
|
|
|
|
# Do not use these methods from outside this module. # |
|
731
|
|
|
|
|
|
|
# # |
|
732
|
|
|
|
|
|
|
####################################################################### |
|
733
|
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
####################################################################### |
|
735
|
|
|
|
|
|
|
# _cache_lock_fh([$fh]); |
|
736
|
|
|
|
|
|
|
# |
|
737
|
|
|
|
|
|
|
# Get/Set accessor used to store a reference to the filehandle |
|
738
|
|
|
|
|
|
|
# used for locking. |
|
739
|
|
|
|
|
|
|
|
|
740
|
134
|
|
|
134
|
|
400
|
sub _cache_lock_fh { return shift->_property('_cache_lock_fh', @_); } |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
####################################################################### |
|
743
|
|
|
|
|
|
|
# _lock_cache; |
|
744
|
|
|
|
|
|
|
# |
|
745
|
|
|
|
|
|
|
# Obtains a lock on the 'cache.lock' file for this LRU cache. |
|
746
|
|
|
|
|
|
|
# |
|
747
|
|
|
|
|
|
|
# Example: |
|
748
|
|
|
|
|
|
|
# $self->_lock_cache; |
|
749
|
|
|
|
|
|
|
# |
|
750
|
|
|
|
|
|
|
# This will create the 'cache.lock' file if it does not already exist, |
|
751
|
|
|
|
|
|
|
# creating any intermediate directories as needed. |
|
752
|
|
|
|
|
|
|
# |
|
753
|
|
|
|
|
|
|
# It also writes the current PID to the lock file. |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
sub _lock_cache { |
|
756
|
67
|
|
|
67
|
|
114
|
my $self = shift; |
|
757
|
67
|
|
|
|
|
95
|
my $package = __PACKAGE__; |
|
758
|
|
|
|
|
|
|
|
|
759
|
67
|
|
|
|
|
171
|
my $cache_dir = $self->cache_dir; |
|
760
|
67
|
50
|
|
|
|
3238
|
if (not defined $cache_dir) { |
|
761
|
0
|
|
|
|
|
0
|
require Carp; |
|
762
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - No cache directory set.\n"); |
|
763
|
|
|
|
|
|
|
} |
|
764
|
67
|
50
|
|
|
|
5420
|
if ($cache_dir eq '') { |
|
765
|
0
|
|
|
|
|
0
|
require Carp; |
|
766
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Cannot use root directory as cache directory.\n"); |
|
767
|
|
|
|
|
|
|
} |
|
768
|
67
|
50
|
33
|
|
|
7122
|
if ((-e $cache_dir) and (not -d _)) { |
|
769
|
0
|
|
|
|
|
0
|
require Carp; |
|
770
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - '$cache_dir' already exists and is not a directory.\n"); |
|
771
|
|
|
|
|
|
|
} |
|
772
|
67
|
50
|
|
|
|
1689
|
if (not -e $cache_dir) { |
|
773
|
0
|
|
|
|
|
0
|
eval { |
|
774
|
0
|
|
|
|
|
0
|
require File::Path; |
|
775
|
0
|
|
|
|
|
0
|
File::Path::mkpath ($cache_dir); |
|
776
|
|
|
|
|
|
|
}; |
|
777
|
0
|
0
|
|
|
|
0
|
if ($@) { |
|
778
|
0
|
|
|
|
|
0
|
my $error = $@; |
|
779
|
0
|
|
|
|
|
0
|
require Carp; |
|
780
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - unable to create directory '$cache_dir': $error"); |
|
781
|
|
|
|
|
|
|
} |
|
782
|
|
|
|
|
|
|
} |
|
783
|
67
|
50
|
33
|
|
|
2073
|
if (not ((-e $cache_dir) and (-d _))) { |
|
784
|
0
|
|
|
|
|
0
|
require Carp; |
|
785
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Unable to create directory '$cache_dir'\n"); |
|
786
|
|
|
|
|
|
|
} |
|
787
|
67
|
|
|
|
|
1296
|
my $document_name = File::Spec->catfile($cache_dir,'.cache.lock'); |
|
788
|
67
|
|
|
|
|
375
|
my $cache_lock_fh = gensym; |
|
789
|
67
|
50
|
|
|
|
14474
|
unless (open ($cache_lock_fh,">>$document_name")) { |
|
790
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
791
|
0
|
|
|
|
|
0
|
require Carp; |
|
792
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Unable to open '$document_name': $error\n"); |
|
793
|
|
|
|
|
|
|
} |
|
794
|
67
|
|
|
|
|
154
|
my $lock_timeout = 100; |
|
795
|
67
|
|
|
|
|
686
|
while (not flock($cache_lock_fh, LOCK_EX()|LOCK_NB())) { |
|
796
|
0
|
|
|
|
|
0
|
$lock_timeout--; |
|
797
|
0
|
|
|
|
|
0
|
select (undef,undef,undef,0.1); |
|
798
|
0
|
0
|
|
|
|
0
|
if ($lock_timeout == 0) { |
|
799
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
800
|
0
|
|
|
|
|
0
|
require Carp; |
|
801
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Unable to get an exclusive lock on '$document_name': $error\n"); |
|
802
|
|
|
|
|
|
|
} |
|
803
|
|
|
|
|
|
|
} |
|
804
|
67
|
|
|
|
|
289
|
my $fh = select ($cache_lock_fh); |
|
805
|
67
|
|
|
|
|
9665
|
$|++; |
|
806
|
67
|
|
|
|
|
214
|
select ($fh); |
|
807
|
67
|
50
|
|
|
|
1063084
|
unless (truncate ($cache_lock_fh, 0)) { |
|
808
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
809
|
0
|
|
|
|
|
0
|
require Carp; |
|
810
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Unable to truncate '$document_name': $error\n"); |
|
811
|
|
|
|
|
|
|
} |
|
812
|
67
|
|
|
|
|
3356146
|
print $cache_lock_fh "$$\n"; |
|
813
|
67
|
|
|
|
|
354
|
$self->_cache_lock_fh($cache_lock_fh); |
|
814
|
|
|
|
|
|
|
|
|
815
|
67
|
|
|
|
|
520
|
return; |
|
816
|
|
|
|
|
|
|
} |
|
817
|
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
####################################################################### |
|
819
|
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
# _unlock_cache; |
|
821
|
|
|
|
|
|
|
# |
|
822
|
|
|
|
|
|
|
# Release a lock on the 'cache.lock' file for this LRU cache. |
|
823
|
|
|
|
|
|
|
# |
|
824
|
|
|
|
|
|
|
# Example: |
|
825
|
|
|
|
|
|
|
# $self->_unlock_cache; |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
sub _unlock_cache { |
|
828
|
67
|
|
|
67
|
|
119
|
my $self = shift; |
|
829
|
67
|
|
|
|
|
128
|
my $package = __PACKAGE__; |
|
830
|
|
|
|
|
|
|
|
|
831
|
67
|
|
|
|
|
176
|
my $cache_lock_fh = $self->_cache_lock_fh; |
|
832
|
67
|
50
|
|
|
|
4013798
|
unless (truncate ($cache_lock_fh,0)) { |
|
833
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
834
|
0
|
|
|
|
|
0
|
require Carp; |
|
835
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_lock_cache - Unable to truncate cache.lock file: $error\n"); |
|
836
|
|
|
|
|
|
|
} |
|
837
|
67
|
50
|
|
|
|
8148
|
unless (close ($cache_lock_fh)) { |
|
838
|
0
|
|
|
|
|
0
|
my $error = $!; |
|
839
|
0
|
|
|
|
|
0
|
require Carp; |
|
840
|
0
|
|
|
|
|
0
|
Carp::croak ($package . "::_unlock_cache - Error while closing cache.lock file: $error\n"); |
|
841
|
|
|
|
|
|
|
} |
|
842
|
67
|
|
|
|
|
224
|
return; |
|
843
|
|
|
|
|
|
|
} |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
#################################################################### |
|
846
|
|
|
|
|
|
|
# _property('property_name' => $property_value) |
|
847
|
|
|
|
|
|
|
# |
|
848
|
|
|
|
|
|
|
# get/set base accessor for property values |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
sub _property { |
|
851
|
334
|
|
|
334
|
|
472
|
my $self = shift; |
|
852
|
|
|
|
|
|
|
|
|
853
|
334
|
|
|
|
|
1285
|
my $property = shift; |
|
854
|
|
|
|
|
|
|
|
|
855
|
334
|
|
|
|
|
1779
|
my $package = __PACKAGE__; |
|
856
|
334
|
100
|
|
|
|
829
|
if (0 == @_) { |
|
|
|
50
|
|
|
|
|
|
|
857
|
229
|
|
|
|
|
537
|
my $output = $self->{$package}->{$property}; |
|
858
|
229
|
|
|
|
|
1878
|
return $output; |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
} elsif (1 == @_) { |
|
861
|
105
|
|
|
|
|
149
|
my $input = shift; |
|
862
|
105
|
|
|
|
|
316
|
$self->{$package}->{$property} = $input; |
|
863
|
105
|
|
|
|
|
1039
|
return; |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
} else { |
|
866
|
0
|
|
|
|
|
0
|
require Carp; |
|
867
|
0
|
|
|
|
|
0
|
Carp::croak("Bad calling parameters to ${package}::${property}()\n"); |
|
868
|
|
|
|
|
|
|
} |
|
869
|
|
|
|
|
|
|
} |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
#################################################################### |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub TIEHASH { |
|
874
|
4
|
|
|
4
|
|
5641
|
my $proto = shift; |
|
875
|
4
|
|
|
|
|
7
|
my $package = __PACKAGE__; |
|
876
|
4
|
|
33
|
|
|
42
|
my $class = ref ($proto) || $proto || $package; |
|
877
|
4
|
|
|
|
|
10
|
my $self = bless {}, $class; |
|
878
|
|
|
|
|
|
|
|
|
879
|
4
|
|
|
|
|
9
|
my ($cache_dir,$keep_last) = @_; |
|
880
|
|
|
|
|
|
|
|
|
881
|
4
|
100
|
|
|
|
38
|
$keep_last = 100 unless (defined $keep_last); |
|
882
|
4
|
100
|
66
|
|
|
21
|
unless (defined ($cache_dir) and ($cache_dir ne '')) { |
|
883
|
1
|
|
|
|
|
14
|
require Carp; |
|
884
|
1
|
|
|
|
|
684
|
Carp::croak($package . ": Missing required parameter (cache_dir)\n"); |
|
885
|
|
|
|
|
|
|
} |
|
886
|
3
|
|
|
|
|
9
|
$self->cache_dir($cache_dir); |
|
887
|
3
|
|
|
|
|
9
|
$self->keep_last($keep_last); |
|
888
|
3
|
|
|
|
|
11
|
return $self; |
|
889
|
|
|
|
|
|
|
} |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
####################################################################### |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
sub STORE { |
|
894
|
9
|
|
|
9
|
|
6006297
|
my $self = shift; |
|
895
|
|
|
|
|
|
|
|
|
896
|
9
|
|
|
|
|
42
|
my ($key,$value) = @_; |
|
897
|
|
|
|
|
|
|
|
|
898
|
9
|
100
|
|
|
|
76
|
if (ref(\$key) eq 'SCALAR') { |
|
899
|
8
|
|
|
|
|
100
|
$self->update({ -cache_key => $key, -value => $value }); |
|
900
|
|
|
|
|
|
|
} else { |
|
901
|
1
|
|
|
|
|
6
|
$self->update({ -key => $key, -value => $value }); |
|
902
|
|
|
|
|
|
|
} |
|
903
|
|
|
|
|
|
|
} |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
####################################################################### |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
sub FETCH { |
|
908
|
7
|
|
|
7
|
|
64
|
my $self = shift; |
|
909
|
|
|
|
|
|
|
|
|
910
|
7
|
|
|
|
|
19
|
my ($key) = @_; |
|
911
|
|
|
|
|
|
|
|
|
912
|
7
|
100
|
|
|
|
28
|
if (ref(\$key) eq 'SCALAR') { |
|
913
|
6
|
|
|
|
|
33
|
my ($cache_hit, $value) = $self->check({ -cache_key => $key }); |
|
914
|
6
|
|
|
|
|
44
|
return $value; |
|
915
|
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
} else { |
|
917
|
1
|
|
|
|
|
22
|
my ($cache_hit,$value) = $self->check({ -key => $key }); |
|
918
|
1
|
|
|
|
|
10
|
return $value; |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
####################################################################### |
|
924
|
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
sub DELETE { |
|
926
|
2
|
|
|
2
|
|
26
|
my $self = shift; |
|
927
|
|
|
|
|
|
|
|
|
928
|
2
|
|
|
|
|
5
|
my ($key) = @_; |
|
929
|
|
|
|
|
|
|
|
|
930
|
2
|
100
|
|
|
|
10
|
if (ref(\$key) eq 'SCALAR') { |
|
931
|
1
|
|
|
|
|
9
|
$self->delete({ -cache_key => $key }); |
|
932
|
|
|
|
|
|
|
} else { |
|
933
|
1
|
|
|
|
|
7
|
$self->delete({ -key => $key }); |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
} |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
####################################################################### |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
sub CLEAR { |
|
940
|
1
|
|
|
1
|
|
9
|
my $self = shift; |
|
941
|
|
|
|
|
|
|
|
|
942
|
1
|
|
|
|
|
6
|
$self->clear; |
|
943
|
|
|
|
|
|
|
} |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
####################################################################### |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
sub EXISTS { |
|
948
|
18
|
|
|
18
|
|
207
|
my $self = shift; |
|
949
|
|
|
|
|
|
|
|
|
950
|
18
|
|
|
|
|
39
|
my ($key) = @_; |
|
951
|
|
|
|
|
|
|
|
|
952
|
18
|
100
|
|
|
|
79
|
if (ref(\$key) eq 'SCALAR') { |
|
953
|
16
|
|
|
|
|
92
|
my ($cache_hit,$value) = $self->check({ -cache_key => $key }); |
|
954
|
16
|
|
|
|
|
92
|
return $cache_hit; |
|
955
|
|
|
|
|
|
|
} else { |
|
956
|
2
|
|
|
|
|
12
|
my ($cache_hit,$value) = $self->check({ -key => $key }); |
|
957
|
2
|
|
|
|
|
11
|
return $cache_hit; |
|
958
|
|
|
|
|
|
|
} |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
####################################################################### |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
# |
|
964
|
|
|
|
|
|
|
# Iteration over the cache is not supported |
|
965
|
|
|
|
|
|
|
# |
|
966
|
|
|
|
|
|
|
|
|
967
|
1
|
|
|
1
|
|
20
|
sub FIRSTKEY { undef; } |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
####################################################################### |
|
970
|
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
# |
|
972
|
|
|
|
|
|
|
# Iteration over the cache is not supported |
|
973
|
|
|
|
|
|
|
# |
|
974
|
|
|
|
|
|
|
|
|
975
|
0
|
|
|
0
|
|
|
sub NEXTKEY { undef; } |
|
976
|
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
####################################################################### |
|
978
|
|
|
|
|
|
|
# |
|
979
|
|
|
|
|
|
|
# We return the number of cache entries in a scalar context |
|
980
|
|
|
|
|
|
|
# |
|
981
|
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
sub SCALAR { |
|
983
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
984
|
|
|
|
|
|
|
|
|
985
|
0
|
|
|
|
|
|
return $self->number_of_entries; |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
####################################################################### |
|
989
|
|
|
|
|
|
|
####################################################################### |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
Copyright 1999, Benjamin Franz () and |
|
994
|
|
|
|
|
|
|
FreeRun Technologies, Inc. (). All Rights Reserved. |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=head1 VERSION |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
1.05 released 2005.09.14 |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
=head1 LICENSE |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
This software may be copied or redistributed under the same terms as Perl itelf. |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
This means that you can, at your option, redistribute it and/or modify it under |
|
1005
|
|
|
|
|
|
|
either the terms the GNU Public License (GPL) version 1 or later, or under the |
|
1006
|
|
|
|
|
|
|
Perl Artistic License. |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=head1 DISCLAIMER |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS |
|
1013
|
|
|
|
|
|
|
OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE |
|
1014
|
|
|
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
1015
|
|
|
|
|
|
|
PARTICULAR PURPOSE. |
|
1016
|
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
Use of this software in any way or in any form, source or binary, |
|
1018
|
|
|
|
|
|
|
is not allowed in any country which prohibits disclaimers of any |
|
1019
|
|
|
|
|
|
|
implied warranties of merchantability or fitness for a particular |
|
1020
|
|
|
|
|
|
|
purpose or any disclaimers of a similar nature. |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
IN NO EVENT SHALL I BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, |
|
1023
|
|
|
|
|
|
|
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
|
1024
|
|
|
|
|
|
|
USE OF THIS SOFTWARE AND ITS DOCUMENTATION (INCLUDING, BUT NOT |
|
1025
|
|
|
|
|
|
|
LIMITED TO, LOST PROFITS) EVEN IF I HAVE BEEN ADVISED OF THE |
|
1026
|
|
|
|
|
|
|
POSSIBILITY OF SUCH DAMAGE |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
Benjamin Franz |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
=head1 TODO |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
Nothing. |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
=cut |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
1; |