1 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4 * Copyright 2004 Paul Querna
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include "apr_memcache.h"
20 #include "apr_version.h"
23 #define BUFFER_SIZE 512
24 struct apr_memcache_conn_t
30 apr_bucket_alloc_t
*balloc
;
31 apr_bucket_brigade
*bb
;
32 apr_bucket_brigade
*tb
;
33 apr_memcache_server_t
*ms
;
36 /* Strings for Client Commands */
39 #define MC_EOL_LEN (sizeof(MC_EOL)-1)
42 #define MC_GET_LEN (sizeof(MC_GET)-1)
45 #define MC_SET_LEN (sizeof(MC_SET)-1)
48 #define MC_ADD_LEN (sizeof(MC_ADD)-1)
50 #define MC_REPLACE "replace "
51 #define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1)
53 #define MC_DELETE "delete "
54 #define MC_DELETE_LEN (sizeof(MC_DELETE)-1)
56 #define MC_INCR "incr "
57 #define MC_INCR_LEN (sizeof(MC_INCR)-1)
59 #define MC_DECR "decr "
60 #define MC_DECR_LEN (sizeof(MC_DECR)-1)
62 #define MC_VERSION "version"
63 #define MC_VERSION_LEN (sizeof(MC_VERSION)-1)
65 #define MC_STATS "stats"
66 #define MC_STATS_LEN (sizeof(MC_STATS)-1)
68 /* Strings for Server Replies */
70 #define MS_STORED "STORED"
71 #define MS_STORED_LEN (sizeof(MS_STORED)-1)
73 #define MS_NOT_STORED "NOT_STORED"
74 #define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1)
76 #define MS_DELETED "DELETED"
77 #define MS_DELETED_LEN (sizeof(MS_DELETED)-1)
79 #define MS_NOT_FOUND "NOT_FOUND"
80 #define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1)
82 #define MS_VALUE "VALUE"
83 #define MS_VALUE_LEN (sizeof(MS_VALUE)-1)
85 #define MS_ERROR "ERROR"
86 #define MS_ERROR_LEN (sizeof(MS_ERROR)-1)
88 #define MS_VERSION "VERSION"
89 #define MS_VERSION_LEN (sizeof(MS_VERSION)-1)
91 #define MS_STAT "STAT"
92 #define MS_STAT_LEN (sizeof(MS_STAT)-1)
95 #define MS_END_LEN (sizeof(MS_END)-1)
98 static apr_status_t
make_server_dead(apr_memcache_t
*mc
, apr_memcache_server_t
*ms
)
101 apr_thread_mutex_lock(ms
->lock
);
103 ms
->status
= APR_MC_SERVER_DEAD
;
104 ms
->btime
= apr_time_now();
106 apr_thread_mutex_unlock(ms
->lock
);
111 static apr_status_t
make_server_live(apr_memcache_t
*mc
, apr_memcache_server_t
*ms
)
113 ms
->status
= APR_MC_SERVER_LIVE
;
118 APR_DECLARE(apr_status_t
) apr_memcache_add_server(apr_memcache_t
*mc
, apr_memcache_server_t
*ms
)
120 apr_status_t rv
= APR_SUCCESS
;
122 if(mc
->ntotal
>= mc
->nalloc
) {
126 mc
->live_servers
[mc
->ntotal
] = ms
;
128 make_server_live(mc
, ms
);
132 static apr_status_t
mc_version_ping(apr_memcache_server_t
*ms
);
134 APR_DECLARE(apr_memcache_server_t
*)
135 apr_memcache_find_server_hash(apr_memcache_t
*mc
, const apr_uint32_t hash
)
137 apr_memcache_server_t
*ms
= NULL
;
138 apr_uint32_t h
= hash
;
140 apr_time_t curtime
= 0;
142 if(mc
->ntotal
== 0) {
147 ms
= mc
->live_servers
[h
% mc
->ntotal
];
148 if(ms
->status
== APR_MC_SERVER_LIVE
) {
153 curtime
= apr_time_now();
156 apr_thread_mutex_lock(ms
->lock
);
158 /* Try the the dead server, every 5 seconds */
159 if (curtime
- ms
->btime
> apr_time_from_sec(5)) {
160 if (mc_version_ping(ms
) == APR_SUCCESS
) {
162 make_server_live(mc
, ms
);
164 apr_thread_mutex_unlock(ms
->lock
);
170 apr_thread_mutex_unlock(ms
->lock
);
175 } while(i
< mc
->ntotal
);
177 if (i
== mc
->ntotal
) {
184 APR_DECLARE(apr_memcache_server_t
*) apr_memcache_find_server(apr_memcache_t
*mc
, const char *host
, apr_port_t port
)
188 for (i
= 0; i
< mc
->ntotal
; i
++) {
189 if (strcmp(mc
->live_servers
[i
]->host
, host
) == 0
190 && mc
->live_servers
[i
]->port
== port
) {
192 return mc
->live_servers
[i
];
199 static apr_status_t
ms_find_conn(apr_memcache_server_t
*ms
, apr_memcache_conn_t
**conn
)
202 return apr_reslist_acquire(ms
->conns
, (void **)conn
);
209 static apr_status_t
ms_bad_conn(apr_memcache_server_t
*ms
, apr_memcache_conn_t
*conn
)
212 return apr_reslist_invalidate(ms
->conns
, conn
);
218 static apr_status_t
ms_release_conn(apr_memcache_server_t
*ms
, apr_memcache_conn_t
*conn
)
221 return apr_reslist_release(ms
->conns
, conn
);
227 APR_DECLARE(apr_status_t
) apr_memcache_enable_server(apr_memcache_t
*mc
, apr_memcache_server_t
*ms
)
229 apr_status_t rv
= APR_SUCCESS
;
231 if (ms
->status
== APR_MC_SERVER_LIVE
) {
235 rv
= make_server_live(mc
, ms
);
239 APR_DECLARE(apr_status_t
) apr_memcache_disable_server(apr_memcache_t
*mc
, apr_memcache_server_t
*ms
)
241 return make_server_dead(mc
, ms
);
244 static apr_status_t
conn_connect(apr_memcache_conn_t
*conn
)
246 apr_status_t rv
= APR_SUCCESS
;
249 rv
= apr_sockaddr_info_get(&sa
, conn
->ms
->host
, APR_INET
, conn
->ms
->port
, 0, conn
->p
);
250 if (rv
!= APR_SUCCESS
) {
254 rv
= apr_socket_timeout_set(conn
->sock
, 1 * APR_USEC_PER_SEC
);
255 if (rv
!= APR_SUCCESS
) {
259 rv
= apr_socket_connect(conn
->sock
, sa
);
260 if (rv
!= APR_SUCCESS
) {
269 mc_conn_construct(void **conn_
, void *params
, apr_pool_t
*pool
)
271 apr_status_t rv
= APR_SUCCESS
;
272 apr_memcache_conn_t
*conn
;
275 apr_memcache_server_t
*ms
= params
;
277 rv
= apr_pool_create(&np
, pool
);
278 if (rv
!= APR_SUCCESS
) {
282 conn
= apr_palloc(np
, sizeof( apr_memcache_conn_t
));
286 rv
= apr_socket_create(&conn
->sock
, APR_INET
, SOCK_STREAM
, 0, np
);
288 if (rv
!= APR_SUCCESS
) {
292 conn
->balloc
= apr_bucket_alloc_create(conn
->p
);
293 conn
->bb
= apr_brigade_create(conn
->p
, conn
->balloc
);
294 conn
->tb
= apr_brigade_create(conn
->p
, conn
->balloc
);
295 conn
->buffer
= apr_palloc(conn
->p
, BUFFER_SIZE
);
299 e
= apr_bucket_socket_create(conn
->sock
, conn
->balloc
);
300 APR_BRIGADE_INSERT_TAIL(conn
->bb
, e
);
302 rv
= conn_connect(conn
);
309 mc_conn_destruct(void *conn_
, void *params
, apr_pool_t
*pool
)
311 /* Currently a NOOP */
315 APR_DECLARE(apr_status_t
) apr_memcache_server_create(apr_pool_t
*p
,
316 const char *host
, apr_port_t port
,
317 apr_uint32_t min
, apr_uint32_t smax
,
318 apr_uint32_t max
, apr_uint32_t ttl
,
319 apr_memcache_server_t
**ms
)
321 apr_status_t rv
= APR_SUCCESS
;
322 apr_memcache_server_t
*server
;
325 rv
= apr_pool_create(&np
, p
);
327 server
= apr_palloc(np
, sizeof(apr_memcache_server_t
));
330 server
->host
= apr_pstrdup(np
, host
);
332 server
->status
= APR_MC_SERVER_DEAD
;
334 rv
= apr_thread_mutex_create(&server
->lock
, APR_THREAD_MUTEX_DEFAULT
, np
);
335 if (rv
!= APR_SUCCESS
) {
339 rv
= apr_reslist_create(&server
->conns
,
340 min
, /* hard minimum */
341 smax
, /* soft maximum */
342 max
, /* hard maximum */
343 ttl
, /* Time to live */
344 mc_conn_construct
, /* Make a New Connection */
345 mc_conn_destruct
, /* Kill Old Connection */
348 rv
= mc_conn_construct((void**)&(server
->conn
), server
, np
);
351 if (rv
!= APR_SUCCESS
) {
360 APR_DECLARE(apr_status_t
) apr_memcache_create(apr_pool_t
*p
,
361 apr_uint16_t max_servers
, apr_uint32_t flags
,
362 apr_memcache_t
**memcache
)
364 apr_status_t rv
= APR_SUCCESS
;
367 mc
= apr_palloc(p
, sizeof(apr_memcache_t
));
369 mc
->nalloc
= max_servers
;
371 mc
->live_servers
= apr_palloc(p
, mc
->nalloc
* sizeof(struct apr_memcache_server_t
*));
377 /* The crc32 functions and data was originally written by Spencer
378 * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
379 * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
380 * src/usr.bin/cksum/crc32.c.
383 static const apr_uint32_t crc32tab
[256] = {
384 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
385 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
386 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
387 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
388 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
389 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
390 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
391 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
392 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
393 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
394 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
395 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
396 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
397 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
398 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
399 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
400 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
401 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
402 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
403 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
404 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
405 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
406 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
407 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
408 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
409 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
410 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
411 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
412 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
413 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
414 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
415 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
416 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
417 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
418 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
419 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
420 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
421 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
422 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
423 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
424 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
425 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
426 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
427 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
428 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
429 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
430 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
431 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
432 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
433 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
434 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
435 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
436 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
437 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
438 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
439 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
440 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
441 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
442 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
443 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
444 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
445 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
446 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
447 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
450 APR_DECLARE(apr_uint32_t
) apr_memcache_hash(const char *data
, const apr_size_t data_len
)
456 for (i
= 0; i
< data_len
; i
++)
457 crc
= (crc
>> 8) ^ crc32tab
[(crc
^ (data
[i
])) & 0xff];
459 return ((~crc
>> 16) & 0x7fff);
462 static apr_status_t
get_server_line(apr_memcache_conn_t
*conn
)
464 apr_size_t bsize
= BUFFER_SIZE
;
465 apr_status_t rv
= APR_SUCCESS
;
467 rv
= apr_brigade_split_line(conn
->tb
, conn
->bb
, APR_BLOCK_READ
, BUFFER_SIZE
);
469 if (rv
!= APR_SUCCESS
) {
473 rv
= apr_brigade_flatten(conn
->tb
, conn
->buffer
, &bsize
);
475 if (rv
!= APR_SUCCESS
) {
480 conn
->buffer
[bsize
] = '\0';
482 return apr_brigade_cleanup(conn
->tb
);
485 static apr_status_t
storage_cmd_write(apr_memcache_t
*mc
,
487 const apr_size_t cmd_size
,
490 const apr_size_t data_size
,
491 apr_uint32_t timeout
,
495 apr_memcache_server_t
*ms
;
496 apr_memcache_conn_t
*conn
;
502 apr_size_t key_size
= strlen(key
);
504 hash
= apr_memcache_hash(key
, key_size
);
506 ms
= apr_memcache_find_server_hash(mc
, hash
);
511 rv
= ms_find_conn(ms
, &conn
);
513 if (rv
!= APR_SUCCESS
) {
514 apr_memcache_disable_server(mc
, ms
);
518 /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */
520 vec
[0].iov_base
= cmd
;
521 vec
[0].iov_len
= cmd_size
;
523 vec
[1].iov_base
= (void*)key
;
524 vec
[1].iov_len
= key_size
;
526 klen
= apr_snprintf(conn
->buffer
, BUFFER_SIZE
, " %u %u %" APR_SIZE_T_FMT
" " MC_EOL
,
527 flags
, timeout
, data_size
);
529 vec
[2].iov_base
= conn
->buffer
;
530 vec
[2].iov_len
= klen
;
532 vec
[3].iov_base
= data
;
533 vec
[3].iov_len
= data_size
;
535 vec
[4].iov_base
= MC_EOL
;
536 vec
[4].iov_len
= MC_EOL_LEN
;
538 rv
= apr_socket_sendv(conn
->sock
, vec
, 5, &written
);
540 if (rv
!= APR_SUCCESS
) {
541 ms_bad_conn(ms
, conn
);
542 apr_memcache_disable_server(mc
, ms
);
546 rv
= get_server_line(conn
);
548 if (rv
!= APR_SUCCESS
) {
549 ms_bad_conn(ms
, conn
);
550 apr_memcache_disable_server(mc
, ms
);
554 if (strcmp(conn
->buffer
, MS_STORED MC_EOL
) == 0) {
557 else if (strcmp(conn
->buffer
, MS_NOT_STORED MC_EOL
) == 0) {
564 ms_release_conn(ms
, conn
);
569 APR_DECLARE(apr_status_t
)
570 apr_memcache_set(apr_memcache_t
*mc
,
573 const apr_size_t data_size
,
574 apr_uint32_t timeout
,
577 return storage_cmd_write(mc
,
584 APR_DECLARE(apr_status_t
)
585 apr_memcache_add(apr_memcache_t
*mc
,
588 const apr_size_t data_size
,
589 apr_uint32_t timeout
,
592 return storage_cmd_write(mc
,
599 APR_DECLARE(apr_status_t
)
600 apr_memcache_replace(apr_memcache_t
*mc
,
603 const apr_size_t data_size
,
604 apr_uint32_t timeout
,
607 return storage_cmd_write(mc
,
608 MC_REPLACE
, MC_REPLACE_LEN
,
615 APR_DECLARE(apr_status_t
)
616 apr_memcache_getp(apr_memcache_t
*mc
,
620 apr_size_t
*new_length
,
621 apr_uint16_t
*flags_
)
624 apr_memcache_server_t
*ms
;
625 apr_memcache_conn_t
*conn
;
628 int klen
= strlen(key
);
631 hash
= apr_memcache_hash(key
, klen
);
632 ms
= apr_memcache_find_server_hash(mc
, hash
);
636 rv
= ms_find_conn(ms
, &conn
);
638 if (rv
!= APR_SUCCESS
) {
639 apr_memcache_disable_server(mc
, ms
);
643 /* get <key>[ <key>[...]]\r\n */
644 vec
[0].iov_base
= MC_GET
;
645 vec
[0].iov_len
= MC_GET_LEN
;
647 vec
[1].iov_base
= (void*)key
;
648 vec
[1].iov_len
= klen
;
650 vec
[2].iov_base
= MC_EOL
;
651 vec
[2].iov_len
= MC_EOL_LEN
;
653 rv
= apr_socket_sendv(conn
->sock
, vec
, 3, &written
);
655 if (rv
!= APR_SUCCESS
) {
656 ms_bad_conn(ms
, conn
);
657 apr_memcache_disable_server(mc
, ms
);
661 rv
= get_server_line(conn
);
662 if (rv
!= APR_SUCCESS
) {
663 ms_bad_conn(ms
, conn
);
664 apr_memcache_disable_server(mc
, ms
);
668 if (strncmp(MS_VALUE
, conn
->buffer
, MS_VALUE_LEN
) == 0) {
675 start
= conn
->buffer
;
676 flags
= apr_strtok(conn
->buffer
," ",&last
);
677 flags
= apr_strtok(NULL
," ",&last
);
678 flags
= apr_strtok(NULL
," ",&last
);
681 *flags_
= atoi(flags
);
683 length
= apr_strtok(NULL
," ",&last
);
690 apr_bucket_brigade
*bbb
;
693 /* eat the trailing \r\n */
694 rv
= apr_brigade_partition(conn
->bb
, len
+2, &e
);
696 if (rv
!= APR_SUCCESS
) {
697 ms_bad_conn(ms
, conn
);
698 apr_memcache_disable_server(mc
, ms
);
702 bbb
= apr_brigade_split(conn
->bb
, e
);
704 rv
= apr_brigade_pflatten(conn
->bb
, baton
, &len
, p
);
706 if (rv
!= APR_SUCCESS
) {
707 ms_bad_conn(ms
, conn
);
708 apr_memcache_disable_server(mc
, ms
);
712 rv
= apr_brigade_destroy(conn
->bb
);
713 if (rv
!= APR_SUCCESS
) {
714 ms_bad_conn(ms
, conn
);
715 apr_memcache_disable_server(mc
, ms
);
721 *new_length
= len
- 2;
722 (*baton
)[*new_length
] = '\0';
725 rv
= get_server_line(conn
);
726 if (rv
!= APR_SUCCESS
) {
727 ms_bad_conn(ms
, conn
);
728 apr_memcache_disable_server(mc
, ms
);
732 if (strncmp(MS_END
, conn
->buffer
, MS_END_LEN
) != 0) {
736 else if (strncmp(MS_END
, conn
->buffer
, MS_END_LEN
) == 0) {
743 ms_release_conn(ms
, conn
);
748 APR_DECLARE(apr_status_t
)
749 apr_memcache_delete(apr_memcache_t
*mc
,
751 apr_uint32_t timeout
)
754 apr_memcache_server_t
*ms
;
755 apr_memcache_conn_t
*conn
;
759 int klen
= strlen(key
);
761 hash
= apr_memcache_hash(key
, klen
);
762 ms
= apr_memcache_find_server_hash(mc
, hash
);
766 rv
= ms_find_conn(ms
, &conn
);
768 if (rv
!= APR_SUCCESS
) {
769 apr_memcache_disable_server(mc
, ms
);
773 /* delete <key> <time>\r\n */
774 vec
[0].iov_base
= MC_DELETE
;
775 vec
[0].iov_len
= MC_DELETE_LEN
;
777 vec
[1].iov_base
= (void*)key
;
778 vec
[1].iov_len
= klen
;
780 klen
= apr_snprintf(conn
->buffer
, BUFFER_SIZE
, " %u" MC_EOL
, timeout
);
782 vec
[2].iov_base
= conn
->buffer
;
783 vec
[2].iov_len
= klen
;
785 rv
= apr_socket_sendv(conn
->sock
, vec
, 3, &written
);
787 if (rv
!= APR_SUCCESS
) {
788 ms_bad_conn(ms
, conn
);
789 apr_memcache_disable_server(mc
, ms
);
793 rv
= get_server_line(conn
);
794 if (rv
!= APR_SUCCESS
) {
795 ms_bad_conn(ms
, conn
);
796 apr_memcache_disable_server(mc
, ms
);
800 if (strncmp(MS_DELETED
, conn
->buffer
, MS_DELETED_LEN
) == 0) {
803 else if (strncmp(MS_NOT_FOUND
, conn
->buffer
, MS_NOT_FOUND_LEN
) == 0) {
810 ms_release_conn(ms
, conn
);
815 static apr_status_t
num_cmd_write(apr_memcache_t
*mc
,
817 const apr_uint32_t cmd_size
,
819 const apr_int32_t inc
,
820 apr_uint32_t
*new_value
)
823 apr_memcache_server_t
*ms
;
824 apr_memcache_conn_t
*conn
;
828 int klen
= strlen(key
);
830 hash
= apr_memcache_hash(key
, klen
);
831 ms
= apr_memcache_find_server_hash(mc
, hash
);
835 rv
= ms_find_conn(ms
, &conn
);
837 if (rv
!= APR_SUCCESS
) {
838 apr_memcache_disable_server(mc
, ms
);
842 /* <cmd> <key> <value>\r\n */
843 vec
[0].iov_base
= cmd
;
844 vec
[0].iov_len
= cmd_size
;
846 vec
[1].iov_base
= (void*)key
;
847 vec
[1].iov_len
= klen
;
849 klen
= apr_snprintf(conn
->buffer
, BUFFER_SIZE
, " %u" MC_EOL
, inc
);
851 vec
[2].iov_base
= conn
->buffer
;
852 vec
[2].iov_len
= klen
;
854 rv
= apr_socket_sendv(conn
->sock
, vec
, 3, &written
);
856 if (rv
!= APR_SUCCESS
) {
857 ms_bad_conn(ms
, conn
);
858 apr_memcache_disable_server(mc
, ms
);
862 rv
= get_server_line(conn
);
863 if (rv
!= APR_SUCCESS
) {
864 ms_bad_conn(ms
, conn
);
865 apr_memcache_disable_server(mc
, ms
);
869 if (strncmp(MS_ERROR
, conn
->buffer
, MS_ERROR_LEN
) == 0) {
872 else if (strncmp(MS_NOT_FOUND
, conn
->buffer
, MS_NOT_FOUND_LEN
) == 0) {
877 *new_value
= atoi(conn
->buffer
);
882 ms_release_conn(ms
, conn
);
887 APR_DECLARE(apr_status_t
)
888 apr_memcache_incr(apr_memcache_t
*mc
,
891 apr_uint32_t
*new_value
)
893 return num_cmd_write(mc
,
902 APR_DECLARE(apr_status_t
)
903 apr_memcache_decr(apr_memcache_t
*mc
,
906 apr_uint32_t
*new_value
)
908 return num_cmd_write(mc
,
918 APR_DECLARE(apr_status_t
)
919 apr_memcache_version(apr_memcache_server_t
*ms
,
924 apr_memcache_conn_t
*conn
;
928 rv
= ms_find_conn(ms
, &conn
);
930 if (rv
!= APR_SUCCESS
) {
935 vec
[0].iov_base
= MC_VERSION
;
936 vec
[0].iov_len
= MC_VERSION_LEN
;
938 vec
[1].iov_base
= MC_EOL
;
939 vec
[1].iov_len
= MC_EOL_LEN
;
941 rv
= apr_socket_sendv(conn
->sock
, vec
, 2, &written
);
943 if (rv
!= APR_SUCCESS
) {
944 ms_bad_conn(ms
, conn
);
948 rv
= get_server_line(conn
);
949 if (rv
!= APR_SUCCESS
) {
950 ms_bad_conn(ms
, conn
);
954 if (strncmp(MS_VERSION
, conn
->buffer
, MS_VERSION_LEN
) == 0) {
955 *baton
= apr_pstrmemdup(p
, conn
->buffer
+MS_VERSION_LEN
+1,
956 conn
->blen
- MS_VERSION_LEN
- 2);
963 ms_release_conn(ms
, conn
);
968 apr_status_t
mc_version_ping(apr_memcache_server_t
*ms
)
973 apr_memcache_conn_t
*conn
;
975 rv
= ms_find_conn(ms
, &conn
);
977 if (rv
!= APR_SUCCESS
) {
982 vec
[0].iov_base
= MC_VERSION
;
983 vec
[0].iov_len
= MC_VERSION_LEN
;
985 vec
[1].iov_base
= MC_EOL
;
986 vec
[1].iov_len
= MC_EOL_LEN
;
988 rv
= apr_socket_sendv(conn
->sock
, vec
, 2, &written
);
990 if (rv
!= APR_SUCCESS
) {
991 ms_bad_conn(ms
, conn
);
995 rv
= get_server_line(conn
);
996 ms_release_conn(ms
, conn
);
1002 * Define all of the strings for stats
1005 #define STAT_pid MS_STAT " pid "
1006 #define STAT_pid_LEN (sizeof(STAT_pid)-1)
1008 #define STAT_uptime MS_STAT " uptime "
1009 #define STAT_uptime_LEN (sizeof(STAT_uptime)-1)
1011 #define STAT_time MS_STAT " time "
1012 #define STAT_time_LEN (sizeof(STAT_time)-1)
1014 #define STAT_version MS_STAT " version "
1015 #define STAT_version_LEN (sizeof(STAT_version)-1)
1017 #define STAT_rusage_user MS_STAT " rusage_user "
1018 #define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1)
1020 #define STAT_rusage_system MS_STAT " rusage_system "
1021 #define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1)
1023 #define STAT_curr_items MS_STAT " curr_items "
1024 #define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1)
1026 #define STAT_total_items MS_STAT " total_items "
1027 #define STAT_total_items_LEN (sizeof(STAT_total_items)-1)
1029 #define STAT_bytes MS_STAT " bytes "
1030 #define STAT_bytes_LEN (sizeof(STAT_bytes)-1)
1032 #define STAT_curr_connections MS_STAT " curr_connections "
1033 #define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1)
1035 #define STAT_total_connections MS_STAT " total_connections "
1036 #define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1)
1038 #define STAT_connection_structures MS_STAT " connection_structures "
1039 #define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1)
1041 #define STAT_cmd_get MS_STAT " cmd_get "
1042 #define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1)
1044 #define STAT_cmd_set MS_STAT " cmd_set "
1045 #define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1)
1047 #define STAT_get_hits MS_STAT " get_hits "
1048 #define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1)
1050 #define STAT_get_misses MS_STAT " get_misses "
1051 #define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1)
1053 #define STAT_bytes_read MS_STAT " bytes_read "
1054 #define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1)
1056 #define STAT_bytes_written MS_STAT " bytes_written "
1057 #define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1)
1059 #define STAT_limit_maxbytes MS_STAT " limit_maxbytes "
1060 #define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1)
1063 static const char *stat_read_string(apr_pool_t
*p
, char *buf
, int len
)
1065 /* remove trailing \r\n and null char */
1066 return apr_pstrmemdup(p
, buf
, len
-2);
1069 static apr_uint32_t
stat_read_uint32(apr_pool_t
*p
, char *buf
, int len
)
1075 static apr_uint64_t
stat_read_uint64(apr_pool_t
*p
, char *buf
, int len
)
1078 return apr_atoi64(buf
);
1081 static apr_time_t
stat_read_time(apr_pool_t
*p
, char *buf
, int len
)
1084 return apr_time_from_sec(atoi(buf
));
1087 static apr_time_t
stat_read_rtime(apr_pool_t
*p
, char *buf
, int len
)
1092 const char *sep
= ":";
1096 secs
= apr_strtok(buf
, sep
, &tok
);
1099 secs
= apr_strtok(buf
, sep
, &tok
);
1101 usecs
= apr_strtok(NULL
, sep
, &tok
);
1102 if (secs
&& usecs
) {
1103 return apr_time_make(atoi(secs
), atoi(usecs
));
1106 return apr_time_make(0, 0);
1111 * I got tired of Typing. Meh.
1113 * TODO: Convert it to static tables to make it cooler.
1116 #define mc_stat_cmp(name) \
1117 strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0
1119 #define mc_stat_str(name) \
1120 stat_read_string(p, conn->buffer + name, \
1123 #define mc_stat_uint32(name) \
1124 stat_read_uint32(p, conn->buffer + name, \
1127 #define mc_stat_uint64(name) \
1128 stat_read_uint64(p, conn->buffer + name, \
1131 #define mc_stat_time(name) \
1132 stat_read_time(p, conn->buffer + name, \
1135 #define mc_stat_rtime(name) \
1136 stat_read_rtime(p, conn->buffer + name, \
1140 #define mc_do_stat(name, type) \
1141 if (mc_stat_cmp(name)) { \
1142 stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \
1145 static void update_stats(apr_pool_t
*p
, apr_memcache_conn_t
*conn
,
1146 apr_memcache_stats_t
*stats
)
1149 mc_do_stat(version
, str
)
1150 else mc_do_stat(pid
, uint32
)
1151 else mc_do_stat(uptime
, uint32
)
1152 else mc_do_stat(time
, time
)
1153 else mc_do_stat(rusage_user
, rtime
)
1154 else mc_do_stat(rusage_system
, rtime
)
1155 else mc_do_stat(curr_items
, uint32
)
1156 else mc_do_stat(total_items
, uint32
)
1157 else mc_do_stat(bytes
, uint64
)
1158 else mc_do_stat(curr_connections
, uint32
)
1159 else mc_do_stat(total_connections
, uint32
)
1160 else mc_do_stat(connection_structures
, uint32
)
1161 else mc_do_stat(cmd_get
, uint32
)
1162 else mc_do_stat(cmd_set
, uint32
)
1163 else mc_do_stat(get_hits
, uint32
)
1164 else mc_do_stat(get_misses
, uint32
)
1165 else mc_do_stat(bytes_read
, uint64
)
1166 else mc_do_stat(bytes_written
, uint64
)
1167 else mc_do_stat(limit_maxbytes
, uint32
)
1170 APR_DECLARE(apr_status_t
)
1171 apr_memcache_stats(apr_memcache_server_t
*ms
,
1173 apr_memcache_stats_t
**stats
)
1175 apr_memcache_stats_t
*ret
;
1177 apr_memcache_conn_t
*conn
;
1179 struct iovec vec
[2];
1181 rv
= ms_find_conn(ms
, &conn
);
1183 if (rv
!= APR_SUCCESS
) {
1188 vec
[0].iov_base
= MC_STATS
;
1189 vec
[0].iov_len
= MC_STATS_LEN
;
1191 vec
[1].iov_base
= MC_EOL
;
1192 vec
[1].iov_len
= MC_EOL_LEN
;
1194 rv
= apr_socket_sendv(conn
->sock
, vec
, 2, &written
);
1196 if (rv
!= APR_SUCCESS
) {
1197 ms_bad_conn(ms
, conn
);
1201 ret
= apr_pcalloc(p
, sizeof(apr_memcache_stats_t
));
1204 rv
= get_server_line(conn
);
1205 if (rv
!= APR_SUCCESS
) {
1206 ms_bad_conn(ms
, conn
);
1210 if (strncmp(MS_END
, conn
->buffer
, MS_END_LEN
) == 0) {
1214 else if (strncmp(MS_STAT
, conn
->buffer
, MS_STAT_LEN
) == 0) {
1215 update_stats(p
, conn
, ret
);
1225 ms_release_conn(ms
, conn
);