source: Fast.xs @ e2906f

Revision e2906f, 32.3 KB checked in by Tomash Brechko <tomash.brechko@…>, 22 months ago (diff)

Fix RT#56142: handle Perl magic.

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