File Coverage

blib/lib/Cache/RedisDB.pm
Criterion Covered Total %
statement 24 65 36.9
branch 1 12 8.3
condition 2 24 8.3
subroutine 10 19 52.6
pod 11 11 100.0
total 48 131 36.6


line stmt bran cond sub pod time code
1              
2             use 5.010;
3 2     2   1668657 use strict;
  2         29  
4 2     2   11 use warnings;
  2         4  
  2         42  
5 2     2   11 use Carp;
  2         5  
  2         45  
6 2     2   10 use RedisDB 2.14;
  2         4  
  2         132  
7 2     2   1272 use Sereal qw(looks_like_sereal);
  2         114714  
  2         81  
8 2     2   911  
  2         1924  
  2         1962  
9             =head1 NAME
10              
11             Cache::RedisDB - RedisDB based cache system
12              
13             =head1 DESCRIPTION
14              
15             This is just a wrapper around RedisDB to have a single Redis object and connection per process. By default uses server redis://127.0.0.1, but it may be overwritten by REDIS_CACHE_SERVER environment variable. It transparently handles forks.
16              
17             =head1 COMPATIBILITY AND REQUIREMENTS
18              
19             Redis 2.6.12 and higher strongly recommended. Required if you want to use
20             extended options in ->set().
21              
22             =cut
23              
24             our $VERSION = '0.13';
25              
26             =head1 SYNOPSIS
27              
28             use Cache::RedisDB;
29             Cache::RedisDB->set("namespace", "key", "value");
30             Cache::RedisDB->get("namespace", "key");
31              
32             =head1 METHODS
33              
34             =head2 redis_uri
35              
36             Returns a C<< redis:// >> redis URI which will be used for the initial Redis connection.
37              
38             This will default to localhost on the standard port, and can be overridden with the
39             C<REDIS_CACHE_SERVER> environment variable.
40              
41             =cut
42              
43              
44             my $redis_uri = $ENV{REDIS_CACHE_SERVER} // 'redis://127.0.0.1';
45              
46 2   50 2 1 12 # Probably a legacy TCP host:port
47             $redis_uri = 'redis://' . $redis_uri if ($redis_uri =~ m#^[^/]+:[0-9]{1,5}$#);
48              
49 2 50       28 return $redis_uri;
50             }
51 2         35  
52             =head2 redis_connection
53              
54             Creates new connection to a Redis server and returns the corresponding L<RedisDB> object.
55              
56             =cut
57              
58             return RedisDB->new(
59             url => redis_uri(),
60             reconnect_attempts => 3,
61             on_connect_error => sub {
62             confess "Cannot connect: " . redis_uri();
63             });
64             }
65 1     1   2004899  
66 1     1 1 7 =head2 redis
67              
68             Returns a singleton L<RedisDB> instance.
69              
70             =cut
71              
72             state $redis;
73             $redis //= redis_connection();
74             return $redis;
75             }
76 1     1 1 178  
77 1   33     7 =head2 get
78 0            
79             Takes a C<$namespace> and C<$key> parameter, and returns the scalar value
80             corresponding to that cache entry.
81              
82             This will automatically deserialise data stored with L<Sereal>. If no data
83             is found, this will return C<undef>.
84              
85             =cut
86              
87             my ($self, $namespace, $key) = @_;
88             my $res = redis()->get(_cache_key($namespace, $key));
89             if (looks_like_sereal($res)) {
90             state $decoder = Sereal::Decoder->new();
91             $res = $decoder->decode($res);
92 0     0 1   }
93 0           return $res;
94 0 0         }
95 0            
96 0           =head2 mget
97              
98 0           Retrieve values for multiple keys in a single call.
99              
100             Similar to L</get>, this takes a C<$namespace> as the first parameter,
101             but it also accepts a list of C<@keys> to look up.
102              
103             Returns an arrayref in the same order as the original keys. For any
104             key that had no value, the resulting arrayref will contain C<undef>.
105              
106             =cut
107              
108             my ($self, $namespace, @keys) = @_;
109             my $res = Cache::RedisDB::redis()->mget(map { Cache::RedisDB::_cache_key($namespace, $_) } @keys);
110             state $decoder = Sereal::Decoder->new();
111             return [map { ($_ && looks_like_sereal($_)) ? $decoder->decode($_) : $_ } @$res];
112             }
113              
114 0     0 1   =head2 set
115 0            
  0            
