File Coverage

lib/Redis/SQLite.pm
Criterion Covered Total %
statement 297 310 95.8
branch 63 74 85.1
condition 30 40 75.0
subroutine 41 44 93.1
pod 36 40 90.0
total 467 508 91.9


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Redis::SQLite - Redis-Compatible module which writes to SQLite.
5              
6             =cut
7              
8             =head1 SYNOPSIS
9              
10             =for example begin
11              
12             #!/usr/bin/perl -w
13              
14             use Redis::SQLite;
15             use strict;
16              
17             my $db = Redis::SQLite->new();
18              
19             $db->set( "foo", "bar" );
20              
21             print $db->get( "foo" ) . "\n";
22              
23             =for example end
24              
25              
26             =head1 DESCRIPTION
27              
28             This package is an implementation of the L Perl-client API, which
29             stores all data in an SQLite database rather than in RAM.
30              
31             It is B a drop-in replacement, because it doesn't implement all the
32             features you'd expect from the real Redis module. Just enough to be useful.
33              
34             =cut
35              
36             =head1 COMPATIBILITY
37              
38             This module is designed to be source compatible with the L module,
39             providing you're only operating upon either sets or simple strings.
40              
41             Specifically we do not support:
42              
43             =over 8
44              
45             =item HASH
46              
47             For example C, C, C, etc.
48              
49             =item Lists
50              
51             For example C, C, etc.
52              
53             =item Scripting
54              
55             Perl is itself a wonderful scripting language, so we've no need for Lua support.
56              
57             =item ZSET
58              
59             For example C, C, C, etc.
60              
61             =back
62              
63             All of the set-related primitives are supported, with the exception of C,
64             and the basic commands for working with string-based keys are also present, such
65             as:
66              
67             =over 8
68              
69             =item append
70              
71             =item del
72              
73             =item exists
74              
75             =item get
76              
77             =item set
78              
79             =item etc..
80              
81             =back
82              
83             =cut
84              
85             =head1 METHODS
86              
87             =cut
88              
89              
90             package Redis::SQLite;
91              
92              
93              
94 20     20   276817 use strict;
  20         26  
  20         483  
95 20     20   61 use warnings;
  20         24  
  20         418  
96 20     20   28131 use DBI;
  20         244726  
  20         47572  
