File Coverage

lib/Bloomd/Client.pm
Criterion Covered Total %
statement 68 100 68.0
branch 12 34 35.2
condition 2 5 40.0
subroutine 17 26 65.3
pod 12 12 100.0
total 111 177 62.7


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.26';
12             }
13              
14             # ABSTRACT: Perl client to the bloomd server
15              
16 1     1   412238 use feature ':5.10';
  1         2  
  1         110  
17 1     1   901 use Moo;
  1         23545  
  1         8  
18 1     1   3994 use List::MoreUtils qw(any mesh);
  1         1924  
  1         103  
19 1     1   9 use Carp;
  1         3  
  1         235  
20 1     1   6 use Socket qw(:crlf);
  1         2  
  1         235  
21 1     1   7 use IO::Socket::INET;
  1         2  
  1         10  
22 1     1   810 use Errno qw(:POSIX);
  1         2  
  1         526  
23 1     1   7 use POSIX qw(strerror);
  1         1  
  1         9  
24 1     1   57 use Config;
  1         20  
  1         45  
25 1     1   1531 use Types::Standard -types;
  1         791704  
  1         13  
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              
41             sub _build__socket {
42 2     2   719 my ($self) = @_;
43 2 50       116 my $socket = IO::Socket::INET->new(
44             Proto => $self->protocol,
45             PeerHost => $self->host,
46             PeerPort => $self->port,
47             Timeout => $self->timeout,
48             ) or die "Can't connect to server: $!";
49              
50 2 50       138490 $self->timeout
51             or return $socket;
52              
53 2 50 33     134 $Config{osname} eq 'netbsd' || $Config{osname} eq 'solaris'
54             and croak "the timeout option is not yet supported on NetBSD or Solaris";
55              
56 2         17 my $seconds = int( $self->timeout );
57 2         218 my $useconds = int( 1_000_000 * ( $self->timeout - $seconds ) );
58 2         23 my $timeout = pack( 'l!l!', $seconds, $useconds );
59              
60 2 50       31 $socket->setsockopt( SOL_SOCKET, SO_RCVTIMEO, $timeout )
61             or croak "setsockopt(SO_RCVTIMEO): $!";
62              
63 2 50       98 $socket->setsockopt( SOL_SOCKET, SO_SNDTIMEO, $timeout )
64             or croak "setsockopt(SO_SNDTIMEO): $!";
65              
66 2         30 return $socket;
67              
68             }
69              
70              
71             sub disconnect {
72 1     1 1 13 my ($self) = @_;
73 1 50       68 $self->_has_socket
74             and $self->_socket->close;
75 1         169 $self->_clear_socket;
76             }
77              
78              
79             sub create {
80 0     0 1 0 my ($self, $name, $capacity, $prob, $in_memory) = @_;
81 0 0       0 my $args =
    0          
    0          
82             ( $capacity ? "capacity=$capacity" : '' )
83             . ( $prob ? " prob=$prob" : '' )
84             . ( $in_memory ? " in_memory=$in_memory" : '' );
85 0         0 $self->_execute("create $name $args" ) eq 'Done';
86             }
87              
88              
89             sub list {
90 1     1 1 2991 my ($self, $prefix) = @_;
91 1   50     62 $prefix //= '';
92 1         44 my @keys = qw(name prob size capacity items);
93             [
94 0         0 map {
95 1         15 my @values = split / /;
96 0         0 +{ mesh @keys, @values };
97             }
98             $self->_execute("list $prefix" )
99             ];
100             }
101              
102              
103             sub drop {
104 0     0 1 0 my ($self, $name) = @_;
105 0         0 $self->_execute("drop $name") eq 'Done';
106             }
107              
108              
109              
110             sub close {
111 0     0 1 0 my ($self, $name) = @_;
112 0         0 $self->_execute("close $name") eq 'Done';
113             }
114              
115              
116             sub clear {
117 0     0 1 0 my ($self, $name) = @_;
118 0         0 $self->_execute("clear $name") eq 'Done';
119             }
120              
121              
122             sub check {
123 0     0 1 0 my ($self, $name, $key) = @_;
124 0         0 $self->_execute("c $name $key") eq 'Yes';
125             }
126              
127              
128             sub multi {
129 0     0 1 0 my ($self, $name, @keys) = @_;
130             @keys
131 0 0       0 or return {};
132 0         0 my @values = map { $_ eq 'Yes' } split / /, $self->_execute("m $name @keys");
  0         0  
133 0         0 +{mesh @keys, @values };
134             }
135              
136              
137             sub set {
138 0     0 1 0 my ($self, $name, $key) = @_;
139 0         0 $self->_execute("s $name $key") eq 'Yes';
140             }
141              
142              
143             sub bulk {
144 0     0 1 0 my ($self, $name, @keys) = @_;
145             @keys
146 0 0       0 or return;
147 0         0 $self->_execute("b $name @keys");
148 0         0 return;
149             }
150              
151              
152             sub info {
153 1     1 1 2003858 my ($self, $name) = @_;
154 1         14 +{ map { split / / } $self->_execute("info $name") };
  1         45  
155             }
156              
157              
158             sub flush {
159 0     0 1 0 my ($self, $name) = @_;
160 0         0 $self->_execute("info $name") eq "Done";
161             }
162              
163             sub _execute {
164 2     2   16 my ($self, $command) = @_;
165 2         148 my $socket = $self->_socket;
166              
167 2         14 local $\;
168 2 50       73 $socket->print($command . $CRLF)
169             or croak "couldn't write to socket";
170              
171 2         430 my $line = $self->_check_line($socket->getline);
172 1 50       8 $line =~ /^Client Error:/
173             and croak "$line: $command";
174              
175 1 50       15 $line eq 'START'
176             or return $line;
177              
178 0         0 my @lines;
179 0         0 while (1) {
180 0         0 $line = $self->_check_line($socket->getline);
181 0 0       0 $line eq 'END'
182             and last;
183 0         0 push @lines, $line;
184             }
185              
186 0         0 return @lines;
187             }
188              
189             sub _check_line {
190 2     2   510613 my ($self, $line) = @_;
191 2 100       21 if (!defined $line) {
192 1         31 my $e = $!;
193 1 50   1   69 if (any { $_ } ( $!{EWOULDBLOCK}, $!{EAGAIN}, $!{ETIMEDOUT} )) {
  1         14  
194 1         103 $e = strerror(ETIMEDOUT);
195 1         27 $self->disconnect;
196             }
197 1         635 undef $!;
198 1         69 croak $e;
199             }
200 1         125 $line =~ s/$CR?$LF?$//;
201 1         6 return $line;
202             }
203              
204             1;
205              
206             __END__