File Coverage

blib/lib/Algorithm/SpatialIndex/Storage/Redis.pm
Criterion Covered Total %
statement 30 95 31.5
branch 0 26 0.0
condition 0 9 0.0
subroutine 10 19 52.6
pod 9 9 100.0
total 49 158 31.0


line stmt bran cond sub pod time code
1             package Algorithm::SpatialIndex::Storage::Redis;
2 2     2   21134 use 5.008001;
  2         7  
  2         93  
3 2     2   14 use strict;
  2         6  
  2         76  
4 2     2   12 use warnings;
  2         14  
  2         85  
5 2     2   12 use Carp qw(confess);
  2         4  
  2         199  
6              
7             our $VERSION = '0.01';
8              
9 2     2   13 use Scalar::Util qw(blessed);
  2         5  
  2         151  
10 2     2   2380 use Redis;
  2         196270  
  2         78  
11              
12 2     2   1303 use parent 'Algorithm::SpatialIndex::Storage';
  2         628  
  2         17  
13 2     2   11354 use Sereal::Encoder;
  2         6  
  2         89  
14 2     2   12 use Sereal::Decoder;
  2         4  
  2         98  
15              
16             use Class::XSAccessor {
17 2         26 getters => {
18             _conn => 'redisconn',
19             _prefix => 'prefix',
20             _encoder => 'encoder',
21             _decoder => 'decoder',
22             },
23 2     2   12 };
  2         4  
24              
25             sub init {
26 0     0 1   my $self = shift;
27 0           my $opt = $self->{opt}{redis};
28              
29             # Determine key prefix
30 0           my $prefix = $opt->{prefix};
31 0 0         confess("Need Redis key name prefix for Redis storage backend")
32             if not defined $prefix;
33 0           $self->{prefix} = $prefix;
34              
35             # Setup (de)serializers
36 0           my $enc = $opt->{encoder};
37 0 0         if (blessed($enc)) {
38 0           $self->{encoder} = $enc;
39             }
40             else {
41 0 0         $self->{encoder} = Sereal::Encoder->new(ref($enc) eq 'HASH' ? $enc : ());
42             }
43 0           my $dec = $opt->{decoder};
44 0 0         if (blessed($dec)) {
45 0           $self->{decoder} = $dec;
46             }
47             else {
48 0 0         $self->{decoder} = Sereal::Decoder->new(ref($dec) eq 'HASH' ? $dec : ());
49             }
50              
51             # Connect to Redis
52 0           my $conn = $opt->{conn};
53 0 0         if (blessed($conn)) {
54 0           $self->{redisconn} = $conn;
55             }
56             else {
57 0           $self->{redisconn} = Redis->new(%$conn);
58             }
59              
60             # Assert state of data in Redis
61 0           $conn = $self->_conn;
62 0           my $type;
63 0           $type = $conn->type($prefix . "_options");
64 0 0 0       if ($type eq "hash" || $type eq "none") {
65             # fine
66             } else {
67 0           confess("Key for option storage in Redis (${prefix}_options) is of incompatible type");
68             }
69              
70 0           $type = $conn->type($prefix . "_buckets");
71 0 0 0       if ($type eq "hash" || $type eq "none") {
72             # fine
73             } else {
74 0           confess("Key for bucket storage in Redis (${prefix}_buckets) is of incompatible type");
75             }
76              
77 0           $type = $conn->type($prefix . "_nodes");
78 0 0 0       if ($type eq "hash" || $type eq "none") {
79             # fine
80             } else {
81 0           confess("Key for node storage in Redis (${prefix}_nodes) is of incompatible type");
82             }
83             }
84              
85             sub get_option {
86 0     0 1   my $self = shift;
87 0           return $self->_conn->hget($self->_prefix . "_options", shift);
88             }
89              
90             sub set_option {
91 0     0 1   my ($self, $key, $value) = @_;
92 0           $self->_conn->hset($self->_prefix . "_options", $key, $value);
93 0           return 1;
94             }
95              
96             sub fetch_node {
97 0     0 1   my ($self, $index) = @_;
98              
99 0           my $node = $self->_conn->hget($self->_prefix . "_nodes", $index);
100 0 0         return() if not defined $node;
101 0           return $self->_decoder->decode($node);
102             }
103              
104             sub store_node {
105 0     0 1   my ($self, $node) = @_;
106              
107 0           my $id = $node->id;
108 0           my $conn = $self->_conn;
109 0           my $key = $self->_prefix . "_nodes";
110 0 0         if (not defined $id) {
111 0           $id = $conn->hincrby($key, "top_id", 1);
112 0           $node->id($id);
113             }
114              
115 0           my $str = $self->_encoder->encode($node);
116 0           $conn->hset($key, $id, $str);
117              
118 0           return $id;
119             }
120              
121             sub store_bucket {
122 0     0 1   my ($self, $bucket) = @_;
123              
124 0           my $str = $self->_encoder->encode($bucket);
125 0           $self->_conn->hset($self->_prefix . "_buckets", $bucket->node_id, $str);
126 0           return 1;
127             }
128              
129             sub fetch_bucket {
130 0     0 1   my ($self, $node_id) = @_;
131              
132 0           my $str = $self->_conn->hget($self->_prefix . "_buckets", $node_id);
133 0 0         return() if not defined $str;
134 0           return $self->_decoder->decode($str);
135             }
136              
137             sub delete_bucket {
138 0     0 1   my ($self, $node_id) = @_;
139              
140 0 0         $node_id = $node_id->node_id if ref($node_id);
141 0           $self->_conn->hdel($self->_prefix . "_buckets", $node_id);
142              
143 0           return();
144             }
145              
146             sub remove_all {
147 0     0 1   my $self = shift;
148 0           my $conn = $self->_conn;
149 0           my $prefix = $self->_prefix;
150 0           $conn->del($prefix . "_options");
151 0           $conn->del($prefix . "_nodes");
152 0           $conn->del($prefix . "_buckets");
153             }
154              
155              
156             1;
157             __END__