From: Thomas Adam Date: Wed, 06 Oct 2010 22:41:11 GMT Subject: Re: [PATCHv5 03/17] gitweb/lib - Very simple file based cache Message-ID: In-Reply-To: <1286402526-13143-4-git-send-email-jnareb@gmail.com> On 6 October 2010 23:01, Jakub Narebski wrote: > +# creates get_depth() and set_depth($depth) etc. methods > +foreach my $i (qw(depth root namespace)) { > +       my $field = $i; > +       no strict 'refs'; For each item, you'll set "no strict refs"? This might be better off outside the loop. It's still scoped appropriately inside the subroutine. > +       my $file = $self->path_to_key($key); > +       return undef unless (defined $file && -f $file); PBP (Perl Best Practises) will tell you that explicitly returning undef is discouraged -- "undef" should be reserved for those errors you cannot handle, not ones you don't want to. > + > +       # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed > +       # via CHI::Driver::File (from CHI-0.33) > +       my $buf = ''; > +       open my $read_fh, '<', $file > +               or return undef; Ditto. > +       binmode $read_fh, ':raw'; > + > +       my $size_left = -s $read_fh; > + > +       while ($size_left > 0) { > +               my $read_cnt = sysread($read_fh, $buf, $size_left, length($buf)); > +               return undef unless defined $read_cnt; Ditto. > +               last if $read_cnt == 0; > +               $size_left -= $read_cnt; > +               #last if $size_left <= 0; > +       } > + > +       close $read_fh > +               or die "Couldn't close file '$file' opened for reading: $!"; > +       return $buf; > +} "use Carp;" would be more useful here, and hence croak() and confess(). > +sub store { > +       my ($self, $key, $data) = @_; > + > +       my $dir; > +       my $file = $self->path_to_key($key, \$dir); > +       return undef unless (defined $file && defined $dir); See above. > +       # ensure that directory leading to cache file exists > +       if (!-d $dir) { > +               eval { mkpath($dir, 0, 0777); 1 } > +                       or die "Couldn't create leading directory '$dir' (mkpath): $!"; > +       } Why is this eval()ed? It will still return false and set $! appropriately. > +       # generate a temporary file > +       my ($temp_fh, $tempname) = $self->_tempfile_to_path($file, $dir); > +       chmod 0666, $tempname > +               or warn "Couldn't change permissions to 0666 / -rw-rw-rw- for '$tempname': $!"; > + > +       # Fast spew, adapted from File::Slurp::write, with unnecessary options removed > +       # via CHI::Driver::File (from CHI-0.33) > +       my $write_fh = $temp_fh; > +       binmode $write_fh, ':raw'; > + > +       my $size_left = length($data); > +       my $offset = 0; > + > +       while ($size_left > 0) { > +               my $write_cnt = syswrite($write_fh, $data, $size_left, $offset); > +               return undef unless defined $write_cnt; Again, with the undef. > +               $size_left -= $write_cnt; > +               $offset += $write_cnt; # == length($data); > +       } > + > +       close $temp_fh > +               or die "Couldn't close temporary file '$tempname' opened for writing: $!"; > +       rename($tempname, $file) > +               or die "Couldn't rename temporary file '$tempname' to '$file': $!"; > +} > + > +# get size of an element associated with the $key (not the size of whole cache) > +sub get_size { > +       my ($self, $key) = @_; > + > +       my $path = $self->path_to_key($key) > +               or return undef; Again with the undef > +       if (-f $path) { > +               return -s $path; > +       } > +       return 0; > +} > + > +# ...................................................................... > +# interface methods > + > +# Removing and expiring > + > +# $cache->remove($key) > +# > +# Remove the data associated with the $key from the cache. > +sub remove { > +       my ($self, $key) = @_; > + > +       my $file = $self->path_to_key($key) > +               or return undef; > +       return undef unless -f $file; Again with the undef. > +       unlink($file) > +               or die "Couldn't remove file '$file': $!"; > +} > + > +# Getting and setting > + > +# $cache->set($key, $data); > +# > +# Associates $data with $key in the cache, overwriting any existing entry. > +# Returns $data. > +sub set { > +       my ($self, $key, $data) = @_; > + > +       return unless (defined $key && defined $data); return what? > +       $self->store($key, $data); > + > +       return $data; > +} > + > +# $data = $cache->get($key); > +# > +# Returns the data associated with $key.  If $key does not exist > +# or has expired, returns undef. > +sub get { > +       my ($self, $key) = @_; > + > +       my $data = $self->fetch($key) > +               or return undef; > + > +       return $data; > +} > + > +# $data = $cache->compute($key, $code); > +# > +# Combines the get and set operations in a single call.  Attempts to > +# get $key; if successful, returns the value.  Otherwise, calls $code > +# and uses the return value as the new value for $key, which is then > +# returned. > +sub compute { > +       my ($self, $key, $code) = @_; > + > +       my $data = $self->get($key); > +       if (!defined $data) { > +               $data = $code->($self, $key); > +               $self->set($key, $data); > +       } Can you guarantee $code here? unless( defined $code and ref $code eq 'CODE' ) { .... } Wouldn't it be easier to eval{} this and checj $@? [...] -- Thomas Adam