/[pgmemcache]/trunk/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 /trunk/pgmemcache.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26