File Coverage

lib/Bloomd/Client.pm
Criterion Covered Total %
statement 69 103 66.9
branch 13 36 36.1
condition 2 5 40.0
subroutine 17 26 65.3
pod 12 12 100.0
total 113 182 62.0


line stmt bran cond sub pod time code
1             #
2             # This file is part of Bloomd-Client
3             #
4             # This software is copyright (c) 2013 by Damien "dams" Krotkine.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9             package Bloomd::Client;
10             {
11             $Bloomd::Client::VERSION = '0.27';
12             }
13              
14             # ABSTRACT: Perl client to the bloomd server
15              
16 1     1   89940 use feature ':5.10';
  1         1  
  1         79  
17 1     1   494 use Moo;
  1         14009  
  1         5  
18 1     1   2601 use List::MoreUtils qw(any mesh);
  1         913  
  1         81  
19 1     1   6 use Carp;
  1         1  
  1         48  
20 1     1   5 use Socket qw(:crlf);
  1         1  
  1         228  
21 1     1   5 use IO::Socket::INET;
  1         2  
  1         8  
22 1     1   560 use Errno qw(:POSIX);
  1         2  
  1         418  
23 1     1   5 use POSIX qw(strerror);
  1         1  
  1         8  
24 1     1   52 use Config;
  1         12  
  1         41  
25 1     1   738 use Types::Standard -types;
  1         64999  
  1         19  
