File Coverage

Fast.xs
Criterion Covered Total %
statement 218 745 29.2
branch 160 1192 13.4
condition n/a
subroutine n/a
pod n/a
total 378 1937 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 0         if (key_count > 1)
1047 0           av_extend((AV *) value_res.vals, key_count - 1);
1048 0           client_reset(memd->c, &object, 0);
1049 0           sv = ST(1);
1050 0 0         SvGETMAGIC(sv);
    0          
1051 0 0         if (SvOK(sv))
    0          
    0          
1052 0 0         exptime = SvPV(sv, exptime_len);
1053 0 0         for (i = 0; i < key_count; ++i)
1054             {
1055             const char *key;
1056             STRLEN key_len;
1057 0           key = SvPV_stable_storage(aTHX_ ST(i + 2), &key_len);
1058 0           client_prepare_gat(memd->c, ix, i, key, key_len, exptime, exptime_len);
1059             }
1060 0           client_execute(memd->c, 4);
1061 0           hv = newHV();
1062 0 0         for (i = 0; i <= av_len((AV *) value_res.vals); ++i)
1063             {
1064 0           SV **val = av_fetch((AV *) value_res.vals, i, 0);
1065 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1066             {
1067 0           SV *key = ST(i + 2);
1068 0           HE *he = hv_store_ent(hv, key,
1069             SvREFCNT_inc(*val), 0);
1070 0 0         if (! he)
1071 0           SvREFCNT_dec(*val);
1072             }
1073             }
1074 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1075 0           XSRETURN(1);
1076              
1077              
1078             void
1079             incr(memd, ...)
1080             Cache_Memcached_Fast * memd
1081             ALIAS:
1082             decr = CMD_DECR
1083             PROTOTYPE: $@
1084             PREINIT:
1085 0           struct result_object object =
1086             { alloc_value, embedded_store, NULL, NULL };
1087             int noreply;
1088             const char *key;
1089             STRLEN key_len;
1090 0           arith_type arg = 1;
1091             PPCODE:
1092 0           object.arg = newAV();
1093 0           sv_2mortal((SV *) object.arg);
1094 0 0         noreply = (GIMME_V == G_VOID);
1095 0           client_reset(memd->c, &object, noreply);
1096 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1097 0 0         if (items > 2)
1098             {
1099             /* increment doesn't have to be defined. */
1100 0           SV *sv = ST(2);
1101 0 0         SvGETMAGIC(sv);
    0          
1102 0 0         if (SvOK(sv))
    0          
    0          
1103 0 0         arg = SvUV(sv);
1104             }
1105 0           client_prepare_incr(memd->c, ix, 0, key, key_len, arg);
1106 0           client_execute(memd->c, 2);
1107 0 0         if (! noreply)
1108             {
1109 0           SV **val = av_fetch(object.arg, 0, 0);
1110 0 0         if (val)
1111             {
1112 0           PUSHs(*val);
1113 0           XSRETURN(1);
1114             }
1115 0           XSRETURN_EMPTY;
1116             }
1117              
1118              
1119             void
1120             incr_multi(memd, ...)
1121             Cache_Memcached_Fast * memd
1122             ALIAS:
1123             decr_multi = CMD_DECR
1124             PROTOTYPE: $@
1125             PREINIT:
1126 0           struct result_object object =
1127             { alloc_value, embedded_store, NULL, NULL };
1128             int i, noreply;
1129             PPCODE:
1130 0           object.arg = newAV();
1131 0           sv_2mortal((SV *) object.arg);
1132 0 0         noreply = (GIMME_V == G_VOID);
1133 0           client_reset(memd->c, &object, noreply);
1134 0 0         for (i = 1; i < items; ++i)
1135             {
1136             SV *sv;
1137             AV *av;
1138             const char *key;
1139             STRLEN key_len;
1140 0           arith_type arg = 1;
1141              
1142 0           sv = ST(i);
1143 0 0         if (! SvROK(sv))
1144             {
1145 0           key = SvPV_stable_storage(aTHX_ sv, &key_len);
1146             }
1147             else
1148             {
1149 0 0         if (SvTYPE(SvRV(sv)) != SVt_PVAV)
1150 0           croak("Not an array reference");
1151              
1152 0           av = (AV *) SvRV(sv);
1153 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
1154 0 0         if (av_len(av) >= 1)
1155             {
1156             /* increment doesn't have to be defined. */
1157 0           SV **ps = av_fetch(av, 1, 0);
1158 0 0         if (ps)
1159 0 0         SvGETMAGIC(*ps);
    0          
1160 0 0         if (ps && SvOK(*ps))
    0          
    0          
    0          
1161 0 0         arg = SvUV(*ps);
1162             }
1163             }
1164            
1165 0           client_prepare_incr(memd->c, ix, i - 1, key, key_len, arg);
1166             }
1167 0           client_execute(memd->c, 2);
1168 0 0         if (! noreply)
1169             {
1170 0 0         if (GIMME_V == G_SCALAR)
    0          
1171             {
1172 0           HV *hv = newHV();
1173 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1174             {
1175 0           SV **val = av_fetch(object.arg, i, 0);
1176 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1177             {
1178             SV *key;
1179             HE *he;
1180              
1181 0           key = ST(i + 1);
1182 0 0         if (SvROK(key))
1183 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1184              
1185 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1186 0 0         if (! he)
1187 0           SvREFCNT_dec(*val);
1188             }
1189             }
1190 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1191 0           XSRETURN(1);
1192             }
1193             else
1194             {
1195 0           I32 max_index = av_len(object.arg);
1196 0 0         EXTEND(SP, max_index + 1);
    0          
1197 0 0         for (i = 0; i <= max_index; ++i)
1198             {
1199 0           SV **val = av_fetch(object.arg, i, 0);
1200 0 0         if (val)
1201 0           PUSHs(*val);
1202             else
1203 0           PUSHs(&PL_sv_undef);
1204             }
1205 0           XSRETURN(max_index + 1);
1206             }
1207             }
1208              
1209              
1210             void
1211             delete(memd, ...)
1212             Cache_Memcached_Fast * memd
1213             PROTOTYPE: $@
1214             PREINIT:
1215 0           struct result_object object =
1216             { NULL, result_store, NULL, NULL };
1217             int noreply;
1218             const char *key;
1219             STRLEN key_len;
1220             PPCODE:
1221 0           object.arg = newAV();
1222 0           sv_2mortal((SV *) object.arg);
1223 0 0         noreply = (GIMME_V == G_VOID);
1224 0           client_reset(memd->c, &object, noreply);
1225 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1226 0 0         if (items > 2)
1227             {
1228             /* Compatibility with old (key, delay) syntax. */
1229              
1230             /* delay doesn't have to be defined. */
1231 0           SV *sv = ST(2);
1232 0 0         SvGETMAGIC(sv);
    0          
1233 0 0         if (SvOK(sv) && SvUV(sv) != 0)
    0          
    0          
    0          
    0          
1234 0           warn("non-zero delete expiration time is ignored");
1235             }
1236 0           client_prepare_delete(memd->c, 0, key, key_len);
1237 0           client_execute(memd->c, 2);
1238 0 0         if (! noreply)
1239             {
1240 0           SV **val = av_fetch(object.arg, 0, 0);
1241 0 0         if (val)
1242             {
1243 0           PUSHs(*val);
1244 0           XSRETURN(1);
1245             }
1246 0           XSRETURN_EMPTY;
1247             }
1248              
1249              
1250             void
1251             delete_multi(memd, ...)
1252             Cache_Memcached_Fast * memd
1253             PROTOTYPE: $@
1254             PREINIT:
1255 0           struct result_object object =
1256             { NULL, result_store, NULL, NULL };
1257             int i, noreply;
1258             PPCODE:
1259 0           object.arg = newAV();
1260 0           sv_2mortal((SV *) object.arg);
1261 0 0         noreply = (GIMME_V == G_VOID);
1262 0           client_reset(memd->c, &object, noreply);
1263 0 0         for (i = 1; i < items; ++i)
1264             {
1265             SV *sv;
1266             const char *key;
1267             STRLEN key_len;
1268              
1269 0           sv = ST(i);
1270 0 0         if (! SvROK(sv))
1271             {
1272 0           key = SvPV_stable_storage(aTHX_ sv, &key_len);
1273             }
1274             else
1275             {
1276             /* Compatibility with old [key, delay] syntax. */
1277              
1278             AV *av;
1279              
1280 0 0         if (SvTYPE(SvRV(sv)) != SVt_PVAV)
1281 0           croak("Not an array reference");
1282              
1283 0           av = (AV *) SvRV(sv);
1284 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
1285 0 0         if (av_len(av) >= 1)
1286             {
1287             /* delay doesn't have to be defined. */
1288 0           SV **ps = av_fetch(av, 1, 0);
1289 0 0         if (ps)
1290 0 0         SvGETMAGIC(*ps);
    0          
1291 0 0         if (ps && SvOK(*ps) && SvUV(*ps) != 0)
    0          
    0          
    0          
    0          
    0          
1292 0           warn("non-zero delete expiration time is ignored");
1293             }
1294             }
1295            
1296 0           client_prepare_delete(memd->c, i - 1, key, key_len);
1297             }
1298 0           client_execute(memd->c, 2);
1299 0 0         if (! noreply)
1300             {
1301 0 0         if (GIMME_V == G_SCALAR)
    0          
1302             {
1303 0           HV *hv = newHV();
1304 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1305             {
1306 0           SV **val = av_fetch(object.arg, i, 0);
1307 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1308             {
1309             SV *key;
1310             HE *he;
1311              
1312 0           key = ST(i + 1);
1313 0 0         if (SvROK(key))
1314 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1315              
1316 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1317 0 0         if (! he)
1318 0           SvREFCNT_dec(*val);
1319             }
1320             }
1321 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1322 0           XSRETURN(1);
1323             }
1324             else
1325             {
1326 0           I32 max_index = av_len(object.arg);
1327 0 0         EXTEND(SP, max_index + 1);
    0          
1328 0 0         for (i = 0; i <= max_index; ++i)
1329             {
1330 0           SV **val = av_fetch(object.arg, i, 0);
1331 0 0         if (val)
1332 0           PUSHs(*val);
1333             else
1334 0           PUSHs(&PL_sv_undef);
1335             }
1336 0           XSRETURN(max_index + 1);
1337             }
1338             }
1339              
1340              
1341             void
1342             touch(memd, ...)
1343             Cache_Memcached_Fast * memd
1344             PROTOTYPE: $@
1345             PREINIT:
1346 0           struct result_object object =
1347             { NULL, result_store, NULL, NULL };
1348             int noreply;
1349             const char *key;
1350             STRLEN key_len;
1351 0           exptime_type exptime = 0;
1352             SV *sv;
1353             PPCODE:
1354 0           object.arg = newAV();
1355 0           sv_2mortal((SV *) object.arg);
1356 0 0         noreply = (GIMME_V == G_VOID);
1357 0           client_reset(memd->c, &object, noreply);
1358 0           key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
1359 0 0         if (items > 2)
1360             {
1361             /* exptime doesn't have to be defined. */
1362 0           sv = ST(2);
1363 0 0         SvGETMAGIC(sv);
    0          
1364 0 0         if (SvOK(sv))
    0          
    0          
1365 0 0         exptime = SvIV(sv);
1366             }
1367 0           client_prepare_touch(memd->c, 0, key, key_len, exptime);
1368 0           client_execute(memd->c, 2);
1369 0 0         if (! noreply)
1370             {
1371 0           SV **val = av_fetch(object.arg, 0, 0);
1372 0 0         if (val)
1373             {
1374 0           PUSHs(*val);
1375 0           XSRETURN(1);
1376             }
1377 0           XSRETURN_EMPTY;
1378             }
1379              
1380              
1381             void
1382             touch_multi(memd, ...)
1383             Cache_Memcached_Fast * memd
1384             PROTOTYPE: $@
1385             PREINIT:
1386 0           struct result_object object =
1387             { NULL, result_store, NULL, NULL };
1388             int i, noreply;
1389             PPCODE:
1390 0           object.arg = newAV();
1391 0           sv_2mortal((SV *) object.arg);
1392 0 0         noreply = (GIMME_V == G_VOID);
1393 0           client_reset(memd->c, &object, noreply);
1394 0 0         for (i = 1; i < items; ++i)
1395             {
1396             SV *sv;
1397             AV *av;
1398             const char *key;
1399             STRLEN key_len;
1400 0           exptime_type exptime = 0;
1401 0           int arg = 0;
1402              
1403 0           sv = ST(i);
1404 0 0         if (! (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV))
    0          
1405 0           croak("Not an array reference");
1406              
1407 0           av = (AV *) SvRV(sv);
1408 0           key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, arg, 0), &key_len);
1409 0           ++arg;
1410              
1411 0 0         if (av_len(av) >= 1)
1412             {
1413             /* exptime doesn't have to be defined. */
1414 0           SV **ps = av_fetch(av, arg, 0);
1415 0 0         if (ps)
1416 0 0         SvGETMAGIC(*ps);
    0          
1417 0 0         if (ps && SvOK(*ps))
    0          
    0          
    0          
1418 0 0         exptime = SvIV(*ps);
1419             }
1420              
1421 0           client_prepare_touch(memd->c, i - 1, key, key_len, exptime);
1422             }
1423 0           client_execute(memd->c, 2);
1424 0 0         if (! noreply)
1425             {
1426 0 0         if (GIMME_V == G_SCALAR)
    0          
1427             {
1428 0           HV *hv = newHV();
1429 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1430             {
1431 0           SV **val = av_fetch(object.arg, i, 0);
1432 0 0         if (val && SvOK(*val))
    0          
    0          
    0          
1433             {
1434             SV *key;
1435             HE *he;
1436              
1437 0           key = ST(i + 1);
1438 0 0         if (SvROK(key))
1439 0           key = *av_fetch((AV *) SvRV(key), 0, 0);
1440              
1441 0           he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
1442 0 0         if (! he)
1443 0           SvREFCNT_dec(*val);
1444             }
1445             }
1446 0           PUSHs(sv_2mortal(newRV_noinc((SV *) hv)));
1447 0           XSRETURN(1);
1448             }
1449             else
1450             {
1451 0           I32 max_index = av_len(object.arg);
1452 0 0         EXTEND(SP, max_index + 1);
    0          
1453 0 0         for (i = 0; i <= max_index; ++i)
1454             {
1455 0           SV **val = av_fetch(object.arg, i, 0);
1456 0 0         if (val)
1457 0           PUSHs(*val);
1458             else
1459 0           PUSHs(&PL_sv_undef);
1460             }
1461 0           XSRETURN(max_index + 1);
1462             }
1463             }
1464              
1465              
1466             HV *
1467             flush_all(memd, ...)
1468             Cache_Memcached_Fast * memd
1469             PROTOTYPE: $;$
1470             PREINIT:
1471 0           delay_type delay = 0;
1472 0           struct result_object object =
1473             { NULL, result_store, NULL, NULL };
1474             int noreply;
1475             CODE:
1476 0           RETVAL = newHV();
1477             /* Why sv_2mortal() is needed is explained in perlxs. */
1478 0           sv_2mortal((SV *) RETVAL);
1479 0           object.arg = sv_2mortal((SV *) newAV());
1480 0 0         if (items > 1)
1481             {
1482 0           SV *sv = ST(1);
1483 0 0         SvGETMAGIC(sv);
    0          
1484 0 0         if (SvOK(sv))
    0          
    0          
1485 0 0         delay = SvUV(sv);
1486             }
1487 0 0         noreply = (GIMME_V == G_VOID);
1488 0           client_flush_all(memd->c, delay, &object, noreply);
1489 0 0         if (! noreply)
1490             {
1491             int i;
1492 0 0         for (i = 0; i <= av_len(object.arg); ++i)
1493             {
1494 0           SV **server = av_fetch(memd->servers, i, 0);
1495 0           SV **version = av_fetch(object.arg, i, 0);
1496 0 0         if (version && SvOK(*version))
    0          
    0          
    0          
1497             {
1498 0           HE *he = hv_store_ent(RETVAL, *server,
1499             SvREFCNT_inc(*version), 0);
1500 0 0         if (! he)
1501 0           SvREFCNT_dec(*version);
1502             }
1503             }
1504             }
1505             OUTPUT:
1506             RETVAL
1507              
1508              
1509             void
1510             nowait_push(memd)
1511             Cache_Memcached_Fast * memd
1512             PROTOTYPE: $
1513             CODE:
1514 0           client_nowait_push(memd->c);
1515              
1516              
1517             HV *
1518             server_versions(memd)
1519             Cache_Memcached_Fast * memd
1520             PROTOTYPE: $
1521             PREINIT:
1522 16           struct result_object object =
1523             { alloc_value, embedded_store, NULL, NULL };
1524             int i;
1525             CODE:
1526 16           RETVAL = newHV();
1527             /* Why sv_2mortal() is needed is explained in perlxs. */
1528 16           sv_2mortal((SV *) RETVAL);
1529 16           object.arg = sv_2mortal((SV *) newAV());
1530 16           client_server_versions(memd->c, &object);
1531 16 50         for (i = 0; i <= av_len(object.arg); ++i)
1532             {
1533 0           SV **server = av_fetch(memd->servers, i, 0);
1534 0           SV **version = av_fetch(object.arg, i, 0);
1535 0 0         if (version && SvOK(*version))
    0          
    0          
    0          
1536             {
1537 0           HE *he = hv_store_ent(RETVAL, *server,
1538             SvREFCNT_inc(*version), 0);
1539 0 0         if (! he)
1540 0           SvREFCNT_dec(*version);
1541             }
1542             }
1543             OUTPUT:
1544             RETVAL
1545              
1546              
1547             SV *
1548             namespace(memd, ...)
1549             Cache_Memcached_Fast * memd
1550             PROTOTYPE: $;$
1551             PREINIT:
1552             const char *ns;
1553             size_t len;
1554             CODE:
1555 0           ns = client_get_prefix(memd->c, &len);
1556 0           RETVAL = newSVpv(ns, len);
1557 0 0         if (items > 1)
1558             {
1559 0 0         ns = SvPV(ST(1), len);
1560 0 0         if (client_set_prefix(memd->c, ns, len) != MEMCACHED_SUCCESS)
1561 0           croak("Not enough memory");
1562             }
1563             OUTPUT:
1564             RETVAL
1565              
1566              
1567             void
1568             disconnect_all(memd)
1569             Cache_Memcached_Fast * memd
1570             PROTOTYPE: $
1571             CODE:
1572 0           client_reinit(memd->c);
1573              
1574              
1575             void
1576             _weaken(sv)
1577             SV *sv
1578             PROTOTYPE: $
1579             CODE:
1580 16           sv_rvweaken(sv);