File Coverage

blib/lib/File/StatCache.pm
Criterion Covered Total %
statement 40 46 86.9
branch 13 20 65.0
condition n/a
subroutine 8 9 88.8
pod 2 2 100.0
total 63 77 81.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2006,2007,2009 -- leonerd@leonerd.org.uk
5              
6             package File::StatCache;
7              
8 4     4   115707 use strict;
  4         9  
  4         160  
9 4     4   23 use warnings;
  4         8  
  4         193  
10              
11             our $VERSION = '0.06';
12              
13 4     4   29 use Exporter;
  4         9  
  4         330  
14             our @ISA = qw( Exporter );
15             our @EXPORT_OK = qw(
16             get_stat
17             stat
18              
19             get_item_mtime
20             );
21              
22 4     4   2746 use File::stat;
  4         30602  
  4         32  
23              
24             =head1 NAME
25              
26             C - a caching wrapper around the C function
27              
28             =head1 DESCRIPTION
29              
30             This module implements a cache of information returned by the C
31             function. It stores the result of a C syscall, to avoid putting excess
32             load on the host's filesystem in case many calls would be generated.
33              
34             By default the cache for any given filename will time out after 10 seconds; so
35             any request for information on the same name after this time will result in
36             another C syscall, ensuring fresh information. This timeout is stored
37             in the package variable C<$File::StatCache::STATTIMEOUT>, and can be
38             modified by other modules if required.
39              
40             =cut
41              
42             my %laststattime;
43             my %stat_cache;
44              
45             # Make $STATTIMEOUT externally visible, so other modules change it
46             our $STATTIMEOUT = 10;
47              
48             =head1 FUNCTIONS
49              
50             =cut
51              
52             =head2 $stats = get_stat( $path [, $now ] )
53              
54             This function wraps a call to C, and caches the result. If
55             the requested file was Ced within C<$STATTIMEOUT> seconds, it will not
56             be requested again, but the previous result (i.e. an object reference or
57             C) will be returned.
58              
59             The $now parameter allows some other time than the current time to be used,
60             rather than re-request it from the kernel using the C function. This
61             allows a succession of tests to be performed in a consistent way, to avoid a
62             race condition.
63              
64             =over 8
65              
66             =item $path
67              
68             The path to the filesystem item to C
69              
70             =item $now
71              
72             Optional. The time to consider as the current time
73              
74             =back
75              
76             =cut
77              
78             sub get_stat($;$)
79              
80             # This stat always returns a File::stat object.
81             {
82 8     8 1 782 my ( $path, $now ) = @_;
83              
84 8 50       58 $now = time() if ( !defined $now );
85              
86 8 100       47 if ( !exists $laststattime{$path} ) {
87              
88             # Definitely new
89 3         20 my $itemstat = File::stat::stat($path);
90 3         655 $laststattime{$path} = $now;
91 3 50       22 if ( !defined $itemstat ) {
92 0         0 return undef;
93             }
94 3         16 return $stat_cache{$path} = $itemstat;
95             }
96              
97 5 100       35 if ( $now - $laststattime{$path} > $STATTIMEOUT ) {
98              
99             # Haven't checked it in a while - check again
100 2         25 my $itemstat = File::stat::stat($path);
101 2         5217 $laststattime{$path} = $now;
102 2 100       13 if ( !defined $itemstat ) {
103 1         7 delete $stat_cache{$path};
104 1         6 return undef;
105             }
106 1         5 return $stat_cache{$path} = $itemstat;
107             }
108              
109 3 50       16 if ( !exists $stat_cache{$path} ) {
110              
111             # Recently checked, and it didn't exist
112 0         0 return undef;
113             }
114              
115             # Recently checked; exists
116 3         8 return $stat_cache{$path};
117             }
118              
119             sub _stat($)
120              
121             # The real call from outside - return an object or list as appropriate
122             {
123 6     6   4014395 my ($path) = @_;
124              
125 6         30 my $stat = get_stat($path);
126              
127 6 100       54 if ( defined $stat ) {
128 5 50       20 return $stat unless wantarray;
129              
130             # Need to construct the full annoying 13-element list
131             return (
132 5         362 $stat->dev, $stat->ino, $stat->mode, $stat->nlink,
133             $stat->uid, $stat->gid, $stat->rdev, $stat->size,
134             $stat->atime, $stat->mtime, $stat->ctime, $stat->blksize,
135             $stat->blocks,
136             );
137             }
138             else {
139 1 50       12 return wantarray ? () : undef;
140             }
141             }
142              
143             =head2 $stats = stat( $path )
144              
145             =head2 @stats = stat( $path )
146              
147             This is a drop-in replacement for either the perl core C function or
148             the C function, depending whether it is called in list or
149             scalar context. It behaves identically to either of these functions, except
150             that it returns cached results if the cached value is recent enough.
151              
152             Note that in the case of failure (i.e. C in scalar context, empty in
153             list context), the value of C<$!> is not reliable as the reason for error.
154             Error results are not currently cached.
155              
156             =over 8
157              
158             =item $path
159              
160             The path to the filesystem item to C
161              
162             =back
163              
164             =cut
165              
166             # Need to work around perl's warning of "Subroutine stat redefined at..."
167              
168 4     4   6959 no warnings;
  4         8  
  4         236  
169             *stat = \&_stat;
170 4     4   18 use warnings;
  4         8  
  4         407  
171              
172             =head2 get_item_mtime( $path [, $now ] )
173              
174             This function is equivalent to
175              
176             (scalar get_stat( $path, $now ))->mtime
177              
178             =over 8
179              
180             =item $path
181              
182             The path to the filesystem item to C
183              
184             =item $now
185              
186             Optional. The time to consider as the current time
187              
188             =back
189              
190             =cut
191              
192             sub get_item_mtime($;$) {
193 0     0 1   my ( $path, $now ) = @_;
194              
195 0           my $itemstat = get_stat( $path, $now );
196 0 0         return $itemstat->mtime if defined $itemstat;
197 0           return undef;
198             }
199              
200             # Keep perl happy; keep Britain tidy
201             1;
202              
203             __END__