File Coverage

Fast.xs
Criterion Covered Total %
statement 218 744 29.3
branch 160 1190 13.4
condition n/a
subroutine n/a
pod n/a
total 378 1934 19.5


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2007-2010 Tomash Brechko. All rights reserved.
3              
4             This library is free software; you can redistribute it and/or modify
5             it under the same terms as Perl itself, either Perl version 5.8.8
6             or, at your option, any later version of Perl 5 you may have
7             available.
8             */
9              
10             #define PERL_NO_GET_CONTEXT
11             #include "EXTERN.h"
12             #include "perl.h"
13             #include "XSUB.h"
14              
15             #include "ppport.h"
16              
17             #include "src/client.h"
18             #include
19             #include
20              
21              
22             #define F_STORABLE 0x1
23             #define F_COMPRESS 0x2
24             #define F_UTF8 0x4
25              
26              
27             struct xs_state
28             {
29             struct client *c;
30             AV *servers;
31             int compress_threshold;
32             double compress_ratio;
33             SV *compress_method;
34             SV *decompress_method;
35             SV *serialize_method;
36             SV *deserialize_method;
37             int utf8;
38             size_t max_size;
39             };
40              
41             typedef struct xs_state Cache_Memcached_Fast;
42              
43             static inline
44             SV**
45 62           safe_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval)
46             {
47 62           SV ** v = av_fetch(av, key, lval);
48 62 50         if ( !v || !SvOK(*v) )
    50          
    0          
    0          
49 0           croak("undefined value passed to av_fetch");
50              
51 62           return v;
52             }
53              
54             static
55             void
56 31           add_server(pTHX_ Cache_Memcached_Fast *memd, SV *addr_sv,
57             double weight, int noreply)
58             {
59 31           struct client *c = memd->c;
60             static const int delim = ':';
61             const char *host, *port;
62             size_t host_len, port_len;
63             STRLEN len;
64             int res;
65              
66 31           av_push(memd->servers, newSVsv(addr_sv));
67              
68 31 50         if (weight <= 0.0)
69 0           croak("Server weight should be positive");
70              
71 31 50         host = SvPV(addr_sv, len);
72             /*
73             NOTE: here we relay on the fact that host is zero-terminated.
74             */
75 31           port = strrchr(host, delim);
76 31 50         if (port)
77             {
78 31           host_len = port - host;
79 31           ++port;
80 31           port_len = len - host_len - 1;
81 31           res = client_add_server(c, host, host_len, port, port_len,
82             weight, noreply);
83             }
84             else
85             {
86 0           res = client_add_server(c, host, len, NULL, 0, weight, noreply);
87             }
88 31 50         if (res != MEMCACHED_SUCCESS)
89 0           croak("Not enough memory");
90 31           }
91              
92              
93             static
94             void
95 31           parse_server(pTHX_ Cache_Memcached_Fast *memd, SV *sv)
96             {
97 31 100         if (! SvROK(sv))
98             {
99 16           add_server(aTHX_ memd, sv, 1.0, 0);
100             }
101             else
102             {
103 15           switch (SvTYPE(SvRV(sv)))
104             {
105             case SVt_PVHV:
106             {
107 15           HV *hv = (HV *) SvRV(sv);
108             SV **addr_sv, **ps;
109 15           double weight = 1.0;
110 15           int noreply = 0;
111              
112 15           addr_sv = hv_fetch(hv, "address", 7, 0);
113 15 50         if (addr_sv)
114 15 50         SvGETMAGIC(*addr_sv);
    0          
115             else
116 0           croak("server should have { address => $addr }");
117 15           ps = hv_fetch(hv, "weight", 6, 0);
118 15 50         if (ps)
119 15 50         SvGETMAGIC(*ps);
    0          
120 15 50         if (ps && SvOK(*ps))
    50          
    0          
    0          
121 15 50         weight = SvNV(*ps);
122 15           ps = hv_fetch(hv, "noreply", 7, 0);
123 15 50         if (ps)
124 0 0         SvGETMAGIC(*ps);
    0          
125 15 50         if (ps && SvOK(*ps))
    0          
    0          
    0          
126 0 0         noreply = SvTRUE(*ps);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
127 15           add_server(aTHX_ memd, *addr_sv, weight, noreply);
128             }
129 15           break;
130              
131             case SVt_PVAV:
132             {
133 0           AV *av = (AV *) SvRV(sv);
134             SV **addr_sv, **weight_sv;
135 0           double weight = 1.0;
136              
137 0           addr_sv = av_fetch(av, 0, 0);
138 0 0         if (addr_sv)
139 0 0         SvGETMAGIC(*addr_sv);
    0          
140             else
141 0           croak("server should be [$addr, $weight]");
142 0           weight_sv = av_fetch(av, 1, 0);
143 0 0         if (weight_sv)
144 0 0         weight = SvNV(*weight_sv);
145 0           add_server(aTHX_ memd, *addr_sv, weight, 0);
146             }
147 0           break;
148              
149             default:
150 0           croak("Not a hash or array reference");
151             break;
152             }
153             }
154 31           }
155              
156              
157             static
158             void
159 16           parse_serialize(pTHX_ Cache_Memcached_Fast *memd, HV *conf)
160             {
161             SV **ps;
162              
163 16           memd->utf8 = 0;
164 16           memd->serialize_method = NULL;
165 16           memd->deserialize_method = NULL;
166              
167 16           ps = hv_fetch(conf, "utf8", 4, 0);
168 16 50         if (ps)
169 16 50         SvGETMAGIC(*ps);
    0          
170 16 50         if (ps && SvOK(*ps))
    50          
    0          
    0          
171 16 50         memd->utf8 = SvTRUE(*ps);
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
172              
173 16           ps = hv_fetch(conf, "serialize_methods", 17, 0);
174 16 50         if (ps)
175 16 50         SvGETMAGIC(*ps);
    0          
176 16 50         if (ps && SvOK(*ps))
    50          
    0          
    0          
177             {
178 16           AV *av = (AV *) SvRV(*ps);
179 16           memd->serialize_method = newSVsv(*safe_av_fetch(aTHX_ av, 0, 0));
180 16           memd->deserialize_method = newSVsv(*safe_av_fetch(aTHX_ av, 1, 0));
181             }
182              
183 16 50         if (! memd->serialize_method)
184 0           croak("Serialize method is not specified");
185              
186 16 50         if (! memd->deserialize_method)
187 0           croak("Deserialize method is not specified");
188 16           }
189              
190              
191             static
192             void
193 16           parse_compress(pTHX_ Cache_Memcached_Fast *memd, HV *conf)
194             {
195             SV **ps;
196              
197 16           memd->compress_threshold = -1;
198 16           memd->compress_ratio = 0.8;
199 16           memd->compress_method = NULL;
200 16           memd->decompress_method = NULL;
201              
202 16           ps = hv_fetch(conf, "compress_threshold", 18, 0);
203 16 100         if (ps)
204 15 50         SvGETMAGIC(*ps);
    0          
205 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
206 15 50         memd->compress_threshold = SvIV(*ps);
207              
208 16           ps = hv_fetch(conf, "compress_ratio", 14, 0);
209 16 50         if (ps)
210 0 0         SvGETMAGIC(*ps);
    0          
211 16 50         if (ps && SvOK(*ps))
    0          
    0          
    0          
212 0 0         memd->compress_ratio = SvNV(*ps);
213              
214 16           ps = hv_fetch(conf, "compress_methods", 16, 0);
215 16 100         if (ps)
216 15 50         SvGETMAGIC(*ps);
    0          
217 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
218 15           {
219 15           AV *av = (AV *) SvRV(*ps);
220 15           memd->compress_method = newSVsv(*safe_av_fetch(aTHX_ av, 0, 0));
221 15           memd->decompress_method = newSVsv(*safe_av_fetch(aTHX_ av, 1, 0));
222             }
223 1 50         else if (memd->compress_threshold > 0)
224             {
225 0           warn("Compression module was not found, disabling compression");
226 0           memd->compress_threshold = -1;
227             }
228 16           }
229              
230              
231             static
232             void
233 16           parse_config(pTHX_ Cache_Memcached_Fast *memd, HV *conf)
234             {
235 16           struct client *c = memd->c;
236             SV **ps;
237              
238 16           memd->servers = newAV();
239              
240 16           ps = hv_fetch(conf, "ketama_points", 13, 0);
241 16 100         if (ps)
242 15 50         SvGETMAGIC(*ps);
    0          
243 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
244             {
245 15 50         int res = client_set_ketama_points(c, SvIV(*ps));
246 15 50         if (res != MEMCACHED_SUCCESS)
247 0           croak("client_set_ketama() failed");
248             }
249              
250 16           ps = hv_fetch(conf, "hash_namespace", 14, 0);
251 16 50         if (ps)
252 0 0         SvGETMAGIC(*ps);
    0          
253 16 50         if (ps && SvOK(*ps))
    0          
    0          
    0          
254 0 0         client_set_hash_namespace(c, SvTRUE(*ps));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
255              
256 16           ps = hv_fetch(conf, "servers", 7, 0);
257 16 50         if (ps)
258 16 50         SvGETMAGIC(*ps);
    0          
259 16 50         if (ps && SvOK(*ps))
    50          
    0          
    0          
260             {
261             AV *a;
262             int max_index, i;
263              
264 16 50         if (! SvROK(*ps) || SvTYPE(SvRV(*ps)) != SVt_PVAV)
    50          
265 0           croak("Not an array reference");
266 16           a = (AV *) SvRV(*ps);
267 16           max_index = av_len(a);
268 47 100         for (i = 0; i <= max_index; ++i)
269             {
270 31           ps = av_fetch(a, i, 0);
271 31 50         if (! ps)
272 0           continue;
273              
274 31 50         SvGETMAGIC(*ps);
    0          
275 31           parse_server(aTHX_ memd, *ps);
276             }
277             }
278              
279 16           ps = hv_fetch(conf, "namespace", 9, 0);
280 16 50         if (ps)
281 16 50         SvGETMAGIC(*ps);
    0          
282 16 50         if (ps && SvOK(*ps))
    50          
    0          
    0          
283             {
284             const char *ns;
285             STRLEN len;
286 16 50         ns = SvPV(*ps, len);
287 16 50         if (client_set_prefix(c, ns, len) != MEMCACHED_SUCCESS)
288 16           croak("Not enough memory");
289             }
290              
291 16           ps = hv_fetch(conf, "connect_timeout", 15, 0);
292 16 100         if (ps)
293 15 50         SvGETMAGIC(*ps);
    0          
294 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
295 15 50         client_set_connect_timeout(c, SvNV(*ps) * 1000.0);
296              
297 16           ps = hv_fetch(conf, "io_timeout", 10, 0);
298 16 100         if (ps)
299 15 50         SvGETMAGIC(*ps);
    0          
300 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
301 15 50         client_set_io_timeout(c, SvNV(*ps) * 1000.0);
302              
303             /* For compatibility with Cache::Memcached. */
304 16           ps = hv_fetch(conf, "select_timeout", 14, 0);
305 16 50         if (ps)
306 0 0         SvGETMAGIC(*ps);
    0          
307 16 50         if (ps && SvOK(*ps))
    0          
    0          
    0          
308 0 0         client_set_io_timeout(c, SvNV(*ps) * 1000.0);
309              
310 16           ps = hv_fetch(conf, "max_failures", 12, 0);
311 16 100         if (ps)
312 15 50         SvGETMAGIC(*ps);
    0          
313 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
314 15 50         client_set_max_failures(c, SvIV(*ps));
315              
316 16           ps = hv_fetch(conf, "failure_timeout", 15, 0);
317 16 100         if (ps)
318 15 50         SvGETMAGIC(*ps);
    0          
319 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
320 15 50         client_set_failure_timeout(c, SvIV(*ps));
321              
322 16           ps = hv_fetch(conf, "close_on_error", 14, 0);
323 16 100         if (ps)
324 15 50         SvGETMAGIC(*ps);
    0          
325 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
326 15 50         client_set_close_on_error(c, SvTRUE(*ps));
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
327              
328 16           ps = hv_fetch(conf, "nowait", 6, 0);
329 16 100         if (ps)
330 15 50         SvGETMAGIC(*ps);
    0          
331 16 100         if (ps && SvOK(*ps))
    50          
    0          
    0          
332 15 50         client_set_nowait(c, SvTRUE(*ps));
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
333              
334 16           ps = hv_fetch(conf, "max_size", 8, 0);
335 16 50         if (ps)
336 0 0         SvGETMAGIC(*ps);
    0          
337 16 50         if (ps && SvOK(*ps))
    0          
    0          
    0          
338 0 0         memd->max_size = SvUV(*ps);
339             else
340 16           memd->max_size = 1024 * 1024;
341              
342 16           parse_compress(aTHX_ memd, conf);
343 16           parse_serialize(aTHX_ memd, conf);
344 16           }
345              
346              
347             static inline
348             SV *
349 1           compress(pTHX_ Cache_Memcached_Fast *memd, SV *sv, flags_type *flags)
350             {
351 1 50         if (memd->compress_threshold > 0)
352             {
353 0           STRLEN len = sv_len(sv);
354             SV *csv, *bsv;
355             int count;
356 0           dSP;
357              
358 0 0         if (len < (STRLEN) memd->compress_threshold)
359 0           return sv;
360              
361 0           csv = newSV(0);
362              
363 0 0         PUSHMARK(SP);
364 0 0         XPUSHs(sv_2mortal(newRV_inc(sv)));
365 0 0         XPUSHs(sv_2mortal(newRV_noinc(csv)));
366 0           PUTBACK;
367              
368 0           count = call_sv(memd->compress_method, G_SCALAR);
369              
370 0           SPAGAIN;
371              
372 0 0         if (count != 1)
373 0           croak("Compress method returned nothing");
374              
375 0           bsv = POPs;
376 0 0         if (SvTRUE(bsv) && sv_len(csv) <= len * memd->compress_ratio)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
377             {
378 0           sv = csv;
379 0           *flags |= F_COMPRESS;
380             }
381              
382 0           PUTBACK;
383             }
384              
385 1           return sv;
386             }
387              
388              
389             static inline
390             int
391 0           decompress(pTHX_ Cache_Memcached_Fast *memd, SV **sv, flags_type flags)
392             {
393 0           int res = 1;
394              
395 0 0         if (flags & F_COMPRESS)
396             {
397             SV *rsv, *bsv;
398             int count;
399 0           dSP;
400              
401 0           rsv = newSV(0);
402              
403 0 0         PUSHMARK(SP);
404 0 0         XPUSHs(sv_2mortal(newRV_inc(*sv)));
405 0 0         XPUSHs(sv_2mortal(newRV_inc(rsv)));
406 0           PUTBACK;
407              
408 0           count = call_sv(memd->decompress_method, G_SCALAR);
409              
410 0           SPAGAIN;
411              
412 0 0         if (count != 1)
413 0           croak("Decompress method returned nothing");
414              
415 0           bsv = POPs;
416 0 0         if (SvTRUE(bsv))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
417             {
418 0           SvREFCNT_dec(*sv);
419 0           *sv = rsv;
420             }
421             else
422             {
423 0           SvREFCNT_dec(rsv);
424 0           res = 0;
425             }
426              
427 0           PUTBACK;
428             }
429              
430 0           return res;
431             }
432              
433              
434             static inline
435             SV *
436 1           serialize(pTHX_ Cache_Memcached_Fast *memd, SV *sv, flags_type *flags)
437             {
438 1 50         if (SvROK(sv))
439             {
440             int count;
441 0           dSP;
442              
443 0 0         PUSHMARK(SP);
444 0 0         XPUSHs(sv);
445 0           PUTBACK;
446              
447 0           count = call_sv(memd->serialize_method, G_SCALAR);
448              
449 0           SPAGAIN;
450              
451 0 0         if (count != 1)
452 0           croak("Serialize method returned nothing");
453              
454 0           sv = POPs;
455 0           *flags |= F_STORABLE;
456              
457 0           PUTBACK;
458             }
459 1 50         else if (SvUTF8(sv))
460             {
461             /* Copy the value because we will modify it in place. */
462 0           sv = sv_2mortal(newSVsv(sv));
463 0 0         if (memd->utf8)
464             {
465 0           sv_utf8_encode(sv);
466 0           *flags |= F_UTF8;
467             }
468             else
469             {
470 0           sv_utf8_downgrade(sv, 0);
471             }
472             }
473              
474 1           return sv;
475             }
476              
477              
478             static inline
479             int
480 0           deserialize(pTHX_ Cache_Memcached_Fast *memd, SV **sv, flags_type flags)
481             {
482 0           int res = 1;
483              
484 0 0         if (flags & F_STORABLE)
485             {
486             SV *rsv;
487             int count;
488 0           dSP;
489              
490 0 0         PUSHMARK(SP);
491 0 0         XPUSHs(*sv);
492 0           PUTBACK;
493              
494             /* FIXME: do we need G_KEPEERR here? */
495 0           count = call_sv(memd->deserialize_method, G_SCALAR | G_EVAL);
496              
497 0           SPAGAIN;
498              
499 0 0         if (count != 1)
500 0           croak("Deserialize method returned nothing");
501              
502 0           rsv = POPs;
503 0 0         if (! SvTRUE(ERRSV))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
504             {
505 0           SvREFCNT_dec(*sv);
506 0           *sv = SvREFCNT_inc(rsv);
507             }
508             else
509             {
510 0           res = 0;
511             }
512              
513 0           PUTBACK;
514             }
515 0 0         else if ((flags & F_UTF8) && memd->utf8)
    0          
516             {
517 0           res = sv_utf8_decode(*sv);
518             }
519            
520 0           return res;
521             }
522              
523              
524             static
525             void *
526 0           alloc_value(value_size_type value_size, void **opaque)
527             {
528             dTHX;
529             SV *sv;
530             char *res;
531              
532 0           sv = newSVpvn("", 0);
533 0 0         res = SvGROW(sv, value_size + 1); /* FIXME: check OOM. */
    0          
534 0           res[value_size] = '\0';
535 0           SvCUR_set(sv, value_size);
536              
537 0           *opaque = sv;
538              
539 0           return (void *) res;
540             }
541              
542              
543             static
544             void
545 0           free_value(void *opaque)
546             {
547             dTHX;
548 0           SV *sv = (SV *) opaque;
549              
550 0           SvREFCNT_dec(sv);
551 0           }
552              
553              
554             struct xs_value_result
555             {
556             Cache_Memcached_Fast *memd;
557             SV *vals;
558             };
559              
560              
561             static
562             void
563 0           svalue_store(void *arg, void *opaque, int key_index, void *meta)
564             {
565             dTHX;
566 0           SV *value_sv = (SV *) opaque;
567 0           struct xs_value_result *value_res = (struct xs_value_result *) arg;
568 0           struct meta_object *m = (struct meta_object *) meta;
569              
570             /* Suppress warning about unused key_index. */
571             if (key_index) {}
572              
573 0 0         if (! decompress(aTHX_ value_res->memd, &value_sv, m->flags)
574 0 0         || ! deserialize(aTHX_ value_res->memd, &value_sv, m->flags))
575             {
576 0           free_value(value_sv);
577 0           return;
578             }
579              
580 0 0         if (! m->use_cas)
581             {
582 0           value_res->vals = value_sv;
583             }
584             else
585             {
586 0           AV *cas_val = newAV();
587 0           av_extend(cas_val, 1);
588 0           av_push(cas_val, newSVuv(m->cas));
589 0           av_push(cas_val, value_sv);
590 0           value_res->vals = newRV_noinc((SV *) cas_val);
591             }
592             }
593              
594              
595             static
596             void
597 0           mvalue_store(void *arg, void *opaque, int key_index, void *meta)
598             {
599             dTHX;
600 0           SV *value_sv = (SV *) opaque;
601 0           struct xs_value_result *value_res = (struct xs_value_result *) arg;
602 0           struct meta_object *m = (struct meta_object *) meta;
603              
604 0 0         if (! decompress(aTHX_ value_res->memd, &value_sv, m->flags)
605 0 0         || ! deserialize(aTHX_ value_res->memd, &value_sv, m->flags))
606             {
607 0           free_value(value_sv);
608 0           return;
609             }
610              
611 0 0         if (! m->use_cas)
612             {
613 0           av_store((AV *) value_res->vals, key_index, value_sv);
614             }
615             else
616             {
617 0           AV *cas_val = newAV();
618 0           av_extend(cas_val, 1);
619 0           av_push(cas_val, newSVuv(m->cas));
620 0           av_push(cas_val, value_sv);
621 0           av_store((AV *) value_res->vals, key_index, newRV_noinc((SV *) cas_val));
622             }
623             }
624              
625              
626             static
627             void
628 0           result_store(void *arg, void *opaque, int key_index, void *meta)
629             {
630             dTHX;
631 0           AV *av = (AV *) arg;
632 0           int res = (ptrdiff_t) opaque;
633              
634             /* Suppress warning about unused meta. */
635             if (meta) {}
636              
637 0 0         if (res)
638 0           av_store(av, key_index, newSViv(res));
639             else
640 0           av_store(av, key_index, newSVpvn("", 0));
641 0           }
642              
643              
644             static
645             void
646 0           embedded_store(void *arg, void *opaque, int key_index, void *meta)
647             {
648             dTHX;
649 0           AV *av = (AV *) arg;
650 0           SV *sv = (SV *) opaque;
651              
652             /* Suppress warning about unused meta. */
653             if (meta) {}
654              
655 0           av_store(av, key_index, sv);
656 0           }
657              
658              
659             /*
660             When SvPV() is called on a magic SV the result of mg_get() is cached
661             in PV slot. Since we pass around pointers to this storage we have
662             to avoid value refetch and reallocation that would happen if
663             mg_get() is called again. Because any magic SV may be put to the
664             argument list more than once we create a temporal copies of them,
665             thus braking possible ties and ensuring that every argument is
666             fetched exactly once.
667             */
668             static inline
669             char *
670 2           SvPV_stable_storage(pTHX_ SV *sv, STRLEN *lp)
671             {
672 2 50         if (SvGAMAGIC(sv))
    50          
    0          
    0          
673 0           sv = sv_2mortal(newSVsv(sv));
674              
675 2 50         return SvPV(sv, *lp);
676             }
677              
678              
679             MODULE = Cache::Memcached::Fast PACKAGE = Cache::Memcached::Fast
680              
681              
682             Cache_Memcached_Fast *
683             _new(class, conf)
684             char * class
685             SV * conf
686             PROTOTYPE: $$
687             PREINIT:
688             Cache_Memcached_Fast *memd;
689             CODE:
690 16           memd = (Cache_Memcached_Fast *) malloc(sizeof(Cache_Memcached_Fast));
691 16           memd->c = client_init();
692 16 50         if (! memd->c)
693 0           croak("Not enough memory");
694 16 50         if (! SvROK(conf) || SvTYPE(SvRV(conf)) != SVt_PVHV)
    50          
