File Coverage

lib/Cache/AgainstFile/Memory.pm
Criterion Covered Total %
statement 70 74 94.5
branch 8 12 66.6
condition 9 10 90.0
subroutine 12 12 100.0
pod 4 4 100.0
total 103 112 91.9


line stmt bran cond sub pod time code
1             ###############################################################################
2             # Purpose : Cache data structures in memory against a file
3             # Author : John Alden
4             # Created : 22 Apr 2005 (based on IFL::FileCache)
5             # CVS : $Id: Memory.pm,v 1.15 2005/11/10 15:13:57 johna Exp $
6             ###############################################################################
7              
8             package Cache::AgainstFile::Memory;
9              
10 1     1   381 use strict;
  1         2  
  1         28  
11 1     1   302 use Cache::AgainstFile::Base;
  1         3  
  1         27  
12              
13 1     1   5 use vars qw($VERSION @ISA);
  1         2  
  1         91  
14             $VERSION = sprintf"%d.%03d", q$Revision: 1.15 $ =~ /: (\d+)\.(\d+)/;
15             @ISA = qw(Cache::AgainstFile::Base);
16              
17 1         2 use constant HAVE_FILE_POLICY => eval {
18 1         731 require File::Policy;
19 0         0 import File::Policy qw(check_safe);
20 0         0 1;
21 1     1   5 };
  1         1  
22              
23              
24             #
25             # Public interface
26             #
27              
28             sub new {
29 4     4 1 7 my $class = shift;
30 4         25 my $self = $class->SUPER::new(@_);
31              
32 4         17 $self->{'cache'} = {};
33 4         8 $self->{'modified'} = {}; #Time file was last modified (days ago)
34 4         9 $self->{'accessed'} = {}; #Time file was last accessed (days ago)
35 4         8 $self->{'stat'} = {}; #Timestamp of last stat (seconds since epoch)
36              
37 4         15 return $self;
38             }
39              
40             sub get {
41 36     36 1 107 my ($self, $filename, @opts) = @_;
42 36         344 my $stale = (! exists $self->{cache}{$filename});
43 36         55 my $source_mtime;
44 36 100 100     166 unless ($self->{options}->{NoStat} && !$stale)
45             {
46             #Are we within the grace period since our last stat?
47 34   50     267 my $grace = $self->{options}->{Grace} || 0;
48 34   100     141 my $last_checked = $self->{'stat'}{$filename} || 0;
49 34 50       134 unless($grace > time - $last_checked)
50             {
51 34         996 TRACE("stat: $filename");
52 34 50       302 check_safe($filename, "r") if(HAVE_FILE_POLICY);
53 34         491 $source_mtime = (stat($filename))[9];
54 34         106 my $last_modified = $self->{modified}{$filename};
55 34   100     213 $stale |= (!defined $source_mtime) || (!defined $last_modified) || ($source_mtime ne $last_modified);
56 34         10114 $self->{'stat'}{$filename} = time;
57             }
58             }
59 36         125 my $data;
60 36 100       5532 if($stale)
61             {
62 27         121 TRACE("stale memory: $filename");
63 27         141 $data = $self->{loader}->($filename, @opts);
64 27 50       10001347 if (defined $source_mtime) {
65 27         95 $self->{cache}{$filename} = $data;
66 27         249 $self->{modified}{$filename} = $source_mtime;
67             }
68             }
69             else
70             {
71 9         34 TRACE("not stale memory: $filename");
72 9         24 $data = $self->{cache}{$filename};
73             }
74 36         100 $self->{accessed}{$filename} = time();
75 36         154 return $data;
76             }
77              
78             sub count {
79 7     7 1 9 my $self = shift();
80 7         10 return scalar keys %{$self->{cache}};
  7         52  
81             }
82              
83             sub size {
84 2     2 1 5 my $self = shift();
85 2         6 eval {
86 1     1   6 no warnings;
  1         2  
  1         271  
87 2         1165 require Devel::Size;
88 0         0 local $Devel::Size::warn = 0;
89 0         0 return Devel::Size::total_size($self->{cache});
90             };
91 2         16 return undef;
92             }
93              
94             #
95             # Protected methods referenced from Base class
96             #
97              
98             sub _remove {
99 6     6   14 my($self, $keys) = @_;
100 6         17 foreach(@$keys)
101             {
102 11         35 TRACE("clearing $_");
103 11         33 delete $self->{cache}{$_};
104 11         17 delete $self->{modified}{$_};
105 11         20 delete $self->{accessed}{$_};
106 11         53 delete $self->{'stat'}{$_};
107             }
108             }
109              
110             sub _accessed {
111 10     10   19 my($self) = @_;
112 10         14 my %atimes = %{$self->{accessed}};
  10         62  
113 10         42 return \%atimes;
114             }
115              
116             sub _stale {
117 1     1   32 my($self) = @_;
118 1         3 my $modified = $self->{modified};
119 1         17 return grep {
120 1         4 my $src = (stat($_))[9];
121 1 50       13 (!defined $src) || ($src ne $modified->{$_})
122             } keys %$modified;
123             }
124              
125             #
126             # Log::Trace stubs
127             #
128              
129             sub TRACE {}
130             sub DUMP {}
131              
132             1;
133              
134              
135             =head1 NAME
136              
137             Cache::AgainstFile::Memory - cache data parsed from files in memory
138              
139             =head1 SYNOPSIS
140              
141             use Cache::AgainstFile;
142             my $cache = new Cache::AgainstFile(
143             \&loader,
144             {
145             Method => 'Memory',
146             MaxItems => 16,
147             # ...
148             }
149             );
150              
151             $data = $cache->get($filename);
152              
153              
154             =head1 DESCRIPTION
155              
156             Data structures parsed from files are cached in memory.
157             This is particularly suited to persistent environments such as modperl or other daemon processes.
158              
159             For short-lived processes such as CGI scripts, the Storable backend might be more appropriate.
160              
161             Note that the C method uses Devel::Size if available, otherwise it returns undef.
162             Devel::Size can consume a reasonable amount of memory working out how much memory you are using!
163             This memory is released after the operation but it will have expanded your process' memory footprint in the process.
164              
165             =head1 OPTIONS
166              
167             =over 4
168              
169             =item Grace
170              
171             How long to defer statting the file (in seconds).
172             Be careful if you use this in modperl environments as it will result in some children having a
173             new version of the cached item, and some still having the old version.
174              
175             =item NoStat
176              
177             Don't stat files to validate the cache - items are served from the cache until they are purged.
178             Valid values are 0|1 (default=0, i.e. files are statted)
179              
180             Setting this to 1 is equivalent to setting Grace to an infinite value.
181              
182             =item MaxATime
183              
184             Purge items older than this.
185             Value is in seconds (default=undefined=infinity)
186              
187             =item MaxItems
188              
189             Purge oldest items to reduce cache to this size.
190             Value should be an integer (default=undefined=infinity)
191              
192             =back
193              
194             =head1 VERSION
195              
196             $Revision: 1.15 $ on $Date: 2005/11/10 15:13:57 $ by $Author: johna $
197              
198             =head1 AUTHOR
199              
200             John Alden & Piers Kent
201              
202             =head1 COPYRIGHT
203              
204             (c) BBC 2005. This program is free software; you can redistribute it and/or modify it under the GNU GPL.
205              
206             See the file COPYING in this distribution, or http://www.gnu.org/licenses/gpl.txt
207              
208             =cut