26              
27              
28             has protocol => ( is => 'ro', default => sub {'tcp'} );
29              
30              
31             has host => ( is => 'ro', isa => StrMatch[qr/.+/], default => sub {'127.0.0.1'} );
32              
33              
34             has port => ( is => 'ro', isa => Int, default => sub {8673} );
35             has _socket => ( is => 'lazy', predicate => 1, clearer => 1 );
36              
37              
38             has timeout => ( is => 'ro', , default => sub { 10 } );
39              
40             has '_pid' => (is => 'ro', lazy => 1, clearer => 1, default => sub { $$ });
41              
42              
43             sub _build__socket {
44 2     2   537 my ($self) = @_;
45 2 50       60 my $socket = IO::Socket::INET->new(
46             Proto => $self->protocol,
47             PeerHost => $self->host,
48             PeerPort => $self->port,
49             Timeout => $self->timeout,
50             ) or die "Can't connect to server: $!";
51              
52 2 50       4652 $self->timeout
53             or return $socket;
54              
55 2 50 33     114 $Config{osname} eq 'netbsd' || $Config{osname} eq 'solaris'
56             and croak "the timeout option is not yet supported on NetBSD or Solaris";
57              
58 2         14 my $seconds = int( $self->timeout );
59 2         21 my $useconds = int( 1_000_000 * ( $self->timeout - $seconds ) );
60 2         17 my $timeout = pack( 'l!l!', $seconds, $useconds );
61              
62 2 50       25 $socket->setsockopt( SOL_SOCKET, SO_RCVTIMEO, $timeout )
63             or croak "setsockopt(SO_RCVTIMEO): $!";
64              
65 2 50       97 $socket->setsockopt( SOL_SOCKET, SO_SNDTIMEO, $timeout )
66             or croak "setsockopt(SO_SNDTIMEO): $!";
67              
68 2         29 return $socket;
69              
70             }
71              
72              
73             sub disconnect {
74 1     1 1 3 my ($self) = @_;
75 1 50       51 $self->_has_socket
76             and $self->_socket->close;
77 1         138 $self->_clear_socket;
78             }
79              
80              
81             sub create {
82 0     0 1 0 my ($self, $name, $capacity, $prob, $in_memory) = @_;
83 0 0       0 my $args =
    0          
    0          
84             ( $capacity ? "capacity=$capacity" : '' )
85             . ( $prob ? " prob=$prob" : '' )
86             . ( $in_memory ? " in_memory=$in_memory" : '' );
87 0         0 $self->_execute("create $name $args" ) eq 'Done';
88             }
89              
90              
91             sub list {
92 1     1 1 3316 my ($self, $prefix) = @_;
93 1   50     34 $prefix //= '';
94 1         37 my @keys = qw(name prob size capacity items);
95             [
96 0         0 map {
97 1         12 my @values = split / /;
98 0         0 +{ mesh @keys, @values };
99             }
100             $self->_execute("list $prefix" )
101             ];
102             }
103              
104              
105             sub drop {
106 0     0 1 0 my ($self, $name) = @_;
107 0         0 $self->_execute("drop $name") eq 'Done';
108             }
109              
110              
111              
112             sub close {
113 0     0 1 0 my ($self, $name) = @_;
114 0         0 $self->_execute("close $name") eq 'Done';
115             }
116              
117              
118             sub clear {
119 0     0 1 0 my ($self, $name) = @_;
120 0         0 $self->_execute("clear $name") eq 'Done';
121             }
122              
123              
124             sub check {
125 0     0 1 0 my ($self, $name, $key) = @_;
126 0         0 $self->_execute("c $name $key") eq 'Yes';
127             }
128              
129              
130             sub multi {
131 0     0 1 0 my ($self, $name, @keys) = @_;
132             @keys
133 0 0       0 or return {};
134 0         0 my @values = map { $_ eq 'Yes' } split / /, $self->_execute("m $name @keys");
  0         0  
135 0         0 +{mesh @keys, @values };
136             }
137              
138              
139             sub set {
140 0     0 1 0 my ($self, $name, $key) = @_;
141 0         0 $self->_execute("s $name $key") eq 'Yes';
142             }
143              
144              
145             sub bulk {
146 0     0 1 0 my ($self, $name, @keys) = @_;
147             @keys
148 0 0       0 or return;
149 0         0 $self->_execute("b $name @keys");
150 0         0 return;
151             }
152              
153              
154             sub info {
155 1     1 1 2003071 my ($self, $name) = @_;
156 1         11 +{ map { split / / } $self->_execute("info $name") };
  1         35  
157             }
158              
159              
160             sub flush {
161 0     0 1 0 my ($self, $name) = @_;
162 0         0 $self->_execute("info $name") eq "Done";
163             }
164              
165             sub _execute {
166 2     2   9 my ($self, $command) = @_;
167 2 50       95 if ($self->_pid ne $$) {
168 0         0 $self->_clear_socket;
169 0         0 $self->_clear_pid;
170             }
171 2         58 my $socket = $self->_socket;
172              
173 2         11 local $\;
174 2 50       37 $socket->print($command . $CRLF)
175             or croak "couldn't write to socket";
176              
177 2         260 my $line = $self->_check_line($socket->getline);
178 1 50       7 $line =~ /^Client Error:/
179             and croak "$line: $command";
180              
181 1 50       10 $line eq 'START'
182             or return $line;
183              
184 0         0 my @lines;
185 0         0 while (1) {
186 0         0 $line = $self->_check_line($socket->getline);
187 0 0       0 $line eq 'END'
188             and last;
189 0         0 push @lines, $line;
190             }
191              
192 0         0 return @lines;
193             }
194              
195             sub _check_line {
196 2     2   497700 my ($self, $line) = @_;
197 2 100       14 if (!defined $line) {
198 1         17 my $e = $!;
199 1 50   1   29 if (any { $_ } ( $!{EWOULDBLOCK}, $!{EAGAIN}, $!{ETIMEDOUT} )) {
  1         10  
200 1         75 $e = strerror(ETIMEDOUT);
201 1         27 $self->disconnect;
202             }
203 1         565 undef $!;
204 1         78 croak $e;
205             }
206 1         32 $line =~ s/$CR?$LF?$//;
207 1         5 return $line;
208             }
209              
210             1;
211              
212             __END__