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