1b39c5158Smillertpackage FileCache; 2b39c5158Smillert 3*5759b3d2Safresh1our $VERSION = '1.10'; 4b39c5158Smillert 5b39c5158Smillert=head1 NAME 6b39c5158Smillert 7b39c5158SmillertFileCache - keep more files open than the system permits 8b39c5158Smillert 9b39c5158Smillert=head1 SYNOPSIS 10b39c5158Smillert 11b39c5158Smillert no strict 'refs'; 12b39c5158Smillert 13b39c5158Smillert use FileCache; 14b39c5158Smillert # or 15b39c5158Smillert use FileCache maxopen => 16; 16b39c5158Smillert 17b39c5158Smillert cacheout $mode, $path; 18b39c5158Smillert # or 19b39c5158Smillert cacheout $path; 20b39c5158Smillert print $path @data; 21b39c5158Smillert 22b39c5158Smillert $fh = cacheout $mode, $path; 23b39c5158Smillert # or 24b39c5158Smillert $fh = cacheout $path; 25b39c5158Smillert print $fh @data; 26b39c5158Smillert 27b39c5158Smillert=head1 DESCRIPTION 28b39c5158Smillert 29b39c5158SmillertThe C<cacheout> function will make sure that there's a filehandle open 30b39c5158Smillertfor reading or writing available as the pathname you give it. It 31b39c5158Smillertautomatically closes and re-opens files if you exceed your system's 32b39c5158Smillertmaximum number of file descriptors, or the suggested maximum I<maxopen>. 33b39c5158Smillert 34b39c5158Smillert=over 35b39c5158Smillert 36b39c5158Smillert=item cacheout EXPR 37b39c5158Smillert 38b39c5158SmillertThe 1-argument form of cacheout will open a file for writing (C<< '>' >>) 39b39c5158Smillerton it's first use, and appending (C<<< '>>' >>>) thereafter. 40b39c5158Smillert 41b39c5158SmillertReturns EXPR on success for convenience. You may neglect the 42b39c5158Smillertreturn value and manipulate EXPR as the filehandle directly if you prefer. 43b39c5158Smillert 44b39c5158Smillert=item cacheout MODE, EXPR 45b39c5158Smillert 46b39c5158SmillertThe 2-argument form of cacheout will use the supplied mode for the initial 47b39c5158Smillertand subsequent openings. Most valid modes for 3-argument C<open> are supported 48b39c5158Smillertnamely; C<< '>' >>, C<< '+>' >>, C<< '<' >>, C<< '<+' >>, C<<< '>>' >>>, 49b39c5158SmillertC< '|-' > and C< '-|' > 50b39c5158Smillert 51b39c5158SmillertTo pass supplemental arguments to a program opened with C< '|-' > or C< '-|' > 52b39c5158Smillertappend them to the command string as you would system EXPR. 53b39c5158Smillert 54b39c5158SmillertReturns EXPR on success for convenience. You may neglect the 55b39c5158Smillertreturn value and manipulate EXPR as the filehandle directly if you prefer. 56b39c5158Smillert 57b39c5158Smillert=back 58b39c5158Smillert 59b39c5158Smillert=head1 CAVEATS 60b39c5158Smillert 61b39c5158SmillertWhile it is permissible to C<close> a FileCache managed file, 62b39c5158Smillertdo not do so if you are calling C<FileCache::cacheout> from a package other 63b39c5158Smillertthan which it was imported, or with another module which overrides C<close>. 64b39c5158SmillertIf you must, use C<FileCache::cacheout_close>. 65b39c5158Smillert 66b39c5158SmillertAlthough FileCache can be used with piped opens ('-|' or '|-') doing so is 67b39c5158Smillertstrongly discouraged. If FileCache finds it necessary to close and then reopen 68b39c5158Smillerta pipe, the command at the far end of the pipe will be reexecuted - the results 69b39c5158Smillertof performing IO on FileCache'd pipes is unlikely to be what you expect. The 70b39c5158Smillertability to use FileCache on pipes may be removed in a future release. 71b39c5158Smillert 72b39c5158SmillertFileCache does not store the current file offset if it finds it necessary to 73b39c5158Smillertclose a file. When the file is reopened, the offset will be as specified by the 74b39c5158Smillertoriginal C<open> file mode. This could be construed to be a bug. 75b39c5158Smillert 76b39c5158SmillertThe module functionality relies on symbolic references, so things will break 77b39c5158Smillertunder 'use strict' unless 'no strict "refs"' is also specified. 78b39c5158Smillert 79b39c5158Smillert=head1 BUGS 80b39c5158Smillert 81b39c5158SmillertF<sys/param.h> lies with its C<NOFILE> define on some systems, 82b39c5158Smillertso you may have to set I<maxopen> yourself. 83b39c5158Smillert 84b39c5158Smillert=cut 85b39c5158Smillert 86b39c5158Smillertrequire 5.006; 87b39c5158Smillertuse Carp; 88b39c5158Smillertuse strict; 89b39c5158Smillertno strict 'refs'; 90b39c5158Smillert 91b39c5158Smillert# These are not C<my> for legacy reasons. 92b39c5158Smillert# Previous versions requested the user set $cacheout_maxopen by hand. 93b39c5158Smillert# Some authors fiddled with %saw to overcome the clobber on initial open. 94*5759b3d2Safresh1our %saw; 95*5759b3d2Safresh1our $cacheout_maxopen = 16; 96b39c5158Smillert 976fb12b70Safresh1use parent 'Exporter'; 98b39c5158Smillertour @EXPORT = qw[cacheout cacheout_close]; 99b39c5158Smillert 100b39c5158Smillert 101b39c5158Smillertmy %isopen; 102b39c5158Smillertmy $cacheout_seq = 0; 103b39c5158Smillert 104b39c5158Smillertsub import { 105b39c5158Smillert my ($pkg,%args) = @_; 106b39c5158Smillert 107b39c5158Smillert # Use Exporter. %args are for us, not Exporter. 108b39c5158Smillert # Make sure to up export_to_level, or we will import into ourselves, 109b39c5158Smillert # rather than our calling package; 110b39c5158Smillert 111b39c5158Smillert __PACKAGE__->export_to_level(1); 112b39c5158Smillert Exporter::import( $pkg ); 113b39c5158Smillert 114b39c5158Smillert # Truth is okay here because setting maxopen to 0 would be bad 115b39c5158Smillert return $cacheout_maxopen = $args{maxopen} if $args{maxopen}; 116b39c5158Smillert 117b39c5158Smillert # XXX This code is crazy. Why is it a one element foreach loop? 118b39c5158Smillert # Why is it using $param both as a filename and filehandle? 119b39c5158Smillert foreach my $param ( '/usr/include/sys/param.h' ){ 120b39c5158Smillert if (open($param, '<', $param)) { 121b39c5158Smillert local ($_, $.); 122b39c5158Smillert while (<$param>) { 123b39c5158Smillert if( /^\s*#\s*define\s+NOFILE\s+(\d+)/ ){ 124b39c5158Smillert $cacheout_maxopen = $1 - 4; 125b39c5158Smillert close($param); 126b39c5158Smillert last; 127b39c5158Smillert } 128b39c5158Smillert } 129b39c5158Smillert close $param; 130b39c5158Smillert } 131b39c5158Smillert } 132b39c5158Smillert $cacheout_maxopen ||= 16; 133b39c5158Smillert} 134b39c5158Smillert 135b39c5158Smillert# Open in their package. 136b39c5158Smillertsub cacheout_open { 137b39c5158Smillert return open(*{caller(1) . '::' . $_[1]}, $_[0], $_[1]) && $_[1]; 138b39c5158Smillert} 139b39c5158Smillert 140b39c5158Smillert# Close in their package. 141b39c5158Smillertsub cacheout_close { 142b39c5158Smillert # Short-circuit in case the filehandle disappeared 143b39c5158Smillert my $pkg = caller($_[1]||0); 144b39c5158Smillert defined fileno(*{$pkg . '::' . $_[0]}) && 145b39c5158Smillert CORE::close(*{$pkg . '::' . $_[0]}); 146b39c5158Smillert delete $isopen{$_[0]}; 147b39c5158Smillert} 148b39c5158Smillert 149b39c5158Smillert# But only this sub name is visible to them. 150b39c5158Smillertsub cacheout { 151b39c5158Smillert my($mode, $file, $class, $ret, $ref, $narg); 152b39c5158Smillert croak "Not enough arguments for cacheout" unless $narg = scalar @_; 153b39c5158Smillert croak "Too many arguments for cacheout" if $narg > 2; 154b39c5158Smillert 155b39c5158Smillert ($mode, $file) = @_; 156b39c5158Smillert ($file, $mode) = ($mode, $file) if $narg == 1; 157b39c5158Smillert croak "Invalid mode for cacheout" if $mode && 158b39c5158Smillert ( $mode !~ /^\s*(?:>>|\+?>|\+?<|\|\-|)|\-\|\s*$/ ); 159b39c5158Smillert 160b39c5158Smillert # Mode changed? 161b39c5158Smillert if( $isopen{$file} && ($mode||'>') ne $isopen{$file}->[1] ){ 162b39c5158Smillert &cacheout_close($file, 1); 163b39c5158Smillert } 164b39c5158Smillert 165b39c5158Smillert if( $isopen{$file}) { 166b39c5158Smillert $ret = $file; 167b39c5158Smillert $isopen{$file}->[0]++; 168b39c5158Smillert } 169b39c5158Smillert else{ 170b39c5158Smillert if( scalar keys(%isopen) > $cacheout_maxopen -1 ) { 171b39c5158Smillert my @lru = sort{ $isopen{$a}->[0] <=> $isopen{$b}->[0] } keys(%isopen); 172b39c5158Smillert $cacheout_seq = 0; 173b39c5158Smillert $isopen{$_}->[0] = $cacheout_seq++ for 174b39c5158Smillert splice(@lru, int($cacheout_maxopen / 3)||$cacheout_maxopen); 175b39c5158Smillert &cacheout_close($_, 1) for @lru; 176b39c5158Smillert } 177b39c5158Smillert 178b39c5158Smillert unless( $ref ){ 179b39c5158Smillert $mode ||= $saw{$file} ? '>>' : ($saw{$file}=1, '>'); 180b39c5158Smillert } 181b39c5158Smillert #XXX should we just return the value from cacheout_open, no croak? 182b39c5158Smillert $ret = cacheout_open($mode, $file) or croak("Can't create $file: $!"); 183b39c5158Smillert 184b39c5158Smillert $isopen{$file} = [++$cacheout_seq, $mode]; 185b39c5158Smillert } 186b39c5158Smillert return $ret; 187b39c5158Smillert} 188b39c5158Smillert1; 189