File Coverage

blib/lib/Cache/RedisDB.pm
Criterion Covered Total %
statement 24 59 40.6
branch 1 10 10.0
condition 2 21 9.5
subroutine 10 18 55.5
pod 10 10 100.0
total 47 118 39.8


line stmt bran cond sub pod time code
1             package Cache::RedisDB;
2              
3 3     3   772798 use 5.010;
  3         9  
4 3     3   14 use strict;
  3         3  
  3         71  
5 3     3   13 use warnings FATAL => 'all';
  3         7  
  3         99  
6 3     3   11 use Carp;
  3         4  
  3         170  
7 3     3   2016 use RedisDB 2.14;
  3         175327  
  3         109  
8 3     3   1524 use Sereal qw(looks_like_sereal);
  3         1361  
  3         2057  
9              
10             =head1 NAME
11              
12             Cache::RedisDB - RedisDB based cache system
13              
14             =head1 VERSION
15              
16             Version 0.11
17              
18             =head1 DESCRIPTION
19              
20             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.
21              
22             =head1 COMPATIBILITY AND REQUIREMENTS
23              
24             Redis 2.6.12 and higher strongly recommended. Required if you want to use
25             extended options in ->set().
26              
27             =cut
28              
29             our $VERSION = '0.11';
30              
31             =head1 SYNOPSIS
32              
33             use Cache::RedisDB;
34             Cache::RedisDB->set("namespace", "key", "value");
35             Cache::RedisDB->get("namespace", "key");
36              
37             =head1 SUBROUTINES/METHODS
38              
39             =head2 redis_uri
40              
41             Returns redis uri
42              
43             =cut
44              
45             sub redis_uri {
46              
47 2   50 2 1 14 my $redis_uri = $ENV{REDIS_CACHE_SERVER} // 'redis://127.0.0.1';
48              
49             # Probably a legacy TCP host:port
50 2 50       30 $redis_uri = 'redis://' . $redis_uri if ($redis_uri =~ m#^[^/]+:[0-9]{1,5}$#);
51              
52 2         45 return $redis_uri;
53             }
54              
55             =head2 redis_connection
56              
57             Creates new connection to redis-server and returns corresponding RedisDB object.
58              
59             =cut
60              
61             sub redis_connection {
62             return RedisDB->new(
63             url => redis_uri(),
64             reconnect_attempts => 3,
65             on_connect_error => sub {
66 1     1   2004733 confess "Cannot connect: " . redis_uri();
67 1     1 1 6 });
68             }
69              
70             =head2 redis
71              
72             Returns RedisDB object connected to the correct redis server.
73              
74             =cut
75              
76             sub redis {
77 1     1 1 160 state $redis;
78 1   33     9 $redis //= redis_connection();
79 0           return $redis;
80             }
81              
82             =head2 get($namespace, $key)
83              
84             Retrieve I<$key> value from the cache.
85              
86             =cut
87              
88             sub get {
89 0     0 1   my ($self, $namespace, $key) = @_;
90 0           my $res = redis->get(_cache_key($namespace, $key));
91 0 0         if (looks_like_sereal($res)) {
92 0           state $decoder = Sereal::Decoder->new();
93 0           $res = $decoder->decode($res);
94             }
95 0           return $res;
96             }
97              
98             =head2 set($namespace, $key, $value[, $exptime])
99              
100             Assigns I<$value> to the I<$key>. I<$value> should be scalar value.
101             If I<$exptime> specified, it is expiration time in seconds.
102              
103             =cut
104              
105             sub set {
106 0     0 1   my ($self, $namespace, $key, $value, $exptime, $callback) = @_;
107 0 0 0       if (not defined $value or ref $value or Encode::is_utf8($value)) {
      0        
108 0           state $encoder = Sereal::Encoder->new({
109             freeze_callbacks => 1,
110             });
111 0           $value = $encoder->encode($value);
112             }
113 0           my $cache_key = _cache_key($namespace, $key);
114 0 0         if (defined $exptime) {
115 0           $exptime = int(1000 * $exptime);
116             # PX milliseconds -- Set the specified expire time, in milliseconds
117 0   0       return redis->set($cache_key, $value, "PX", $exptime, $callback // ());
118             } else {
119 0   0       return redis->set($cache_key, $value, $callback // ());
120             }
121             }
122              
123             =head2 set_nw($namespace, $key, $value[, $exptime])
124              
125             Same as I<set> but do not wait confirmation from server. If server will return
126             error, there's no way to catch it.
127              
128             =cut
129              
130             sub set_nw {
131 0     0 1   my ($self, $namespace, $key, $value, $exptime) = @_;
132 0           return $self->set($namespace, $key, $value, $exptime, RedisDB::IGNORE_REPLY);
133             }
134              
135             =head2 del($namespace, $key1[, $key2, ...])
136              
137             Delete given keys and associated values from the cache. I<$namespace> is common for all keys.
138             Returns number of deleted keys.
139              
140             =cut
141              
142             sub del {
143 0     0 1   my ($self, $namespace, @keys) = @_;
144 0           return redis->del(map { _cache_key($namespace, $_) } @keys);
  0            
145             }
146              
147             =head2 keys($namespace)
148              
149             Return a list of all known keys in the provided I<$namespace>.
150              
151             =cut
152              
153             sub keys {
154 0     0 1   my ($self, $namespace) = @_;
155 0           my $prefix = _cache_key($namespace, undef);
156 0           my $pl = length($prefix);
157 0           return [map { substr($_, $pl) } @{redis->keys($prefix . '*')}];
  0            
  0            
158             }
159              
160             =head2 ttl($namespace, $key)
161              
162             Return the Time To Live (in seconds) of a key in the provided I<$namespace>.
163              
164             =cut
165              
166             sub ttl {
167 0     0 1   my ($self, $namespace, $key) = @_;
168              
169 0           my $ms = redis->pttl(_cache_key($namespace, $key));
170             # We pessimistically round to the start of the second where it
171             # will disappear. While slightly wrong, it is likely less confusing.
172             # Nonexistent (or already expired) keys should return 0;
173 0 0         return ($ms <= 0) ? 0 : int($ms / 1000);
174             }
175              
176             sub _cache_key {
177 0     0     my ($namespace, $key) = @_;
178 0   0       $namespace //= '';
179 0   0       $key //= '';
180              
181 0           return $namespace . '::' . $key;
182             }
183              
184             =head3 flushall
185              
186             Delete all keys and associated values from the cache.
187              
188             =cut
189              
190             sub flushall {
191 0     0 1   return redis->flushall();
192             }
193              
194             =head1 AUTHOR
195              
196             binary.com, C<< <rakesh at binary.com> >>
197              
198             =head1 BUGS
199              
200             Please report any bugs or feature requests to C<bug-cache-redisdb at rt.cpan.org>, or through
201             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Cache-RedisDB>. I will be notified, and then you'll
202             automatically be notified of progress on your bug as I make changes.
203              
204              
205              
206              
207             =head1 SUPPORT
208              
209             You can find documentation for this module with the perldoc command.
210              
211             perldoc Cache::RedisDB
212              
213              
214             You can also look for information at:
215              
216             =over 4
217              
218             =item * RT: CPAN's request tracker (report bugs here)
219              
220             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Cache-RedisDB>
221              
222             =item * AnnoCPAN: Annotated CPAN documentation
223              
224             L<http://annocpan.org/dist/Cache-RedisDB>
225              
226             =item * CPAN Ratings
227              
228             L<http://cpanratings.perl.org/d/Cache-RedisDB>
229              
230             =item * Search CPAN
231              
232             L<http://search.cpan.org/dist/Cache-RedisDB/>
233              
234             =back
235              
236             =head1 LICENSE AND COPYRIGHT
237              
238             Copyright 2014 binary.com.
239              
240             This program is free software; you can redistribute it and/or modify it
241             under the terms of the the Artistic License (2.0). You may obtain a
242             copy of the full license at:
243              
244             L<http://www.perlfoundation.org/artistic_license_2_0>
245              
246             Any use, modification, and distribution of the Standard or Modified
247             Versions is governed by this Artistic License. By using, modifying or
248             distributing the Package, you accept this license. Do not use, modify,
249             or distribute the Package, if you do not accept this license.
250              
251             If your Modified Version has been derived from a Modified Version made
252             by someone other than you, you are nevertheless required to ensure that
253             your Modified Version complies with the requirements of this license.
254              
255             This license does not grant you the right to use any trademark, service
256             mark, tradename, or logo of the Copyright Holder.
257              
258             This license includes the non-exclusive, worldwide, free-of-charge
259             patent license to make, have made, use, offer to sell, sell, import and
260             otherwise transfer the Package with respect to any patent claims
261             licensable by the Copyright Holder that are necessarily infringed by the
262             Package. If you institute patent litigation (including a cross-claim or
263             counterclaim) against any party alleging that the Package constitutes
264             direct or contributory patent infringement, then this Artistic License
265             to you shall terminate on the date that such litigation is filed.
266              
267             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
268             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
269             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
270             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
271             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
272             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
273             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
274             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275              
276              
277             =cut
278              
279             1; # End of Cache::RedisDB