File Coverage

blib/lib/Cache/Memcached/GetParserXS.pm
Criterion Covered Total %
statement 53 81 65.4
branch 4 20 20.0
condition 1 9 11.1
subroutine 11 14 78.5
pod 0 4 0.0
total 69 128 53.9


line stmt bran cond sub pod time code
1             package Cache::Memcached::GetParserXS;
2              
3             =head1 NAME
4              
5             Cache::Memcached::GetParserXS - GetParser implementation in XS for use with Cache::Memcached
6              
7             =head1 SYNOPSIS
8              
9             use Cache::Memcached::GetParserXS;
10             use Cache::Memcached;
11              
12             # Everything else is the same as Cache::Memcached has documented it.
13             # Seriously.
14              
15             =head1 DESCRIPTION
16              
17             This module implements the same function as Cache::Memcached::GetParser, except it's written
18             in C/XS. Initial benchmarks have shown it to be possibly twice as fast as the original perl
19             version.
20              
21             =cut
22              
23 1     1   22832 use 5.006;
  1         3  
  1         45  
24 1     1   6 use strict;
  1         2  
  1         35  
25 1     1   5 use warnings;
  1         5  
  1         38  
26              
27             # We don't want to inherit from this, because our constants may be different.
28             # use base 'Cache::Memcached::GetParser';
29              
30 1     1   5 use Carp;
  1         2  
  1         105  
31 1     1   871 use Errno qw( EINPROGRESS EWOULDBLOCK EISCONN );
  1         1258  
  1         112  
32 1     1   1013 use Cache::Memcached 1.21;
  1         193034  
  1         884  
33              
34             our $VERSION = '0.01';
35              
36             require XSLoader;
37             XSLoader::load('Cache::Memcached::GetParserXS', $VERSION);
38              
39             sub DEST;
40             sub NSLEN;
41             sub ON_ITEM;
42             sub BUF;
43             sub STATE;
44             sub OFFSET;
45             sub FLAGS;
46             sub KEY;
47             sub FINISHED;
48              
49             sub new {
50 2     2 0 2931 my ($class, $dest, $nslen, $on_item) = @_;
51              
52 2   33     22 my $self = bless [], (ref $class || $class);
53              
54 2         17 $self->[DEST] = $dest;
55 2         11 $self->[NSLEN] = $nslen;
56 2         10 $self->[ON_ITEM] = $on_item;
57 2         268 $self->[BUF] = '';
58 2         13 $self->[STATE] = 0;
59 2         13 $self->[OFFSET] = 0;
60 2         11 $self->[FLAGS] = undef;
61 2         9 $self->[KEY] = undef;
62 2         11 $self->[FINISHED] = {};
63              
64 2         83 return $self
65             }
66              
67             sub current_key {
68 0     0 0 0 return $_[0][KEY];
69             }
70              
71             sub t_parse_buf {
72 4     4 0 3152 my ($self, $buf) = @_;
73             # force buf into \r\n format
74 4         19 $buf =~ s/\n/\r\n/g;
75 4         8 $buf =~ s/\r\r/\r/g;
76              
77 4         10 $self->[BUF] .= $buf;
78 4         10 $self->[OFFSET] += length $buf;
79 4         38 my $rv = $self->parse_buffer;
80 4 100       14 if ($rv > 0) {
81 2         13 $self->[ON_ITEM]->($self->[FINISHED]);
82 2         9 $self->[ON_ITEM] = undef;
83             }
84 4         15 return $rv;
85             }
86              
87             # returns 1 on success, -1 on failure, and 0 if still working.
88             sub parse_from_sock {
89 0     0 0 0 my ($self, $sock) = @_;
90 0         0 my $res;
91              
92             # where are we reading into?
93 0 0       0 if ($self->[STATE]) { # reading value into $ret
94 0         0 my $ret = $self->[DEST];
95 0         0 $res = sysread($sock, $ret->{$self->[KEY]},
96             $self->[STATE] - $self->[OFFSET],
97             $self->[OFFSET]);
98              
99 0 0 0     0 return 0
100             if !defined($res) and $!==EWOULDBLOCK;
101              
102 0 0       0 if ($res == 0) { # catches 0=conn closed or undef=error
103 0         0 $self->[ON_ITEM] = undef;
104 0         0 return -1;
105             }
106              
107 0         0 $self->[OFFSET] += $res;
108 0 0       0 if ($self->[OFFSET] == $self->[STATE]) { # finished reading
109 0         0 $self->[OFFSET] = 0;
110 0         0 $self->[STATE] = 0;
111             # wait for another VALUE line or END...
112             }
113 0         0 return 0; # still working, haven't got to end yet
114             }
115              
116             # we're reading a single line.
117             # first, read whatever's there, but be satisfied with 2048 bytes
118 0         0 $res = sysread($sock, $self->[BUF],
119             128*1024, $self->[OFFSET]);
120 0 0 0     0 return 0
121             if !defined($res) and $!==EWOULDBLOCK;
122 0 0       0 if ($res == 0) {
123 0         0 $self->[ON_ITEM] = undef;
124 0         0 return -1;
125             }
126              
127 0         0 $self->[OFFSET] += $res;
128              
129 0         0 my $answer = $self->parse_buffer;
130              
131 0 0       0 if ($answer > 0) {
132 0         0 $self->[ON_ITEM]->($self->[FINISHED]);
133 0         0 $self->[ON_ITEM] = undef;
134             }
135              
136 0         0 return $answer;
137             }
138              
139 0     0   0 sub DESTROY {} # Empty definition, so AUTOLOAD doesn't catch it
140              
141             # sub parse_buffer is defined in XS
142              
143             sub AUTOLOAD {
144             # This AUTOLOAD is used to 'autoload' constants from the constant()
145             # XS function.
146              
147 9     9   13 my $constname;
148 9         9 our $AUTOLOAD;
149 9         40 ($constname = $AUTOLOAD) =~ s/.*:://;
150 9 50       26 croak "&Cache::Memcached::GetParserXS::constant not defined" if $constname eq 'constant';
151 9         28 my ($error, $val) = constant($constname);
152 9 50       26 if ($error) { croak $error; }
  0         0  
153             {
154 1     1   46 no strict 'refs';
  1         1  
  1         82  
  9         11  
155             # Fixed between 5.005_53 and 5.005_61
156             #XXX if ($] >= 5.00561) {
157             #XXX *$AUTOLOAD = sub () { $val };
158             #XXX }
159             #XXX else {
160 9     32   50 *$AUTOLOAD = sub { $val };
  32         70  
161             #XXX }
162             }
163 9         106 goto &$AUTOLOAD;
164             }
165              
166             1;
167             __END__