97              
98              
99             our $VERSION = '0.3';
100              
101              
102             =head2 new
103              
104             Constructor. The only (optional) argument is C which will
105             change the default SQLite database-file location, if unspecified
106             C<~/.predis.db> will be used.
107              
108             =cut
109              
110             sub new
111             {
112 19     19 1 188 my ( $proto, %supplied ) = (@_);
113 19   33     101 my $class = ref($proto) || $proto;
114              
115 19         35 my $self = {};
116 19         31 bless( $self, $class );
117              
118             # Get the user's home-directory
119             my $home =
120 19   0     82 $ENV{ 'HOME' } || $ENV{ 'USERPROFILE' } || ( getpwuid($<) )[7] || "C:/";
121              
122             # Create ~/.predis.db unless an alternative path was specified.
123 19   33     77 my $file = $supplied{ 'path' } || "$home/.predis.db";
124              
125 19         26 my $create = 1;
126 19 50       166 $create = 0 if ( -e $file );
127              
128 19         180 $self->{ 'db' } =
129             DBI->connect( "dbi:SQLite:dbname=$file", "", "", { AutoCommit => 1 } );
130              
131             #
132             # Populate the database tables, if it was missing.
133             #
134 19 50       163158 if ($create)
135             {
136 19         107 $self->{ 'db' }->do(
137             "CREATE TABLE string (id INTEGER PRIMARY KEY, key UNIQUE, val );");
138 19         10038 $self->{ 'db' }
139             ->do("CREATE TABLE sets (id INTEGER PRIMARY KEY, key, val );");
140             }
141              
142             #
143             # This is potentially risky, but improves the throughput by several
144             # orders of magnitude.
145             #
146 19 50       2863 if ( !$ENV{ 'SAFE' } )
147             {
148 19         91 $self->{ 'db' }->do("PRAGMA synchronous = OFF");
149 19         532 $self->{ 'db' }->do("PRAGMA journal_mode = MEMORY");
150             }
151              
152 19         345 return $self;
153             }
154              
155              
156             =head2 append
157              
158             Append the given string to the contents of the existing key, creating it
159             if didn't previously exist.
160              
161             =cut
162              
163             sub append
164             {
165 2     2 1 4 my ( $self, $key, $data ) = (@_);
166              
167 2         7 my $r = $self->get($key);
168 2         5 $r .= $data;
169 2         4 $self->set( $key, $r );
170             }
171              
172              
173             =head2 exists
174              
175             Does the given key exist?
176              
177             =cut
178              
179             sub exists
180             {
181 37     37 1 1934 my ( $self, $key ) = (@_);
182              
183 37         152 my $sql = $self->{ 'db' }->prepare("SELECT key FROM string WHERE key=?");
184 37         1953 $sql->execute($key);
185 37   100     236 my $x = $sql->fetchrow_array() || undef;
186 37         71 $sql->finish();
187              
188 37 100       62 if ($x)
189             {
190 22         227 return 1;
191             }
192              
193 15         53 $sql = $self->{ 'db' }->prepare("SELECT key FROM sets WHERE key=?");
194 15         798 $sql->execute($key);
195 15   100     78 $x = $sql->fetchrow_array() || undef;
196 15         26 $sql->finish();
197              
198 15 100       23 if ($x)
199             {
200 1         8 return 1;
201             }
202              
203 14         101 return 0;
204             }
205              
206              
207             =head2 get
208              
209             Get the value of a string-key. Returns C if the key didn't exist,
210             or contain data.
211              
212             =cut
213              
214             sub get
215             {
216 352     352 1 584 my ( $self, $key ) = (@_);
217              
218 352 100       660 if ( !$self->{ 'get' } )
219             {
220             $self->{ 'get' } =
221 12         61 $self->{ 'db' }->prepare("SELECT val FROM string WHERE key=?");
222             }
223 352         5881 $self->{ 'get' }->execute($key);
224 352         3984 my $x = $self->{ 'get' }->fetchrow_array();
225 352         633 $self->{ 'get' }->finish();
226 352         846 return ($x);
227             }
228              
229              
230              
231             =head2 getset
232              
233             Update the value of a key, and return the previous value if any.
234              
235             =cut
236              
237             sub getset
238             {
239 1     1 1 2 my ( $self, $key, $val ) = (@_);
240              
241 1         2 my $old = $self->get($key);
242 1         3 $self->set( $key, $val );
243              
244 1         5 return ($old);
245             }
246              
247              
248             =head2 getrange
249              
250             Return the chunk of the key's value between the given offsets.
251              
252             =cut
253              
254             sub getrange
255             {
256 4     4 1 9 my ( $self, $key, $start, $end ) = (@_);
257              
258 4         5 my $val = $self->get($key);
259 4         4 my $s = $start;
260 4         3 my $e = $end;
261              
262 4 100       9 if ( $s < 0 )
263             {
264 1         2 $s = length($val) + $s;
265             }
266 4 100       8 if ( $e < 0 )
267             {
268 2         2 $e = length($val) + $e;
269             }
270              
271 4         16 return ( substr( $val, $s, ( $e - $s + 1 ) ) );
272             }
273              
274              
275              
276             =head2 strlen
277              
278             Return the length of the given value of the given key.
279              
280             =cut
281              
282             sub strlen
283             {
284 6     6 1 12 my ( $self, $key ) = (@_);
285              
286 6         14 my $data = $self->get($key);
287 6 50       18 if ( defined($data) )
288             {
289 6         40 return ( length($data) );
290             }
291 0         0 return 0;
292             }
293              
294              
295             =head2 rename
296              
297             Rename a string key. Deleting the target if it exists.
298              
299             =cut
300              
301             sub rename
302             {
303 1     1 1 3 my ( $self, $key, $new_name ) = (@_);
304              
305 1         3 $self->del($new_name);
306              
307 1         2 my $val = $self->get($key);
308 1         3 $self->set( $new_name, $val );
309              
310 1         2 $self->del($key);
311             }
312              
313              
314             =head2 renamenx
315              
316             Attempt to rename the given key, if the destination exists then
317             nothing happens.
318              
319             =cut
320              
321             sub renamenx
322             {
323 2     2 1 3 my ( $self, $key, $new_name ) = (@_);
324              
325 2 100       4 return 0 if ( $self->exists($new_name) );
326              
327             # Get the value and save it.
328 1         3 my $val = $self->get($key);
329 1         3 $self->set( $new_name, $val );
330              
331             # Remove the original
332 1         2 $self->del($key);
333              
334 1         4 return "OK";
335             }
336              
337              
338             =head2 set
339              
340             Set the value of a string-key.
341              
342             =cut
343              
344             sub set
345             {
346 175     175 1 5662 my ( $self, $key, $val ) = (@_);
347              
348 175 100       319 if ( !$self->{ 'ins' } )
349             {
350             $self->{ 'ins' } =
351 13         70 $self->{ 'db' }
352             ->prepare("INSERT OR REPLACE INTO string (key,val) VALUES( ?,? )");
353             }
354 175         13770 $self->{ 'ins' }->execute( $key, $val );
355 175         704 $self->{ 'ins' }->finish();
356              
357             }
358              
359              
360             =head2 setnx
361              
362             Store the given value in the named key, unless that key exists.
363              
364             =cut
365              
366             sub setnx
367             {
368 1     1 1 2 my ( $self, $key, $val ) = (@_);
369              
370 1 50       3 return 0 if ( $self->exists($key) );
371              
372 0         0 $self->set( $key, $val );
373 0         0 return 1;
374             }
375              
376              
377             =head2 setrange
378              
379             Insert some new data at the given offset of the specific key's value.
380              
381             If the current length of the key's value is too short it is NULL-padded
382             first.
383              
384             =cut
385              
386             sub setrange
387             {
388 2     2 1 3 my ( $self, $key, $offset, $data ) = (@_);
389              
390 2         8 my $val = $self->get($key);
391              
392 2 100       9 while ( ( $val ? length($val) : 0 ) < $offset )
393             {
394 6         10 $val .= chr(0x00);
395             }
396              
397              
398 2         4 substr( $val, $offset, length($data), $data );
399 2         4 $self->set( $key, $val );
400 2         4 return ( length($val) );
401             }
402              
403              
404             =head2 type
405              
406             Return the type of the named key.
407              
408             =cut
409              
410             sub type
411             {
412 6     6 1 15 my ( $self, $key ) = (@_);
413              
414              
415 6         30 my $sql = $self->{ 'db' }->prepare("SELECT key FROM string WHERE key=?");
416 6         337 $sql->execute($key);
417 6   100     55 my $x = $sql->fetchrow_array() || undef;
418 6         13 $sql->finish();
419              
420 6 100       44 return 'string' if ($x);
421              
422 3         14 $sql = $self->{ 'db' }->prepare("SELECT key FROM sets WHERE key=?");
423 3         191 $sql->execute($key);
424 3   100     18 $x = $sql->fetchrow_array() || undef;
425 3         9 $sql->finish();
426              
427 3 100       14 return 'set' if ($x);
428              
429 2         17 return undef;
430             }
431              
432              
433             =head2 incr
434              
435             Increment and return the value of an (integer) string-key.
436              
437             =cut
438              
439             sub incr
440             {
441 9     9 1 18 my ( $self, $key ) = (@_);
442              
443 9         16 return ( $self->incrby( $key, 1 ) );
444             }
445              
446              
447              
448             =head2 incrby
449              
450             Increment and return the value of an (integer) string-key.
451              
452             =cut
453              
454             sub incrby
455             {
456 12     12 1 484 my ( $self, $key, $amt ) = (@_);
457              
458 12 50       21 $amt = 1 if ( !defined($amt) );
459              
460 12   100     21 my $cur = $self->get($key) || 0;
461 12         16 $cur += $amt;
462 12         19 $self->set( $key, $cur );
463              
464 12         37 return ($cur);
465             }
466              
467              
468             =head2 decr
469              
470             Decrement and return the value of an (integer) string-key.
471              
472             =cut
473              
474             sub decr
475             {
476 4     4 1 5 my ( $self, $key ) = (@_);
477              
478 4         8 return ( $self->decrby( $key, 1 ) );
479             }
480              
481              
482              
483             =head2 decrby
484              
485             Decrement and return the value of an (integer) string-key.
486              
487             =cut
488              
489             sub decrby
490             {
491 12     12 1 40 my ( $self, $key, $amt ) = (@_);
492              
493 12 50       24 $amt = 1 if ( !defined($amt) );
494              
495 12   100     21 my $cur = $self->get($key) || 0;
496 12         18 $cur -= $amt;
497 12         19 $self->set( $key, $cur );
498              
499 12         48 return ($cur);
500             }
501              
502              
503             =head2 del
504              
505             Delete a given key, regardless of whether it holds a string or a set.
506              
507             =cut
508              
509             sub del
510             {
511 78     78 1 23444 my ( $self, $key ) = (@_);
512              
513             # strings
514 78         350 my $str = $self->{ 'db' }->prepare("DELETE FROM string WHERE key=?");
515 78         4935 $str->execute($key);
516 78         187 $str->finish();
517              
518             # Deleted a string-keyu
519 78 100       833 return 1 if ( $str->rows > 0 );
520              
521             # sets
522 6         28 my $set = $self->{ 'db' }->prepare("DELETE FROM sets WHERE key=?");
523 6         419 $set->execute($key);
524 6         18 $set->finish();
525              
526             # Deleted a set-key.
527 6 100       41 return 1 if ( $set->rows > 0 );
528              
529             # Deleted nothing.
530 5         67 return 0;
531             }
532              
533              
534             =head2 keys
535              
536             Return the names of each known key.
537              
538             These can be optionally filtered by a (perl) regular expression, for example:
539              
540             =for example begin
541              
542             $redis->set( "foo", 1 );
543             $redis->set( "moo", 1 );
544              
545             $redis->keys( "^f" ); # -> [ "foo" ]
546             $redis->keys( "oo\$" ); # -> [ "foo", "moo" ]
547              
548             =for example end
549              
550             =cut
551              
552             sub keys
553             {
554 42     42 1 11927 my ( $self, $pattern ) = (@_);
555              
556             # Get all keys into this hash
557 42         52 my %known;
558              
559             # We run the same query against two tables.
560 42         78 foreach my $table (qw! string sets !)
561             {
562             # Get the names of the key.
563 84         442 my $str = $self->{ 'db' }->prepare("SELECT key FROM $table");
564 84         3934 $str->execute();
565 84         474 while ( my ($name) = $str->fetchrow_array )
566             {
567 122         386 $known{ $name } += 1;
568             }
569 84         702 $str->finish();
570             }
571              
572             # The keys we've found
573 42         127 my @keys = keys %known;
574              
575 42 100       98 if ($pattern)
576             {
577 4         4 my @ret;
578 4         8 foreach my $ent (@keys)
579             {
580 30 100       95 push( @ret, $ent ) if ( $ent =~ /$pattern/ );
581             }
582 4         29 return (@ret);
583             }
584             else
585             {
586 38         204 return (@keys);
587             }
588             }
589              
590              
591             =head2 randomkey
592              
593             Return the name of a random key.
594              
595             =cut
596              
597             sub randomkey
598             {
599 1     1 1 2 my ($self) = (@_);
600              
601             # Get all keys into this hash
602 1         1 my %known;
603              
604             # We run the same query against two tables.
605 1         3 foreach my $table (qw! string sets !)
606             {
607             # Get the names of the key.
608 2         11 my $str = $self->{ 'db' }->prepare("SELECT key FROM $table");
609 2         91 $str->execute();
610 2         12 while ( my ($name) = $str->fetchrow_array )
611             {
612 9         42 $known{ $name } += 1;
613             }
614 2         17 $str->finish();
615             }
616              
617             # The keys we've found
618 1         5 my @keys = CORE::keys %known;
619              
620 1         38 return ( $keys[rand @keys] );
621             }
622              
623              
624             =head2 smembers
625              
626             Return the members of the given set.
627              
628             =cut
629              
630             sub smembers
631             {
632 13     13 1 16 my ( $self, $key ) = (@_);
633              
634 13 100       25 if ( !$self->{ 'smembers' } )
635             {
636             $self->{ 'smembers' } =
637 3         32 $self->{ 'db' }->prepare("SELECT val FROM sets WHERE key=?");
638             }
639 13         253 $self->{ 'smembers' }->execute($key);
640              
641 13         13 my @vals;
642 13         56 while ( my ($name) = $self->{ 'smembers' }->fetchrow_array )
643             {
644 42         140 push( @vals, $name );
645             }
646 13         20 $self->{ 'smembers' }->finish();
647              
648 13         36 return (@vals);
649             }
650              
651              
652             =head2 smove
653              
654             Move a member from a given set to a new one.
655              
656             =cut
657              
658             sub smove
659             {
660 2     2 1 3 my ( $self, $src, $dst, $ent ) = (@_);
661              
662             # Get the value from the original set
663 2         9 my $sql = $self->{ 'db' }
664             ->prepare("UPDATE sets SET key=? WHERE ( key=? AND val=?)");
665              
666 2         157 $sql->execute( $dst, $src, $ent );
667 2         5 $sql->finish();
668              
669 2 100       7 if ( $sql->rows > 0 )
670             {
671 1         10 return 1;
672             }
673 1         10 return 0;
674              
675             }
676              
677              
678             =head2 sismember
679              
680             Is the given item a member of the set?
681              
682             =cut
683              
684             sub sismember
685             {
686 22     22 1 6623 my ( $self, $set, $key ) = (@_);
687              
688             my $sql =
689 22         105 $self->{ 'db' }->prepare("SELECT val FROM sets WHERE key=? AND val=?");
690 22         1309 $sql->execute( $set, $key );
691              
692 22   100     141 my $x = $sql->fetchrow_array() || undef;
693 22         40 $sql->finish();
694              
695 22 100 66     70 if ( defined($x) && ( $x eq $key ) )
696             {
697 11         112 return 1;
698             }
699 11         113 return 0;
700             }
701              
702              
703             =head2 sadd
704              
705             Add a member to a set.
706              
707             =cut
708              
709             sub sadd
710             {
711 65     65 1 829 my ( $self, $key, $val ) = (@_);
712              
713 65 100       114 if ( !$self->{ 'sadd' } )
714             {
715             $self->{ 'sadd' } =
716 7         40 $self->{ 'db' }->prepare(
717             "INSERT INTO sets (key,val) SELECT ?,? WHERE NOT EXISTS( SELECT key, val FROM sets WHERE key=? AND val=? );"
718             );
719              
720             }
721 65         4138 $self->{ 'sadd' }->execute( $key, $val, $key, $val );
722 65         152 $self->{ 'sadd' }->finish();
723              
724 65 50       179 if ( $self->{ 'sadd' }->rows > 0 )
725             {
726 65         107 return 1;
727             }
728 0         0 return 0;
729              
730             }
731              
732              
733             =head2 srem
734              
735             Remove a member from a set.
736              
737             =cut
738              
739             sub srem
740             {
741 9     9 1 405 my ( $self, $key, $val ) = (@_);
742              
743 9 100       19 if ( !$self->{ 'srem' } )
744             {
745             $self->{ 'srem' } =
746 3         17 $self->{ 'db' }->prepare("DELETE FROM sets WHERE (key=? AND val=?)");
747             }
748 9         256 $self->{ 'srem' }->execute( $key, $val );
749 9         21 $self->{ 'srem' }->finish();
750              
751 9 50       34 if ( $self->{ 'srem' }->rows > 0 )
752             {
753 9         12 return 1;
754             }
755 0         0 return 0;
756             }
757              
758              
759             =head2 spop
760              
761             Remove a given number of elements from the named set, and return them.
762              
763             =cut
764              
765             sub spop
766             {
767 4     4 1 7 my ( $self, $key, $count ) = (@_);
768              
769 4 100       8 $count = 1 if ( !defined($count) );
770              
771 4         2 my @res;
772              
773 4   100     16 while ( ( $count > 0 ) && ( $count <= $self->scard($key) ) )
774             {
775 5         12 my $rand = $self->srandmember($key);
776 5         6 push( @res, $rand );
777 5         8 $self->srem( $key, $rand );
778              
779 5         12 $count -= 1;
780             }
781              
782 4         8 return (@res);
783             }
784              
785              
786              
787             =head2 srandmember
788              
789             Fetch the value of a random member from a set.
790              
791             =cut
792              
793             sub srandmember
794             {
795 6     6 1 2167 my ( $self, $key ) = (@_);
796              
797 6 100       13 if ( !$self->{ 'srandommember' } )
798             {
799             $self->{ 'srandommember' } =
800 2 50       11 $self->{ 'db' }->prepare(
801             "SELECT val FROM sets where key=? ORDER BY RANDOM() LIMIT 1") or
802             die "Failed to prepare";
803             }
804 6         269 $self->{ 'srandommember' }->execute($key);
805 6   50     55 my $x = $self->{ 'srandommember' }->fetchrow_array() || "";
806 6         15 $self->{ 'srandommember' }->finish();
807              
808 6         13 return ($x);
809             }
810              
811              
812             =head2 sunion
813              
814             Return the values which are present in each of the sets named, duplicates
815             will only be returned one time.
816              
817             For example:
818              
819             =for example begin
820              
821             $redis->sadd( "one", 1 );
822             $redis->sadd( "one", 2 );
823             $redis->sadd( "one", 3 );
824              
825             $redis->sadd( "two", 2 );
826             $redis->sadd( "two", 3 );
827             $redis->sadd( "two", 4 );
828              
829             $redis->sunion( "one", "two" ); # -> [ 1,2,3,4 ]
830              
831             =for example end
832              
833             =cut
834              
835             sub sunion
836             {
837 2     2 1 5 my ( $self, @keys ) = (@_);
838              
839              
840 2         2 my %result;
841              
842 2         3 foreach my $key (@keys)
843             {
844 4         8 my @vals = $self->smembers($key);
845 4         5 foreach my $val (@vals)
846             {
847 12         16 $result{ $val } += 1;
848             }
849             }
850              
851 2         8 return ( CORE::keys(%result) );
852             }
853              
854              
855             =head2 sunionstore
856              
857             Store the values which are present in each of the named sets in a new set.
858              
859             =cut
860              
861             sub sunionstore
862             {
863 1     1 1 3 my ( $self, $dest, @keys ) = (@_);
864              
865             # Get the union
866 1         2 my @union = $self->sunion(@keys);
867              
868             # Delete the current contents of the destination.
869 1         4 $self->del($dest);
870              
871             # Now store the members
872 1         1 foreach my $ent (@union)
873             {
874 6         10 $self->sadd( $dest, $ent );
875             }
876              
877             # Return the number of entries added
878 1         3 return ( scalar @union );
879             }
880              
881              
882             =head2 sinter
883              
884             Return only those members who exist in each of the named sets.
885              
886             =for example begin
887              
888             $redis->sadd( "one", 1 );
889             $redis->sadd( "one", 2 );
890             $redis->sadd( "one", 3 );
891              
892             $redis->sadd( "two", 2 );
893             $redis->sadd( "two", 3 );
894             $redis->sadd( "two", 4 );
895              
896             $redis->sinter( "one", "two" ); # -> [ 2,3 ]
897              
898             =for example end
899              
900             =cut
901              
902             sub sinter
903             {
904 3     3 1 7 my ( $self, @names ) = (@_);
905              
906 3         4 my %seen;
907              
908 3         4 foreach my $key (@names)
909             {
910 6         10 my @vals = $self->smembers($key);
911 6         9 foreach my $val (@vals)
912             {
913 20         24 $seen{ $val } += 1;
914             }
915             }
916              
917 3         2 my @result;
918              
919 3         8 foreach my $key ( CORE::keys(%seen) )
920             {
921 15 100       26 if ( $seen{ $key } == scalar @names )
922             {
923 5         6 push( @result, $key );
924             }
925             }
926 3         14 return (@result);
927             }
928              
929              
930              
931             =head2 sinterstore
932              
933             Store those members who exist in all the named sets in a new set.
934              
935             =cut
936              
937             sub sinterstore
938             {
939 1     1 1 3 my ( $self, $dest, @names ) = (@_);
940              
941             # Get the values that intersect
942 1         2 my @update = $self->sinter(@names);
943              
944             # Delete the current contents of the destination.
945 1         4 $self->del($dest);
946              
947             # Now store the members
948 1         2 foreach my $ent (@update)
949             {
950 2         4 $self->sadd( $dest, $ent );
951             }
952              
953             # Return the number of entries added
954 1         3 return ( scalar @update );
955             }
956              
957              
958             =head2 scard
959              
960             Count the number of entries in the given set.
961              
962             =cut
963              
964             sub scard
965             {
966 26     26 1 381 my ( $self, $key ) = (@_);
967              
968 26 100       59 if ( !$self->{ 'scard' } )
969             {
970             $self->{ 'scard' } =
971 6         28 $self->{ 'db' }->prepare("SELECT COUNT(id) FROM sets where key=?");
972             }
973 26         614 $self->{ 'scard' }->execute($key);
974 26   100     187 my $count = $self->{ 'scard' }->fetchrow_array() || 0;
975 26         172 $self->{ 'scard' }->finish();
976              
977 26         124 return ($count);
978             }
979              
980              
981              
982             =head2 bitcount
983              
984             Count the number of set bits in the content of the given key.
985              
986             =cut
987              
988             sub bitcount
989             {
990 74     74 1 76 my ( $self, $key ) = (@_);
991              
992 74         91 my $val = $self->get($key);
993              
994             # Use a lookup-table for each byte.
995 74         700 my @bitcounts = ( 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2,
996             2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3,
997             2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
998             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
999             2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
1000             4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
1001             4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
1002             6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1003             2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,
1004             3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,
1005             4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4,
1006             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
1007             4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,
1008             5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7,
1009             6, 7, 7, 8
1010             );
1011              
1012 74         43 my $sum = 0;
1013              
1014 74         159 foreach my $char ( split( //, $val ) )
1015             {
1016 316         253 $sum += $bitcounts[ord($char)];
1017             }
1018              
1019 74         538 return ($sum);
1020             }
1021              
1022              
1023             sub setbit
1024             {
1025 88     88 0 164 my ( $self, $key, $offset, $value ) = (@_);
1026              
1027 88   100     128 my $val = $self->get($key) || "";
1028 88   100     183 my $len = length($val) || 0;
1029              
1030             # Convert to binary.
1031 88         59 my $bin;
1032              
1033             # Convert the current value to binary.
1034 88         165 foreach my $byte ( split( //, $val ) )
1035             {
1036 20         41 $bin .= unpack( "B*", $byte );
1037             }
1038              
1039             # Ensure we have a long-enough string.
1040 88 100       170 while ( $offset >= ( $bin ? length($bin) : 0 ) )
1041             {
1042 300         453 $bin .= "00000000";
1043             }
1044              
1045             # Change the bit.
1046 88         97 substr( $bin, $offset, 1, $value );
1047              
1048 88         57 my $updated;
1049 88         109 while ( length($bin) )
1050             {
1051 320         265 my $next = substr( $bin, 0, 8 );
1052 320         221 $bin = substr( $bin, 8 );
1053              
1054 320         501 $updated .= pack( "B*", $next );
1055              
1056             }
1057              
1058 88         134 $self->set( $key, $updated );
1059             }
1060              
1061              
1062              
1063             sub getbit
1064             {
1065 40     40 0 4700 my ( $self, $key, $offset ) = (@_);
1066              
1067 40   50     67 my $val = $self->get($key) || "";
1068 40   50     61 my $len = length($val) || 0;
1069              
1070             # Convert to binary.
1071 40         25 my $bin;
1072              
1073             # Convert the current value to binary.
1074 40         82 foreach my $byte ( split( //, $val ) )
1075             {
1076 40         104 $bin .= unpack( "B*", $byte );
1077             }
1078              
1079             # Ensure we have a long-enough string.
1080 40 50       92 while ( $offset >= ( $bin ? length($bin) : 0 ) )
1081             {
1082 0         0 $bin .= "00000000";
1083             }
1084              
1085             # Get the bit.
1086 40         139 return ( substr( $bin, $offset, 1 ) );
1087             }
1088              
1089              
1090             =head2 ping
1091              
1092             This would usually check if the Redis connection was alive, and the
1093             server was present, in this implementation we always return true.
1094              
1095             =cut
1096              
1097             sub ping
1098             {
1099 0     0 1 0 return 1;
1100             }
1101              
1102              
1103             =head2 echo
1104              
1105             Return the parameters given.
1106              
1107             =cut
1108              
1109             sub echo
1110             {
1111 0     0 1 0 my ( $self, $arg ) = (@_);
1112              
1113 0         0 return ($arg);
1114             }
1115              
1116             our $AUTOLOAD;
1117              
1118             sub AUTOLOAD
1119             {
1120 0     0   0 my $command = $AUTOLOAD;
1121 0         0 $command =~ s/.*://;
1122 0         0 warn "NOT IMPLEMENTED:$command";
1123              
1124 0         0 return 1;
1125             }
1126              
1127              
1128             =head2 mget
1129              
1130             Return the values of multiple-keys. If a given key doesn't exist
1131             then C will be returned for that entry.
1132              
1133             =cut
1134              
1135             sub mget
1136             {
1137 2     2 1 1329 my ( $self, @keys ) = (@_);
1138              
1139 2         2 my @ret;
1140              
1141 2         5 foreach my $key (@keys)
1142             {
1143 5 100       10 if ( $self->exists($key) )
1144             {
1145 4         8 push( @ret, $self->get($key) );
1146             }
1147             else
1148             {
1149 1         3 push( @ret, undef );
1150             }
1151             }
1152              
1153 2         8 return (@ret);
1154             }
1155              
1156              
1157             =head2 mget
1158              
1159             Update the values of multiple-keys.
1160              
1161             =cut
1162              
1163             sub mset
1164             {
1165 2     2 0 1614 my ( $self, @keys ) = (@_);
1166              
1167 2         7 while ( scalar @keys )
1168             {
1169 5         7 my ( $key, $val ) = splice( @keys, 0, 2 );
1170              
1171 5         8 $self->set( $key, $val );
1172             }
1173             }
1174              
1175              
1176              
1177             =head2 mgetnx
1178              
1179             Update the values of multiple-keys, only if all the keys don't already exist.
1180              
1181             =cut
1182              
1183             sub msetnx
1184             {
1185 2     2 0 5 my ( $self, @keys ) = (@_);
1186              
1187 2         1 my %hash;
1188              
1189             # Update so we can test the keys.
1190 2         5 while ( scalar @keys )
1191             {
1192 3         3 my ( $key, $val ) = splice( @keys, 0, 2 );
1193 3         9 $hash{ $key } = $val;
1194             }
1195              
1196             # Does any key already exist? If so we should do nothing.
1197 2         6 foreach my $key ( CORE::keys %hash )
1198             {
1199 3 100       4 return 0 if ( $self->exists($key) );
1200             }
1201              
1202 1         3 foreach my $key ( CORE::keys %hash )
1203             {
1204 2         4 $self->set( $key, $hash{ $key } );
1205             }
1206 1         5 return 1;
1207              
1208             }
1209              
1210             1;
1211              
1212              
1213              
1214             =head1 AUTHOR
1215              
1216             Steve Kemp
1217              
1218             http://www.steve.org.uk/
1219              
1220             =cut
1221              
1222              
1223              
1224             =head1 LICENSE
1225              
1226             Copyright (c) 2016 by Steve Kemp. All rights reserved.
1227              
1228             This module is free software;
1229             you can redistribute it and/or modify it under
1230             the same terms as Perl itself.
1231             The LICENSE file contains the full text of the license.
1232              
1233             =cut