File Coverage

blib/lib/Memcached/Client.pm
Criterion Covered Total %
statement 25 112 22.3
branch 0 32 0.0
condition 0 23 0.0
subroutine 9 20 45.0
pod 8 8 100.0
total 42 195 21.5


line stmt bran cond sub pod time code
1             package Memcached::Client;
2             BEGIN {
3 2     2   1946 $Memcached::Client::VERSION = '2.01';
4             }
5             # ABSTRACT: All-singing, all-dancing Perl client for Memcached
6              
7 2     2   16 use strict;
  2         4  
  2         74  
8 2     2   12 use warnings;
  2         4  
  2         80  
9 2     2   3926 use AnyEvent qw{};
  2         15854  
  2         58  
10 2     2   3592 use AnyEvent::Handle qw{};
  2         90242  
  2         68  
11 2     2   3380 use Memcached::Client::Connection qw{};
  2         8  
  2         54  
12 2     2   16 use Memcached::Client::Log qw{DEBUG LOG};
  2         4  
  2         110  
13 2     2   1830 use Memcached::Client::Request qw{};
  2         6  
  2         86  
14 2     2   4648 use Module::Load qw{load};
  2         2856  
  2         16  
15              
16              
17             sub new {
18 0     0 1   my ($class, @args) = @_;
19 0 0         my %args = 1 == scalar @args ? %{$args[0]} : @args;
  0            
20              
21 0           my $self = bless {}, $class;
22              
23 0           $self->log ("new: %s", \%args) if DEBUG;
24              
25             # Get all of our objects instantiated
26 0   0       $self->{compressor} = $self->__class_loader (Compressor => $args{compressor} || 'Gzip')->new;
27 0   0       $self->{selector} = $self->__class_loader (Selector => $args{selector} || 'Traditional')->new;
28 0   0       $self->{serializer} = $self->__class_loader (Serializer => $args{serializer} || 'Storable')->new;
29 0   0       $self->{protocol} = $self->__class_loader (Protocol => $args{protocol} || 'Text')->new (compressor => $self->{compressor}, serializer => $self->{serializer});
30              
31 0   0       $self->compress_threshold ($args{compress_threshold} || 10000);
32 0   0       $self->hash_namespace ($args{hash_namespace} || 1);
33 0   0       $self->namespace ($args{namespace} || "");
34 0           $self->set_servers ($args{servers});
35 0           $self->set_preprocessor ($args{preprocessor});
36              
37 0           $self->log ("new: done") if DEBUG;
38              
39 0           $self;
40             }
41              
42              
43             sub log {
44 0     0 1   my ($self, $format, @args) = @_;
45 0           LOG ("Client> " . $format, @args);
46             }
47              
48             # This manages class loading for the sub-classes
49             sub __class_loader {
50 0     0     my ($self, $prefix, $class) = @_;
51             # Add our prefixes if the class name isn't called out as absolute
52 0 0         $class = join ('::', 'Memcached::Client', $prefix, $class) if ($class !~ s/^\+//);
53             # Sanitize our class name
54 0           $class =~ s/[^\w:_]//g;
55 0           $self->log ("loading %s", $class) if DEBUG;
56 0           load $class;
57 0           $class;
58             }
59              
60              
61             sub compress_threshold {
62 0     0 1   my ($self, $new) = @_;
63 0           $self->log ("compress threshold: %d", $new) if DEBUG;
64 0           $self->{compressor}->compress_threshold ($new);
65             }
66              
67              
68             sub namespace {
69 0     0 1   my ($self, $new) = @_;
70 0           my $ret = $self->{namespace};
71 0           $self->log ("namespace: %s", $new) if DEBUG;
72 0 0         $self->{namespace} = $new if (defined $new);
73 0           return $ret;
74             }
75              
76              
77             sub hash_namespace {
78 0     0 1   my ($self, $new) = @_;
79 0           my $ret = $self->{hash_namespace};
80 0           $self->log ("hash namespace: %s", $new) if DEBUG;
81 0 0         $self->{hash_namespace} = !!$new if (defined $new);
82 0           return $ret;
83             }
84              
85              
86             sub set_preprocessor {
87 0     0 1   my ($self, $new) = @_;
88 0 0         $self->{preprocessor} = $new if (ref $new eq "CODE");
89 0           return 1;
90             }
91              
92              
93             sub set_servers {
94 0     0 1   my ($self, $servers) = @_;
95              
96             # Give the selector the list of servers first
97 0           $self->{selector}->set_servers ($servers);
98              
99             # Shut down the servers that are no longer part of the list
100 0 0         my $list = {map {(ref $_ ? $_->[0] : $_), {}} @{$servers}};
  0            
  0            
101 0 0         for my $server (keys %{$self->{servers} || {}}) {
  0            
102 0 0         next if (delete $list->{$server});
103 0           $self->log ("disconnecting %s", $server) if DEBUG;
104 0           my $connection = delete $self->{servers}->{$server};
105 0           $connection->disconnect;
106             }
107              
108             # Spawn connection handlers for all the others
109 0           for my $server (sort keys %{$list}) {
  0            
110 0           $self->log ("creating connection for %s", $server) if DEBUG;
111 0   0       $self->{servers}->{$server} ||= Memcached::Client::Connection->new ($server, $self->{protocol});
112             }
113              
114 0           return 1;
115             }
116              
117              
118             sub disconnect {
119 0     0 1   my ($self) = @_;
120              
121 0           $self->log ("disconnecting all") if DEBUG;
122 0           for my $server (keys %{$self->{servers}}) {
  0            
123 0 0         next unless defined $self->{servers}->{$server};
124 0           $self->log ("disconnecting %s", $server) if DEBUG;
125 0           $self->{servers}->{$server}->disconnect;
126             }
127             }
128              
129             # When the object leaves scope, be sure to run C to make
130             # certain that we shut everything down.
131             sub DESTROY {
132 0     0     my $self = shift;
133 0           $self->disconnect;
134             }
135              
136              
137             # This is really where all the action happens---where actual requests
138             # are submitted and handled.
139             #
140             # The routine iterates over the requests its given. It serializes and
141             # compresses any data in the request as necessary. If the request has
142             # a key, then it follows the keyed-submission process, preprocessing
143             # the key as necessary, checking its validity, mapping it to a server,
144             # adding a namespace, and finally submitting it.
145             #
146             # If the request has no key, it is assumed to be a broadcast request,
147             # so we call the ->server method on the request for each of our
148             # servers, to create the appropriate number of requests, and we queue
149             # each of them.
150              
151             sub __submit {
152 0     0     my ($self, @requests) = @_;
153 0           $self->log ("Submitting request(s)") if DEBUG;
154 0           for my $request (@requests) {
155 0           $self->log ("Request is %s", $request) if DEBUG;
156 0 0         if (defined $request->{key}) {
157 0 0         if ($self->{preprocessor}) {
158 0 0         if (ref $request->{key}) {
159 0           $request->{key}->[1] = $self->{preprocessor}->($request->{key}->[1]);
160             } else {
161 0           $request->{key} = $self->{preprocessor}->($request->{key});
162             }
163             }
164 0 0 0       if (ref $request->{key} # Pre-hashed
    0 0        
165             ? ($request->{key}->[0] =~ m/^\d+$/ and # Hash is a decimal #
166             length $request->{key}->[1] > 0 and # Real key has a length
167             length $request->{key}->[1] <= 250 and # Real key is shorter than 250 chars
168             -1 == index $request->{key}->[1], " ") # Key contains no spaces
169             : (length $request->{key} > 0 and # Real key has a length
170             length $request->{key} <= 250 and # Real key is shorter than 250 chars
171             -1 == index $request->{key}, " ") # Key contains no spaces
172             ) {
173 0           $self->log ("Finding server for key %s", $request->{key}) if DEBUG;
174 0 0         my $server = $self->{selector}->get_server ($request->{key}, $self->{hash_namespace} ? $self->{namespace} : "");
175 0 0         $request->{key} = ref $request->{key} ? $request->{key}->[1] : $request->{key};
176 0           $request->{nskey} = $self->{namespace} . $request->{key};
177 0           $self->{servers}->{$server}->enqueue ($request);
178             } else {
179 0           $self->log ("Key is invalid") if DEBUG;
180 0           $request->result;
181             }
182             } else {
183 0           $self->log ("Sending request to all servers") if DEBUG;
184 0           for my $server (keys %{$self->{servers}} ) {
  0            
185 0           $self->log ("Queueing for %s", $server) if DEBUG;
186 0           $self->{servers}->{$server}->enqueue ($request->server ($server));
187             }
188             }
189             }
190             }
191              
192              
193             1;
194              
195             __END__