File Coverage

lib/File/DataClass/Cache.pm
Criterion Covered Total %
statement 58 58 100.0
branch 15 16 93.7
condition 2 2 100.0
subroutine 18 18 100.0
pod 7 7 100.0
total 100 101 99.0


line stmt bran cond sub pod time code
1             package File::DataClass::Cache;
2              
3 3     3   41 use 5.01;
  3         7  
4 3     3   11 use namespace::autoclean;
  3         4  
  3         16  
5              
6 3     3   143 use File::DataClass::Constants qw( FALSE NUL SPC TRUE );
  3         4  
  3         174  
7 3     3   12 use File::DataClass::Functions qw( merge_attributes throw );
  3         6  
  3         130  
8 3         42 use File::DataClass::Types qw( Bool Cache ClassName HashRef
9 3     3   1012 LoadableClass Object Str );
  3         5  
10 3     3   3523 use Try::Tiny;
  3         5  
  3         176  
11 3     3   10 use Moo;
  3         4  
  3         22  
12              
13             # Public attributes
14             has 'cache' => is => 'lazy', isa => Object, builder => sub {
15 3     3   1043 $_[ 0 ]->cache_class->new( %{ $_[ 0 ]->cache_attributes } ) };
  3         9440  
16              
17             has 'cache_attributes' => is => 'ro', isa => HashRef, required => TRUE;
18              
19             has 'cache_class' => is => 'lazy', isa => LoadableClass,
20             default => 'Cache::FastMmap';
21              
22             has 'log' => is => 'ro', isa => Object, required => TRUE;
23              
24             # Private attributes
25             has '_mtimes_key' => is => 'ro', isa => Str, default => '_mtimes';
26              
27             # Construction
28             around 'BUILDARGS' => sub {
29             my ($orig, $class, @args) = @_; my $attr = $orig->( $class, @args );
30              
31             $attr->{cache_attributes} //= {}; my $cache_class;
32              
33             $cache_class = delete $attr->{cache_attributes}->{cache_class}
34             and $attr->{cache_class} = $cache_class;
35              
36             my $builder = delete $attr->{builder} or return $attr;
37              
38             merge_attributes $attr, $builder, [ 'log' ];
39              
40             return $attr;
41             };
42              
43             # Private methods
44             my $_get_key_and_newest = sub {
45             my ($self, $paths) = @_; my $newest = 0; my $is_valid = TRUE; my $key;
46              
47             for my $path (grep { defined && length "${_}" } @{ $paths }) {
48             my $mtime = $self->get_mtime( "${path}" ) or $is_valid = FALSE;
49              
50             ($mtime and $path->exists and $mtime == $path->stat->{mtime})
51             or $is_valid = FALSE;
52             $mtime and $mtime > $newest and $newest = $mtime;
53             $key .= $key ? "~${path}" : "${path}";
54             }
55              
56             return ($key, $is_valid ? $newest : undef);
57             };
58              
59             # Public methods
60             sub get {
61 75     75 1 2392 my ($self, $key) = @_; $key .= NUL;
  75         228  
62              
63 75 100       2562 my $cached = $key ? $self->cache->get( $key ) : FALSE;
64              
65 75 100       68472 $cached and return ($cached->{data}, $cached->{meta});
66              
67 29         120 return (undef, { mtime => undef });
68             }
69              
70             sub get_by_paths {
71 2     2 1 376 my ($self, $paths) = @_;
72 2         7 my ($key, $newest) = $self->$_get_key_and_newest( $paths );
73              
74 2         7 return ($self->get( $key ), $newest);
75             }
76              
77             sub get_mtime {
78 10 100   10 1 1827 my ($self, $k) = @_; $k or return;
  10         26  
79              
80 9 100       122 my $mtimes = $self->cache->get( $self->_mtimes_key ) or return;
81              
82 8         488 return $mtimes->{ $k };
83             }
84              
85             sub remove {
86 24 100   24 1 835 my ($self, $key) = @_; defined $key or return;
  24         71  
87              
88 23         342 $self->cache->remove( $key ); $self->set_mtime( $key, undef );
  23         922  
89              
90 23         2227 return;
91             }
92              
93             sub set {
94 28   100 28 1 1555 my ($self, $key, $data, $meta) = @_; $meta //= { mtime => undef };
  28         79  
95              
96             try {
97 28 100   28   858 $key eq $self->_mtimes_key and throw 'key not allowed';
98 27 50       890 $self->cache->set( $key, { data => $data, meta => $meta } )
99             or throw 'set operation returned false';
100 27         1501 $self->set_mtime( $key, $meta->{mtime} );
101             }
102 28     1   198 catch { $self->log->error( "Cache key ${key} set failed - ${_}" ) };
  1         1609  
103              
104 28         2144 return ($data, $meta);
105             }
106              
107             sub set_by_paths {
108 2     2 1 5 my ($self, $paths, $data, $meta) = @_;
109              
110 2         7 my ($key, $newest) = $self->$_get_key_and_newest( $paths );
111              
112 2         4 $meta->{mtime} = $newest;
113              
114 2         130 return $self->set( $key, $data, $meta );
115             }
116              
117             sub set_mtime {
118 50     50 1 77 my ($self, $k, $v) = @_;
119              
120             return $self->cache->get_and_set( $self->_mtimes_key, sub {
121 50     50   2525 my (undef, $mtimes) = @_;
122              
123 50 100       105 if (defined $v) { $mtimes->{ $k } = $v } else { delete $mtimes->{ $k } }
  25         188  
  25         66  
124              
125 50         1011 return $mtimes;
126 50         738 } );
127             }
128              
129             1;
130              
131             __END__