116 0           Creates or updates a Redis key under C<$namespace>, C<$key> using the scalar C<$value>.
117 0 0 0       Also takes an optional C<$exptime> as expiration time in seconds.
  0            
118              
119             $redis->set($namespace, $key, $value);
120             $redis->set($namespace, $key, $value, $expiry_time);
121              
122             Can also be provided a callback which will be executed once the command completes.
123              
124             =cut
125              
126             my ($self, $namespace, $key, $value, $exptime, $callback) = @_;
127             if (not defined $value or ref $value or Encode::is_utf8($value)) {
128             state $encoder = Sereal::Encoder->new({
129             freeze_callbacks => 1,
130             });
131             $value = $encoder->encode($value);
132             }
133 0     0 1   my $cache_key = _cache_key($namespace, $key);
134 0 0 0       if (defined $exptime) {
      0        
135 0           $exptime = int(1000 * $exptime);
136             # PX milliseconds -- Set the specified expire time, in milliseconds
137             return redis()->set($cache_key, $value, "PX", $exptime, $callback // ());
138 0           } else {
139             return redis()->set($cache_key, $value, $callback // ());
140 0           }
141 0 0         }
142 0            
143             =head2 set_nw($namespace, $key, $value[, $exptime])
144 0   0        
145             Same as I<set> but do not wait confirmation from server. If the server returns
146 0   0       an error, it will be ignored.
147              
148             =cut
149              
150             my ($self, $namespace, $key, $value, $exptime) = @_;
151             return $self->set($namespace, $key, $value, $exptime, RedisDB::IGNORE_REPLY);
152             }
153              
154             =head2 del($namespace, $key1[, $key2, ...])
155              
156             Delete given keys and associated values from the cache. I<$namespace> is common for all keys.
157             Returns number of deleted keys.
158 0     0 1    
159 0           =cut
160              
161             my ($self, $namespace, @keys) = @_;
162             return redis->del(map { _cache_key($namespace, $_) } @keys);
163             }
164              
165             =head2 keys($namespace)
166              
167             Return an arrayref of all known keys in the provided C<$namespace>.
168              
169             =cut
170 0     0 1    
171 0           my ($self, $namespace) = @_;
  0            
172             my $prefix = _cache_key($namespace, undef);
173             my $pl = length($prefix);
174             return [map { substr($_, $pl) } @{redis()->keys($prefix . '*')}];
175             }
176              
177             =head2 ttl($namespace, $key)
178              
179             Return the Time To Live (in seconds) of a key in the provided I<$namespace>.
180              
181 0     0 1   =cut
182 0            
183 0           my ($self, $namespace, $key) = @_;
184 0            
  0            
  0            
185             my $ms = redis()->pttl(_cache_key($namespace, $key));
186             # We pessimistically round to the start of the second where it
187             # will disappear. While slightly wrong, it is likely less confusing.
188             # Nonexistent (or already expired) keys should return 0;
189             return ($ms <= 0) ? 0 : int($ms / 1000);
190             }
191              
192             my ($namespace, $key) = @_;
193             $namespace //= '';
194 0     0 1   $key //= '';
195              
196 0           return $namespace . '::' . $key;
197             }
198              
199             =head3 flushall
200 0 0          
201             Delete all keys and associated values from the cache.
202              
203             =cut
204 0     0      
205 0   0       return redis()->flushall();
206 0   0       }
207              
208 0           =head1 AUTHOR
209              
210             binary.com, C<< <perl at binary.com> >>
211              
212             =head1 BUGS
213              
214             Please report any bugs or feature requests to C<bug-cache-redisdb at rt.cpan.org>, or through
215             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Cache-RedisDB>. I will be notified, and then you'll
216             automatically be notified of progress on your bug as I make changes.
217              
218 0     0 1   =head1 SUPPORT
219              
220             You can find documentation for this module with the perldoc command.
221              
222             perldoc Cache::RedisDB
223              
224             You can also look for information at:
225              
226             =over 4
227              
228             =item * RT: CPAN's request tracker (report bugs here)
229              
230             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Cache-RedisDB>
231              
232             =item * AnnoCPAN: Annotated CPAN documentation
233              
234             L<http://annocpan.org/dist/Cache-RedisDB>
235              
236             =item * CPAN Ratings
237              
238             L<http://cpanratings.perl.org/d/Cache-RedisDB>
239              
240             =item * Search CPAN
241              
242             L<http://search.cpan.org/dist/Cache-RedisDB/>
243              
244             =back
245              
246             =cut
247              
248             1; # End of Cache::RedisDB