File Coverage

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