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

Contents of /trunk/pgmemcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Thu Jul 20 10:09:18 2006 UTC (17 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 19842 byte(s)
small fixes to make it compile on 8.1
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 #include "utils/memutils.h"
38
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 if (timestamp2tm(timestamptz, NULL, &tm, &fsec, NULL, NULL) !=0)
475 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 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 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 appendStringInfo(str, "%u.%u", (uint)stats->rusage_user.tv_sec, (uint)stats->rusage_user.tv_usec);
704 else if (pg_strncasecmp("rusage_system", VARDATA(stat), stat_len) == 0)
705 appendStringInfo(str, "%u.%u", (uint)stats->rusage_system.tv_sec, (uint)stats->rusage_system.tv_usec);
706 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