File-Locate-Iterator
view release on metacpan or search on metacpan
lib/File/Locate/Iterator/FileMap.pm view on Meta::CPAN
use Carp;
# uncomment this to run the ### lines
#use Devel::Comments;
our $VERSION = 28;
our %cache;
sub _key {
my ($fh) = @_;
my ($dev, $ino, undef, undef, undef, undef, undef, $size) = stat ($fh);
return "$dev,$ino,$size,".tell($fh);
}
sub find {
my ($class, $fh) = @_;
return $cache{_key($fh)};
}
# return a FileMap object which is $fh mmapped
sub get {
my ($class, $fh) = @_;
my $key = _key($fh);
### cache get: "$fh, $key, size=".(-s $fh)
return ($cache{$key} || do {
require File::Map;
# File::Map->VERSION('0.35'); # for binary handled properly, maybe
File::Map->VERSION('0.38'); # for tainting
require PerlIO::Layers;
require Scalar::Util;
PerlIO::Layers::query_handle ($fh, 'mappable')
or croak "Handle not mappable";
my $self = bless { key => $key,
mmap => undef,
}, $class;
my $tell = tell($fh);
if ($tell < 0) {
# assume if tell() doesn't work then $fh is not mmappable, or in any
# case don't know where the current position is to map
croak "Cannot tell() file position: $!";
}
# File::Map 0.38 does tainting itself
#
# # induce taint on the mmap -- seems to cause segvs though
# read $fh, $self->{'mmap'}, 0;
# use Devel::Peek;
# Dump ($self->{'mmap'});
#
# # crib: must taint before mapping, doesn't work afterwards
# require Taint::Util;
# Taint::Util::taint($self->{'mmap'});
File::Map::map_handle ($self->{'mmap'}, $fh, '<', $tell);
File::Map::advise ($self->{'mmap'}, 'sequential');
Scalar::Util::weaken ($cache{$key} = $self);
$self;
});
}
# return a scalar ref to the mmapped string
sub mmap_ref {
my ($self) = @_;
return \($self->{'mmap'});
}
sub DESTROY {
my ($self) = @_;
delete $cache{$self->{'key'}};
}
use constant::defer _PAGESIZE => sub {
require POSIX;
my $pagesize = eval { POSIX::sysconf (POSIX::_SC_PAGESIZE()) } || -1;
return ($pagesize > 0 ? $pagesize : 1024);
};
# return the total bytes used by mmaps here plus prospective further $space
sub _total_space {
my ($space) = @_;
### total space of: $space, values(%cache)
$space = _round_up_pagesize($space);
foreach my $self (values %cache) {
$space += _round_up_pagesize (length (${$self->mmap_ref}));
}
return $space;
}
sub _round_up_pagesize {
my ($n) = @_;
my $pagesize = _PAGESIZE();
return $pagesize * int (($n + $pagesize - 1) / $pagesize);
}
#-----------------------------------------------------------------------------
# return true if $fh has an ":mmap" layer
sub _have_mmap_layer {
my ($fh) = @_;
my $ret;
eval {
require PerlIO; # new in perl 5.8
foreach my $layer (PerlIO::get_layers ($fh)) {
if ($layer eq 'mmap') { $ret = 1; last; }
}
};
return $ret;
}
# return true if mmapping $fh would be an excessive cumulative size
sub _mmap_size_excessive {
my ($fh) = @_;
if (File::Locate::Iterator::FileMap->find($fh)) {
# if already mapped then not excessive
return 0;
}
# in 32-bits this is 4G*(1/4)*(1/5) which is 200Mb
( run in 2.219 seconds using v1.01-cache-2.11-cpan-5511b514fd6 )