695 0           croak("Not a hash reference");
696 16           parse_config(aTHX_ memd, (HV *) SvRV(conf));
697 16           RETVAL = memd;
698             OUTPUT:
699             RETVAL
700              
701              
702             void
703             _destroy(memd)
704             Cache_Memcached_Fast * memd
705             PROTOTYPE: $
706             CODE:
707 16           client_destroy(memd->c);
708 16 100         if (memd->compress_method)
709             {
710 15           SvREFCNT_dec(memd->compress_method);
711 15           SvREFCNT_dec(memd->decompress_method);
712             }
713 16 50         if (memd->serialize_method)
714             {
715 16           SvREFCNT_dec(memd->serialize_method);
716 16           SvREFCNT_dec(memd->deserialize_method);
717             }
718 16           SvREFCNT_dec(memd->servers);
719 16           free(memd);
720              
721              
722             void
723             enable_compress(memd, enable)
724             Cache_Memcached_Fast * memd
725             bool enable
726             PROTOTYPE: $$
727             CODE:
728 0 0         if (enable && ! memd->compress_method)
    0          
729 0           warn("Compression module was not found, can't enable compression");
730 0 0         else if ((memd->compress_threshold > 0) != enable)
731 0           memd->compress_threshold = -memd->compress_threshold;
732              
733              
734             void
735             set(memd, ...)
736             Cache_Memcached_Fast * memd
737             ALIAS:
738             add = CMD_ADD
739             replace = CMD_REPLACE
740             append = CMD_APPEND
741             prepend = CMD_PREPEND
742             cas = CMD_CAS
743             PROTOTYPE: $@
744             PREINIT:
745             int noreply;
746 1           struct result_object object =
747             { NULL, result_store, NULL, NULL };
748             const char *key;
749             STRLEN key_len;
750 1           cas_type cas = 0;
751             const void *buf;
752             STRLEN buf_len;
753 1           flags_type flags = 0;
754 1           exptime_type exptime = 0;
755 1           int arg = 1;
756             SV *sv;
757             PPCODE:
758 1           object.arg = newAV();
759 1           sv_2mortal((SV *) object.arg);
760 1 50         noreply = (GIMME_V == G_VOID);
761 1           client_reset(memd->c, &object, noreply);
762 1           key = SvPV_stable_storage(aTHX_ ST(arg), &key_len);
763 1           ++arg;
764 1 50         if (ix == CMD_CAS)
765             {
766 0 0         cas = SvUV(ST(arg));
767 0           ++arg;
768             }
769 1           sv = ST(arg);
770 1           ++arg;
771 1           sv = serialize(aTHX_ memd, sv, &flags);
772 1           sv = compress(aTHX_ memd, sv, &flags);
773 1           buf = (void *) SvPV_stable_storage(aTHX_ sv, &buf_len);
774 1 50         if (buf_len > memd->max_size)
775 0           XSRETURN_EMPTY;
776 1 50         if (items > arg)
777             {
778             /* exptime doesn't have to be defined. */
779 0           sv = ST(arg);
780 0 0         SvGETMAGIC(sv);
    0          
781 0 0         if (SvOK(sv))
    0          
    0          
782 0 0         exptime = SvIV(sv);
783             }
784 1 50         if (ix != CMD_CAS)
785             {
786 1           client_prepare_set(memd->c, ix, 0, key, key_len, flags,
787             exptime, buf, buf_len);
788             }
789             else
790             {
791 0           client_prepare_cas(memd->c, 0, key, key_len, cas, flags,
792             exptime, buf, buf_len);
793             }
794 1           client_execute(memd->c, 2);
795 1 50         if (! noreply)
796             {
797 1           SV **val = av_fetch(object.arg, 0, 0);
798 1 50         if (val)
799             {
800 0           PUSHs(*val);
801 0           XSRETURN(1);
802             }
803 1           XSRETURN_EMPTY;
804             }
805              
806              
807             void
808             set_multi(memd, ...)
809             Cache_Memcached_Fast * memd
810             ALIAS:
811             add_multi = CMD_ADD
812             replace_multi = CMD_REPLACE
813             append_multi = CMD_APPEND
814             prepend_multi = CMD_PREPEND
815             cas_multi = CMD_CAS
816             PROTOTYPE: $@
817             PREINIT:
818             int i, noreply;
819 0           struct result_object object =
820             { NULL, result_store, NULL, NULL };
821             PPCODE:
822 0           object.arg = newAV();
823 0           sv_2mortal((SV *) object.arg);
824 0 0         noreply = (GIMME_V == G_VOID);
825 0           client_reset(memd->c, &object, noreply);
826 0 0         for (i = 1; i < items; ++i)
827             {
828             SV *sv;
829             AV *av;
830             const char *key;
831             STRLEN key_len;
832             /*
833             gcc-3.4.2 gives a warning about possibly uninitialized
834             cas, so we set it to zero.
835             */
836 0           cas_type cas = 0;
837             const void *buf;
838             STRLEN buf_len;
839 0           flags_type flags = 0;
840 0           exptime_type exptime = 0;
841 0           int arg = 0;
842              
843 0           sv = ST(i);
844 0 0         if (! (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV))
    0          
845 0           croak("Not an array reference");
846              
847 0           av = (AV *) SvRV(sv);
848 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, arg, 0), &key_len);
849 0           ++arg;
850 0 0         if (ix == CMD_CAS)
851             {
852 0 0         cas = SvUV(*safe_av_fetch(aTHX_ av, arg, 0));
853 0           ++arg;
854             }
855 0           sv = *safe_av_fetch(aTHX_ av, arg, 0);
856 0           ++arg;
857 0           sv = serialize(aTHX_ memd, sv, &flags);
858 0           sv = compress(aTHX_ memd, sv, &flags);
859 0           buf = (void *) SvPV_stable_storage(aTHX_ sv, &buf_len);
860 0 0         if (buf_len > memd->max_size)
861 0           continue;
862 0 0         if (av_len(av) >= arg)
863             {
864             /* exptime doesn't have to be defined. */
865 0           SV **ps = av_fetch(av, arg, 0);
866 0 0         if (ps)
867 0 0         SvGETMAGIC(*ps);
    0          
868 0 0         if (ps && SvOK(*ps))
    0          
    0          
    0          
869 0 0         exptime = SvIV(*ps);
870             }
871              
872 0 0         if (ix != CMD_CAS)
873             {
874 0           client_prepare_set(memd->c, ix, i - 1, key, key_len, flags,
875             exptime, buf, buf_len);
876             }
877             else
878             {
879 0           client_prepare_cas(memd->c, i - 1, key, key_len, cas, flags,
880             exptime, buf, buf_len);
881             }
882             }
883 0           client_execute(memd->c, 2);
884 0 0         if (! noreply)
885             {
886 0 0         if (GIMME_V == G_SCALAR)
    0          
887             {
888 0           HV *hv = newHV();
889 0 0         for (i = 0; i <= av_len(object.arg); ++i)
890             {
891 0           SV **val = av_fetch(object.arg, i, 0);
892 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
893             {
894 0           SV *key = *av_fetch((AV *) SvRV(ST(i + 1)), 0, 0);
895 0           HE *he = hv_store_ent(hv, key,
896             SvREFCNT_inc(*val), 0);
897 0 0         if (! he)
898 0           SvREFCNT_dec(*val);
899             }
900             }
901 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
902 0           XSRETURN(1);
903             }
904             else
905             {
906 0           I32 max_index = av_len(object.arg);
907 0 0         EXTEND(SP, max_index + 1);
    0          
908 0 0         for (i = 0; i <= max_index; ++i)
909             {
910 0           SV **val = av_fetch(object.arg, i, 0);
911 0 0         if (val)
912 0           PUSHs(*val);
913             else
914 0           PUSHs(&PL_sv_undef);
915             }
916 0           XSRETURN(max_index + 1);
917             }
918             }
919              
920              
921             void
922             get(memd, ...)
923             Cache_Memcached_Fast * memd
924             ALIAS:
925             gets = CMD_GETS
926             PROTOTYPE: $@
927             PREINIT:
928             struct xs_value_result value_res;
929 1           struct result_object object =
930             { alloc_value, svalue_store, free_value, &value_res };
931             const char *key;
932             STRLEN key_len;
933             PPCODE:
934 1           value_res.memd = memd;
935 1           value_res.vals = NULL;
936 1           client_reset(memd->c, &object, 0);
937 1 50         key = SvPV(ST(1), key_len);
938 1           client_prepare_get(memd->c, ix, 0, key, key_len);
939 1           client_execute(memd->c, 2);
940 1 50         if (value_res.vals)
941             {
942 0           PUSHs(sv_2mortal(value_res.vals));
943 0           XSRETURN(1);
944             }
945 1           XSRETURN_EMPTY;
946              
947              
948             void
949             get_multi(memd, ...)
950             Cache_Memcached_Fast * memd
951             ALIAS:
952             gets_multi = CMD_GETS
953             PROTOTYPE: $@
954             PREINIT:
955             struct xs_value_result value_res;
956 0           struct result_object object =
957             { alloc_value, mvalue_store, free_value, &value_res };
958             int i, key_count;
959             HV *hv;
960             PPCODE:
961 0           key_count = items - 1;
962 0           value_res.memd = memd;
963 0           value_res.vals = (SV *) newAV();
964 0           sv_2mortal(value_res.vals);
965 0           av_extend((AV *) value_res.vals, key_count - 1);
966 0           client_reset(memd->c, &object, 0);
967 0 0         for (i = 0; i < key_count; ++i)
968             {
969             const char *key;
970             STRLEN key_len;
971              
972 0           key = SvPV_stable_storage(aTHX_ ST(i + 1), &key_len);
973 0           client_prepare_get(memd->c, ix, i, key, key_len);
974             }
975 0           client_execute(memd->c, 2);
976 0           hv = newHV();
977 0 0         for (i = 0; i <= av_len((AV *) value_res.vals); ++i)
978             {
979 0           SV **val = av_fetch((AV *) value_res.vals, i, 0);
980 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
981             {
982 0           SV *key = ST(i + 1);
983 0           HE *he = hv_store_ent(hv, key,
984             SvREFCNT_inc(*val), 0);
985 0 0         if (! he)
986 0           SvREFCNT_dec(*val);
987             }
988             }
989 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
990 0           XSRETURN(1);
991              
992              
993             void
994             gat(memd, ...)
995             Cache_Memcached_Fast * memd
996             ALIAS:
997             gats = CMD_GATS
998             PROTOTYPE: $@
999             PREINIT:
1000             struct xs_value_result value_res;
1001 0           struct result_object object =
1002             { alloc_value, svalue_store, free_value, &value_res };
1003             const char *key;
1004             STRLEN key_len;
1005 0           const char *exptime = "0";
1006 0           STRLEN exptime_len = 1;
1007             SV *sv;
1008             PPCODE:
1009 0           value_res.memd = memd;
1010 0           value_res.vals = NULL;
1011 0           client_reset(memd->c, &object, 0);
1012 0           sv = ST(1);
1013 0 0         SvGETMAGIC(sv);
    0          
