/[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

Contents of /upstream/1.0/pgmemcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show 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 /*
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