1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_memcache.h" 18#include "apr_poll.h" 19#include "apr_version.h" 20#include <stdlib.h> 21 22#define BUFFER_SIZE 512 23struct apr_memcache_conn_t 24{ 25 char *buffer; 26 apr_size_t blen; 27 apr_pool_t *p; 28 apr_pool_t *tp; 29 apr_socket_t *sock; 30 apr_bucket_brigade *bb; 31 apr_bucket_brigade *tb; 32 apr_memcache_server_t *ms; 33}; 34 35/* Strings for Client Commands */ 36 37#define MC_EOL "\r\n" 38#define MC_EOL_LEN (sizeof(MC_EOL)-1) 39 40#define MC_WS " " 41#define MC_WS_LEN (sizeof(MC_WS)-1) 42 43#define MC_GET "get " 44#define MC_GET_LEN (sizeof(MC_GET)-1) 45 46#define MC_SET "set " 47#define MC_SET_LEN (sizeof(MC_SET)-1) 48 49#define MC_ADD "add " 50#define MC_ADD_LEN (sizeof(MC_ADD)-1) 51 52#define MC_REPLACE "replace " 53#define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1) 54 55#define MC_DELETE "delete " 56#define MC_DELETE_LEN (sizeof(MC_DELETE)-1) 57 58#define MC_INCR "incr " 59#define MC_INCR_LEN (sizeof(MC_INCR)-1) 60 61#define MC_DECR "decr " 62#define MC_DECR_LEN (sizeof(MC_DECR)-1) 63 64#define MC_VERSION "version" 65#define MC_VERSION_LEN (sizeof(MC_VERSION)-1) 66 67#define MC_STATS "stats" 68#define MC_STATS_LEN (sizeof(MC_STATS)-1) 69 70#define MC_QUIT "quit" 71#define MC_QUIT_LEN (sizeof(MC_QUIT)-1) 72 73/* Strings for Server Replies */ 74 75#define MS_STORED "STORED" 76#define MS_STORED_LEN (sizeof(MS_STORED)-1) 77 78#define MS_NOT_STORED "NOT_STORED" 79#define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1) 80 81#define MS_DELETED "DELETED" 82#define MS_DELETED_LEN (sizeof(MS_DELETED)-1) 83 84#define MS_NOT_FOUND "NOT_FOUND" 85#define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1) 86 87#define MS_VALUE "VALUE" 88#define MS_VALUE_LEN (sizeof(MS_VALUE)-1) 89 90#define MS_ERROR "ERROR" 91#define MS_ERROR_LEN (sizeof(MS_ERROR)-1) 92 93#define MS_VERSION "VERSION" 94#define MS_VERSION_LEN (sizeof(MS_VERSION)-1) 95 96#define MS_STAT "STAT" 97#define MS_STAT_LEN (sizeof(MS_STAT)-1) 98 99#define MS_END "END" 100#define MS_END_LEN (sizeof(MS_END)-1) 101 102/** Server and Query Structure for a multiple get */ 103struct cache_server_query_t { 104 apr_memcache_server_t* ms; 105 apr_memcache_conn_t* conn; 106 struct iovec* query_vec; 107 apr_int32_t query_vec_count; 108}; 109 110#define MULT_GET_TIMEOUT 50000 111 112static apr_status_t make_server_dead(apr_memcache_t *mc, apr_memcache_server_t *ms) 113{ 114#if APR_HAS_THREADS 115 apr_thread_mutex_lock(ms->lock); 116#endif 117 ms->status = APR_MC_SERVER_DEAD; 118 ms->btime = apr_time_now(); 119#if APR_HAS_THREADS 120 apr_thread_mutex_unlock(ms->lock); 121#endif 122 return APR_SUCCESS; 123} 124 125static apr_status_t make_server_live(apr_memcache_t *mc, apr_memcache_server_t *ms) 126{ 127 ms->status = APR_MC_SERVER_LIVE; 128 return APR_SUCCESS; 129} 130 131 132APU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 133{ 134 apr_status_t rv = APR_SUCCESS; 135 136 if(mc->ntotal >= mc->nalloc) { 137 return APR_ENOMEM; 138 } 139 140 mc->live_servers[mc->ntotal] = ms; 141 mc->ntotal++; 142 make_server_live(mc, ms); 143 return rv; 144} 145 146static apr_status_t mc_version_ping(apr_memcache_server_t *ms); 147 148APU_DECLARE(apr_memcache_server_t *) 149apr_memcache_find_server_hash(apr_memcache_t *mc, const apr_uint32_t hash) 150{ 151 if (mc->server_func) { 152 return mc->server_func(mc->server_baton, mc, hash); 153 } 154 else { 155 return apr_memcache_find_server_hash_default(NULL, mc, hash); 156 } 157} 158 159APU_DECLARE(apr_memcache_server_t *) 160apr_memcache_find_server_hash_default(void *baton, apr_memcache_t *mc, 161 const apr_uint32_t hash) 162{ 163 apr_memcache_server_t *ms = NULL; 164 apr_uint32_t h = hash ? hash : 1; 165 apr_uint32_t i = 0; 166 apr_time_t curtime = 0; 167 168 if(mc->ntotal == 0) { 169 return NULL; 170 } 171 172 do { 173 ms = mc->live_servers[h % mc->ntotal]; 174 if(ms->status == APR_MC_SERVER_LIVE) { 175 break; 176 } 177 else { 178 if (curtime == 0) { 179 curtime = apr_time_now(); 180 } 181#if APR_HAS_THREADS 182 apr_thread_mutex_lock(ms->lock); 183#endif 184 /* Try the dead server, every 5 seconds */ 185 if (curtime - ms->btime > apr_time_from_sec(5)) { 186 ms->btime = curtime; 187 if (mc_version_ping(ms) == APR_SUCCESS) { 188 make_server_live(mc, ms); 189#if APR_HAS_THREADS 190 apr_thread_mutex_unlock(ms->lock); 191#endif 192 break; 193 } 194 } 195#if APR_HAS_THREADS 196 apr_thread_mutex_unlock(ms->lock); 197#endif 198 } 199 h++; 200 i++; 201 } while(i < mc->ntotal); 202 203 if (i == mc->ntotal) { 204 ms = NULL; 205 } 206 207 return ms; 208} 209 210APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, const char *host, apr_port_t port) 211{ 212 int i; 213 214 for (i = 0; i < mc->ntotal; i++) { 215 if (strcmp(mc->live_servers[i]->host, host) == 0 216 && mc->live_servers[i]->port == port) { 217 218 return mc->live_servers[i]; 219 } 220 } 221 222 return NULL; 223} 224 225static apr_status_t ms_find_conn(apr_memcache_server_t *ms, apr_memcache_conn_t **conn) 226{ 227 apr_status_t rv; 228 apr_bucket_alloc_t *balloc; 229 apr_bucket *e; 230 231#if APR_HAS_THREADS 232 rv = apr_reslist_acquire(ms->conns, (void **)conn); 233#else 234 *conn = ms->conn; 235 rv = APR_SUCCESS; 236#endif 237 238 if (rv != APR_SUCCESS) { 239 return rv; 240 } 241 242 balloc = apr_bucket_alloc_create((*conn)->tp); 243 (*conn)->bb = apr_brigade_create((*conn)->tp, balloc); 244 (*conn)->tb = apr_brigade_create((*conn)->tp, balloc); 245 246 e = apr_bucket_socket_create((*conn)->sock, balloc); 247 APR_BRIGADE_INSERT_TAIL((*conn)->bb, e); 248 249 return rv; 250} 251 252static apr_status_t ms_bad_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) 253{ 254#if APR_HAS_THREADS 255 return apr_reslist_invalidate(ms->conns, conn); 256#else 257 return APR_SUCCESS; 258#endif 259} 260 261static apr_status_t ms_release_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) 262{ 263 apr_pool_clear(conn->tp); 264#if APR_HAS_THREADS 265 return apr_reslist_release(ms->conns, conn); 266#else 267 return APR_SUCCESS; 268#endif 269} 270 271APU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 272{ 273 apr_status_t rv = APR_SUCCESS; 274 275 if (ms->status == APR_MC_SERVER_LIVE) { 276 return rv; 277 } 278 279 rv = make_server_live(mc, ms); 280 return rv; 281} 282 283APU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 284{ 285 return make_server_dead(mc, ms); 286} 287 288static apr_status_t conn_connect(apr_memcache_conn_t *conn) 289{ 290 apr_status_t rv = APR_SUCCESS; 291 apr_sockaddr_t *sa; 292#if APR_HAVE_SOCKADDR_UN 293 apr_int32_t family = conn->ms->host[0] != '/' ? APR_INET : APR_UNIX; 294#else 295 apr_int32_t family = APR_INET; 296#endif 297 298 rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p); 299 if (rv != APR_SUCCESS) { 300 return rv; 301 } 302 303 rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC); 304 if (rv != APR_SUCCESS) { 305 return rv; 306 } 307 308 rv = apr_socket_connect(conn->sock, sa); 309 if (rv != APR_SUCCESS) { 310 return rv; 311 } 312 313 rv = apr_socket_timeout_set(conn->sock, -1); 314 if (rv != APR_SUCCESS) { 315 return rv; 316 } 317 318 return rv; 319} 320 321 322static apr_status_t 323mc_conn_construct(void **conn_, void *params, apr_pool_t *pool) 324{ 325 apr_status_t rv = APR_SUCCESS; 326 apr_memcache_conn_t *conn; 327 apr_pool_t *np; 328 apr_pool_t *tp; 329 apr_memcache_server_t *ms = params; 330#if APR_HAVE_SOCKADDR_UN 331 apr_int32_t family = ms->host[0] != '/' ? APR_INET : APR_UNIX; 332#else 333 apr_int32_t family = APR_INET; 334#endif 335 336 rv = apr_pool_create(&np, pool); 337 if (rv != APR_SUCCESS) { 338 return rv; 339 } 340 341 rv = apr_pool_create(&tp, np); 342 if (rv != APR_SUCCESS) { 343 apr_pool_destroy(np); 344 return rv; 345 } 346 347 conn = apr_palloc(np, sizeof( apr_memcache_conn_t )); 348 349 conn->p = np; 350 conn->tp = tp; 351 352 rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np); 353 354 if (rv != APR_SUCCESS) { 355 apr_pool_destroy(np); 356 return rv; 357 } 358 359 conn->buffer = apr_palloc(conn->p, BUFFER_SIZE); 360 conn->blen = 0; 361 conn->ms = ms; 362 363 rv = conn_connect(conn); 364 if (rv != APR_SUCCESS) { 365 apr_pool_destroy(np); 366 } 367 else { 368 *conn_ = conn; 369 } 370 371 return rv; 372} 373 374#if APR_HAS_THREADS 375static apr_status_t 376mc_conn_destruct(void *conn_, void *params, apr_pool_t *pool) 377{ 378 apr_memcache_conn_t *conn = (apr_memcache_conn_t*)conn_; 379 struct iovec vec[2]; 380 apr_size_t written; 381 382 /* send a quit message to the memcached server to be nice about it. */ 383 vec[0].iov_base = MC_QUIT; 384 vec[0].iov_len = MC_QUIT_LEN; 385 386 vec[1].iov_base = MC_EOL; 387 vec[1].iov_len = MC_EOL_LEN; 388 389 /* Return values not checked, since we just want to make it go away. */ 390 apr_socket_sendv(conn->sock, vec, 2, &written); 391 apr_socket_close(conn->sock); 392 393 apr_pool_destroy(conn->p); 394 395 return APR_SUCCESS; 396} 397#endif 398 399APU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, 400 const char *host, apr_port_t port, 401 apr_uint32_t min, apr_uint32_t smax, 402 apr_uint32_t max, apr_uint32_t ttl, 403 apr_memcache_server_t **ms) 404{ 405 apr_status_t rv = APR_SUCCESS; 406 apr_memcache_server_t *server; 407 apr_pool_t *np; 408 409 rv = apr_pool_create(&np, p); 410 411 server = apr_palloc(np, sizeof(apr_memcache_server_t)); 412 413 server->p = np; 414 server->host = apr_pstrdup(np, host); 415 server->port = port; 416 server->status = APR_MC_SERVER_DEAD; 417#if APR_HAS_THREADS 418 rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np); 419 if (rv != APR_SUCCESS) { 420 return rv; 421 } 422 423 rv = apr_reslist_create(&server->conns, 424 min, /* hard minimum */ 425 smax, /* soft maximum */ 426 max, /* hard maximum */ 427 ttl, /* Time to live */ 428 mc_conn_construct, /* Make a New Connection */ 429 mc_conn_destruct, /* Kill Old Connection */ 430 server, np); 431 if (rv != APR_SUCCESS) { 432 return rv; 433 } 434 435 apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST); 436#else 437 rv = mc_conn_construct((void**)&(server->conn), server, np); 438 if (rv != APR_SUCCESS) { 439 return rv; 440 } 441#endif 442 443 *ms = server; 444 445 return rv; 446} 447 448APU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, 449 apr_uint16_t max_servers, apr_uint32_t flags, 450 apr_memcache_t **memcache) 451{ 452 apr_status_t rv = APR_SUCCESS; 453 apr_memcache_t *mc; 454 455 mc = apr_palloc(p, sizeof(apr_memcache_t)); 456 mc->p = p; 457 mc->nalloc = max_servers; 458 mc->ntotal = 0; 459 mc->live_servers = apr_palloc(p, mc->nalloc * sizeof(struct apr_memcache_server_t *)); 460 mc->hash_func = NULL; 461 mc->hash_baton = NULL; 462 mc->server_func = NULL; 463 mc->server_baton = NULL; 464 *memcache = mc; 465 return rv; 466} 467 468 469/* The crc32 functions and data was originally written by Spencer 470 * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source 471 * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at 472 * src/usr.bin/cksum/crc32.c. 473 */ 474 475static const apr_uint32_t crc32tab[256] = { 476 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 477 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 478 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 479 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 480 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 481 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 482 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 483 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 484 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 485 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 486 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 487 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 488 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 489 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 490 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 491 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 492 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 493 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 494 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 495 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 496 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 497 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 498 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 499 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 500 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 501 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 502 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 503 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 504 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 505 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 506 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 507 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 508 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 509 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 510 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 511 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 512 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 513 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 514 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 515 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 516 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 517 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 518 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 519 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 520 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 521 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 522 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 523 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 524 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 525 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 526 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 527 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 528 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 529 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 530 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 531 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 532 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 533 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 534 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 535 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 536 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 537 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 538 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 539 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 540}; 541 542APU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, 543 const char *data, 544 const apr_size_t data_len) 545{ 546 apr_uint32_t i; 547 apr_uint32_t crc; 548 crc = ~0; 549 550 for (i = 0; i < data_len; i++) 551 crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff]; 552 553 return ~crc; 554} 555 556APU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, 557 const char *data, 558 const apr_size_t data_len) 559{ 560 /* The default Perl Client doesn't actually use just crc32 -- it shifts it again 561 * like this.... 562 */ 563 return ((apr_memcache_hash_crc32(baton, data, data_len) >> 16) & 0x7fff); 564} 565 566APU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, 567 const char *data, 568 const apr_size_t data_len) 569{ 570 if (mc->hash_func) { 571 return mc->hash_func(mc->hash_baton, data, data_len); 572 } 573 else { 574 return apr_memcache_hash_default(NULL, data, data_len); 575 } 576} 577 578static apr_status_t get_server_line(apr_memcache_conn_t *conn) 579{ 580 apr_size_t bsize = BUFFER_SIZE; 581 apr_status_t rv = APR_SUCCESS; 582 583 rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, BUFFER_SIZE); 584 585 if (rv != APR_SUCCESS) { 586 return rv; 587 } 588 589 rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize); 590 591 if (rv != APR_SUCCESS) { 592 return rv; 593 } 594 595 conn->blen = bsize; 596 conn->buffer[bsize] = '\0'; 597 598 return apr_brigade_cleanup(conn->tb); 599} 600 601static apr_status_t storage_cmd_write(apr_memcache_t *mc, 602 char *cmd, 603 const apr_size_t cmd_size, 604 const char *key, 605 char *data, 606 const apr_size_t data_size, 607 apr_uint32_t timeout, 608 apr_uint16_t flags) 609{ 610 apr_uint32_t hash; 611 apr_memcache_server_t *ms; 612 apr_memcache_conn_t *conn; 613 apr_status_t rv; 614 apr_size_t written; 615 struct iovec vec[5]; 616 apr_size_t klen; 617 618 apr_size_t key_size = strlen(key); 619 620 hash = apr_memcache_hash(mc, key, key_size); 621 622 ms = apr_memcache_find_server_hash(mc, hash); 623 624 if (ms == NULL) 625 return APR_NOTFOUND; 626 627 rv = ms_find_conn(ms, &conn); 628 629 if (rv != APR_SUCCESS) { 630 apr_memcache_disable_server(mc, ms); 631 return rv; 632 } 633 634 /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */ 635 636 vec[0].iov_base = cmd; 637 vec[0].iov_len = cmd_size; 638 639 vec[1].iov_base = (void*)key; 640 vec[1].iov_len = key_size; 641 642 klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u %u %" APR_SIZE_T_FMT " " MC_EOL, 643 flags, timeout, data_size); 644 645 vec[2].iov_base = conn->buffer; 646 vec[2].iov_len = klen; 647 648 vec[3].iov_base = data; 649 vec[3].iov_len = data_size; 650 651 vec[4].iov_base = MC_EOL; 652 vec[4].iov_len = MC_EOL_LEN; 653 654 rv = apr_socket_sendv(conn->sock, vec, 5, &written); 655 656 if (rv != APR_SUCCESS) { 657 ms_bad_conn(ms, conn); 658 apr_memcache_disable_server(mc, ms); 659 return rv; 660 } 661 662 rv = get_server_line(conn); 663 664 if (rv != APR_SUCCESS) { 665 ms_bad_conn(ms, conn); 666 apr_memcache_disable_server(mc, ms); 667 return rv; 668 } 669 670 if (strcmp(conn->buffer, MS_STORED MC_EOL) == 0) { 671 rv = APR_SUCCESS; 672 } 673 else if (strcmp(conn->buffer, MS_NOT_STORED MC_EOL) == 0) { 674 rv = APR_EEXIST; 675 } 676 else { 677 rv = APR_EGENERAL; 678 } 679 680 ms_release_conn(ms, conn); 681 682 return rv; 683} 684 685APU_DECLARE(apr_status_t) 686apr_memcache_set(apr_memcache_t *mc, 687 const char *key, 688 char *data, 689 const apr_size_t data_size, 690 apr_uint32_t timeout, 691 apr_uint16_t flags) 692{ 693 return storage_cmd_write(mc, 694 MC_SET, MC_SET_LEN, 695 key, 696 data, data_size, 697 timeout, flags); 698} 699 700APU_DECLARE(apr_status_t) 701apr_memcache_add(apr_memcache_t *mc, 702 const char *key, 703 char *data, 704 const apr_size_t data_size, 705 apr_uint32_t timeout, 706 apr_uint16_t flags) 707{ 708 return storage_cmd_write(mc, 709 MC_ADD, MC_ADD_LEN, 710 key, 711 data, data_size, 712 timeout, flags); 713} 714 715APU_DECLARE(apr_status_t) 716apr_memcache_replace(apr_memcache_t *mc, 717 const char *key, 718 char *data, 719 const apr_size_t data_size, 720 apr_uint32_t timeout, 721 apr_uint16_t flags) 722{ 723 return storage_cmd_write(mc, 724 MC_REPLACE, MC_REPLACE_LEN, 725 key, 726 data, data_size, 727 timeout, flags); 728 729} 730 731APU_DECLARE(apr_status_t) 732apr_memcache_getp(apr_memcache_t *mc, 733 apr_pool_t *p, 734 const char *key, 735 char **baton, 736 apr_size_t *new_length, 737 apr_uint16_t *flags_) 738{ 739 apr_status_t rv; 740 apr_memcache_server_t *ms; 741 apr_memcache_conn_t *conn; 742 apr_uint32_t hash; 743 apr_size_t written; 744 apr_size_t klen = strlen(key); 745 struct iovec vec[3]; 746 747 hash = apr_memcache_hash(mc, key, klen); 748 ms = apr_memcache_find_server_hash(mc, hash); 749 if (ms == NULL) 750 return APR_NOTFOUND; 751 752 rv = ms_find_conn(ms, &conn); 753 754 if (rv != APR_SUCCESS) { 755 apr_memcache_disable_server(mc, ms); 756 return rv; 757 } 758 759 /* get <key>[ <key>[...]]\r\n */ 760 vec[0].iov_base = MC_GET; 761 vec[0].iov_len = MC_GET_LEN; 762 763 vec[1].iov_base = (void*)key; 764 vec[1].iov_len = klen; 765 766 vec[2].iov_base = MC_EOL; 767 vec[2].iov_len = MC_EOL_LEN; 768 769 rv = apr_socket_sendv(conn->sock, vec, 3, &written); 770 771 if (rv != APR_SUCCESS) { 772 ms_bad_conn(ms, conn); 773 apr_memcache_disable_server(mc, ms); 774 return rv; 775 } 776 777 rv = get_server_line(conn); 778 if (rv != APR_SUCCESS) { 779 ms_bad_conn(ms, conn); 780 apr_memcache_disable_server(mc, ms); 781 return rv; 782 } 783 784 if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { 785 char *flags; 786 char *length; 787 char *last; 788 apr_size_t len = 0; 789 790 flags = apr_strtok(conn->buffer, " ", &last); 791 flags = apr_strtok(NULL, " ", &last); 792 flags = apr_strtok(NULL, " ", &last); 793 794 if (flags_) { 795 *flags_ = atoi(flags); 796 } 797 798 length = apr_strtok(NULL, " ", &last); 799 if (length) { 800 len = strtol(length, (char **)NULL, 10); 801 } 802 803 if (len == 0 ) { 804 *new_length = 0; 805 *baton = NULL; 806 } 807 else { 808 apr_bucket_brigade *bbb; 809 apr_bucket *e; 810 811 /* eat the trailing \r\n */ 812 rv = apr_brigade_partition(conn->bb, len+2, &e); 813 814 if (rv != APR_SUCCESS) { 815 ms_bad_conn(ms, conn); 816 apr_memcache_disable_server(mc, ms); 817 return rv; 818 } 819 820 bbb = apr_brigade_split(conn->bb, e); 821 822 rv = apr_brigade_pflatten(conn->bb, baton, &len, p); 823 824 if (rv != APR_SUCCESS) { 825 ms_bad_conn(ms, conn); 826 apr_memcache_disable_server(mc, ms); 827 return rv; 828 } 829 830 rv = apr_brigade_destroy(conn->bb); 831 if (rv != APR_SUCCESS) { 832 ms_bad_conn(ms, conn); 833 apr_memcache_disable_server(mc, ms); 834 return rv; 835 } 836 837 conn->bb = bbb; 838 839 *new_length = len - 2; 840 (*baton)[*new_length] = '\0'; 841 } 842 843 rv = get_server_line(conn); 844 if (rv != APR_SUCCESS) { 845 ms_bad_conn(ms, conn); 846 apr_memcache_disable_server(mc, ms); 847 return rv; 848 } 849 850 if (strncmp(MS_END, conn->buffer, MS_END_LEN) != 0) { 851 rv = APR_EGENERAL; 852 } 853 } 854 else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 855 rv = APR_NOTFOUND; 856 } 857 else { 858 rv = APR_EGENERAL; 859 } 860 861 ms_release_conn(ms, conn); 862 863 return rv; 864} 865 866APU_DECLARE(apr_status_t) 867apr_memcache_delete(apr_memcache_t *mc, 868 const char *key, 869 apr_uint32_t timeout) 870{ 871 apr_status_t rv; 872 apr_memcache_server_t *ms; 873 apr_memcache_conn_t *conn; 874 apr_uint32_t hash; 875 apr_size_t written; 876 struct iovec vec[3]; 877 apr_size_t klen = strlen(key); 878 879 hash = apr_memcache_hash(mc, key, klen); 880 ms = apr_memcache_find_server_hash(mc, hash); 881 if (ms == NULL) 882 return APR_NOTFOUND; 883 884 rv = ms_find_conn(ms, &conn); 885 886 if (rv != APR_SUCCESS) { 887 apr_memcache_disable_server(mc, ms); 888 return rv; 889 } 890 891 /* delete <key> <time>\r\n */ 892 vec[0].iov_base = MC_DELETE; 893 vec[0].iov_len = MC_DELETE_LEN; 894 895 vec[1].iov_base = (void*)key; 896 vec[1].iov_len = klen; 897 898 klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, timeout); 899 900 vec[2].iov_base = conn->buffer; 901 vec[2].iov_len = klen; 902 903 rv = apr_socket_sendv(conn->sock, vec, 3, &written); 904 905 if (rv != APR_SUCCESS) { 906 ms_bad_conn(ms, conn); 907 apr_memcache_disable_server(mc, ms); 908 return rv; 909 } 910 911 rv = get_server_line(conn); 912 if (rv != APR_SUCCESS) { 913 ms_bad_conn(ms, conn); 914 apr_memcache_disable_server(mc, ms); 915 return rv; 916 } 917 918 if (strncmp(MS_DELETED, conn->buffer, MS_DELETED_LEN) == 0) { 919 rv = APR_SUCCESS; 920 } 921 else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { 922 rv = APR_NOTFOUND; 923 } 924 else { 925 rv = APR_EGENERAL; 926 } 927 928 ms_release_conn(ms, conn); 929 930 return rv; 931} 932 933static apr_status_t num_cmd_write(apr_memcache_t *mc, 934 char *cmd, 935 const apr_uint32_t cmd_size, 936 const char *key, 937 const apr_int32_t inc, 938 apr_uint32_t *new_value) 939{ 940 apr_status_t rv; 941 apr_memcache_server_t *ms; 942 apr_memcache_conn_t *conn; 943 apr_uint32_t hash; 944 apr_size_t written; 945 struct iovec vec[3]; 946 apr_size_t klen = strlen(key); 947 948 hash = apr_memcache_hash(mc, key, klen); 949 ms = apr_memcache_find_server_hash(mc, hash); 950 if (ms == NULL) 951 return APR_NOTFOUND; 952 953 rv = ms_find_conn(ms, &conn); 954 955 if (rv != APR_SUCCESS) { 956 apr_memcache_disable_server(mc, ms); 957 return rv; 958 } 959 960 /* <cmd> <key> <value>\r\n */ 961 vec[0].iov_base = cmd; 962 vec[0].iov_len = cmd_size; 963 964 vec[1].iov_base = (void*)key; 965 vec[1].iov_len = klen; 966 967 klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, inc); 968 969 vec[2].iov_base = conn->buffer; 970 vec[2].iov_len = klen; 971 972 rv = apr_socket_sendv(conn->sock, vec, 3, &written); 973 974 if (rv != APR_SUCCESS) { 975 ms_bad_conn(ms, conn); 976 apr_memcache_disable_server(mc, ms); 977 return rv; 978 } 979 980 rv = get_server_line(conn); 981 if (rv != APR_SUCCESS) { 982 ms_bad_conn(ms, conn); 983 apr_memcache_disable_server(mc, ms); 984 return rv; 985 } 986 987 if (strncmp(MS_ERROR, conn->buffer, MS_ERROR_LEN) == 0) { 988 rv = APR_EGENERAL; 989 } 990 else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { 991 rv = APR_NOTFOUND; 992 } 993 else { 994 if (new_value) { 995 *new_value = atoi(conn->buffer); 996 } 997 rv = APR_SUCCESS; 998 } 999 1000 ms_release_conn(ms, conn); 1001 1002 return rv; 1003} 1004 1005APU_DECLARE(apr_status_t) 1006apr_memcache_incr(apr_memcache_t *mc, 1007 const char *key, 1008 apr_int32_t inc, 1009 apr_uint32_t *new_value) 1010{ 1011 return num_cmd_write(mc, 1012 MC_INCR, 1013 MC_INCR_LEN, 1014 key, 1015 inc, 1016 new_value); 1017} 1018 1019 1020APU_DECLARE(apr_status_t) 1021apr_memcache_decr(apr_memcache_t *mc, 1022 const char *key, 1023 apr_int32_t inc, 1024 apr_uint32_t *new_value) 1025{ 1026 return num_cmd_write(mc, 1027 MC_DECR, 1028 MC_DECR_LEN, 1029 key, 1030 inc, 1031 new_value); 1032} 1033 1034 1035 1036APU_DECLARE(apr_status_t) 1037apr_memcache_version(apr_memcache_server_t *ms, 1038 apr_pool_t *p, 1039 char **baton) 1040{ 1041 apr_status_t rv; 1042 apr_memcache_conn_t *conn; 1043 apr_size_t written; 1044 struct iovec vec[2]; 1045 1046 rv = ms_find_conn(ms, &conn); 1047 1048 if (rv != APR_SUCCESS) { 1049 return rv; 1050 } 1051 1052 /* version\r\n */ 1053 vec[0].iov_base = MC_VERSION; 1054 vec[0].iov_len = MC_VERSION_LEN; 1055 1056 vec[1].iov_base = MC_EOL; 1057 vec[1].iov_len = MC_EOL_LEN; 1058 1059 rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1060 1061 if (rv != APR_SUCCESS) { 1062 ms_bad_conn(ms, conn); 1063 return rv; 1064 } 1065 1066 rv = get_server_line(conn); 1067 if (rv != APR_SUCCESS) { 1068 ms_bad_conn(ms, conn); 1069 return rv; 1070 } 1071 1072 if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) { 1073 *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1, 1074 conn->blen - MS_VERSION_LEN - 2); 1075 rv = APR_SUCCESS; 1076 } 1077 else { 1078 rv = APR_EGENERAL; 1079 } 1080 1081 ms_release_conn(ms, conn); 1082 1083 return rv; 1084} 1085 1086apr_status_t mc_version_ping(apr_memcache_server_t *ms) 1087{ 1088 apr_status_t rv; 1089 apr_size_t written; 1090 struct iovec vec[2]; 1091 apr_memcache_conn_t *conn; 1092 1093 rv = ms_find_conn(ms, &conn); 1094 1095 if (rv != APR_SUCCESS) { 1096 return rv; 1097 } 1098 1099 /* version\r\n */ 1100 vec[0].iov_base = MC_VERSION; 1101 vec[0].iov_len = MC_VERSION_LEN; 1102 1103 vec[1].iov_base = MC_EOL; 1104 vec[1].iov_len = MC_EOL_LEN; 1105 1106 rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1107 1108 if (rv != APR_SUCCESS) { 1109 ms_bad_conn(ms, conn); 1110 return rv; 1111 } 1112 1113 rv = get_server_line(conn); 1114 ms_release_conn(ms, conn); 1115 return rv; 1116} 1117 1118 1119APU_DECLARE(void) 1120apr_memcache_add_multget_key(apr_pool_t *data_pool, 1121 const char* key, 1122 apr_hash_t **values) 1123{ 1124 apr_memcache_value_t* value; 1125 apr_size_t klen = strlen(key); 1126 1127 /* create the value hash if need be */ 1128 if (!*values) { 1129 *values = apr_hash_make(data_pool); 1130 } 1131 1132 /* init key and add it to the value hash */ 1133 value = apr_pcalloc(data_pool, sizeof(apr_memcache_value_t)); 1134 1135 value->status = APR_NOTFOUND; 1136 value->key = apr_pstrdup(data_pool, key); 1137 1138 apr_hash_set(*values, value->key, klen, value); 1139} 1140 1141static void mget_conn_result(int serverup, 1142 int connup, 1143 apr_status_t rv, 1144 apr_memcache_t *mc, 1145 apr_memcache_server_t *ms, 1146 apr_memcache_conn_t *conn, 1147 struct cache_server_query_t *server_query, 1148 apr_hash_t *values, 1149 apr_hash_t *server_queries) 1150{ 1151 apr_int32_t j; 1152 apr_memcache_value_t* value; 1153 1154 apr_hash_set(server_queries, &ms, sizeof(ms), NULL); 1155 1156 if (connup) { 1157 ms_release_conn(ms, conn); 1158 } else { 1159 ms_bad_conn(ms, conn); 1160 1161 if (!serverup) { 1162 apr_memcache_disable_server(mc, ms); 1163 } 1164 } 1165 1166 for (j = 1; j < server_query->query_vec_count ; j+=2) { 1167 if (server_query->query_vec[j].iov_base) { 1168 value = apr_hash_get(values, server_query->query_vec[j].iov_base, 1169 strlen(server_query->query_vec[j].iov_base)); 1170 1171 if (value->status == APR_NOTFOUND) { 1172 value->status = rv; 1173 } 1174 } 1175 } 1176} 1177 1178APU_DECLARE(apr_status_t) 1179apr_memcache_multgetp(apr_memcache_t *mc, 1180 apr_pool_t *temp_pool, 1181 apr_pool_t *data_pool, 1182 apr_hash_t *values) 1183{ 1184 apr_status_t rv; 1185 apr_memcache_server_t* ms; 1186 apr_memcache_conn_t* conn; 1187 apr_uint32_t hash; 1188 apr_size_t written; 1189 apr_size_t klen; 1190 1191 apr_memcache_value_t* value; 1192 apr_hash_index_t* value_hash_index; 1193 1194 /* this is a little over aggresive, but beats multiple loops 1195 * to figure out how long each vector needs to be per-server. 1196 */ 1197 apr_int32_t veclen = 2 + 2 * apr_hash_count(values) - 1; /* get <key>[<space><key>...]\r\n */ 1198 apr_int32_t i, j; 1199 apr_int32_t queries_sent; 1200 apr_int32_t queries_recvd; 1201 1202 apr_hash_t * server_queries = apr_hash_make(temp_pool); 1203 struct cache_server_query_t* server_query; 1204 apr_hash_index_t * query_hash_index; 1205 1206 apr_pollset_t* pollset; 1207 const apr_pollfd_t* activefds; 1208 apr_pollfd_t* pollfds; 1209 1210 1211 /* build all the queries */ 1212 value_hash_index = apr_hash_first(temp_pool, values); 1213 while (value_hash_index) { 1214 void *v; 1215 apr_hash_this(value_hash_index, NULL, NULL, &v); 1216 value = v; 1217 value_hash_index = apr_hash_next(value_hash_index); 1218 klen = strlen(value->key); 1219 1220 hash = apr_memcache_hash(mc, value->key, klen); 1221 ms = apr_memcache_find_server_hash(mc, hash); 1222 if (ms == NULL) { 1223 continue; 1224 } 1225 1226 server_query = apr_hash_get(server_queries, &ms, sizeof(ms)); 1227 1228 if (!server_query) { 1229 rv = ms_find_conn(ms, &conn); 1230 1231 if (rv != APR_SUCCESS) { 1232 apr_memcache_disable_server(mc, ms); 1233 value->status = rv; 1234 continue; 1235 } 1236 1237 server_query = apr_pcalloc(temp_pool,sizeof(struct cache_server_query_t)); 1238 1239 apr_hash_set(server_queries, &ms, sizeof(ms), server_query); 1240 1241 server_query->ms = ms; 1242 server_query->conn = conn; 1243 server_query->query_vec = apr_pcalloc(temp_pool, sizeof(struct iovec)*veclen); 1244 1245 /* set up the first key */ 1246 server_query->query_vec[0].iov_base = MC_GET; 1247 server_query->query_vec[0].iov_len = MC_GET_LEN; 1248 1249 server_query->query_vec[1].iov_base = (void*)(value->key); 1250 server_query->query_vec[1].iov_len = klen; 1251 1252 server_query->query_vec[2].iov_base = MC_EOL; 1253 server_query->query_vec[2].iov_len = MC_EOL_LEN; 1254 1255 server_query->query_vec_count = 3; 1256 } 1257 else { 1258 j = server_query->query_vec_count - 1; 1259 1260 server_query->query_vec[j].iov_base = MC_WS; 1261 server_query->query_vec[j].iov_len = MC_WS_LEN; 1262 j++; 1263 1264 server_query->query_vec[j].iov_base = (void*)(value->key); 1265 server_query->query_vec[j].iov_len = klen; 1266 j++; 1267 1268 server_query->query_vec[j].iov_base = MC_EOL; 1269 server_query->query_vec[j].iov_len = MC_EOL_LEN; 1270 j++; 1271 1272 server_query->query_vec_count = j; 1273 } 1274 } 1275 1276 /* create polling structures */ 1277 pollfds = apr_pcalloc(temp_pool, apr_hash_count(server_queries) * sizeof(apr_pollfd_t)); 1278 1279 rv = apr_pollset_create(&pollset, apr_hash_count(server_queries), temp_pool, 0); 1280 1281 if (rv != APR_SUCCESS) { 1282 query_hash_index = apr_hash_first(temp_pool, server_queries); 1283 1284 while (query_hash_index) { 1285 void *v; 1286 apr_hash_this(query_hash_index, NULL, NULL, &v); 1287 server_query = v; 1288 query_hash_index = apr_hash_next(query_hash_index); 1289 1290 mget_conn_result(TRUE, TRUE, rv, mc, server_query->ms, server_query->conn, 1291 server_query, values, server_queries); 1292 } 1293 1294 return rv; 1295 } 1296 1297 /* send all the queries */ 1298 queries_sent = 0; 1299 query_hash_index = apr_hash_first(temp_pool, server_queries); 1300 1301 while (query_hash_index) { 1302 void *v; 1303 apr_hash_this(query_hash_index, NULL, NULL, &v); 1304 server_query = v; 1305 query_hash_index = apr_hash_next(query_hash_index); 1306 1307 conn = server_query->conn; 1308 ms = server_query->ms; 1309 1310 for (i = 0, rv = APR_SUCCESS; i < veclen && rv == APR_SUCCESS; i += APR_MAX_IOVEC_SIZE) { 1311 rv = apr_socket_sendv(conn->sock, &(server_query->query_vec[i]), 1312 veclen-i>APR_MAX_IOVEC_SIZE ? APR_MAX_IOVEC_SIZE : veclen-i , &written); 1313 } 1314 1315 if (rv != APR_SUCCESS) { 1316 mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1317 server_query, values, server_queries); 1318 continue; 1319 } 1320 1321 pollfds[queries_sent].desc_type = APR_POLL_SOCKET; 1322 pollfds[queries_sent].reqevents = APR_POLLIN; 1323 pollfds[queries_sent].p = temp_pool; 1324 pollfds[queries_sent].desc.s = conn->sock; 1325 pollfds[queries_sent].client_data = (void *)server_query; 1326 apr_pollset_add (pollset, &pollfds[queries_sent]); 1327 1328 queries_sent++; 1329 } 1330 1331 while (queries_sent) { 1332 rv = apr_pollset_poll(pollset, MULT_GET_TIMEOUT, &queries_recvd, &activefds); 1333 1334 if (rv != APR_SUCCESS) { 1335 /* timeout */ 1336 queries_sent = 0; 1337 continue; 1338 } 1339 for (i = 0; i < queries_recvd; i++) { 1340 server_query = activefds[i].client_data; 1341 conn = server_query->conn; 1342 ms = server_query->ms; 1343 1344 rv = get_server_line(conn); 1345 1346 if (rv != APR_SUCCESS) { 1347 apr_pollset_remove (pollset, &activefds[i]); 1348 mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1349 server_query, values, server_queries); 1350 queries_sent--; 1351 continue; 1352 } 1353 1354 if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { 1355 char *key; 1356 char *flags; 1357 char *length; 1358 char *last; 1359 char *data; 1360 apr_size_t len = 0; 1361 1362 key = apr_strtok(conn->buffer, " ", &last); /* just the VALUE, ignore */ 1363 key = apr_strtok(NULL, " ", &last); 1364 flags = apr_strtok(NULL, " ", &last); 1365 1366 1367 length = apr_strtok(NULL, " ", &last); 1368 if (length) { 1369 len = strtol(length, (char **) NULL, 10); 1370 } 1371 1372 value = apr_hash_get(values, key, strlen(key)); 1373 1374 1375 if (value) { 1376 if (len != 0) { 1377 apr_bucket_brigade *bbb; 1378 apr_bucket *e; 1379 1380 /* eat the trailing \r\n */ 1381 rv = apr_brigade_partition(conn->bb, len+2, &e); 1382 1383 if (rv != APR_SUCCESS) { 1384 apr_pollset_remove (pollset, &activefds[i]); 1385 mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1386 server_query, values, server_queries); 1387 queries_sent--; 1388 continue; 1389 } 1390 1391 bbb = apr_brigade_split(conn->bb, e); 1392 1393 rv = apr_brigade_pflatten(conn->bb, &data, &len, data_pool); 1394 1395 if (rv != APR_SUCCESS) { 1396 apr_pollset_remove (pollset, &activefds[i]); 1397 mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1398 server_query, values, server_queries); 1399 queries_sent--; 1400 continue; 1401 } 1402 1403 rv = apr_brigade_destroy(conn->bb); 1404 if (rv != APR_SUCCESS) { 1405 apr_pollset_remove (pollset, &activefds[i]); 1406 mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1407 server_query, values, server_queries); 1408 queries_sent--; 1409 continue; 1410 } 1411 1412 conn->bb = bbb; 1413 1414 value->len = len - 2; 1415 data[value->len] = '\0'; 1416 value->data = data; 1417 } 1418 1419 value->status = rv; 1420 value->flags = atoi(flags); 1421 1422 /* stay on the server */ 1423 i--; 1424 1425 } 1426 else { 1427 /* TODO: Server Sent back a key I didn't ask for or my 1428 * hash is corrupt */ 1429 } 1430 } 1431 else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 1432 /* this connection is done */ 1433 apr_pollset_remove (pollset, &activefds[i]); 1434 ms_release_conn(ms, conn); 1435 apr_hash_set(server_queries, &ms, sizeof(ms), NULL); 1436 1437 queries_sent--; 1438 } 1439 else { 1440 /* unknown reply? */ 1441 rv = APR_EGENERAL; 1442 } 1443 1444 } /* /for */ 1445 } /* /while */ 1446 1447 query_hash_index = apr_hash_first(temp_pool, server_queries); 1448 while (query_hash_index) { 1449 void *v; 1450 apr_hash_this(query_hash_index, NULL, NULL, &v); 1451 server_query = v; 1452 query_hash_index = apr_hash_next(query_hash_index); 1453 1454 conn = server_query->conn; 1455 ms = server_query->ms; 1456 1457 mget_conn_result(TRUE, (rv == APR_SUCCESS), rv, mc, ms, conn, 1458 server_query, values, server_queries); 1459 continue; 1460 } 1461 1462 apr_pollset_destroy(pollset); 1463 apr_pool_clear(temp_pool); 1464 return APR_SUCCESS; 1465 1466} 1467 1468 1469 1470/** 1471 * Define all of the strings for stats 1472 */ 1473 1474#define STAT_pid MS_STAT " pid " 1475#define STAT_pid_LEN (sizeof(STAT_pid)-1) 1476 1477#define STAT_uptime MS_STAT " uptime " 1478#define STAT_uptime_LEN (sizeof(STAT_uptime)-1) 1479 1480#define STAT_time MS_STAT " time " 1481#define STAT_time_LEN (sizeof(STAT_time)-1) 1482 1483#define STAT_version MS_STAT " version " 1484#define STAT_version_LEN (sizeof(STAT_version)-1) 1485 1486#define STAT_pointer_size MS_STAT " pointer_size " 1487#define STAT_pointer_size_LEN (sizeof(STAT_pointer_size)-1) 1488 1489#define STAT_rusage_user MS_STAT " rusage_user " 1490#define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1) 1491 1492#define STAT_rusage_system MS_STAT " rusage_system " 1493#define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1) 1494 1495#define STAT_curr_items MS_STAT " curr_items " 1496#define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1) 1497 1498#define STAT_total_items MS_STAT " total_items " 1499#define STAT_total_items_LEN (sizeof(STAT_total_items)-1) 1500 1501#define STAT_bytes MS_STAT " bytes " 1502#define STAT_bytes_LEN (sizeof(STAT_bytes)-1) 1503 1504#define STAT_curr_connections MS_STAT " curr_connections " 1505#define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1) 1506 1507#define STAT_total_connections MS_STAT " total_connections " 1508#define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1) 1509 1510#define STAT_connection_structures MS_STAT " connection_structures " 1511#define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1) 1512 1513#define STAT_cmd_get MS_STAT " cmd_get " 1514#define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1) 1515 1516#define STAT_cmd_set MS_STAT " cmd_set " 1517#define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1) 1518 1519#define STAT_get_hits MS_STAT " get_hits " 1520#define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1) 1521 1522#define STAT_get_misses MS_STAT " get_misses " 1523#define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1) 1524 1525#define STAT_evictions MS_STAT " evictions " 1526#define STAT_evictions_LEN (sizeof(STAT_evictions)-1) 1527 1528#define STAT_bytes_read MS_STAT " bytes_read " 1529#define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1) 1530 1531#define STAT_bytes_written MS_STAT " bytes_written " 1532#define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1) 1533 1534#define STAT_limit_maxbytes MS_STAT " limit_maxbytes " 1535#define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1) 1536 1537#define STAT_threads MS_STAT " threads " 1538#define STAT_threads_LEN (sizeof(STAT_threads)-1) 1539 1540static const char *stat_read_string(apr_pool_t *p, char *buf, apr_size_t len) 1541{ 1542 /* remove trailing \r\n and null char */ 1543 return apr_pstrmemdup(p, buf, len-2); 1544} 1545 1546static apr_uint32_t stat_read_uint32(apr_pool_t *p, char *buf, apr_size_t len) 1547{ 1548 buf[len-2] = '\0'; 1549 return atoi(buf); 1550} 1551 1552static apr_uint64_t stat_read_uint64(apr_pool_t *p, char *buf, apr_size_t len) 1553{ 1554 buf[len-2] = '\0'; 1555 return apr_atoi64(buf); 1556} 1557 1558static apr_time_t stat_read_time(apr_pool_t *p, char *buf, apr_size_t len) 1559{ 1560 buf[len-2] = '\0'; 1561 return apr_time_from_sec(atoi(buf)); 1562} 1563 1564static apr_time_t stat_read_rtime(apr_pool_t *p, char *buf, apr_size_t len) 1565{ 1566 char *tok; 1567 char *secs; 1568 char *usecs; 1569 const char *sep = ":."; 1570 1571 buf[len-2] = '\0'; 1572 1573 secs = apr_strtok(buf, sep, &tok); 1574 usecs = apr_strtok(NULL, sep, &tok); 1575 if (secs && usecs) { 1576 return apr_time_make(atoi(secs), atoi(usecs)); 1577 } 1578 else { 1579 return apr_time_make(0, 0); 1580 } 1581} 1582 1583/** 1584 * I got tired of Typing. Meh. 1585 * 1586 * TODO: Convert it to static tables to make it cooler. 1587 */ 1588 1589#define mc_stat_cmp(name) \ 1590 strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0 1591 1592#define mc_stat_str(name) \ 1593 stat_read_string(p, conn->buffer + name, \ 1594 conn->blen - name) 1595 1596#define mc_stat_uint32(name) \ 1597 stat_read_uint32(p, conn->buffer + name, \ 1598 conn->blen - name) 1599 1600#define mc_stat_uint64(name) \ 1601 stat_read_uint64(p, conn->buffer + name, \ 1602 conn->blen - name) 1603 1604#define mc_stat_time(name) \ 1605 stat_read_time(p, conn->buffer + name, \ 1606 conn->blen - name) 1607 1608#define mc_stat_rtime(name) \ 1609 stat_read_rtime(p, conn->buffer + name, \ 1610 conn->blen - name) 1611 1612 1613#define mc_do_stat(name, type) \ 1614 if (mc_stat_cmp(name)) { \ 1615 stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \ 1616 } 1617 1618static void update_stats(apr_pool_t *p, apr_memcache_conn_t *conn, 1619 apr_memcache_stats_t *stats) 1620{ 1621 1622 mc_do_stat(version, str) 1623 else mc_do_stat(pid, uint32) 1624 else mc_do_stat(uptime, uint32) 1625 else mc_do_stat(pointer_size, uint32) 1626 else mc_do_stat(time, time) 1627 else mc_do_stat(rusage_user, rtime) 1628 else mc_do_stat(rusage_system, rtime) 1629 else mc_do_stat(curr_items, uint32) 1630 else mc_do_stat(total_items, uint32) 1631 else mc_do_stat(bytes, uint64) 1632 else mc_do_stat(curr_connections, uint32) 1633 else mc_do_stat(total_connections, uint32) 1634 else mc_do_stat(connection_structures, uint32) 1635 else mc_do_stat(cmd_get, uint32) 1636 else mc_do_stat(cmd_set, uint32) 1637 else mc_do_stat(get_hits, uint32) 1638 else mc_do_stat(get_misses, uint32) 1639 else mc_do_stat(evictions, uint64) 1640 else mc_do_stat(bytes_read, uint64) 1641 else mc_do_stat(bytes_written, uint64) 1642 else mc_do_stat(limit_maxbytes, uint32) 1643 else mc_do_stat(threads, uint32) 1644} 1645 1646APU_DECLARE(apr_status_t) 1647apr_memcache_stats(apr_memcache_server_t *ms, 1648 apr_pool_t *p, 1649 apr_memcache_stats_t **stats) 1650{ 1651 apr_memcache_stats_t *ret; 1652 apr_status_t rv; 1653 apr_memcache_conn_t *conn; 1654 apr_size_t written; 1655 struct iovec vec[2]; 1656 1657 rv = ms_find_conn(ms, &conn); 1658 1659 if (rv != APR_SUCCESS) { 1660 return rv; 1661 } 1662 1663 /* version\r\n */ 1664 vec[0].iov_base = MC_STATS; 1665 vec[0].iov_len = MC_STATS_LEN; 1666 1667 vec[1].iov_base = MC_EOL; 1668 vec[1].iov_len = MC_EOL_LEN; 1669 1670 rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1671 1672 if (rv != APR_SUCCESS) { 1673 ms_bad_conn(ms, conn); 1674 return rv; 1675 } 1676 1677 ret = apr_pcalloc(p, sizeof(apr_memcache_stats_t)); 1678 1679 do { 1680 rv = get_server_line(conn); 1681 if (rv != APR_SUCCESS) { 1682 ms_bad_conn(ms, conn); 1683 return rv; 1684 } 1685 1686 if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 1687 rv = APR_SUCCESS; 1688 break; 1689 } 1690 else if (strncmp(MS_STAT, conn->buffer, MS_STAT_LEN) == 0) { 1691 update_stats(p, conn, ret); 1692 continue; 1693 } 1694 else { 1695 rv = APR_EGENERAL; 1696 break; 1697 } 1698 1699 } while(1); 1700 1701 ms_release_conn(ms, conn); 1702 1703 if (stats) { 1704 *stats = ret; 1705 } 1706 1707 return rv; 1708} 1709 1710