root/lang/perl/Cache-Memcached-LibMemcached/trunk/perl-libmemcached.c @ 5038

Revision 5038, 18.8 kB (checked in by daisuke, 7 years ago)

lang/perl/Cache-Memcached-LibMemcached?; call compress/serialize via CVs, not SV(w/pv)

Line 
1/* $Id$
2 *
3 * Copyright (c) 2008 Daisuke Maki <daisuke@endeworks.jp>
4 * All rights reserved
5 */
6
7#ifndef __PERL_LIBMEMCACHED_C__
8#define __PERL_LIBMEMCACHED_C__
9#include "perl-libmemcached.h"
10
11#define ASSERT_CALLBACK(x) \
12    if (! SvOK(x) || ! SvROK(x) || SvTYPE(SvRV(x) ) != SVt_PVCV) { \
13        croak("provided argument is not a coderef!"); \
14    }
15
16#define CONSTSUBi(name, x) \
17    { \
18        SV *sv = newSViv(x); \
19        newCONSTSUB(stash, name, sv); \
20        av_push(export, newSVpv(name, PL_na)); \
21    }
22
23void
24Cache_LibMemcached_bootstrap()
25{
26    HV *stash;
27    AV *export;
28
29    stash = gv_stashpv("Cache::Memcached::LibMemcached::Constants", 1);
30    export = get_av("Cache::Memcached::LibMemcached::Constants::EXPORT_OK", 1);
31
32    CONSTSUBi( "F_STORABLE", F_STORABLE );
33    CONSTSUBi( "F_COMPRESS", F_COMPRESS );
34
35    /* There has to be an easier way, eh? */
36    CONSTSUBi( "MEMCACHED_SUCCESS", MEMCACHED_SUCCESS );
37    CONSTSUBi( "MEMCACHED_FAILURE", MEMCACHED_FAILURE );
38    CONSTSUBi( "MEMCACHED_HOST_LOOKUP_FAILURE", MEMCACHED_HOST_LOOKUP_FAILURE );
39    CONSTSUBi( "MEMCACHED_CONNECTION_BIND_FAILURE", MEMCACHED_CONNECTION_BIND_FAILURE );
40    CONSTSUBi( "MEMCACHED_WRITE_FAILURE", MEMCACHED_WRITE_FAILURE );
41    CONSTSUBi( "MEMCACHED_READ_FAILURE", MEMCACHED_READ_FAILURE );
42    CONSTSUBi( "MEMCACHED_UNKNOWN_READ_FAILURE", MEMCACHED_UNKNOWN_READ_FAILURE );
43    CONSTSUBi( "MEMCACHED_PROTOCOL_ERROR", MEMCACHED_PROTOCOL_ERROR );
44    CONSTSUBi( "MEMCACHED_CLIENT_ERROR", MEMCACHED_CLIENT_ERROR );
45    CONSTSUBi( "MEMCACHED_SERVER_ERROR", MEMCACHED_SERVER_ERROR );
46    CONSTSUBi( "MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE", MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE );
47    CONSTSUBi( "MEMCACHED_DATA_EXISTS", MEMCACHED_DATA_EXISTS );
48    CONSTSUBi( "MEMCACHED_DATA_DOES_NOT_EXIST", MEMCACHED_DATA_DOES_NOT_EXIST );
49    CONSTSUBi( "MEMCACHED_NOTSTORED", MEMCACHED_NOTSTORED );
50    CONSTSUBi( "MEMCACHED_STORED", MEMCACHED_STORED );
51    CONSTSUBi( "MEMCACHED_NOTFOUND", MEMCACHED_NOTFOUND );
52    CONSTSUBi( "MEMCACHED_MEMORY_ALLOCATION_FAILURE", MEMCACHED_MEMORY_ALLOCATION_FAILURE );
53    CONSTSUBi( "MEMCACHED_PARTIAL_READ", MEMCACHED_PARTIAL_READ );
54    CONSTSUBi( "MEMCACHED_SOME_ERRORS", MEMCACHED_SOME_ERRORS );
55    CONSTSUBi( "MEMCACHED_NO_SERVERS", MEMCACHED_NO_SERVERS );
56    CONSTSUBi( "MEMCACHED_END", MEMCACHED_END );
57    CONSTSUBi( "MEMCACHED_DELETED", MEMCACHED_DELETED );
58    CONSTSUBi( "MEMCACHED_VALUE", MEMCACHED_VALUE );
59    CONSTSUBi( "MEMCACHED_STAT", MEMCACHED_STAT );
60    CONSTSUBi( "MEMCACHED_ERRNO", MEMCACHED_ERRNO );
61    CONSTSUBi( "MEMCACHED_FAIL_UNIX_SOCKET", MEMCACHED_FAIL_UNIX_SOCKET );
62    CONSTSUBi( "MEMCACHED_NOT_SUPPORTED", MEMCACHED_NOT_SUPPORTED );
63    CONSTSUBi( "MEMCACHED_NO_KEY_PROVIDED", MEMCACHED_NO_KEY_PROVIDED );
64    CONSTSUBi( "MEMCACHED_FETCH_NOTFINISHED", MEMCACHED_FETCH_NOTFINISHED );
65    CONSTSUBi( "MEMCACHED_TIMEOUT", MEMCACHED_TIMEOUT );
66    CONSTSUBi( "MEMCACHED_MAXIMUM_RETURN", MEMCACHED_MAXIMUM_RETURN );
67
68/*
69    CONSTSUBi( "MEMCACHED_BEHAVIOR_NO_BLOCK", MEMCACHED_BEHAVIOR_NO_BLOCK );
70  MEMCACHED_BEHAVIOR_TCP_NODELAY,
71  MEMCACHED_BEHAVIOR_HASH,
72  MEMCACHED_BEHAVIOR_KETAMA,
73  MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
74  MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
75  MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
76  MEMCACHED_BEHAVIOR_SUPPORT_CAS,
77  MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
78  MEMCACHED_BEHAVIOR_DISTRIBUTION,
79*/
80
81    CONSTSUBi( "MEMCACHED_DISTRIBUTION_MODULA", MEMCACHED_DISTRIBUTION_MODULA );
82    CONSTSUBi( "MEMCACHED_DISTRIBUTION_CONSISTENT", MEMCACHED_DISTRIBUTION_CONSISTENT );
83
84    CONSTSUBi( "MEMCACHED_HASH_DEFAULT", MEMCACHED_HASH_DEFAULT );
85    CONSTSUBi( "MEMCACHED_HASH_MD5", MEMCACHED_HASH_MD5 );
86    CONSTSUBi( "MEMCACHED_HASH_CRC", MEMCACHED_HASH_CRC );
87    CONSTSUBi( "MEMCACHED_HASH_FNV1_64", MEMCACHED_HASH_FNV1_64 );
88    CONSTSUBi( "MEMCACHED_HASH_FNV1A_64", MEMCACHED_HASH_FNV1A_64 );
89    CONSTSUBi( "MEMCACHED_HASH_FNV1_32", MEMCACHED_HASH_FNV1_32 );
90    CONSTSUBi( "MEMCACHED_HASH_FNV1A_32", MEMCACHED_HASH_FNV1A_32 );
91    CONSTSUBi( "MEMCACHED_HASH_KETAMA", MEMCACHED_HASH_KETAMA );
92    CONSTSUBi( "MEMCACHED_HASH_HSIEH", MEMCACHED_HASH_HSIEH );
93}
94
95/* The next functions (compress, uncompress, freeze, thaw) are implemented
96 * as simple static method calls emulating a Perl method calls to
97 * Compress::Zlib and Storable, respectively
98 */
99
100inline static void
101Cache_LibMemcached_uncompress(cache, value, value_len, flags)
102        Cache_LibMemcached *cache;
103        char **value;
104        size_t *value_len;
105        uint16_t flags;
106{
107    if (MEMCACHED_HAVE_ZLIB(cache) && (flags & F_COMPRESS)) {
108        SV *sv;
109        dSP;
110
111        ENTER;
112        SAVETMPS;
113
114        PUSHMARK(SP);
115        EXTEND(SP, 1);
116        PUSHs(sv_2mortal(newSVpv(*value, *value_len)));
117        PUTBACK;
118
119        if (call_sv(MEMCACHED_UNCOMPRESS_METHOD(cache), G_SCALAR) <= 0) {
120            croak("uncompress_method did not return a proper value");
121        }
122        SPAGAIN;
123
124        sv = POPs;
125        *value = SvPV(sv, *value_len);
126
127        FREETMPS;
128        LEAVE;
129    }
130}
131
132inline static void
133Cache_LibMemcached_thaw(cache, sv, flags)
134        Cache_LibMemcached *cache;
135        SV *sv;
136        uint16_t flags;
137{
138    if (flags & F_STORABLE) {
139        SV *rv;
140        dSP;
141        ENTER;
142        SAVETMPS;
143
144        PUSHMARK(SP);
145        EXTEND(SP, 1);
146        PUSHs(sv);
147        PUTBACK;
148
149        if (call_sv(MEMCACHED_DESERIALIZE_METHOD(cache), G_SCALAR) <= 0) {
150            croak("deserialize_method did not return a proper value");
151        }
152        SPAGAIN;
153
154        rv = POPs;
155       
156        SvSetSV(sv, rv);
157
158        FREETMPS;
159        LEAVE;
160    }
161}
162
163inline static void
164Cache_LibMemcached_freeze(cache, sv, flags)
165        Cache_LibMemcached *cache;
166        SV *sv;
167        uint16_t *flags;
168{
169    if (SvROK(sv)) {
170        SV *rv;
171        dSP;
172        ENTER;
173        SAVETMPS;
174
175        PUSHMARK(SP);
176        EXTEND(SP, 1);
177        PUSHs(sv);
178        PUTBACK;
179
180        if (call_sv(MEMCACHED_SERIALIZE_METHOD(cache), G_SCALAR) <= 0) {
181            croak("serialize_method did not return a proper value");
182        }
183        SPAGAIN;
184
185        rv = POPs;
186       
187        SvSetSV(sv, rv);
188
189        FREETMPS;
190        LEAVE;
191
192        *flags |= F_STORABLE;
193    }
194}
195
196inline static void
197Cache_LibMemcached_compress(cache, sv, flags)
198        Cache_LibMemcached *cache;
199        SV *sv;
200        uint16_t *flags;
201{
202    size_t compress_threshold;
203    bool   compress_enabled;
204    size_t sv_length = sv_len(sv);
205
206    compress_threshold = MEMCACHED_COMPRESS_THRESHOLD(cache);
207    if (MEMCACHED_HAVE_ZLIB(cache) &&
208        MEMCACHED_COMPRESS_ENABLED(cache) &&
209        compress_threshold > 0 &&
210        sv_length > compress_threshold
211    ) {
212        SV *rv;
213        size_t rv_length;
214        dSP;
215
216        ENTER;
217        SAVETMPS;
218
219        PUSHMARK(SP);
220        EXTEND(SP, 1);
221        PUSHs(sv);
222        PUTBACK;
223
224        if (call_sv(MEMCACHED_COMPRESS_METHOD(cache), G_SCALAR) <= 0) {
225            croak("compress_method did not return a proper value");
226        }
227        SPAGAIN;
228
229        rv = POPs;
230        rv_length = SvCUR(rv);
231
232        /* We won't reset the contents of the original SV unless
233         * the savings are actually greater than the savings threshold
234         */
235        if (rv_length < sv_length * ( 1 - MEMCACHED_COMPRESS_SAVINGS(cache) ) ) {
236            SvSetSV(sv, rv);
237            *flags |= F_COMPRESS;
238        }
239        FREETMPS;
240        LEAVE;
241
242    }
243}
244
245Cache_LibMemcached_rc
246Cache_LibMemcached_set(cache, key, value, expires)
247        Cache_LibMemcached *cache;
248        SV *key;
249        SV *value;
250        time_t expires;
251{
252    STRLEN key_len, value_len;
253    char *key_char;
254    char *value_char;
255    uint16_t flags = 0;
256    SV *value_copy;
257
258    value_copy = newSVsv(value);
259
260    Cache_LibMemcached_freeze(cache, value_copy, &flags);
261    Cache_LibMemcached_compress(cache, value_copy, &flags);
262
263    key_char = SvPVbyte(key, key_len);
264    value_char = SvPVbyte(value_copy, value_len);
265
266    return memcached_set(MEMCACHED_CACHE(cache), key_char, key_len, value_char, value_len, expires, flags);
267}
268
269Cache_LibMemcached_rc
270Cache_LibMemcached_add(cache, key, value, expires)
271        Cache_LibMemcached *cache;
272        SV *key;
273        SV *value;
274        time_t expires;
275{
276    STRLEN key_len, value_len;
277    char *key_char;
278    char *value_char;
279    uint16_t flags = 0;
280    SV *value_copy;
281
282    value_copy = newSVsv(value);
283
284    Cache_LibMemcached_freeze(cache, value_copy, &flags);
285    Cache_LibMemcached_compress(cache, value_copy, &flags);
286
287    key_char = SvPVbyte(key, key_len);
288    value_char = SvPVbyte(value_copy, value_len);
289
290    return memcached_add(MEMCACHED_CACHE(cache), key_char, key_len, value_char, value_len, expires, flags);
291}
292
293Cache_LibMemcached_rc
294Cache_LibMemcached_replace(cache, key, value, expires)
295        Cache_LibMemcached *cache;
296        SV *key;
297        SV *value;
298        time_t expires;
299{
300    STRLEN key_len, value_len;
301    char *key_char;
302    char *value_char;
303    uint16_t flags = 0;
304    SV *value_copy;
305
306    value_copy = newSVsv(value);
307
308    Cache_LibMemcached_freeze(cache, value_copy, &flags);
309    Cache_LibMemcached_compress(cache, value_copy, &flags);
310
311    key_char = SvPVbyte(key, key_len);
312    value_char = SvPVbyte(value_copy, value_len);
313
314    return memcached_replace(MEMCACHED_CACHE(cache), key_char, key_len, value_char, value_len, expires, flags);
315}
316
317SV *
318Cache_LibMemcached_create(pkg, have_zlib, compress_enabled, compress_threshold, compress_savings, compress_method, uncompress_method, serialize_method, deserialize_method)
319        char *pkg;
320        bool have_zlib;
321        bool compress_enabled;
322        size_t compress_threshold;
323        float compress_savings;
324        SV *compress_method;
325        SV *uncompress_method;
326        SV *serialize_method;
327        SV *deserialize_method;
328{
329    SV *sv;
330    Cache_LibMemcached *xs;
331    memcached_st *cache;
332
333    Newxz(xs, 1, Cache_LibMemcached);
334
335    MEMCACHED_CACHE(xs)              = memcached_create(NULL);
336    MEMCACHED_HAVE_ZLIB(xs)          = have_zlib;
337    MEMCACHED_COMPRESS_ENABLED(xs)   = compress_enabled;
338    MEMCACHED_COMPRESS_THRESHOLD(xs) = compress_threshold;
339    MEMCACHED_COMPRESS_SAVINGS(xs)   = compress_savings;
340    MEMCACHED_COMPRESS_METHOD(xs)    = compress_method;
341    MEMCACHED_UNCOMPRESS_METHOD(xs)  = uncompress_method;
342    MEMCACHED_SERIALIZE_METHOD(xs)   = serialize_method;
343    MEMCACHED_DESERIALIZE_METHOD(xs) = deserialize_method;
344
345    SvREFCNT_inc(compress_method);
346    SvREFCNT_inc(uncompress_method);
347    SvREFCNT_inc(serialize_method);
348    SvREFCNT_inc(deserialize_method);
349    ASSERT_CALLBACK( MEMCACHED_SERIALIZE_METHOD(xs) );
350
351    XS_STRUCT2OBJ(sv, "Cache::Memcached::LibMemcached", xs);
352
353    return sv;
354}
355
356void
357Cache_LibMemcached_DESTROY(cache)
358        Cache_LibMemcached *cache;
359{
360    memcached_quit(MEMCACHED_CACHE(cache));
361    memcached_free(MEMCACHED_CACHE(cache));
362    SvREFCNT_dec(MEMCACHED_COMPRESS_METHOD(cache));
363    SvREFCNT_dec(MEMCACHED_UNCOMPRESS_METHOD(cache));
364    SvREFCNT_dec(MEMCACHED_DESERIALIZE_METHOD(cache));
365    SvREFCNT_dec(MEMCACHED_SERIALIZE_METHOD(cache));
366}
367
368Cache_LibMemcached_rc
369Cache_LibMemcached_server_add(cache, hostname, port)
370        Cache_LibMemcached *cache;
371        char *hostname;
372        unsigned int port;
373{
374    return memcached_server_add(MEMCACHED_CACHE(cache), hostname, port);
375}
376
377Cache_LibMemcached_rc
378Cache_LibMemcached_server_add_unix_socket(cache, filename)
379        Cache_LibMemcached *cache;
380        char *filename;
381{
382    return memcached_server_add_unix_socket(MEMCACHED_CACHE(cache), filename);
383}
384
385unsigned int
386Cache_LibMemcached_server_list_count(cache)
387        Cache_LibMemcached *cache;
388{
389    return memcached_server_list_count( MEMCACHED_CACHE(cache)->hosts );
390}
391
392void
393Cache_LibMemcached_server_list_free(cache)
394        Cache_LibMemcached *cache;
395{
396    memcached_server_list_free( MEMCACHED_CACHE(cache)->hosts );
397}
398
399SV *
400Cache_LibMemcached_get(cache, key)
401        Cache_LibMemcached *cache;
402        SV *key;
403{
404    STRLEN key_len;
405    size_t value_len = 0;
406    char *key_char, *value;
407    Cache_LibMemcached_rc rc;
408    uint16_t flags;
409    SV *sv;
410
411    key_char = SvPVbyte(key, key_len);
412   
413    value = memcached_get(MEMCACHED_CACHE(cache), key_char, key_len, &value_len, &flags, &rc);
414    if (!value || rc != MEMCACHED_SUCCESS) {
415        return &PL_sv_undef;
416    }
417
418    Cache_LibMemcached_uncompress( cache, &value, &value_len, flags );
419    sv = newSVpv(value, value_len);
420
421    Cache_LibMemcached_thaw( cache, sv, flags );
422
423    return sv;
424}
425
426SV *
427Cache_LibMemcached_mget(cache, keys, key_len_list, keys_len)
428        Cache_LibMemcached *cache;
429        char **keys;
430        size_t *key_len_list;
431        unsigned int keys_len;
432{
433    Cache_LibMemcached_rc rc;
434    HV *hv;
435    unsigned int i;
436
437    rc = memcached_mget(MEMCACHED_CACHE(cache), keys, key_len_list, keys_len);
438    if (rc != MEMCACHED_SUCCESS) {
439        memcached_quit(MEMCACHED_CACHE(cache));
440        croak("memcached_mget failed :(");
441    }
442
443    hv = newHV();
444    for(i = 0; i < keys_len; i++) {
445/*    while (1) {*/
446        char *value;
447        char key[MEMCACHED_MAX_KEY];
448        size_t key_length = 0;
449        size_t value_length = 0;
450        uint16_t flags = 0;
451        Cache_LibMemcached_rc rc;
452        SV *sv;
453
454        value = memcached_fetch(MEMCACHED_CACHE(cache), key, &key_length, &value_length, &flags, &rc);
455        if (value == NULL) {
456            break;
457        }
458
459        Cache_LibMemcached_uncompress( cache, &value, &value_length, flags );
460
461        sv = newSVpv(value, value_length);
462
463        Cache_LibMemcached_thaw( cache, sv, flags );
464
465        SvREFCNT_inc(sv);
466        if (hv_store_ent(hv, newSVpv(key, key_length), sv, 0) == NULL) {
467            croak("Failed to insert into hash");
468        }
469    }
470
471    return newRV_noinc((SV *) hv);
472}
473
474SV *
475Cache_LibMemcached_delete(cache, key_sv, expiration)
476        Cache_LibMemcached *cache;
477        SV *key_sv;
478        time_t expiration;
479{
480    char *key;
481    size_t key_len;
482    Cache_LibMemcached_rc rc;
483
484    key = SvPVbyte(key_sv, key_len);
485
486    rc = memcached_delete(MEMCACHED_CACHE(cache), key, key_len, expiration);
487    return (rc == MEMCACHED_SUCCESS) ?
488        &PL_sv_yes : &PL_sv_no
489    ;
490}
491
492SV *
493Cache_LibMemcached_incr(cache, key_sv, offset)
494        Cache_LibMemcached *cache;
495        SV *key_sv;
496        unsigned int offset;
497{
498    char *key;
499    size_t key_len;
500    uint64_t value;
501    Cache_LibMemcached_rc rc;
502
503    key = SvPVbyte(key_sv, key_len);
504
505    rc = memcached_increment(MEMCACHED_CACHE(cache), key, key_len, offset, &value);
506
507    if (rc != MEMCACHED_SUCCESS) {
508        return &PL_sv_undef;
509    }
510
511    return newSViv(value);
512}
513
514SV *
515Cache_LibMemcached_decr(cache, key_sv, offset)
516        Cache_LibMemcached *cache;
517        SV *key_sv;
518        unsigned int offset;
519{
520    char *key;
521    size_t key_len;
522    uint64_t value;
523    Cache_LibMemcached_rc rc;
524
525    key = SvPVbyte(key_sv, key_len);
526
527    rc = memcached_decrement(MEMCACHED_CACHE(cache), key, key_len, offset, &value);
528
529    if (rc != MEMCACHED_SUCCESS) {
530        return &PL_sv_undef;
531    }
532
533    return newSViv(value);
534}
535
536Cache_LibMemcached_rc
537Cache_LibMemcached_flush_all(cache, expiration)
538        Cache_LibMemcached *cache;
539        time_t expiration;
540{
541    return memcached_flush( MEMCACHED_CACHE(cache), expiration );
542}
543
544void
545Cache_LibMemcached_set_no_block(cache, value)
546        Cache_LibMemcached *cache;
547        IV value;
548{
549    memcached_behavior_set( MEMCACHED_CACHE(cache),
550        MEMCACHED_BEHAVIOR_NO_BLOCK, (void *) value );
551}
552
553IV
554Cache_LibMemcached_is_no_block(cache)
555        Cache_LibMemcached *cache;
556{
557    return memcached_behavior_get( MEMCACHED_CACHE(cache),
558        MEMCACHED_BEHAVIOR_NO_BLOCK );
559}
560
561void
562Cache_LibMemcached_set_distribution_method(cache, value)
563        Cache_LibMemcached *cache;
564        IV value;
565{
566    memcached_behavior_set( MEMCACHED_CACHE(cache),
567        MEMCACHED_BEHAVIOR_DISTRIBUTION, &value );
568}
569
570IV
571Cache_LibMemcached_get_distribution_method(cache)
572        Cache_LibMemcached *cache;
573{
574    return memcached_behavior_get( MEMCACHED_CACHE(cache),
575        MEMCACHED_BEHAVIOR_DISTRIBUTION );
576}
577
578void
579Cache_LibMemcached_set_hashing_algorithm(cache, value)
580        Cache_LibMemcached *cache;
581        IV value;
582{
583    memcached_behavior_set( MEMCACHED_CACHE(cache),
584        MEMCACHED_BEHAVIOR_HASH, &value );
585}
586
587IV
588Cache_LibMemcached_get_hashing_algorithm(cache)
589        Cache_LibMemcached *cache;
590{
591    return memcached_behavior_get( MEMCACHED_CACHE(cache),
592        MEMCACHED_BEHAVIOR_HASH );
593}
594
595Cache_LibMemcached_rc
596Cache_LibMemcached_populate_stathv(cache, hv, stat)
597        Cache_LibMemcached *cache;
598        HV *hv;
599        Cache_LibMemcached_stat stat;
600{
601    Cache_LibMemcached_rc rc;
602    char **list;
603    char **ptr;
604
605    list = memcached_stat_get_keys(MEMCACHED_CACHE(cache), &stat, &rc);
606    if (rc != MEMCACHED_SUCCESS)
607        return rc;
608
609    for(ptr = list; *ptr; ptr++) {
610        SV *key, *sv;
611        char *value;
612
613        value = memcached_stat_get_value(
614            MEMCACHED_CACHE(cache),
615            &stat,
616            *ptr,
617            &rc
618        );
619        if (rc != MEMCACHED_SUCCESS) {
620            free(value);
621            break;
622        }
623        key = newSVpvf("%s", *ptr);
624        sv  = newSVpvf("%s", value);
625        if (hv_store_ent(hv, key, sv, 0) == NULL) {
626            /* croak("Failed to insert into hash"); */
627            free(value);
628            break;
629        }
630        free(value);
631    }
632    free(list);
633
634    return rc;
635}
636       
637
638/* This is so half-baked, it's not even funny */
639SV *
640Cache_LibMemcached_stats(cache)
641        Cache_LibMemcached *cache;
642{
643    Cache_LibMemcached_rc   rc;
644    Cache_LibMemcached_stat *stat;
645    memcached_server_st *server_list;
646    unsigned int i;
647    unsigned int server_count;
648    HV *hv, *hosts_hv, *single_host_hv;
649
650    stat = memcached_stat(MEMCACHED_CACHE(cache), NULL, &rc);
651    if (rc != MEMCACHED_SUCCESS)
652        croak("memcached_stat failed: %s", memcached_strerror(MEMCACHED_CACHE(cache), rc));
653
654    /* need a structure like
655     *   { hosts => {
656     *      "server:port" => {
657     *          key => value
658     *      }
659     *    }
660     */
661
662    hosts_hv = newHV();
663    server_list  = memcached_server_list(MEMCACHED_CACHE(cache));
664    server_count = memcached_server_count(MEMCACHED_CACHE(cache));
665    for (i = 0; i < server_count; i++) {
666        SV *key;
667        single_host_hv = newHV();
668
669        rc = Cache_LibMemcached_populate_stathv(cache, single_host_hv, stat[i]);
670        if (rc != MEMCACHED_SUCCESS)
671            break;
672
673        key = newSVpvf("%s:%u",
674            memcached_server_name(cache, server_list[i]),
675            memcached_server_port(cache, server_list[i])
676        );
677        if (hv_store_ent(hosts_hv, key, newRV_inc((SV *) single_host_hv), 0) == NULL) {
678            /* croak("Failed to insert into hash"); */
679            break;
680        }
681    }
682    free(stat);
683   
684    hv = newHV(); /* top level hash */
685    if (hv_store_ent(hv, newSVpv("hosts", 5), newRV_inc((SV *) hosts_hv), 0) == NULL) {
686        croak("Failed insert into hash");
687    }
688    return newRV_inc((SV *) hv);
689}
690
691void
692Cache_LibMemcached_disconnect_all(cache)
693        Cache_LibMemcached *cache;
694{
695    memcached_quit(MEMCACHED_CACHE(cache));
696}
697
698#endif /* __PERL_LIBMEMCACHED_C__ */
Note: See TracBrowser for help on using the browser.