1014 0 0         if (SvOK(sv))
    0          
    0          
1015 0 0         exptime = SvPV(sv, exptime_len);
1016 0 0         key = SvPV(ST(2), key_len);
1017 0           client_prepare_gat(memd->c, ix, 0, key, key_len, exptime, exptime_len);
1018 0           client_execute(memd->c, 4);
1019 0 0         if (value_res.vals)
1020             {
1021 0           PUSHs(sv_2mortal(value_res.vals));
1022 0           XSRETURN(1);
1023             }
1024 0           XSRETURN_EMPTY;
1025              
1026             void
1027             gat_multi(memd, ...)
1028             Cache_Memcached_Fast * memd
1029             ALIAS:
1030             gats_multi = CMD_GATS
1031             PROTOTYPE: $@
1032             PREINIT:
1033             struct xs_value_result value_res;
1034 0           struct result_object object =
1035             { alloc_value, mvalue_store, free_value, &value_res };
1036             int i, key_count;
1037             HV *hv;
1038             SV *sv;
1039 0           const char *exptime = "0";
1040 0           STRLEN exptime_len = 1;
1041             PPCODE:
1042 0           key_count = items - 2;
1043 0           value_res.memd = memd;
1044 0           value_res.vals = (SV *) newAV();
1045 0           sv_2mortal(value_res.vals);
1046 0           av_extend((AV *) value_res.vals, key_count - 1);
1047 0           client_reset(memd->c, &object, 0);
1048 0           sv = ST(1);
1049 0 0         SvGETMAGIC(sv);
    0          
