/[pgmemcache]/upstream/1.0/pgmemcache.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /upstream/1.0/pgmemcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Thu Jul 20 09:57:30 2006 UTC (17 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 19760 byte(s)
import upstream version 1.0
1 dpavlin 2 /*
2     * PostgreSQL functions to interface with memcache.
3     *
4     * $PostgreSQL: pgmemcache/pgmemcache.c,v 1.6 2004/12/29 18:20:57 seanc Exp $
5     *
6     * Copyright (c) 2004 Sean Chittenden <sean@chittenden.org>
7     *
8     * Permission is hereby granted, free of charge, to any person
9     * obtaining a copy of this software and associated documentation
10     * files (the "Software"), to deal in the Software without
11     * restriction, including without limitation the rights to use, copy,
12     * modify, merge, publish, distribute, sublicense, and/or sell copies
13     * of the Software, and to permit persons to whom the Software is
14     * furnished to do so, subject to the following conditions:
15     *
16     * The above copyright notice and this permission notice shall be
17     * included in all copies or substantial portions of the Software.
18     *
19     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23     * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24     * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26     * SOFTWARE.
27     *
28     * http://people.FreeBSD.org/~seanc/pgmemcache/
29     */
30    
31     #include "postgres.h"
32     #include "fmgr.h"
33     #include "executor/spi.h"
34     #include "lib/stringinfo.h"
35     #include "utils/datetime.h"
36     #include "utils/palloc.h"
37    
38     #include "pgmemcache.h"
39    
40     /* Global memcache instance. */
41     static struct memcache *mc = NULL;
42     static struct memcache_ctxt *ctxt = NULL;
43    
44     /* Add a small work around function to compensate for PostgreSQLs lack
45     * of actual memory functions: PostgreSQL supplies macros instead. */
46     inline static void mcm_pfree(void *ptr);
47     inline static void *mcm_palloc(const size_t size);
48     inline static void *mcm_repalloc(void *ptr, const size_t size);
49     static bool _memcache_init(void);
50     static Datum memcache_atomic_op(int type, PG_FUNCTION_ARGS);
51     static text *memcache_gen_host(const struct memcache_server *ms);
52     static Datum memcache_set_cmd(int type, PG_FUNCTION_ARGS);
53    
54     #define MCM_SET_CMD_TYPE_ADD 0x0001
55     #define MCM_SET_CMD_TYPE_REPLACE 0x0002
56     #define MCM_SET_CMD_TYPE_SET 0x0004
57    
58     #define MCM_DATE_TYPE_INTERVAL 0x0010
59     #define MCM_DATE_TYPE_TIMESTAMP 0x0020
60    
61     #define MCM_ATOMIC_TYPE_DECR 0x0040
62     #define MCM_ATOMIC_TYPE_INCR 0x0080
63    
64     /* Don't add a server until a caller has called memcache_init(). This
65     * is probably an unnecessary degree of explicitness, but it forces
66     * good calling conventions for pgmemcache. */
67     #define MCM_CHECK(_ret) do { \
68     if (mc == NULL || ctxt == NULL) { \
69     elog(ERROR, "%s(): mc is NULL, call memcache_init()", __FUNCTION__); \
70     _ret; \
71     } \
72     } while(0)
73    
74     /* Add a small work around function to compensate for PostgreSQLs lack
75     * of a palloc(3), pfree(3), and prealloc(3) functions. They exist,
76     * but are macros, which is useless with regards to function pointers
77     * if the macro doesn't have the same signature. Create that
78     * signature here. */
79     inline static void
80     mcm_pfree(void *ptr) {
81     return pfree(ptr);
82     }
83    
84    
85     inline static void *
86     mcm_palloc(const size_t size) {
87     return palloc(size);
88     }
89    
90    
91     inline static void *
92     mcm_repalloc(void *ptr, const size_t size) {
93     return repalloc(ptr, size);
94     }
95    
96    
97     Datum
98     memcache_add(PG_FUNCTION_ARGS) {
99     return memcache_set_cmd(MCM_SET_CMD_TYPE_ADD | MCM_DATE_TYPE_INTERVAL, fcinfo);
100     }
101    
102    
103     Datum
104     memcache_add_absexpire(PG_FUNCTION_ARGS) {
105     return memcache_set_cmd(MCM_SET_CMD_TYPE_ADD | MCM_DATE_TYPE_TIMESTAMP, fcinfo);
106     }
107    
108    
109     static Datum
110     memcache_atomic_op(int type, PG_FUNCTION_ARGS) {
111     text *key;
112     size_t key_len;
113     u_int32_t val,
114     ret = 0;
115    
116     MCM_CHECK(PG_RETURN_NULL());
117    
118     SPI_connect();
119    
120     key = PG_GETARG_TEXT_P(0);
121     key_len = VARSIZE(key) - VARHDRSZ;
122     if (key_len < 1)
123     elog(ERROR, "Unable to have a zero length key");
124    
125     val = 1;
126     if (fcinfo->arg[1] != NULL && !PG_ARGISNULL(1)) {
127     val = PG_GETARG_UINT32(1);
128     }
129    
130     if (type & MCM_ATOMIC_TYPE_DECR)
131     ret = mcm_decr(ctxt, mc, VARDATA(key), key_len, val);
132     else if (type & MCM_ATOMIC_TYPE_INCR)
133     ret = mcm_incr(ctxt, mc, VARDATA(key), key_len, val);
134     else
135     elog(ERROR, "%s():%s:%u\tunknown atomic type 0x%x", __FUNCTION__, __FILE__, __LINE__, type);
136    
137     SPI_finish();
138    
139     PG_RETURN_UINT32(ret);
140     }
141    
142    
143     Datum
144     memcache_decr(PG_FUNCTION_ARGS) {
145     return memcache_atomic_op(MCM_ATOMIC_TYPE_DECR, fcinfo);
146     }
147    
148    
149     Datum
150     memcache_delete(PG_FUNCTION_ARGS) {
151     text *key;
152     size_t key_len;
153     Interval *span;
154     float8 hold;
155     int ret;
156    
157     MCM_CHECK(PG_RETURN_NULL());
158    
159     SPI_connect();
160    
161     key = PG_GETARG_TEXT_P(0);
162     key_len = VARSIZE(key) - VARHDRSZ;
163     if (key_len < 1)
164     elog(ERROR, "Unable to have a zero length key");
165    
166     hold = 0.0;
167     if (fcinfo->arg[1] != NULL && !PG_ARGISNULL(1)) {
168     span = PG_GETARG_INTERVAL_P(1);
169    
170     #ifdef HAVE_INT64_TIMESTAMP
171     hold = (span->time / 1000000e0);
172     #else
173     hold = span->time;
174     #endif
175     if (span->month != 0) {
176     hold += ((365.25 * 86400) * (span->month / 12));
177     hold += ((30.0 * 86400) * (span->month % 12));
178     }
179     }
180    
181     ret = mcm_delete(ctxt, mc, VARDATA(key), key_len, (time_t)hold);
182    
183     SPI_finish();
184    
185     if (ret == 0)
186     PG_RETURN_BOOL(true);
187     else if (ret > 0)
188     PG_RETURN_BOOL(false);
189     else
190     elog(ERROR, "Internal libmemcache(3) error");
191    
192     PG_RETURN_BOOL(ret);
193     }
194    
195    
196     /* Depreciated: use memcache_flush() */
197     Datum
198     memcache_flush_all(PG_FUNCTION_ARGS) {
199     return memcache_flush(fcinfo);
200     }
201    
202    
203     Datum
204     memcache_flush_all0(PG_FUNCTION_ARGS) {
205     text *key;
206     size_t key_len;
207     int ret;
208    
209     MCM_CHECK(PG_RETURN_NULL());
210    
211     SPI_connect();
212    
213     key = PG_GETARG_TEXT_P(0);
214     key_len = VARSIZE(key) - VARHDRSZ;
215     if (key_len < 1)
216     elog(ERROR, "Unable to have a zero length key");
217    
218     ret = mcm_flush_all(ctxt, mc);
219    
220     SPI_finish();
221    
222     if (ret == 0)
223     PG_RETURN_BOOL(true);
224     else if (ret > 0)
225     PG_RETURN_BOOL(false);
226     else
227     elog(ERROR, "Internal libmemcache(3) error");
228    
229     PG_RETURN_BOOL(ret);
230     }
231    
232    
233     Datum
234     memcache_flush(PG_FUNCTION_ARGS) {
235     struct memcache_server *ms;
236     text *key;
237     size_t key_len;
238     int ret;
239     u_int32_t hash;
240    
241     MCM_CHECK(PG_RETURN_NULL());
242    
243     SPI_connect();
244    
245     key = PG_GETARG_TEXT_P(0);
246     key_len = VARSIZE(key) - VARHDRSZ;
247     if (key_len < 1)
248     elog(ERROR, "Unable to have a zero length key");
249    
250     hash = mcm_hash_key(ctxt, VARDATA(key), key_len);
251     ms = mcm_server_find(ctxt, mc, hash);
252    
253     ret = mcm_flush(ctxt, mc, ms);
254    
255     SPI_finish();
256    
257     if (ret == 0)
258     PG_RETURN_BOOL(true);
259     else if (ret > 0)
260     PG_RETURN_BOOL(false);
261     else
262     elog(ERROR, "Internal libmemcache(3) error");
263    
264     PG_RETURN_BOOL(ret);
265     }
266    
267    
268     Datum
269     memcache_free(PG_FUNCTION_ARGS) {
270     MCM_CHECK(PG_RETURN_BOOL(false));
271    
272     SPI_connect();
273    
274     mcm_free(ctxt, mc);
275     mc = NULL;
276    
277     mcMemFreeCtxt(ctxt);
278     ctxt = NULL;
279    
280     SPI_finish();
281    
282     PG_RETURN_BOOL(true);
283     }
284    
285    
286     Datum
287     memcache_get(PG_FUNCTION_ARGS) {
288     text *key,
289     *ret;
290     size_t key_len;
291     struct memcache_req *req;
292     struct memcache_res *res;
293    
294     MCM_CHECK(PG_RETURN_NULL());
295    
296     SPI_connect();
297    
298     key = PG_GETARG_TEXT_P(0);
299     key_len = VARSIZE(key) - VARHDRSZ;
300     if (key_len < 1)
301     elog(ERROR, "Unable to have a zero length key");
302    
303     req = mcm_req_new(ctxt);
304     if (req == NULL)
305     elog(ERROR, "Unable to create a new memcache request structure");
306    
307     res = mcm_req_add(ctxt, req, VARDATA(key), key_len);
308     if (res == NULL)
309     elog(ERROR, "Unable to create a new memcache responose structure");
310    
311     mcm_get(ctxt, mc, req);
312    
313     if (!(res->_flags & MCM_RES_FOUND)) {
314     SPI_finish();
315     PG_RETURN_NULL();
316     }
317    
318     ret = (text *)SPI_palloc(res->bytes + VARHDRSZ);
319     VARATT_SIZEP(ret) = res->bytes + VARHDRSZ;
320     memcpy(VARDATA(ret), res->val, res->bytes);
321    
322     SPI_finish();
323    
324     PG_RETURN_TEXT_P(ret);
325     }
326    
327    
328     Datum
329     memcache_hash(PG_FUNCTION_ARGS) {
330     text *key;
331     size_t key_len;
332     u_int32_t hash;
333    
334     SPI_connect();
335    
336     key = PG_GETARG_TEXT_P(0);
337     key_len = VARSIZE(key) - VARHDRSZ;
338     if (key_len < 1)
339     elog(ERROR, "Unable to have a zero length key");
340    
341     hash = mcm_hash_key(ctxt, VARDATA(key), key_len);
342    
343     SPI_finish();
344    
345     PG_RETURN_UINT32(hash);
346     }
347    
348    
349     Datum
350     memcache_incr(PG_FUNCTION_ARGS) {
351     return memcache_atomic_op(MCM_ATOMIC_TYPE_INCR, fcinfo);
352     }
353    
354    
355     Datum
356     memcache_init(PG_FUNCTION_ARGS) {
357     bool ret;
358    
359     SPI_connect();
360     ret = _memcache_init();
361     SPI_finish();
362     PG_RETURN_BOOL(ret);
363     }
364    
365    
366     /* Caller of _memcache_init() must call SPI_connect() before calling
367     * _memcache_init(). */
368     static bool
369     _memcache_init(void) {
370     MemoryContext oc;
371    
372     /* Return FALSE that way callers can conditionally add servers to
373     * the instance. */
374     if (ctxt != NULL)
375     return false;
376    
377     /* Make sure mc is allocated in the top memory context */
378     oc = MemoryContextSwitchTo(TopMemoryContext);
379    
380     /* Initialize libmemcache's memory functions */
381     ctxt = mcMemNewCtxt(mcm_pfree, mcm_palloc, NULL, mcm_repalloc);
382     if (ctxt == NULL)
383     elog(ERROR, "memcache_init: unable to create a memcache(3) memory context");
384    
385     mc = mcm_new(ctxt);
386     if (mc == NULL)
387     elog(ERROR, "memcache_init: unable to allocate memory");
388    
389     /* Return to old memory context */
390     MemoryContextSwitchTo(oc);
391    
392     return true;
393     }
394    
395    
396     Datum
397     memcache_replace(PG_FUNCTION_ARGS) {
398     return memcache_set_cmd(MCM_SET_CMD_TYPE_REPLACE | MCM_DATE_TYPE_INTERVAL, fcinfo);
399     }
400    
401    
402     Datum
403     memcache_replace_absexpire(PG_FUNCTION_ARGS) {
404     return memcache_set_cmd(MCM_SET_CMD_TYPE_REPLACE | MCM_DATE_TYPE_TIMESTAMP, fcinfo);
405     }
406    
407    
408     Datum
409     memcache_set(PG_FUNCTION_ARGS) {
410     return memcache_set_cmd(MCM_SET_CMD_TYPE_SET | MCM_DATE_TYPE_INTERVAL, fcinfo);
411     }
412    
413    
414     Datum
415     memcache_set_absexpire(PG_FUNCTION_ARGS) {
416     return memcache_set_cmd(MCM_SET_CMD_TYPE_SET | MCM_DATE_TYPE_TIMESTAMP, fcinfo);
417     }
418    
419    
420     static Datum
421     memcache_set_cmd(int type, PG_FUNCTION_ARGS) {
422     text *key,
423     *val_t;
424     char *val;
425     size_t key_len, val_len;
426     Interval *span;
427     float8 expire;
428     TimestampTz timestamptz;
429     struct pg_tm tm;
430     fsec_t fsec;
431     u_int16_t flags;
432     int ret = 0;
433    
434     MCM_CHECK(PG_RETURN_BOOL(false));
435    
436     SPI_connect();
437    
438     if (PG_ARGISNULL(0)) {
439     elog(ERROR, "Unable to have a NULL key");
440     }
441     key = PG_GETARG_TEXT_P(0);
442     key_len = VARSIZE(key) - VARHDRSZ;
443     if (key_len < 1)
444     elog(ERROR, "Unable to have a zero length key");
445    
446     if (fcinfo->arg[1] == NULL || PG_ARGISNULL(1)) {
447     val_t = NULL;
448     val = NULL;
449     val_len = 0;
450     } else {
451     val_t = PG_GETARG_TEXT_P(1);
452     val = (char *)VARDATA(val_t);
453     val_len = VARSIZE(val_t) - VARHDRSZ;
454     }
455    
456     expire = 0.0;
457     if (fcinfo->arg[2] != NULL && !PG_ARGISNULL(2)) {
458     if (type & MCM_DATE_TYPE_INTERVAL) {
459     span = PG_GETARG_INTERVAL_P(2);
460     #ifdef HAVE_INT64_TIMESTAMP
461     expire = (span->time / 1000000e0);
462     #else
463     expire = span->time;
464     #endif
465     if (span->month != 0) {
466     expire += ((365.25 * 86400) * (span->month / 12));
467     expire += ((30.0 * 86400) * (span->month % 12));
468     }
469     } else if (type & MCM_DATE_TYPE_TIMESTAMP) {
470     timestamptz = PG_GETARG_TIMESTAMPTZ(2);
471    
472     /* convert to timestamptz to produce consistent results */
473     if (timestamp2tm(timestamptz, NULL, &tm, &fsec, NULL) !=0)
474     ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
475     errmsg("timestamp out of range")));
476    
477     #ifdef HAVE_INT64_TIMESTAMP
478     expire = ((timestamptz - SetEpochTimestamp()) / 1000000e0);
479     #else
480     expire = timestamptz - SetEpochTimestamp();
481     #endif
482     } else {
483     elog(ERROR, "%s():%s:%u: invalid date type", __FUNCTION__, __FILE__, __LINE__);
484     }
485     }
486    
487     flags = 0;
488     if (fcinfo->arg[3] != NULL && !PG_ARGISNULL(3))
489     flags = PG_GETARG_INT16(3);
490    
491     if (type & MCM_SET_CMD_TYPE_ADD)
492     ret = mcm_add(ctxt, mc, VARDATA(key), key_len, val, val_len, (time_t)expire, flags);
493     else if (type & MCM_SET_CMD_TYPE_REPLACE)
494     ret = mcm_add(ctxt, mc, VARDATA(key), key_len, val, val_len, (time_t)expire, flags);
495     else if (type & MCM_SET_CMD_TYPE_SET)
496     ret = mcm_add(ctxt, mc, VARDATA(key), key_len, val, val_len, (time_t)expire, flags);
497     else
498     elog(ERROR, "%s():%s:%u\tunknown set type 0x%x", __FUNCTION__, __FILE__, __LINE__, type);
499    
500     SPI_finish();
501     if (ret == 0)
502     PG_RETURN_BOOL(true);
503     else if (ret > 0)
504     PG_RETURN_BOOL(false);
505     else
506     elog(ERROR, "Internal libmemcache(3) error");
507    
508     /* Not reached */
509     abort();
510     }
511    
512    
513     Datum
514     memcache_server_add(PG_FUNCTION_ARGS) {
515     text *server, *port;
516     int ret;
517     MemoryContext oc;
518    
519     MCM_CHECK(PG_RETURN_BOOL(false));
520    
521     SPI_connect();
522    
523     /* Make sure new servers are in the top memory context */
524     oc = MemoryContextSwitchTo(TopMemoryContext);
525    
526     server = PG_GETARG_TEXT_P(0);
527     port = PG_GETARG_TEXT_P(1);
528    
529     elog(DEBUG1, "%s(): host=\"%.*s\" port=\"%.*s\"", __FUNCTION__, VARSIZE(server) - VARHDRSZ, VARDATA(server), VARSIZE(port) - VARHDRSZ, VARDATA(port));
530    
531     /* Add the server and port */
532     ret = mcm_server_add2(ctxt, mc, VARDATA(server), VARSIZE(server) - VARHDRSZ, VARDATA(port), VARSIZE(port) - VARHDRSZ);
533     if (ret < 0) {
534     elog(NOTICE, "%s(): libmemcache unable to add server: %d", __FUNCTION__, ret);
535     MemoryContextSwitchTo(oc);
536     SPI_finish();
537     PG_RETURN_BOOL(false);
538     }
539    
540     /* Return to current context */
541     MemoryContextSwitchTo(oc);
542    
543     SPI_finish();
544    
545     PG_RETURN_BOOL(true);
546     }
547    
548    
549     static text *
550     memcache_gen_host(const struct memcache_server *ms) {
551     text *ret;
552     char *cp;
553    
554     ret = (text *)SPI_palloc(strlen(ms->hostname) + strlen(ms->port) + 1); /* + 1 is for the colon */
555     VARATT_SIZEP(ret) = strlen(ms->hostname) + strlen(ms->port) + 1 + VARHDRSZ;
556     cp = VARDATA(ret);
557    
558     /* Copy the hostname */
559     if (ms->hostname != NULL)
560     memcpy(cp, ms->hostname, strlen(ms->hostname));
561    
562     /* Advance the pointer */
563     cp += strlen(ms->hostname);
564    
565     /* Add a colon and advance the pointer */
566     cp[0] = ':';
567     cp++;
568    
569     /* Copy the port */
570     if (ms->port != NULL)
571     memcpy(cp, ms->port, strlen(ms->port));
572    
573     return ret;
574     }
575    
576    
577     Datum
578     memcache_server_find(PG_FUNCTION_ARGS) {
579     struct memcache_server *ms;
580     text *key, *ret;
581     u_int32_t hash;
582     size_t key_len;
583    
584     MCM_CHECK(PG_RETURN_BOOL(false));
585    
586     SPI_connect();
587    
588     key = PG_GETARG_TEXT_P(0);
589     key_len = VARSIZE(key) - VARHDRSZ;
590     if (key_len < 1)
591     elog(ERROR, "Unable to have a zero length key");
592    
593     hash = mcm_hash_key(ctxt, VARDATA(key), key_len);
594     ms = mcm_server_find(ctxt, mc, hash);
595     ret = memcache_gen_host(ms);
596    
597     SPI_finish();
598    
599     PG_RETURN_TEXT_P(ret);
600     }
601    
602    
603     Datum
604     memcache_server_find_hash(PG_FUNCTION_ARGS) {
605     struct memcache_server *ms;
606     text *ret;
607    
608     MCM_CHECK(PG_RETURN_BOOL(false));
609    
610     SPI_connect();
611    
612     ms = mcm_server_find(ctxt, mc, PG_GETARG_UINT32(0));
613     ret = memcache_gen_host(ms);
614    
615     SPI_finish();
616    
617     PG_RETURN_TEXT_P(ret);
618     }
619    
620    
621     Datum
622     memcache_stats(PG_FUNCTION_ARGS) {
623     struct memcache_server_stats *stats;
624     text *ret;
625     StringInfo str;
626    
627     MCM_CHECK(PG_RETURN_NULL());
628    
629     SPI_connect();
630    
631     stats = mcm_stats(ctxt, mc);
632     if (stats == NULL)
633     elog(ERROR, "Unable to create a new memcache stats structure");
634    
635     str = makeStringInfo();
636     if (str == NULL)
637     elog(ERROR, "Unable to create a new string object for stats");
638    
639     appendStringInfo(str, "pid: %u\n", stats->pid);
640     appendStringInfo(str, "uptime: %llu\n", (uint64)stats->uptime);
641     appendStringInfo(str, "time: %llu\n", (uint64)stats->time);
642     appendStringInfo(str, "version: %s\n", stats->version);
643     appendStringInfo(str, "rusage_user: %u.%us\n", stats->rusage_user.tv_sec, stats->rusage_user.tv_usec);
644     appendStringInfo(str, "rusage_system: %u.%us\n", stats->rusage_system.tv_sec, stats->rusage_system.tv_usec);
645     appendStringInfo(str, "curr_items: %u\n", stats->curr_items);
646     appendStringInfo(str, "total_items: %llu\n", stats->total_items);
647     appendStringInfo(str, "bytes: %llu\n", stats->bytes);
648     appendStringInfo(str, "curr_connections: %u\n", stats->curr_connections);
649     appendStringInfo(str, "total_connections: %llu\n", stats->total_connections);
650     appendStringInfo(str, "connection_structures: %u\n", stats->connection_structures);
651     appendStringInfo(str, "cmd_get: %llu\n", stats->cmd_get);
652     appendStringInfo(str, "cmd_set: %llu\n", stats->cmd_set);
653     appendStringInfo(str, "get_hits: %llu\n", stats->get_hits);
654     appendStringInfo(str, "get_misses: %llu\n", stats->get_misses);
655     appendStringInfo(str, "bytes_read: %llu\n", stats->bytes_read);
656     appendStringInfo(str, "bytes_written: %llu\n", stats->bytes_written);
657     appendStringInfo(str, "limit_maxbytes: %llu\n", stats->limit_maxbytes);
658    
659     ret = (text *)SPI_palloc(str->len + VARHDRSZ);
660     VARATT_SIZEP(ret) = str->len + VARHDRSZ;
661     memcpy(VARDATA(ret), str->data, str->len);
662    
663     SPI_finish();
664    
665     PG_RETURN_TEXT_P(ret);
666     }
667    
668    
669     Datum
670     memcache_stat(PG_FUNCTION_ARGS) {
671     struct memcache_server_stats *stats;
672     text *ret, *stat;
673     size_t stat_len;
674     StringInfo str;
675    
676     MCM_CHECK(PG_RETURN_NULL());
677    
678     SPI_connect();
679    
680     stat = PG_GETARG_TEXT_P(0);
681     stat_len = VARSIZE(stat) - VARHDRSZ;
682     if (stat_len < 1)
683     elog(ERROR, "Unable to have a zero length stat");
684    
685     stats = mcm_stats(ctxt, mc);
686     if (stats == NULL)
687     elog(ERROR, "Unable to create a new memcache stats structure");
688    
689     str = makeStringInfo();
690     if (str == NULL)
691     elog(ERROR, "Unable to create a new string object for stats");
692    
693     if (pg_strncasecmp("pid", VARDATA(stat), stat_len) == 0)
694     appendStringInfo(str, "%u", stats->pid);
695     else if (pg_strncasecmp("uptime", VARDATA(stat), stat_len) == 0)
696     appendStringInfo(str, "%llu", (uint64)stats->uptime);
697     else if (pg_strncasecmp("time", VARDATA(stat), stat_len) == 0)
698     appendStringInfo(str, "%llu", (uint64)stats->time);
699     else if (pg_strncasecmp("version", VARDATA(stat), stat_len) == 0)
700     appendStringInfo(str, "%s", stats->version);
701     else if (pg_strncasecmp("rusage_user", VARDATA(stat), stat_len) == 0)
702     appendStringInfo(str, "%u.%u", stats->rusage_user.tv_sec, stats->rusage_user.tv_usec);
703     else if (pg_strncasecmp("rusage_system", VARDATA(stat), stat_len) == 0)
704     appendStringInfo(str, "%u.%u", stats->rusage_system.tv_sec, stats->rusage_system.tv_usec);
705     else if (pg_strncasecmp("curr_items", VARDATA(stat), stat_len) == 0)
706     appendStringInfo(str, "%u", stats->curr_items);
707     else if (pg_strncasecmp("total_itmes", VARDATA(stat), stat_len) == 0)
708     appendStringInfo(str, "%llu", stats->total_items);
709     else if (pg_strncasecmp("bytes", VARDATA(stat), stat_len) == 0)
710     appendStringInfo(str, "%llu", stats->bytes);
711     else if (pg_strncasecmp("curr_connections", VARDATA(stat), stat_len) == 0)
712     appendStringInfo(str, "%u", stats->curr_connections);
713     else if (pg_strncasecmp("total_connections", VARDATA(stat), stat_len) == 0)
714     appendStringInfo(str, "%llu", stats->total_connections);
715     else if (pg_strncasecmp("connection_structures", VARDATA(stat), stat_len) == 0)
716     appendStringInfo(str, "%u", stats->connection_structures);
717     else if (pg_strncasecmp("cmd_get", VARDATA(stat), stat_len) == 0)
718     appendStringInfo(str, "%llu", stats->cmd_get);
719     else if (pg_strncasecmp("cmd_set", VARDATA(stat), stat_len) == 0)
720     appendStringInfo(str, "%llu", stats->cmd_set);
721     else if (pg_strncasecmp("get_hits", VARDATA(stat), stat_len) == 0)
722     appendStringInfo(str, "%llu", stats->get_hits);
723     else if (pg_strncasecmp("get_misses", VARDATA(stat), stat_len) == 0)
724     appendStringInfo(str, "%llu", stats->get_misses);
725     else if (pg_strncasecmp("bytes_read", VARDATA(stat), stat_len) == 0)
726     appendStringInfo(str, "%llu", stats->bytes_read);
727     else if (pg_strncasecmp("bytes_written", VARDATA(stat), stat_len) == 0)
728     appendStringInfo(str, "%llu", stats->bytes_written);
729     else if (pg_strncasecmp("limit_maxbytes", VARDATA(stat), stat_len) == 0)
730     appendStringInfo(str, "%llu", stats->limit_maxbytes);
731     else
732     elog(ERROR, "Unknown memcache statistic \"%.*s\"", (int)stat_len, VARDATA(stat));
733    
734     ret = (text *)SPI_palloc(str->len + VARHDRSZ);
735     VARATT_SIZEP(ret) = str->len + VARHDRSZ;
736     memcpy(VARDATA(ret), str->data, str->len);
737    
738     SPI_finish();
739    
740     PG_RETURN_TEXT_P(ret);
741     }

  ViewVC Help
Powered by ViewVC 1.1.26