root/lang/perl/Cache-Memcached-Fast-0.12/Fast.xs @ 38927

Revision 19958, 30.9 kB (checked in by mattn, 5 years ago)

- imported Cache-Memcached-Fast-0.12 (I'll work for porting to win32 later)

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