1050 0 0         if (SvOK(sv))
    0          
    0          
1051 0 0         exptime = SvPV(sv, exptime_len);
1052 0 0         for (i = 0; i < key_count; ++i)
1053             {
1054             const char *key;
1055             STRLEN key_len;
1056 0           key = SvPV_stable_storage(aTHX_ ST(i + 2), &key_len);
1057 0           client_prepare_gat(memd->c, ix, i, key, key_len, exptime, exptime_len);
1058             }
1059 0           client_execute(memd->c, 4);
1060 0           hv = newHV();
1061 0 0         for (i = 0; i <= av_len((AV *) value_res.vals); ++i)
1062             {
1063 0           SV **val = av_fetch((AV *) value_res.vals, i, 0);
1064 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1065             {
1066 0           SV *key = ST(i + 2);
1067 0           HE *he = hv_store_ent(hv, key,
1068             SvREFCNT_inc(*val), 0);
1069 0 0         if (! he)
1070 0           SvREFCNT_dec(*val);
1071             }
1072             }
1073 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1074 0           XSRETURN(1);
1075              
1076              
1077             void
1078             incr(memd, ...)
1079             Cache_Memcached_Fast * memd
1080             ALIAS:
1081             decr = CMD_DECR
1082             PROTOTYPE: $@
1083             PREINIT:
1084 0           struct result_object object =
1085             { alloc_value, embedded_store, NULL, NULL };
1086             int noreply;
1087             const char *key;
1088             STRLEN key_len;
1089 0           arith_type arg = 1;
1090             PPCODE:
1091 0           object.arg = newAV();
1092 0           sv_2mortal((SV *) object.arg);
1093 0 0         noreply = (GIMME_V == G_VOID);
1094 0           client_reset(memd->c, &object, noreply);
1095 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1096 0 0         if (items > 2)
1097             {
1098             /* increment doesn't have to be defined. */
1099 0           SV *sv = ST(2);
1100 0 0         SvGETMAGIC(sv);
    0          
1101 0 0         if (SvOK(sv))
    0          
    0          
1102 0 0         arg = SvUV(sv);
1103             }
1104 0           client_prepare_incr(memd->c, ix, 0, key, key_len, arg);
1105 0           client_execute(memd->c, 2);
1106 0 0         if (! noreply)
1107             {
1108 0           SV **val = av_fetch(object.arg, 0, 0);
1109 0 0         if (val)
1110             {
1111 0           PUSHs(*val);
1112 0           XSRETURN(1);
1113             }
1114 0           XSRETURN_EMPTY;
1115             }
1116              
1117              
1118             void
1119             incr_multi(memd, ...)
1120             Cache_Memcached_Fast * memd
1121             ALIAS:
1122             decr_multi = CMD_DECR
1123             PROTOTYPE: $@
1124             PREINIT:
1125 0           struct result_object object =
1126             { alloc_value, embedded_store, NULL, NULL };
1127             int i, noreply;
1128             PPCODE:
1129 0           object.arg = newAV();
1130 0           sv_2mortal((SV *) object.arg);
1131 0 0         noreply = (GIMME_V == G_VOID);
1132 0           client_reset(memd->c, &object, noreply);
1133 0 0         for (i = 1; i < items; ++i)
1134             {
1135             SV *sv;
1136             AV *av;
1137             const char *key;
1138             STRLEN key_len;
1139 0           arith_type arg = 1;
1140              
1141 0           sv = ST(i);
1142 0 0         if (! SvROK(sv))
1143             {
1144 0           key = SvPV_stable_storage(aTHX_ sv, &key_len);
1145             }
1146             else
1147             {
1148 0 0         if (SvTYPE(SvRV(sv)) != SVt_PVAV)
1149 0           croak("Not an array reference");
1150              
1151 0           av = (AV *) SvRV(sv);
1152 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
1153 0 0         if (av_len(av) >= 1)
1154             {
1155             /* increment doesn't have to be defined. */
1156 0           SV **ps = av_fetch(av, 1, 0);
1157 0 0         if (ps)
1158 0 0         SvGETMAGIC(*ps);
    0          
1159 0 0         if (ps && SvOK(*ps))
    0          
    0          
    0          
1160 0 0         arg = SvUV(*ps);
1161             }
1162             }
1163            
1164 0           client_prepare_incr(memd->c, ix, i - 1, key, key_len, arg);
1165             }
1166 0           client_execute(memd->c, 2);
1167 0 0         if (! noreply)
1168             {
1169 0 0         if (GIMME_V == G_SCALAR)
    0          
1170             {
1171 0           HV *hv = newHV();
1172 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1173             {
1174 0           SV **val = av_fetch(object.arg, i, 0);
1175 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1176             {
1177             SV *key;
1178             HE *he;
1179              
1180 0           key = ST(i + 1);
1181 0 0         if (SvROK(key))
1182 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1183              
1184 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1185 0 0         if (! he)
1186 0           SvREFCNT_dec(*val);
1187             }
1188             }
1189 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1190 0           XSRETURN(1);
1191             }
1192             else
1193             {
1194 0           I32 max_index = av_len(object.arg);
1195 0 0         EXTEND(SP, max_index + 1);
    0          
1196 0 0         for (i = 0; i <= max_index; ++i)
1197             {
1198 0           SV **val = av_fetch(object.arg, i, 0);
1199 0 0         if (val)
1200 0           PUSHs(*val);
1201             else
1202 0           PUSHs(&PL_sv_undef);
1203             }
1204 0           XSRETURN(max_index + 1);
1205             }
1206             }
1207              
1208              
1209             void
1210             delete(memd, ...)
1211             Cache_Memcached_Fast * memd
1212             PROTOTYPE: $@
1213             PREINIT:
1214 0           struct result_object object =
1215             { NULL, result_store, NULL, NULL };
1216             int noreply;
1217             const char *key;
1218             STRLEN key_len;
1219             PPCODE:
1220 0           object.arg = newAV();
1221 0           sv_2mortal((SV *) object.arg);
1222 0 0         noreply = (GIMME_V == G_VOID);
1223 0           client_reset(memd->c, &object, noreply);
1224 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1225 0 0         if (items > 2)
1226             {
1227             /* Compatibility with old (key, delay) syntax. */
1228              
1229             /* delay doesn't have to be defined. */
1230 0           SV *sv = ST(2);
1231 0 0         SvGETMAGIC(sv);
    0          
1232 0 0         if (SvOK(sv) && SvUV(sv) != 0)
    0          
    0          
    0          
    0          
1233 0           warn("non-zero delete expiration time is ignored");
1234             }
1235 0           client_prepare_delete(memd->c, 0, key, key_len);
1236 0           client_execute(memd->c, 2);
1237 0 0         if (! noreply)
1238             {
1239 0           SV **val = av_fetch(object.arg, 0, 0);
1240 0 0         if (val)
1241             {
1242 0           PUSHs(*val);
1243 0           XSRETURN(1);
1244             }
1245 0           XSRETURN_EMPTY;
1246             }
1247              
1248              
1249             void
1250             delete_multi(memd, ...)
1251             Cache_Memcached_Fast * memd
1252             PROTOTYPE: $@
1253             PREINIT:
1254 0           struct result_object object =
1255             { NULL, result_store, NULL, NULL };
1256             int i, noreply;
1257             PPCODE:
1258 0           object.arg = newAV();
1259 0           sv_2mortal((SV *) object.arg);
1260 0 0         noreply = (GIMME_V == G_VOID);
1261 0           client_reset(memd->c, &object, noreply);
1262 0 0         for (i = 1; i < items; ++i)
1263             {
1264             SV *sv;
1265             const char *key;
1266             STRLEN key_len;
1267              
1268 0           sv = ST(i);
1269 0 0         if (! SvROK(sv))
1270             {
1271 0           key = SvPV_stable_storage(aTHX_ sv, &key_len);
1272             }
1273             else
1274             {
1275             /* Compatibility with old [key, delay] syntax. */
1276              
1277             AV *av;
1278              
1279 0 0         if (SvTYPE(SvRV(sv)) != SVt_PVAV)
1280 0           croak("Not an array reference");
1281              
1282 0           av = (AV *) SvRV(sv);
1283 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
1284 0 0         if (av_len(av) >= 1)
1285             {
1286             /* delay doesn't have to be defined. */
1287 0           SV **ps = av_fetch(av, 1, 0);
1288 0 0         if (ps)
1289 0 0         SvGETMAGIC(*ps);
    0          
1290 0 0         if (ps && SvOK(*ps) && SvUV(*ps) != 0)
    0          
    0          
    0          
    0          
    0          
1291 0           warn("non-zero delete expiration time is ignored");
1292             }
1293             }
1294            
1295 0           client_prepare_delete(memd->c, i - 1, key, key_len);
1296             }
1297 0           client_execute(memd->c, 2);
1298 0 0         if (! noreply)
1299             {
1300 0 0         if (GIMME_V == G_SCALAR)
    0          
1301             {
1302 0           HV *hv = newHV();
1303 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1304             {
1305 0           SV **val = av_fetch(object.arg, i, 0);
1306 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1307             {
1308             SV *key;
1309             HE *he;
1310              
1311 0           key = ST(i + 1);
1312 0 0         if (SvROK(key))
1313 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1314              
1315 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1316 0 0         if (! he)
1317 0           SvREFCNT_dec(*val);
1318             }
1319             }
1320 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1321 0           XSRETURN(1);
1322             }
1323             else
1324             {
1325 0           I32 max_index = av_len(object.arg);
1326 0 0         EXTEND(SP, max_index + 1);
    0          
1327 0 0         for (i = 0; i <= max_index; ++i)
1328             {
1329 0           SV **val = av_fetch(object.arg, i, 0);
1330 0 0         if (val)
1331 0           PUSHs(*val);
1332             else
1333 0           PUSHs(&PL_sv_undef);
1334             }
1335 0           XSRETURN(max_index + 1);
1336             }
1337             }
1338              
1339              
1340             void
1341             touch(memd, ...)
1342             Cache_Memcached_Fast * memd
1343             PROTOTYPE: $@
1344             PREINIT:
1345 0           struct result_object object =
1346             { NULL, result_store, NULL, NULL };
1347             int noreply;
1348             const char *key;
1349             STRLEN key_len;
1350 0           exptime_type exptime = 0;
1351             SV *sv;
1352             PPCODE:
1353 0           object.arg = newAV();
1354 0           sv_2mortal((SV *) object.arg);
1355 0 0         noreply = (GIMME_V == G_VOID);
1356 0           client_reset(memd->c, &object, noreply);
1357 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1358 0 0         if (items > 2)
1359             {
1360             /* exptime doesn't have to be defined. */
1361 0           sv = ST(2);
1362 0 0         SvGETMAGIC(sv);
    0          
1363 0 0         if (SvOK(sv))
    0          
    0          
1364 0 0         exptime = SvIV(sv);
1365             }
1366 0           client_prepare_touch(memd->c, 0, key, key_len, exptime);
1367 0           client_execute(memd->c, 2);
1368 0 0         if (! noreply)
1369             {
1370 0           SV **val = av_fetch(object.arg, 0, 0);
1371 0 0         if (val)
1372             {
1373 0           PUSHs(*val);
1374 0           XSRETURN(1);
1375             }
1376 0           XSRETURN_EMPTY;
1377             }
1378              
1379              
1380             void
1381             touch_multi(memd, ...)
1382             Cache_Memcached_Fast * memd
1383             PROTOTYPE: $@
1384             PREINIT:
1385 0           struct result_object object =
1386             { NULL, result_store, NULL, NULL };
1387             int i, noreply;
1388             PPCODE:
1389 0           object.arg = newAV();
1390 0           sv_2mortal((SV *) object.arg);
1391 0 0         noreply = (GIMME_V == G_VOID);
1392 0           client_reset(memd->c, &object, noreply);
1393 0 0         for (i = 1; i < items; ++i)
1394             {
1395             SV *sv;
1396             AV *av;
1397             const char *key;
1398             STRLEN key_len;
1399 0           exptime_type exptime = 0;
1400 0           int arg = 0;
1401              
1402 0           sv = ST(i);
1403 0 0         if (! (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV))
    0          
1404 0           croak("Not an array reference");
1405              
1406 0           av = (AV *) SvRV(sv);
1407 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, arg, 0), &key_len);
1408 0           ++arg;
1409              
1410 0 0         if (av_len(av) >= 1)
1411             {
1412             /* exptime doesn't have to be defined. */
1413 0           SV **ps = av_fetch(av, arg, 0);
1414 0 0         if (ps)
1415 0 0         SvGETMAGIC(*ps);
    0          
1416 0 0         if (ps && SvOK(*ps))
    0          
    0          
    0          
1417 0 0         exptime = SvIV(*ps);
1418             }
1419              
1420 0           client_prepare_touch(memd->c, i - 1, key, key_len, exptime);
1421             }
1422 0           client_execute(memd->c, 2);
1423 0 0         if (! noreply)
1424             {
1425 0 0         if (GIMME_V == G_SCALAR)
    0          
1426             {
1427 0           HV *hv = newHV();
1428 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1429             {
1430 0           SV **val = av_fetch(object.arg, i, 0);
1431 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1432             {
1433             SV *key;
1434             HE *he;
1435              
1436 0           key = ST(i + 1);
1437 0 0         if (SvROK(key))
1438 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1439              
1440 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1441 0 0         if (! he)
1442 0           SvREFCNT_dec(*val);
1443             }
1444             }
1445 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1446 0           XSRETURN(1);
1447             }
1448             else
1449             {
1450 0           I32 max_index = av_len(object.arg);
1451 0 0         EXTEND(SP, max_index + 1);
    0          
1452 0 0         for (i = 0; i <= max_index; ++i)
1453             {
1454 0           SV **val = av_fetch(object.arg, i, 0);
1455 0 0         if (val)
1456 0           PUSHs(*val);
1457             else
1458 0           PUSHs(&PL_sv_undef);
1459             }
1460 0           XSRETURN(max_index + 1);
1461             }
1462             }
1463              
1464              
1465             HV *
1466             flush_all(memd, ...)
1467             Cache_Memcached_Fast * memd
1468             PROTOTYPE: $;$
1469             PREINIT:
1470 0           delay_type delay = 0;
1471 0           struct result_object object =
1472             { NULL, result_store, NULL, NULL };
1473             int noreply;
1474             CODE:
1475 0           RETVAL = newHV();
1476             /* Why sv_2mortal() is needed is explained in perlxs. */
1477 0           sv_2mortal((SV *) RETVAL);
1478 0           object.arg = sv_2mortal((SV *) newAV());
1479 0 0         if (items > 1)
1480             {
1481 0           SV *sv = ST(1);
1482 0 0         SvGETMAGIC(sv);
    0          
1483 0 0         if (SvOK(sv))
    0          
    0          
1484 0 0         delay = SvUV(sv);
1485             }
1486 0 0         noreply = (GIMME_V == G_VOID);
1487 0           client_flush_all(memd->c, delay, &object, noreply);
1488 0 0         if (! noreply)
1489             {
1490             int i;
1491 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1492             {
1493 0           SV **server = av_fetch(memd->servers, i, 0);
1494 0           SV **version = av_fetch(object.arg, i, 0);
1495 0 0         if (version && SvOK(*version))
    0          
    0          
    0          
1496             {
1497 0           HE *he = hv_store_ent(RETVAL, *server,
1498             SvREFCNT_inc(*version), 0);
1499 0 0         if (! he)
1500 0           SvREFCNT_dec(*version);
1501             }
1502             }
1503             }
1504             OUTPUT:
1505             RETVAL
1506              
1507              
1508             void
1509             nowait_push(memd)
1510             Cache_Memcached_Fast * memd
1511             PROTOTYPE: $
1512             CODE:
1513 0           client_nowait_push(memd->c);
1514              
1515              
1516             HV *
1517             server_versions(memd)
1518             Cache_Memcached_Fast * memd
1519             PROTOTYPE: $
1520             PREINIT:
1521 16           struct result_object object =
1522             { alloc_value, embedded_store, NULL, NULL };
1523             int i;
1524             CODE:
1525 16           RETVAL = newHV();
1526             /* Why sv_2mortal() is needed is explained in perlxs. */
1527 16           sv_2mortal((SV *) RETVAL);
1528 16           object.arg = sv_2mortal((SV *) newAV());
1529 16           client_server_versions(memd->c, &object);
1530 16 50         for (i = 0; i <= av_len(object.arg); ++i)
1531             {
1532 0           SV **server = av_fetch(memd->servers, i, 0);
1533 0           SV **version = av_fetch(object.arg, i, 0);
1534 0 0         if (version && SvOK(*version))
    0          
    0          
    0          
1535             {
1536 0           HE *he = hv_store_ent(RETVAL, *server,
1537             SvREFCNT_inc(*version), 0);
1538 0 0         if (! he)
1539 0           SvREFCNT_dec(*version);
1540             }
1541             }
1542             OUTPUT:
1543             RETVAL
1544              
1545              
1546             SV *
1547             namespace(memd, ...)
1548             Cache_Memcached_Fast * memd
1549             PROTOTYPE: $;$
1550             PREINIT:
1551             const char *ns;
1552             size_t len;
1553             CODE:
1554 0           ns = client_get_prefix(memd->c, &len);
1555 0           RETVAL = newSVpv(ns, len);
1556 0 0         if (items > 1)
1557             {
1558 0 0         ns = SvPV(ST(1), len);
1559 0 0         if (client_set_prefix(memd->c, ns, len) != MEMCACHED_SUCCESS)
1560 0           croak("Not enough memory");
1561             }
1562             OUTPUT:
1563             RETVAL
1564              
1565              
1566             void
1567             disconnect_all(memd)
1568             Cache_Memcached_Fast * memd
1569             PROTOTYPE: $
1570             CODE:
1571 0           client_reinit(memd->c);
1572              
1573              
1574             void
1575             _weaken(sv)
1576             SV *sv
1577             PROTOTYPE: $
1578             CODE:
1579 16           sv_rvweaken(sv);