1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251876Speter * contributor license agreements. See the NOTICE file distributed with 3251876Speter * this work for additional information regarding copyright ownership. 4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251876Speter * (the "License"); you may not use this file except in compliance with 6251876Speter * the License. You may obtain a copy of the License at 7251876Speter * 8251876Speter * http://www.apache.org/licenses/LICENSE-2.0 9251876Speter * 10251876Speter * Unless required by applicable law or agreed to in writing, software 11251876Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251876Speter * See the License for the specific language governing permissions and 14251876Speter * limitations under the License. 15251876Speter */ 16251876Speter 17251876Speter#include "apr_memcache.h" 18251876Speter#include "apr_poll.h" 19251876Speter#include "apr_version.h" 20251876Speter#include <stdlib.h> 21251876Speter 22251876Speter#define BUFFER_SIZE 512 23251876Speterstruct apr_memcache_conn_t 24251876Speter{ 25251876Speter char *buffer; 26251876Speter apr_size_t blen; 27251876Speter apr_pool_t *p; 28251876Speter apr_pool_t *tp; 29251876Speter apr_socket_t *sock; 30251876Speter apr_bucket_brigade *bb; 31251876Speter apr_bucket_brigade *tb; 32251876Speter apr_memcache_server_t *ms; 33251876Speter}; 34251876Speter 35251876Speter/* Strings for Client Commands */ 36251876Speter 37251876Speter#define MC_EOL "\r\n" 38251876Speter#define MC_EOL_LEN (sizeof(MC_EOL)-1) 39251876Speter 40251876Speter#define MC_WS " " 41251876Speter#define MC_WS_LEN (sizeof(MC_WS)-1) 42251876Speter 43251876Speter#define MC_GET "get " 44251876Speter#define MC_GET_LEN (sizeof(MC_GET)-1) 45251876Speter 46251876Speter#define MC_SET "set " 47251876Speter#define MC_SET_LEN (sizeof(MC_SET)-1) 48251876Speter 49251876Speter#define MC_ADD "add " 50251876Speter#define MC_ADD_LEN (sizeof(MC_ADD)-1) 51251876Speter 52251876Speter#define MC_REPLACE "replace " 53251876Speter#define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1) 54251876Speter 55251876Speter#define MC_DELETE "delete " 56251876Speter#define MC_DELETE_LEN (sizeof(MC_DELETE)-1) 57251876Speter 58251876Speter#define MC_INCR "incr " 59251876Speter#define MC_INCR_LEN (sizeof(MC_INCR)-1) 60251876Speter 61251876Speter#define MC_DECR "decr " 62251876Speter#define MC_DECR_LEN (sizeof(MC_DECR)-1) 63251876Speter 64251876Speter#define MC_VERSION "version" 65251876Speter#define MC_VERSION_LEN (sizeof(MC_VERSION)-1) 66251876Speter 67251876Speter#define MC_STATS "stats" 68251876Speter#define MC_STATS_LEN (sizeof(MC_STATS)-1) 69251876Speter 70251876Speter#define MC_QUIT "quit" 71251876Speter#define MC_QUIT_LEN (sizeof(MC_QUIT)-1) 72251876Speter 73251876Speter/* Strings for Server Replies */ 74251876Speter 75251876Speter#define MS_STORED "STORED" 76251876Speter#define MS_STORED_LEN (sizeof(MS_STORED)-1) 77251876Speter 78251876Speter#define MS_NOT_STORED "NOT_STORED" 79251876Speter#define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1) 80251876Speter 81251876Speter#define MS_DELETED "DELETED" 82251876Speter#define MS_DELETED_LEN (sizeof(MS_DELETED)-1) 83251876Speter 84251876Speter#define MS_NOT_FOUND "NOT_FOUND" 85251876Speter#define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1) 86251876Speter 87251876Speter#define MS_VALUE "VALUE" 88251876Speter#define MS_VALUE_LEN (sizeof(MS_VALUE)-1) 89251876Speter 90251876Speter#define MS_ERROR "ERROR" 91251876Speter#define MS_ERROR_LEN (sizeof(MS_ERROR)-1) 92251876Speter 93251876Speter#define MS_VERSION "VERSION" 94251876Speter#define MS_VERSION_LEN (sizeof(MS_VERSION)-1) 95251876Speter 96251876Speter#define MS_STAT "STAT" 97251876Speter#define MS_STAT_LEN (sizeof(MS_STAT)-1) 98251876Speter 99251876Speter#define MS_END "END" 100251876Speter#define MS_END_LEN (sizeof(MS_END)-1) 101251876Speter 102251876Speter/** Server and Query Structure for a multiple get */ 103251876Speterstruct cache_server_query_t { 104251876Speter apr_memcache_server_t* ms; 105251876Speter apr_memcache_conn_t* conn; 106251876Speter struct iovec* query_vec; 107251876Speter apr_int32_t query_vec_count; 108251876Speter}; 109251876Speter 110251876Speter#define MULT_GET_TIMEOUT 50000 111251876Speter 112251876Speterstatic apr_status_t make_server_dead(apr_memcache_t *mc, apr_memcache_server_t *ms) 113251876Speter{ 114251876Speter#if APR_HAS_THREADS 115251876Speter apr_thread_mutex_lock(ms->lock); 116251876Speter#endif 117251876Speter ms->status = APR_MC_SERVER_DEAD; 118251876Speter ms->btime = apr_time_now(); 119251876Speter#if APR_HAS_THREADS 120251876Speter apr_thread_mutex_unlock(ms->lock); 121251876Speter#endif 122251876Speter return APR_SUCCESS; 123251876Speter} 124251876Speter 125251876Speterstatic apr_status_t make_server_live(apr_memcache_t *mc, apr_memcache_server_t *ms) 126251876Speter{ 127251876Speter ms->status = APR_MC_SERVER_LIVE; 128251876Speter return APR_SUCCESS; 129251876Speter} 130251876Speter 131251876Speter 132251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 133251876Speter{ 134251876Speter apr_status_t rv = APR_SUCCESS; 135251876Speter 136251876Speter if(mc->ntotal >= mc->nalloc) { 137251876Speter return APR_ENOMEM; 138251876Speter } 139251876Speter 140251876Speter mc->live_servers[mc->ntotal] = ms; 141251876Speter mc->ntotal++; 142251876Speter make_server_live(mc, ms); 143251876Speter return rv; 144251876Speter} 145251876Speter 146251876Speterstatic apr_status_t mc_version_ping(apr_memcache_server_t *ms); 147251876Speter 148251876SpeterAPU_DECLARE(apr_memcache_server_t *) 149251876Speterapr_memcache_find_server_hash(apr_memcache_t *mc, const apr_uint32_t hash) 150251876Speter{ 151251876Speter if (mc->server_func) { 152251876Speter return mc->server_func(mc->server_baton, mc, hash); 153251876Speter } 154251876Speter else { 155251876Speter return apr_memcache_find_server_hash_default(NULL, mc, hash); 156251876Speter } 157251876Speter} 158251876Speter 159251876SpeterAPU_DECLARE(apr_memcache_server_t *) 160251876Speterapr_memcache_find_server_hash_default(void *baton, apr_memcache_t *mc, 161251876Speter const apr_uint32_t hash) 162251876Speter{ 163251876Speter apr_memcache_server_t *ms = NULL; 164251876Speter apr_uint32_t h = hash ? hash : 1; 165251876Speter apr_uint32_t i = 0; 166251876Speter apr_time_t curtime = 0; 167251876Speter 168251876Speter if(mc->ntotal == 0) { 169251876Speter return NULL; 170251876Speter } 171251876Speter 172251876Speter do { 173251876Speter ms = mc->live_servers[h % mc->ntotal]; 174251876Speter if(ms->status == APR_MC_SERVER_LIVE) { 175251876Speter break; 176251876Speter } 177251876Speter else { 178251876Speter if (curtime == 0) { 179251876Speter curtime = apr_time_now(); 180251876Speter } 181251876Speter#if APR_HAS_THREADS 182251876Speter apr_thread_mutex_lock(ms->lock); 183251876Speter#endif 184262253Speter /* Try the dead server, every 5 seconds */ 185251876Speter if (curtime - ms->btime > apr_time_from_sec(5)) { 186253734Speter ms->btime = curtime; 187251876Speter if (mc_version_ping(ms) == APR_SUCCESS) { 188251876Speter make_server_live(mc, ms); 189251876Speter#if APR_HAS_THREADS 190251876Speter apr_thread_mutex_unlock(ms->lock); 191251876Speter#endif 192251876Speter break; 193251876Speter } 194251876Speter } 195251876Speter#if APR_HAS_THREADS 196251876Speter apr_thread_mutex_unlock(ms->lock); 197251876Speter#endif 198251876Speter } 199251876Speter h++; 200251876Speter i++; 201251876Speter } while(i < mc->ntotal); 202251876Speter 203251876Speter if (i == mc->ntotal) { 204251876Speter ms = NULL; 205251876Speter } 206251876Speter 207251876Speter return ms; 208251876Speter} 209251876Speter 210251876SpeterAPU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, const char *host, apr_port_t port) 211251876Speter{ 212251876Speter int i; 213251876Speter 214251876Speter for (i = 0; i < mc->ntotal; i++) { 215251876Speter if (strcmp(mc->live_servers[i]->host, host) == 0 216251876Speter && mc->live_servers[i]->port == port) { 217251876Speter 218251876Speter return mc->live_servers[i]; 219251876Speter } 220251876Speter } 221251876Speter 222251876Speter return NULL; 223251876Speter} 224251876Speter 225251876Speterstatic apr_status_t ms_find_conn(apr_memcache_server_t *ms, apr_memcache_conn_t **conn) 226251876Speter{ 227251876Speter apr_status_t rv; 228251876Speter apr_bucket_alloc_t *balloc; 229251876Speter apr_bucket *e; 230251876Speter 231251876Speter#if APR_HAS_THREADS 232251876Speter rv = apr_reslist_acquire(ms->conns, (void **)conn); 233251876Speter#else 234251876Speter *conn = ms->conn; 235251876Speter rv = APR_SUCCESS; 236251876Speter#endif 237251876Speter 238251876Speter if (rv != APR_SUCCESS) { 239251876Speter return rv; 240251876Speter } 241251876Speter 242251876Speter balloc = apr_bucket_alloc_create((*conn)->tp); 243251876Speter (*conn)->bb = apr_brigade_create((*conn)->tp, balloc); 244251876Speter (*conn)->tb = apr_brigade_create((*conn)->tp, balloc); 245251876Speter 246251876Speter e = apr_bucket_socket_create((*conn)->sock, balloc); 247251876Speter APR_BRIGADE_INSERT_TAIL((*conn)->bb, e); 248251876Speter 249251876Speter return rv; 250251876Speter} 251251876Speter 252251876Speterstatic apr_status_t ms_bad_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) 253251876Speter{ 254251876Speter#if APR_HAS_THREADS 255251876Speter return apr_reslist_invalidate(ms->conns, conn); 256251876Speter#else 257251876Speter return APR_SUCCESS; 258251876Speter#endif 259251876Speter} 260251876Speter 261251876Speterstatic apr_status_t ms_release_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) 262251876Speter{ 263251876Speter apr_pool_clear(conn->tp); 264251876Speter#if APR_HAS_THREADS 265251876Speter return apr_reslist_release(ms->conns, conn); 266251876Speter#else 267251876Speter return APR_SUCCESS; 268251876Speter#endif 269251876Speter} 270251876Speter 271251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 272251876Speter{ 273251876Speter apr_status_t rv = APR_SUCCESS; 274251876Speter 275251876Speter if (ms->status == APR_MC_SERVER_LIVE) { 276251876Speter return rv; 277251876Speter } 278251876Speter 279251876Speter rv = make_server_live(mc, ms); 280251876Speter return rv; 281251876Speter} 282251876Speter 283251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) 284251876Speter{ 285251876Speter return make_server_dead(mc, ms); 286251876Speter} 287251876Speter 288251876Speterstatic apr_status_t conn_connect(apr_memcache_conn_t *conn) 289251876Speter{ 290251876Speter apr_status_t rv = APR_SUCCESS; 291251876Speter apr_sockaddr_t *sa; 292262253Speter#if APR_HAVE_SOCKADDR_UN 293262253Speter apr_int32_t family = conn->ms->host[0] != '/' ? APR_INET : APR_UNIX; 294262253Speter#else 295262253Speter apr_int32_t family = APR_INET; 296262253Speter#endif 297251876Speter 298262253Speter rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p); 299251876Speter if (rv != APR_SUCCESS) { 300251876Speter return rv; 301251876Speter } 302251876Speter 303251876Speter rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC); 304251876Speter if (rv != APR_SUCCESS) { 305251876Speter return rv; 306251876Speter } 307251876Speter 308251876Speter rv = apr_socket_connect(conn->sock, sa); 309251876Speter if (rv != APR_SUCCESS) { 310251876Speter return rv; 311251876Speter } 312251876Speter 313251876Speter rv = apr_socket_timeout_set(conn->sock, -1); 314251876Speter if (rv != APR_SUCCESS) { 315251876Speter return rv; 316251876Speter } 317251876Speter 318251876Speter return rv; 319251876Speter} 320251876Speter 321251876Speter 322251876Speterstatic apr_status_t 323251876Spetermc_conn_construct(void **conn_, void *params, apr_pool_t *pool) 324251876Speter{ 325251876Speter apr_status_t rv = APR_SUCCESS; 326251876Speter apr_memcache_conn_t *conn; 327251876Speter apr_pool_t *np; 328251876Speter apr_pool_t *tp; 329251876Speter apr_memcache_server_t *ms = params; 330262253Speter#if APR_HAVE_SOCKADDR_UN 331262253Speter apr_int32_t family = ms->host[0] != '/' ? APR_INET : APR_UNIX; 332262253Speter#else 333262253Speter apr_int32_t family = APR_INET; 334262253Speter#endif 335251876Speter 336251876Speter rv = apr_pool_create(&np, pool); 337251876Speter if (rv != APR_SUCCESS) { 338251876Speter return rv; 339251876Speter } 340251876Speter 341251876Speter rv = apr_pool_create(&tp, np); 342251876Speter if (rv != APR_SUCCESS) { 343251876Speter apr_pool_destroy(np); 344251876Speter return rv; 345251876Speter } 346251876Speter 347251876Speter conn = apr_palloc(np, sizeof( apr_memcache_conn_t )); 348251876Speter 349251876Speter conn->p = np; 350251876Speter conn->tp = tp; 351251876Speter 352262253Speter rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np); 353251876Speter 354251876Speter if (rv != APR_SUCCESS) { 355251876Speter apr_pool_destroy(np); 356251876Speter return rv; 357251876Speter } 358251876Speter 359251876Speter conn->buffer = apr_palloc(conn->p, BUFFER_SIZE); 360251876Speter conn->blen = 0; 361251876Speter conn->ms = ms; 362251876Speter 363251876Speter rv = conn_connect(conn); 364251876Speter if (rv != APR_SUCCESS) { 365251876Speter apr_pool_destroy(np); 366251876Speter } 367251876Speter else { 368251876Speter *conn_ = conn; 369251876Speter } 370251876Speter 371251876Speter return rv; 372251876Speter} 373251876Speter 374251876Speter#if APR_HAS_THREADS 375251876Speterstatic apr_status_t 376251876Spetermc_conn_destruct(void *conn_, void *params, apr_pool_t *pool) 377251876Speter{ 378251876Speter apr_memcache_conn_t *conn = (apr_memcache_conn_t*)conn_; 379251876Speter struct iovec vec[2]; 380251876Speter apr_size_t written; 381251876Speter 382251876Speter /* send a quit message to the memcached server to be nice about it. */ 383251876Speter vec[0].iov_base = MC_QUIT; 384251876Speter vec[0].iov_len = MC_QUIT_LEN; 385251876Speter 386251876Speter vec[1].iov_base = MC_EOL; 387251876Speter vec[1].iov_len = MC_EOL_LEN; 388251876Speter 389251876Speter /* Return values not checked, since we just want to make it go away. */ 390251876Speter apr_socket_sendv(conn->sock, vec, 2, &written); 391251876Speter apr_socket_close(conn->sock); 392251876Speter 393251876Speter apr_pool_destroy(conn->p); 394251876Speter 395251876Speter return APR_SUCCESS; 396251876Speter} 397251876Speter#endif 398251876Speter 399251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, 400251876Speter const char *host, apr_port_t port, 401251876Speter apr_uint32_t min, apr_uint32_t smax, 402251876Speter apr_uint32_t max, apr_uint32_t ttl, 403251876Speter apr_memcache_server_t **ms) 404251876Speter{ 405251876Speter apr_status_t rv = APR_SUCCESS; 406251876Speter apr_memcache_server_t *server; 407251876Speter apr_pool_t *np; 408251876Speter 409251876Speter rv = apr_pool_create(&np, p); 410251876Speter 411251876Speter server = apr_palloc(np, sizeof(apr_memcache_server_t)); 412251876Speter 413251876Speter server->p = np; 414251876Speter server->host = apr_pstrdup(np, host); 415251876Speter server->port = port; 416251876Speter server->status = APR_MC_SERVER_DEAD; 417251876Speter#if APR_HAS_THREADS 418251876Speter rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np); 419251876Speter if (rv != APR_SUCCESS) { 420251876Speter return rv; 421251876Speter } 422251876Speter 423251876Speter rv = apr_reslist_create(&server->conns, 424251876Speter min, /* hard minimum */ 425251876Speter smax, /* soft maximum */ 426251876Speter max, /* hard maximum */ 427251876Speter ttl, /* Time to live */ 428251876Speter mc_conn_construct, /* Make a New Connection */ 429251876Speter mc_conn_destruct, /* Kill Old Connection */ 430251876Speter server, np); 431251876Speter if (rv != APR_SUCCESS) { 432251876Speter return rv; 433251876Speter } 434251876Speter 435251876Speter apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST); 436251876Speter#else 437251876Speter rv = mc_conn_construct((void**)&(server->conn), server, np); 438251876Speter if (rv != APR_SUCCESS) { 439251876Speter return rv; 440251876Speter } 441251876Speter#endif 442251876Speter 443251876Speter *ms = server; 444251876Speter 445251876Speter return rv; 446251876Speter} 447251876Speter 448251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, 449251876Speter apr_uint16_t max_servers, apr_uint32_t flags, 450251876Speter apr_memcache_t **memcache) 451251876Speter{ 452251876Speter apr_status_t rv = APR_SUCCESS; 453251876Speter apr_memcache_t *mc; 454251876Speter 455251876Speter mc = apr_palloc(p, sizeof(apr_memcache_t)); 456251876Speter mc->p = p; 457251876Speter mc->nalloc = max_servers; 458251876Speter mc->ntotal = 0; 459251876Speter mc->live_servers = apr_palloc(p, mc->nalloc * sizeof(struct apr_memcache_server_t *)); 460251876Speter mc->hash_func = NULL; 461251876Speter mc->hash_baton = NULL; 462251876Speter mc->server_func = NULL; 463251876Speter mc->server_baton = NULL; 464251876Speter *memcache = mc; 465251876Speter return rv; 466251876Speter} 467251876Speter 468251876Speter 469251876Speter/* The crc32 functions and data was originally written by Spencer 470251876Speter * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source 471251876Speter * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at 472251876Speter * src/usr.bin/cksum/crc32.c. 473251876Speter */ 474251876Speter 475251876Speterstatic const apr_uint32_t crc32tab[256] = { 476251876Speter 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 477251876Speter 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 478251876Speter 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 479251876Speter 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 480251876Speter 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 481251876Speter 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 482251876Speter 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 483251876Speter 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 484251876Speter 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 485251876Speter 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 486251876Speter 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 487251876Speter 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 488251876Speter 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 489251876Speter 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 490251876Speter 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 491251876Speter 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 492251876Speter 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 493251876Speter 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 494251876Speter 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 495251876Speter 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 496251876Speter 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 497251876Speter 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 498251876Speter 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 499251876Speter 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 500251876Speter 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 501251876Speter 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 502251876Speter 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 503251876Speter 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 504251876Speter 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 505251876Speter 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 506251876Speter 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 507251876Speter 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 508251876Speter 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 509251876Speter 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 510251876Speter 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 511251876Speter 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 512251876Speter 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 513251876Speter 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 514251876Speter 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 515251876Speter 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 516251876Speter 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 517251876Speter 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 518251876Speter 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 519251876Speter 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 520251876Speter 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 521251876Speter 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 522251876Speter 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 523251876Speter 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 524251876Speter 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 525251876Speter 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 526251876Speter 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 527251876Speter 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 528251876Speter 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 529251876Speter 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 530251876Speter 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 531251876Speter 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 532251876Speter 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 533251876Speter 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 534251876Speter 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 535251876Speter 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 536251876Speter 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 537251876Speter 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 538251876Speter 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 539251876Speter 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 540251876Speter}; 541251876Speter 542251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, 543251876Speter const char *data, 544251876Speter const apr_size_t data_len) 545251876Speter{ 546251876Speter apr_uint32_t i; 547251876Speter apr_uint32_t crc; 548251876Speter crc = ~0; 549251876Speter 550251876Speter for (i = 0; i < data_len; i++) 551251876Speter crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff]; 552251876Speter 553251876Speter return ~crc; 554251876Speter} 555251876Speter 556251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, 557251876Speter const char *data, 558251876Speter const apr_size_t data_len) 559251876Speter{ 560251876Speter /* The default Perl Client doesn't actually use just crc32 -- it shifts it again 561251876Speter * like this.... 562251876Speter */ 563251876Speter return ((apr_memcache_hash_crc32(baton, data, data_len) >> 16) & 0x7fff); 564251876Speter} 565251876Speter 566251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, 567251876Speter const char *data, 568251876Speter const apr_size_t data_len) 569251876Speter{ 570251876Speter if (mc->hash_func) { 571251876Speter return mc->hash_func(mc->hash_baton, data, data_len); 572251876Speter } 573251876Speter else { 574251876Speter return apr_memcache_hash_default(NULL, data, data_len); 575251876Speter } 576251876Speter} 577251876Speter 578251876Speterstatic apr_status_t get_server_line(apr_memcache_conn_t *conn) 579251876Speter{ 580251876Speter apr_size_t bsize = BUFFER_SIZE; 581251876Speter apr_status_t rv = APR_SUCCESS; 582251876Speter 583251876Speter rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, BUFFER_SIZE); 584251876Speter 585251876Speter if (rv != APR_SUCCESS) { 586251876Speter return rv; 587251876Speter } 588251876Speter 589251876Speter rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize); 590251876Speter 591251876Speter if (rv != APR_SUCCESS) { 592251876Speter return rv; 593251876Speter } 594251876Speter 595251876Speter conn->blen = bsize; 596251876Speter conn->buffer[bsize] = '\0'; 597251876Speter 598251876Speter return apr_brigade_cleanup(conn->tb); 599251876Speter} 600251876Speter 601251876Speterstatic apr_status_t storage_cmd_write(apr_memcache_t *mc, 602251876Speter char *cmd, 603251876Speter const apr_size_t cmd_size, 604251876Speter const char *key, 605251876Speter char *data, 606251876Speter const apr_size_t data_size, 607251876Speter apr_uint32_t timeout, 608251876Speter apr_uint16_t flags) 609251876Speter{ 610251876Speter apr_uint32_t hash; 611251876Speter apr_memcache_server_t *ms; 612251876Speter apr_memcache_conn_t *conn; 613251876Speter apr_status_t rv; 614251876Speter apr_size_t written; 615251876Speter struct iovec vec[5]; 616251876Speter apr_size_t klen; 617251876Speter 618251876Speter apr_size_t key_size = strlen(key); 619251876Speter 620251876Speter hash = apr_memcache_hash(mc, key, key_size); 621251876Speter 622251876Speter ms = apr_memcache_find_server_hash(mc, hash); 623251876Speter 624251876Speter if (ms == NULL) 625251876Speter return APR_NOTFOUND; 626251876Speter 627251876Speter rv = ms_find_conn(ms, &conn); 628251876Speter 629251876Speter if (rv != APR_SUCCESS) { 630251876Speter apr_memcache_disable_server(mc, ms); 631251876Speter return rv; 632251876Speter } 633251876Speter 634251876Speter /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */ 635251876Speter 636251876Speter vec[0].iov_base = cmd; 637251876Speter vec[0].iov_len = cmd_size; 638251876Speter 639251876Speter vec[1].iov_base = (void*)key; 640251876Speter vec[1].iov_len = key_size; 641251876Speter 642251876Speter klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u %u %" APR_SIZE_T_FMT " " MC_EOL, 643251876Speter flags, timeout, data_size); 644251876Speter 645251876Speter vec[2].iov_base = conn->buffer; 646251876Speter vec[2].iov_len = klen; 647251876Speter 648251876Speter vec[3].iov_base = data; 649251876Speter vec[3].iov_len = data_size; 650251876Speter 651251876Speter vec[4].iov_base = MC_EOL; 652251876Speter vec[4].iov_len = MC_EOL_LEN; 653251876Speter 654251876Speter rv = apr_socket_sendv(conn->sock, vec, 5, &written); 655251876Speter 656251876Speter if (rv != APR_SUCCESS) { 657251876Speter ms_bad_conn(ms, conn); 658251876Speter apr_memcache_disable_server(mc, ms); 659251876Speter return rv; 660251876Speter } 661251876Speter 662251876Speter rv = get_server_line(conn); 663251876Speter 664251876Speter if (rv != APR_SUCCESS) { 665251876Speter ms_bad_conn(ms, conn); 666251876Speter apr_memcache_disable_server(mc, ms); 667251876Speter return rv; 668251876Speter } 669251876Speter 670251876Speter if (strcmp(conn->buffer, MS_STORED MC_EOL) == 0) { 671251876Speter rv = APR_SUCCESS; 672251876Speter } 673251876Speter else if (strcmp(conn->buffer, MS_NOT_STORED MC_EOL) == 0) { 674251876Speter rv = APR_EEXIST; 675251876Speter } 676251876Speter else { 677251876Speter rv = APR_EGENERAL; 678251876Speter } 679251876Speter 680251876Speter ms_release_conn(ms, conn); 681251876Speter 682251876Speter return rv; 683251876Speter} 684251876Speter 685251876SpeterAPU_DECLARE(apr_status_t) 686251876Speterapr_memcache_set(apr_memcache_t *mc, 687251876Speter const char *key, 688251876Speter char *data, 689251876Speter const apr_size_t data_size, 690251876Speter apr_uint32_t timeout, 691251876Speter apr_uint16_t flags) 692251876Speter{ 693251876Speter return storage_cmd_write(mc, 694251876Speter MC_SET, MC_SET_LEN, 695251876Speter key, 696251876Speter data, data_size, 697251876Speter timeout, flags); 698251876Speter} 699251876Speter 700251876SpeterAPU_DECLARE(apr_status_t) 701251876Speterapr_memcache_add(apr_memcache_t *mc, 702251876Speter const char *key, 703251876Speter char *data, 704251876Speter const apr_size_t data_size, 705251876Speter apr_uint32_t timeout, 706251876Speter apr_uint16_t flags) 707251876Speter{ 708251876Speter return storage_cmd_write(mc, 709251876Speter MC_ADD, MC_ADD_LEN, 710251876Speter key, 711251876Speter data, data_size, 712251876Speter timeout, flags); 713251876Speter} 714251876Speter 715251876SpeterAPU_DECLARE(apr_status_t) 716251876Speterapr_memcache_replace(apr_memcache_t *mc, 717251876Speter const char *key, 718251876Speter char *data, 719251876Speter const apr_size_t data_size, 720251876Speter apr_uint32_t timeout, 721251876Speter apr_uint16_t flags) 722251876Speter{ 723251876Speter return storage_cmd_write(mc, 724251876Speter MC_REPLACE, MC_REPLACE_LEN, 725251876Speter key, 726251876Speter data, data_size, 727251876Speter timeout, flags); 728251876Speter 729251876Speter} 730251876Speter 731251876SpeterAPU_DECLARE(apr_status_t) 732251876Speterapr_memcache_getp(apr_memcache_t *mc, 733251876Speter apr_pool_t *p, 734251876Speter const char *key, 735251876Speter char **baton, 736251876Speter apr_size_t *new_length, 737251876Speter apr_uint16_t *flags_) 738251876Speter{ 739251876Speter apr_status_t rv; 740251876Speter apr_memcache_server_t *ms; 741251876Speter apr_memcache_conn_t *conn; 742251876Speter apr_uint32_t hash; 743251876Speter apr_size_t written; 744251876Speter apr_size_t klen = strlen(key); 745251876Speter struct iovec vec[3]; 746251876Speter 747251876Speter hash = apr_memcache_hash(mc, key, klen); 748251876Speter ms = apr_memcache_find_server_hash(mc, hash); 749251876Speter if (ms == NULL) 750251876Speter return APR_NOTFOUND; 751251876Speter 752251876Speter rv = ms_find_conn(ms, &conn); 753251876Speter 754251876Speter if (rv != APR_SUCCESS) { 755251876Speter apr_memcache_disable_server(mc, ms); 756251876Speter return rv; 757251876Speter } 758251876Speter 759251876Speter /* get <key>[ <key>[...]]\r\n */ 760251876Speter vec[0].iov_base = MC_GET; 761251876Speter vec[0].iov_len = MC_GET_LEN; 762251876Speter 763251876Speter vec[1].iov_base = (void*)key; 764251876Speter vec[1].iov_len = klen; 765251876Speter 766251876Speter vec[2].iov_base = MC_EOL; 767251876Speter vec[2].iov_len = MC_EOL_LEN; 768251876Speter 769251876Speter rv = apr_socket_sendv(conn->sock, vec, 3, &written); 770251876Speter 771251876Speter if (rv != APR_SUCCESS) { 772251876Speter ms_bad_conn(ms, conn); 773251876Speter apr_memcache_disable_server(mc, ms); 774251876Speter return rv; 775251876Speter } 776251876Speter 777251876Speter rv = get_server_line(conn); 778251876Speter if (rv != APR_SUCCESS) { 779251876Speter ms_bad_conn(ms, conn); 780251876Speter apr_memcache_disable_server(mc, ms); 781251876Speter return rv; 782251876Speter } 783251876Speter 784251876Speter if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { 785251876Speter char *flags; 786251876Speter char *length; 787251876Speter char *last; 788251876Speter apr_size_t len = 0; 789251876Speter 790251876Speter flags = apr_strtok(conn->buffer, " ", &last); 791251876Speter flags = apr_strtok(NULL, " ", &last); 792251876Speter flags = apr_strtok(NULL, " ", &last); 793251876Speter 794251876Speter if (flags_) { 795251876Speter *flags_ = atoi(flags); 796251876Speter } 797251876Speter 798251876Speter length = apr_strtok(NULL, " ", &last); 799251876Speter if (length) { 800253734Speter len = strtol(length, (char **)NULL, 10); 801251876Speter } 802251876Speter 803253734Speter if (len == 0 ) { 804251876Speter *new_length = 0; 805251876Speter *baton = NULL; 806251876Speter } 807251876Speter else { 808251876Speter apr_bucket_brigade *bbb; 809251876Speter apr_bucket *e; 810251876Speter 811251876Speter /* eat the trailing \r\n */ 812251876Speter rv = apr_brigade_partition(conn->bb, len+2, &e); 813251876Speter 814251876Speter if (rv != APR_SUCCESS) { 815251876Speter ms_bad_conn(ms, conn); 816251876Speter apr_memcache_disable_server(mc, ms); 817251876Speter return rv; 818251876Speter } 819251876Speter 820251876Speter bbb = apr_brigade_split(conn->bb, e); 821251876Speter 822251876Speter rv = apr_brigade_pflatten(conn->bb, baton, &len, p); 823251876Speter 824251876Speter if (rv != APR_SUCCESS) { 825251876Speter ms_bad_conn(ms, conn); 826251876Speter apr_memcache_disable_server(mc, ms); 827251876Speter return rv; 828251876Speter } 829251876Speter 830251876Speter rv = apr_brigade_destroy(conn->bb); 831251876Speter if (rv != APR_SUCCESS) { 832251876Speter ms_bad_conn(ms, conn); 833251876Speter apr_memcache_disable_server(mc, ms); 834251876Speter return rv; 835251876Speter } 836251876Speter 837251876Speter conn->bb = bbb; 838251876Speter 839251876Speter *new_length = len - 2; 840251876Speter (*baton)[*new_length] = '\0'; 841251876Speter } 842251876Speter 843251876Speter rv = get_server_line(conn); 844251876Speter if (rv != APR_SUCCESS) { 845251876Speter ms_bad_conn(ms, conn); 846251876Speter apr_memcache_disable_server(mc, ms); 847251876Speter return rv; 848251876Speter } 849251876Speter 850251876Speter if (strncmp(MS_END, conn->buffer, MS_END_LEN) != 0) { 851251876Speter rv = APR_EGENERAL; 852251876Speter } 853251876Speter } 854251876Speter else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 855251876Speter rv = APR_NOTFOUND; 856251876Speter } 857251876Speter else { 858251876Speter rv = APR_EGENERAL; 859251876Speter } 860251876Speter 861251876Speter ms_release_conn(ms, conn); 862251876Speter 863251876Speter return rv; 864251876Speter} 865251876Speter 866251876SpeterAPU_DECLARE(apr_status_t) 867251876Speterapr_memcache_delete(apr_memcache_t *mc, 868251876Speter const char *key, 869251876Speter apr_uint32_t timeout) 870251876Speter{ 871251876Speter apr_status_t rv; 872251876Speter apr_memcache_server_t *ms; 873251876Speter apr_memcache_conn_t *conn; 874251876Speter apr_uint32_t hash; 875251876Speter apr_size_t written; 876251876Speter struct iovec vec[3]; 877251876Speter apr_size_t klen = strlen(key); 878251876Speter 879251876Speter hash = apr_memcache_hash(mc, key, klen); 880251876Speter ms = apr_memcache_find_server_hash(mc, hash); 881251876Speter if (ms == NULL) 882251876Speter return APR_NOTFOUND; 883251876Speter 884251876Speter rv = ms_find_conn(ms, &conn); 885251876Speter 886251876Speter if (rv != APR_SUCCESS) { 887251876Speter apr_memcache_disable_server(mc, ms); 888251876Speter return rv; 889251876Speter } 890251876Speter 891251876Speter /* delete <key> <time>\r\n */ 892251876Speter vec[0].iov_base = MC_DELETE; 893251876Speter vec[0].iov_len = MC_DELETE_LEN; 894251876Speter 895251876Speter vec[1].iov_base = (void*)key; 896251876Speter vec[1].iov_len = klen; 897251876Speter 898251876Speter klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, timeout); 899251876Speter 900251876Speter vec[2].iov_base = conn->buffer; 901251876Speter vec[2].iov_len = klen; 902251876Speter 903251876Speter rv = apr_socket_sendv(conn->sock, vec, 3, &written); 904251876Speter 905251876Speter if (rv != APR_SUCCESS) { 906251876Speter ms_bad_conn(ms, conn); 907251876Speter apr_memcache_disable_server(mc, ms); 908251876Speter return rv; 909251876Speter } 910251876Speter 911251876Speter rv = get_server_line(conn); 912251876Speter if (rv != APR_SUCCESS) { 913251876Speter ms_bad_conn(ms, conn); 914251876Speter apr_memcache_disable_server(mc, ms); 915251876Speter return rv; 916251876Speter } 917251876Speter 918251876Speter if (strncmp(MS_DELETED, conn->buffer, MS_DELETED_LEN) == 0) { 919251876Speter rv = APR_SUCCESS; 920251876Speter } 921251876Speter else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { 922251876Speter rv = APR_NOTFOUND; 923251876Speter } 924251876Speter else { 925251876Speter rv = APR_EGENERAL; 926251876Speter } 927251876Speter 928251876Speter ms_release_conn(ms, conn); 929251876Speter 930251876Speter return rv; 931251876Speter} 932251876Speter 933251876Speterstatic apr_status_t num_cmd_write(apr_memcache_t *mc, 934251876Speter char *cmd, 935251876Speter const apr_uint32_t cmd_size, 936251876Speter const char *key, 937251876Speter const apr_int32_t inc, 938251876Speter apr_uint32_t *new_value) 939251876Speter{ 940251876Speter apr_status_t rv; 941251876Speter apr_memcache_server_t *ms; 942251876Speter apr_memcache_conn_t *conn; 943251876Speter apr_uint32_t hash; 944251876Speter apr_size_t written; 945251876Speter struct iovec vec[3]; 946251876Speter apr_size_t klen = strlen(key); 947251876Speter 948251876Speter hash = apr_memcache_hash(mc, key, klen); 949251876Speter ms = apr_memcache_find_server_hash(mc, hash); 950251876Speter if (ms == NULL) 951251876Speter return APR_NOTFOUND; 952251876Speter 953251876Speter rv = ms_find_conn(ms, &conn); 954251876Speter 955251876Speter if (rv != APR_SUCCESS) { 956251876Speter apr_memcache_disable_server(mc, ms); 957251876Speter return rv; 958251876Speter } 959251876Speter 960251876Speter /* <cmd> <key> <value>\r\n */ 961251876Speter vec[0].iov_base = cmd; 962251876Speter vec[0].iov_len = cmd_size; 963251876Speter 964251876Speter vec[1].iov_base = (void*)key; 965251876Speter vec[1].iov_len = klen; 966251876Speter 967251876Speter klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, inc); 968251876Speter 969251876Speter vec[2].iov_base = conn->buffer; 970251876Speter vec[2].iov_len = klen; 971251876Speter 972251876Speter rv = apr_socket_sendv(conn->sock, vec, 3, &written); 973251876Speter 974251876Speter if (rv != APR_SUCCESS) { 975251876Speter ms_bad_conn(ms, conn); 976251876Speter apr_memcache_disable_server(mc, ms); 977251876Speter return rv; 978251876Speter } 979251876Speter 980251876Speter rv = get_server_line(conn); 981251876Speter if (rv != APR_SUCCESS) { 982251876Speter ms_bad_conn(ms, conn); 983251876Speter apr_memcache_disable_server(mc, ms); 984251876Speter return rv; 985251876Speter } 986251876Speter 987251876Speter if (strncmp(MS_ERROR, conn->buffer, MS_ERROR_LEN) == 0) { 988251876Speter rv = APR_EGENERAL; 989251876Speter } 990251876Speter else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { 991251876Speter rv = APR_NOTFOUND; 992251876Speter } 993251876Speter else { 994251876Speter if (new_value) { 995251876Speter *new_value = atoi(conn->buffer); 996251876Speter } 997251876Speter rv = APR_SUCCESS; 998251876Speter } 999251876Speter 1000251876Speter ms_release_conn(ms, conn); 1001251876Speter 1002251876Speter return rv; 1003251876Speter} 1004251876Speter 1005251876SpeterAPU_DECLARE(apr_status_t) 1006251876Speterapr_memcache_incr(apr_memcache_t *mc, 1007251876Speter const char *key, 1008251876Speter apr_int32_t inc, 1009251876Speter apr_uint32_t *new_value) 1010251876Speter{ 1011251876Speter return num_cmd_write(mc, 1012251876Speter MC_INCR, 1013251876Speter MC_INCR_LEN, 1014251876Speter key, 1015251876Speter inc, 1016251876Speter new_value); 1017251876Speter} 1018251876Speter 1019251876Speter 1020251876SpeterAPU_DECLARE(apr_status_t) 1021251876Speterapr_memcache_decr(apr_memcache_t *mc, 1022251876Speter const char *key, 1023251876Speter apr_int32_t inc, 1024251876Speter apr_uint32_t *new_value) 1025251876Speter{ 1026251876Speter return num_cmd_write(mc, 1027251876Speter MC_DECR, 1028251876Speter MC_DECR_LEN, 1029251876Speter key, 1030251876Speter inc, 1031251876Speter new_value); 1032251876Speter} 1033251876Speter 1034251876Speter 1035251876Speter 1036251876SpeterAPU_DECLARE(apr_status_t) 1037251876Speterapr_memcache_version(apr_memcache_server_t *ms, 1038251876Speter apr_pool_t *p, 1039251876Speter char **baton) 1040251876Speter{ 1041251876Speter apr_status_t rv; 1042251876Speter apr_memcache_conn_t *conn; 1043251876Speter apr_size_t written; 1044251876Speter struct iovec vec[2]; 1045251876Speter 1046251876Speter rv = ms_find_conn(ms, &conn); 1047251876Speter 1048251876Speter if (rv != APR_SUCCESS) { 1049251876Speter return rv; 1050251876Speter } 1051251876Speter 1052251876Speter /* version\r\n */ 1053251876Speter vec[0].iov_base = MC_VERSION; 1054251876Speter vec[0].iov_len = MC_VERSION_LEN; 1055251876Speter 1056251876Speter vec[1].iov_base = MC_EOL; 1057251876Speter vec[1].iov_len = MC_EOL_LEN; 1058251876Speter 1059251876Speter rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1060251876Speter 1061251876Speter if (rv != APR_SUCCESS) { 1062251876Speter ms_bad_conn(ms, conn); 1063251876Speter return rv; 1064251876Speter } 1065251876Speter 1066251876Speter rv = get_server_line(conn); 1067251876Speter if (rv != APR_SUCCESS) { 1068251876Speter ms_bad_conn(ms, conn); 1069251876Speter return rv; 1070251876Speter } 1071251876Speter 1072251876Speter if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) { 1073251876Speter *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1, 1074251876Speter conn->blen - MS_VERSION_LEN - 2); 1075251876Speter rv = APR_SUCCESS; 1076251876Speter } 1077251876Speter else { 1078251876Speter rv = APR_EGENERAL; 1079251876Speter } 1080251876Speter 1081251876Speter ms_release_conn(ms, conn); 1082251876Speter 1083251876Speter return rv; 1084251876Speter} 1085251876Speter 1086251876Speterapr_status_t mc_version_ping(apr_memcache_server_t *ms) 1087251876Speter{ 1088251876Speter apr_status_t rv; 1089251876Speter apr_size_t written; 1090251876Speter struct iovec vec[2]; 1091251876Speter apr_memcache_conn_t *conn; 1092251876Speter 1093251876Speter rv = ms_find_conn(ms, &conn); 1094251876Speter 1095251876Speter if (rv != APR_SUCCESS) { 1096251876Speter return rv; 1097251876Speter } 1098251876Speter 1099251876Speter /* version\r\n */ 1100251876Speter vec[0].iov_base = MC_VERSION; 1101251876Speter vec[0].iov_len = MC_VERSION_LEN; 1102251876Speter 1103251876Speter vec[1].iov_base = MC_EOL; 1104251876Speter vec[1].iov_len = MC_EOL_LEN; 1105251876Speter 1106251876Speter rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1107251876Speter 1108251876Speter if (rv != APR_SUCCESS) { 1109251876Speter ms_bad_conn(ms, conn); 1110251876Speter return rv; 1111251876Speter } 1112251876Speter 1113251876Speter rv = get_server_line(conn); 1114251876Speter ms_release_conn(ms, conn); 1115251876Speter return rv; 1116251876Speter} 1117251876Speter 1118251876Speter 1119251876SpeterAPU_DECLARE(void) 1120251876Speterapr_memcache_add_multget_key(apr_pool_t *data_pool, 1121251876Speter const char* key, 1122251876Speter apr_hash_t **values) 1123251876Speter{ 1124251876Speter apr_memcache_value_t* value; 1125251876Speter apr_size_t klen = strlen(key); 1126251876Speter 1127251876Speter /* create the value hash if need be */ 1128251876Speter if (!*values) { 1129251876Speter *values = apr_hash_make(data_pool); 1130251876Speter } 1131251876Speter 1132251876Speter /* init key and add it to the value hash */ 1133251876Speter value = apr_pcalloc(data_pool, sizeof(apr_memcache_value_t)); 1134251876Speter 1135251876Speter value->status = APR_NOTFOUND; 1136251876Speter value->key = apr_pstrdup(data_pool, key); 1137251876Speter 1138251876Speter apr_hash_set(*values, value->key, klen, value); 1139251876Speter} 1140251876Speter 1141251876Speterstatic void mget_conn_result(int serverup, 1142251876Speter int connup, 1143251876Speter apr_status_t rv, 1144251876Speter apr_memcache_t *mc, 1145251876Speter apr_memcache_server_t *ms, 1146251876Speter apr_memcache_conn_t *conn, 1147251876Speter struct cache_server_query_t *server_query, 1148251876Speter apr_hash_t *values, 1149251876Speter apr_hash_t *server_queries) 1150251876Speter{ 1151251876Speter apr_int32_t j; 1152251876Speter apr_memcache_value_t* value; 1153251876Speter 1154251876Speter apr_hash_set(server_queries, &ms, sizeof(ms), NULL); 1155251876Speter 1156251876Speter if (connup) { 1157251876Speter ms_release_conn(ms, conn); 1158251876Speter } else { 1159251876Speter ms_bad_conn(ms, conn); 1160251876Speter 1161251876Speter if (!serverup) { 1162251876Speter apr_memcache_disable_server(mc, ms); 1163251876Speter } 1164251876Speter } 1165251876Speter 1166251876Speter for (j = 1; j < server_query->query_vec_count ; j+=2) { 1167251876Speter if (server_query->query_vec[j].iov_base) { 1168251876Speter value = apr_hash_get(values, server_query->query_vec[j].iov_base, 1169251876Speter strlen(server_query->query_vec[j].iov_base)); 1170251876Speter 1171251876Speter if (value->status == APR_NOTFOUND) { 1172251876Speter value->status = rv; 1173251876Speter } 1174251876Speter } 1175251876Speter } 1176251876Speter} 1177251876Speter 1178251876SpeterAPU_DECLARE(apr_status_t) 1179251876Speterapr_memcache_multgetp(apr_memcache_t *mc, 1180251876Speter apr_pool_t *temp_pool, 1181251876Speter apr_pool_t *data_pool, 1182251876Speter apr_hash_t *values) 1183251876Speter{ 1184251876Speter apr_status_t rv; 1185251876Speter apr_memcache_server_t* ms; 1186251876Speter apr_memcache_conn_t* conn; 1187251876Speter apr_uint32_t hash; 1188251876Speter apr_size_t written; 1189251876Speter apr_size_t klen; 1190251876Speter 1191251876Speter apr_memcache_value_t* value; 1192251876Speter apr_hash_index_t* value_hash_index; 1193251876Speter 1194251876Speter /* this is a little over aggresive, but beats multiple loops 1195251876Speter * to figure out how long each vector needs to be per-server. 1196251876Speter */ 1197251876Speter apr_int32_t veclen = 2 + 2 * apr_hash_count(values) - 1; /* get <key>[<space><key>...]\r\n */ 1198251876Speter apr_int32_t i, j; 1199251876Speter apr_int32_t queries_sent; 1200251876Speter apr_int32_t queries_recvd; 1201251876Speter 1202251876Speter apr_hash_t * server_queries = apr_hash_make(temp_pool); 1203251876Speter struct cache_server_query_t* server_query; 1204251876Speter apr_hash_index_t * query_hash_index; 1205251876Speter 1206251876Speter apr_pollset_t* pollset; 1207251876Speter const apr_pollfd_t* activefds; 1208251876Speter apr_pollfd_t* pollfds; 1209251876Speter 1210251876Speter 1211251876Speter /* build all the queries */ 1212251876Speter value_hash_index = apr_hash_first(temp_pool, values); 1213251876Speter while (value_hash_index) { 1214251876Speter void *v; 1215251876Speter apr_hash_this(value_hash_index, NULL, NULL, &v); 1216251876Speter value = v; 1217251876Speter value_hash_index = apr_hash_next(value_hash_index); 1218251876Speter klen = strlen(value->key); 1219251876Speter 1220251876Speter hash = apr_memcache_hash(mc, value->key, klen); 1221251876Speter ms = apr_memcache_find_server_hash(mc, hash); 1222251876Speter if (ms == NULL) { 1223251876Speter continue; 1224251876Speter } 1225251876Speter 1226251876Speter server_query = apr_hash_get(server_queries, &ms, sizeof(ms)); 1227251876Speter 1228251876Speter if (!server_query) { 1229251876Speter rv = ms_find_conn(ms, &conn); 1230251876Speter 1231251876Speter if (rv != APR_SUCCESS) { 1232251876Speter apr_memcache_disable_server(mc, ms); 1233251876Speter value->status = rv; 1234251876Speter continue; 1235251876Speter } 1236251876Speter 1237251876Speter server_query = apr_pcalloc(temp_pool,sizeof(struct cache_server_query_t)); 1238251876Speter 1239251876Speter apr_hash_set(server_queries, &ms, sizeof(ms), server_query); 1240251876Speter 1241251876Speter server_query->ms = ms; 1242251876Speter server_query->conn = conn; 1243251876Speter server_query->query_vec = apr_pcalloc(temp_pool, sizeof(struct iovec)*veclen); 1244251876Speter 1245251876Speter /* set up the first key */ 1246251876Speter server_query->query_vec[0].iov_base = MC_GET; 1247251876Speter server_query->query_vec[0].iov_len = MC_GET_LEN; 1248251876Speter 1249251876Speter server_query->query_vec[1].iov_base = (void*)(value->key); 1250251876Speter server_query->query_vec[1].iov_len = klen; 1251251876Speter 1252251876Speter server_query->query_vec[2].iov_base = MC_EOL; 1253251876Speter server_query->query_vec[2].iov_len = MC_EOL_LEN; 1254251876Speter 1255251876Speter server_query->query_vec_count = 3; 1256251876Speter } 1257251876Speter else { 1258251876Speter j = server_query->query_vec_count - 1; 1259251876Speter 1260251876Speter server_query->query_vec[j].iov_base = MC_WS; 1261251876Speter server_query->query_vec[j].iov_len = MC_WS_LEN; 1262251876Speter j++; 1263251876Speter 1264251876Speter server_query->query_vec[j].iov_base = (void*)(value->key); 1265251876Speter server_query->query_vec[j].iov_len = klen; 1266251876Speter j++; 1267251876Speter 1268251876Speter server_query->query_vec[j].iov_base = MC_EOL; 1269251876Speter server_query->query_vec[j].iov_len = MC_EOL_LEN; 1270251876Speter j++; 1271251876Speter 1272251876Speter server_query->query_vec_count = j; 1273251876Speter } 1274251876Speter } 1275251876Speter 1276251876Speter /* create polling structures */ 1277251876Speter pollfds = apr_pcalloc(temp_pool, apr_hash_count(server_queries) * sizeof(apr_pollfd_t)); 1278251876Speter 1279251876Speter rv = apr_pollset_create(&pollset, apr_hash_count(server_queries), temp_pool, 0); 1280251876Speter 1281251876Speter if (rv != APR_SUCCESS) { 1282251876Speter query_hash_index = apr_hash_first(temp_pool, server_queries); 1283251876Speter 1284251876Speter while (query_hash_index) { 1285251876Speter void *v; 1286251876Speter apr_hash_this(query_hash_index, NULL, NULL, &v); 1287251876Speter server_query = v; 1288251876Speter query_hash_index = apr_hash_next(query_hash_index); 1289251876Speter 1290251876Speter mget_conn_result(TRUE, TRUE, rv, mc, server_query->ms, server_query->conn, 1291251876Speter server_query, values, server_queries); 1292251876Speter } 1293251876Speter 1294251876Speter return rv; 1295251876Speter } 1296251876Speter 1297251876Speter /* send all the queries */ 1298251876Speter queries_sent = 0; 1299251876Speter query_hash_index = apr_hash_first(temp_pool, server_queries); 1300251876Speter 1301251876Speter while (query_hash_index) { 1302251876Speter void *v; 1303251876Speter apr_hash_this(query_hash_index, NULL, NULL, &v); 1304251876Speter server_query = v; 1305251876Speter query_hash_index = apr_hash_next(query_hash_index); 1306251876Speter 1307251876Speter conn = server_query->conn; 1308251876Speter ms = server_query->ms; 1309251876Speter 1310251876Speter for (i = 0, rv = APR_SUCCESS; i < veclen && rv == APR_SUCCESS; i += APR_MAX_IOVEC_SIZE) { 1311251876Speter rv = apr_socket_sendv(conn->sock, &(server_query->query_vec[i]), 1312251876Speter veclen-i>APR_MAX_IOVEC_SIZE ? APR_MAX_IOVEC_SIZE : veclen-i , &written); 1313251876Speter } 1314251876Speter 1315251876Speter if (rv != APR_SUCCESS) { 1316251876Speter mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1317251876Speter server_query, values, server_queries); 1318251876Speter continue; 1319251876Speter } 1320251876Speter 1321251876Speter pollfds[queries_sent].desc_type = APR_POLL_SOCKET; 1322251876Speter pollfds[queries_sent].reqevents = APR_POLLIN; 1323251876Speter pollfds[queries_sent].p = temp_pool; 1324251876Speter pollfds[queries_sent].desc.s = conn->sock; 1325251876Speter pollfds[queries_sent].client_data = (void *)server_query; 1326251876Speter apr_pollset_add (pollset, &pollfds[queries_sent]); 1327251876Speter 1328251876Speter queries_sent++; 1329251876Speter } 1330251876Speter 1331251876Speter while (queries_sent) { 1332251876Speter rv = apr_pollset_poll(pollset, MULT_GET_TIMEOUT, &queries_recvd, &activefds); 1333251876Speter 1334251876Speter if (rv != APR_SUCCESS) { 1335251876Speter /* timeout */ 1336251876Speter queries_sent = 0; 1337251876Speter continue; 1338251876Speter } 1339251876Speter for (i = 0; i < queries_recvd; i++) { 1340251876Speter server_query = activefds[i].client_data; 1341251876Speter conn = server_query->conn; 1342251876Speter ms = server_query->ms; 1343251876Speter 1344251876Speter rv = get_server_line(conn); 1345251876Speter 1346251876Speter if (rv != APR_SUCCESS) { 1347251876Speter apr_pollset_remove (pollset, &activefds[i]); 1348251876Speter mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1349251876Speter server_query, values, server_queries); 1350251876Speter queries_sent--; 1351251876Speter continue; 1352251876Speter } 1353251876Speter 1354251876Speter if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { 1355251876Speter char *key; 1356251876Speter char *flags; 1357251876Speter char *length; 1358251876Speter char *last; 1359251876Speter char *data; 1360251876Speter apr_size_t len = 0; 1361251876Speter 1362251876Speter key = apr_strtok(conn->buffer, " ", &last); /* just the VALUE, ignore */ 1363251876Speter key = apr_strtok(NULL, " ", &last); 1364251876Speter flags = apr_strtok(NULL, " ", &last); 1365251876Speter 1366251876Speter 1367251876Speter length = apr_strtok(NULL, " ", &last); 1368251876Speter if (length) { 1369253734Speter len = strtol(length, (char **) NULL, 10); 1370251876Speter } 1371251876Speter 1372251876Speter value = apr_hash_get(values, key, strlen(key)); 1373251876Speter 1374251876Speter 1375251876Speter if (value) { 1376253734Speter if (len != 0) { 1377251876Speter apr_bucket_brigade *bbb; 1378251876Speter apr_bucket *e; 1379251876Speter 1380251876Speter /* eat the trailing \r\n */ 1381251876Speter rv = apr_brigade_partition(conn->bb, len+2, &e); 1382251876Speter 1383251876Speter if (rv != APR_SUCCESS) { 1384251876Speter apr_pollset_remove (pollset, &activefds[i]); 1385251876Speter mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1386251876Speter server_query, values, server_queries); 1387251876Speter queries_sent--; 1388251876Speter continue; 1389251876Speter } 1390251876Speter 1391251876Speter bbb = apr_brigade_split(conn->bb, e); 1392251876Speter 1393251876Speter rv = apr_brigade_pflatten(conn->bb, &data, &len, data_pool); 1394251876Speter 1395251876Speter if (rv != APR_SUCCESS) { 1396251876Speter apr_pollset_remove (pollset, &activefds[i]); 1397251876Speter mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1398251876Speter server_query, values, server_queries); 1399251876Speter queries_sent--; 1400251876Speter continue; 1401251876Speter } 1402251876Speter 1403251876Speter rv = apr_brigade_destroy(conn->bb); 1404251876Speter if (rv != APR_SUCCESS) { 1405251876Speter apr_pollset_remove (pollset, &activefds[i]); 1406251876Speter mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, 1407251876Speter server_query, values, server_queries); 1408251876Speter queries_sent--; 1409251876Speter continue; 1410251876Speter } 1411251876Speter 1412251876Speter conn->bb = bbb; 1413251876Speter 1414251876Speter value->len = len - 2; 1415251876Speter data[value->len] = '\0'; 1416251876Speter value->data = data; 1417251876Speter } 1418251876Speter 1419251876Speter value->status = rv; 1420251876Speter value->flags = atoi(flags); 1421251876Speter 1422251876Speter /* stay on the server */ 1423251876Speter i--; 1424251876Speter 1425251876Speter } 1426251876Speter else { 1427251876Speter /* TODO: Server Sent back a key I didn't ask for or my 1428251876Speter * hash is corrupt */ 1429251876Speter } 1430251876Speter } 1431251876Speter else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 1432251876Speter /* this connection is done */ 1433251876Speter apr_pollset_remove (pollset, &activefds[i]); 1434251876Speter ms_release_conn(ms, conn); 1435251876Speter apr_hash_set(server_queries, &ms, sizeof(ms), NULL); 1436251876Speter 1437251876Speter queries_sent--; 1438251876Speter } 1439251876Speter else { 1440251876Speter /* unknown reply? */ 1441251876Speter rv = APR_EGENERAL; 1442251876Speter } 1443251876Speter 1444251876Speter } /* /for */ 1445251876Speter } /* /while */ 1446251876Speter 1447251876Speter query_hash_index = apr_hash_first(temp_pool, server_queries); 1448251876Speter while (query_hash_index) { 1449251876Speter void *v; 1450251876Speter apr_hash_this(query_hash_index, NULL, NULL, &v); 1451251876Speter server_query = v; 1452251876Speter query_hash_index = apr_hash_next(query_hash_index); 1453251876Speter 1454251876Speter conn = server_query->conn; 1455251876Speter ms = server_query->ms; 1456251876Speter 1457251876Speter mget_conn_result(TRUE, (rv == APR_SUCCESS), rv, mc, ms, conn, 1458251876Speter server_query, values, server_queries); 1459251876Speter continue; 1460251876Speter } 1461251876Speter 1462251876Speter apr_pollset_destroy(pollset); 1463251876Speter apr_pool_clear(temp_pool); 1464251876Speter return APR_SUCCESS; 1465251876Speter 1466251876Speter} 1467251876Speter 1468251876Speter 1469251876Speter 1470251876Speter/** 1471251876Speter * Define all of the strings for stats 1472251876Speter */ 1473251876Speter 1474251876Speter#define STAT_pid MS_STAT " pid " 1475251876Speter#define STAT_pid_LEN (sizeof(STAT_pid)-1) 1476251876Speter 1477251876Speter#define STAT_uptime MS_STAT " uptime " 1478251876Speter#define STAT_uptime_LEN (sizeof(STAT_uptime)-1) 1479251876Speter 1480251876Speter#define STAT_time MS_STAT " time " 1481251876Speter#define STAT_time_LEN (sizeof(STAT_time)-1) 1482251876Speter 1483251876Speter#define STAT_version MS_STAT " version " 1484251876Speter#define STAT_version_LEN (sizeof(STAT_version)-1) 1485251876Speter 1486251876Speter#define STAT_pointer_size MS_STAT " pointer_size " 1487251876Speter#define STAT_pointer_size_LEN (sizeof(STAT_pointer_size)-1) 1488251876Speter 1489251876Speter#define STAT_rusage_user MS_STAT " rusage_user " 1490251876Speter#define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1) 1491251876Speter 1492251876Speter#define STAT_rusage_system MS_STAT " rusage_system " 1493251876Speter#define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1) 1494251876Speter 1495251876Speter#define STAT_curr_items MS_STAT " curr_items " 1496251876Speter#define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1) 1497251876Speter 1498251876Speter#define STAT_total_items MS_STAT " total_items " 1499251876Speter#define STAT_total_items_LEN (sizeof(STAT_total_items)-1) 1500251876Speter 1501251876Speter#define STAT_bytes MS_STAT " bytes " 1502251876Speter#define STAT_bytes_LEN (sizeof(STAT_bytes)-1) 1503251876Speter 1504251876Speter#define STAT_curr_connections MS_STAT " curr_connections " 1505251876Speter#define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1) 1506251876Speter 1507251876Speter#define STAT_total_connections MS_STAT " total_connections " 1508251876Speter#define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1) 1509251876Speter 1510251876Speter#define STAT_connection_structures MS_STAT " connection_structures " 1511251876Speter#define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1) 1512251876Speter 1513251876Speter#define STAT_cmd_get MS_STAT " cmd_get " 1514251876Speter#define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1) 1515251876Speter 1516251876Speter#define STAT_cmd_set MS_STAT " cmd_set " 1517251876Speter#define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1) 1518251876Speter 1519251876Speter#define STAT_get_hits MS_STAT " get_hits " 1520251876Speter#define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1) 1521251876Speter 1522251876Speter#define STAT_get_misses MS_STAT " get_misses " 1523251876Speter#define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1) 1524251876Speter 1525251876Speter#define STAT_evictions MS_STAT " evictions " 1526251876Speter#define STAT_evictions_LEN (sizeof(STAT_evictions)-1) 1527251876Speter 1528251876Speter#define STAT_bytes_read MS_STAT " bytes_read " 1529251876Speter#define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1) 1530251876Speter 1531251876Speter#define STAT_bytes_written MS_STAT " bytes_written " 1532251876Speter#define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1) 1533251876Speter 1534251876Speter#define STAT_limit_maxbytes MS_STAT " limit_maxbytes " 1535251876Speter#define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1) 1536251876Speter 1537251876Speter#define STAT_threads MS_STAT " threads " 1538251876Speter#define STAT_threads_LEN (sizeof(STAT_threads)-1) 1539251876Speter 1540251876Speterstatic const char *stat_read_string(apr_pool_t *p, char *buf, apr_size_t len) 1541251876Speter{ 1542251876Speter /* remove trailing \r\n and null char */ 1543251876Speter return apr_pstrmemdup(p, buf, len-2); 1544251876Speter} 1545251876Speter 1546251876Speterstatic apr_uint32_t stat_read_uint32(apr_pool_t *p, char *buf, apr_size_t len) 1547251876Speter{ 1548251876Speter buf[len-2] = '\0'; 1549251876Speter return atoi(buf); 1550251876Speter} 1551251876Speter 1552251876Speterstatic apr_uint64_t stat_read_uint64(apr_pool_t *p, char *buf, apr_size_t len) 1553251876Speter{ 1554251876Speter buf[len-2] = '\0'; 1555251876Speter return apr_atoi64(buf); 1556251876Speter} 1557251876Speter 1558251876Speterstatic apr_time_t stat_read_time(apr_pool_t *p, char *buf, apr_size_t len) 1559251876Speter{ 1560251876Speter buf[len-2] = '\0'; 1561251876Speter return apr_time_from_sec(atoi(buf)); 1562251876Speter} 1563251876Speter 1564251876Speterstatic apr_time_t stat_read_rtime(apr_pool_t *p, char *buf, apr_size_t len) 1565251876Speter{ 1566251876Speter char *tok; 1567251876Speter char *secs; 1568251876Speter char *usecs; 1569251876Speter const char *sep = ":."; 1570251876Speter 1571251876Speter buf[len-2] = '\0'; 1572251876Speter 1573251876Speter secs = apr_strtok(buf, sep, &tok); 1574251876Speter usecs = apr_strtok(NULL, sep, &tok); 1575251876Speter if (secs && usecs) { 1576251876Speter return apr_time_make(atoi(secs), atoi(usecs)); 1577251876Speter } 1578251876Speter else { 1579251876Speter return apr_time_make(0, 0); 1580251876Speter } 1581251876Speter} 1582251876Speter 1583251876Speter/** 1584251876Speter * I got tired of Typing. Meh. 1585251876Speter * 1586251876Speter * TODO: Convert it to static tables to make it cooler. 1587251876Speter */ 1588251876Speter 1589251876Speter#define mc_stat_cmp(name) \ 1590251876Speter strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0 1591251876Speter 1592251876Speter#define mc_stat_str(name) \ 1593251876Speter stat_read_string(p, conn->buffer + name, \ 1594251876Speter conn->blen - name) 1595251876Speter 1596251876Speter#define mc_stat_uint32(name) \ 1597251876Speter stat_read_uint32(p, conn->buffer + name, \ 1598251876Speter conn->blen - name) 1599251876Speter 1600251876Speter#define mc_stat_uint64(name) \ 1601251876Speter stat_read_uint64(p, conn->buffer + name, \ 1602251876Speter conn->blen - name) 1603251876Speter 1604251876Speter#define mc_stat_time(name) \ 1605251876Speter stat_read_time(p, conn->buffer + name, \ 1606251876Speter conn->blen - name) 1607251876Speter 1608251876Speter#define mc_stat_rtime(name) \ 1609251876Speter stat_read_rtime(p, conn->buffer + name, \ 1610251876Speter conn->blen - name) 1611251876Speter 1612251876Speter 1613251876Speter#define mc_do_stat(name, type) \ 1614251876Speter if (mc_stat_cmp(name)) { \ 1615251876Speter stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \ 1616251876Speter } 1617251876Speter 1618251876Speterstatic void update_stats(apr_pool_t *p, apr_memcache_conn_t *conn, 1619251876Speter apr_memcache_stats_t *stats) 1620251876Speter{ 1621251876Speter 1622251876Speter mc_do_stat(version, str) 1623251876Speter else mc_do_stat(pid, uint32) 1624251876Speter else mc_do_stat(uptime, uint32) 1625251876Speter else mc_do_stat(pointer_size, uint32) 1626251876Speter else mc_do_stat(time, time) 1627251876Speter else mc_do_stat(rusage_user, rtime) 1628251876Speter else mc_do_stat(rusage_system, rtime) 1629251876Speter else mc_do_stat(curr_items, uint32) 1630251876Speter else mc_do_stat(total_items, uint32) 1631251876Speter else mc_do_stat(bytes, uint64) 1632251876Speter else mc_do_stat(curr_connections, uint32) 1633251876Speter else mc_do_stat(total_connections, uint32) 1634251876Speter else mc_do_stat(connection_structures, uint32) 1635251876Speter else mc_do_stat(cmd_get, uint32) 1636251876Speter else mc_do_stat(cmd_set, uint32) 1637251876Speter else mc_do_stat(get_hits, uint32) 1638251876Speter else mc_do_stat(get_misses, uint32) 1639251876Speter else mc_do_stat(evictions, uint64) 1640251876Speter else mc_do_stat(bytes_read, uint64) 1641251876Speter else mc_do_stat(bytes_written, uint64) 1642251876Speter else mc_do_stat(limit_maxbytes, uint32) 1643251876Speter else mc_do_stat(threads, uint32) 1644251876Speter} 1645251876Speter 1646251876SpeterAPU_DECLARE(apr_status_t) 1647251876Speterapr_memcache_stats(apr_memcache_server_t *ms, 1648251876Speter apr_pool_t *p, 1649251876Speter apr_memcache_stats_t **stats) 1650251876Speter{ 1651251876Speter apr_memcache_stats_t *ret; 1652251876Speter apr_status_t rv; 1653251876Speter apr_memcache_conn_t *conn; 1654251876Speter apr_size_t written; 1655251876Speter struct iovec vec[2]; 1656251876Speter 1657251876Speter rv = ms_find_conn(ms, &conn); 1658251876Speter 1659251876Speter if (rv != APR_SUCCESS) { 1660251876Speter return rv; 1661251876Speter } 1662251876Speter 1663251876Speter /* version\r\n */ 1664251876Speter vec[0].iov_base = MC_STATS; 1665251876Speter vec[0].iov_len = MC_STATS_LEN; 1666251876Speter 1667251876Speter vec[1].iov_base = MC_EOL; 1668251876Speter vec[1].iov_len = MC_EOL_LEN; 1669251876Speter 1670251876Speter rv = apr_socket_sendv(conn->sock, vec, 2, &written); 1671251876Speter 1672251876Speter if (rv != APR_SUCCESS) { 1673251876Speter ms_bad_conn(ms, conn); 1674251876Speter return rv; 1675251876Speter } 1676251876Speter 1677251876Speter ret = apr_pcalloc(p, sizeof(apr_memcache_stats_t)); 1678251876Speter 1679251876Speter do { 1680251876Speter rv = get_server_line(conn); 1681251876Speter if (rv != APR_SUCCESS) { 1682251876Speter ms_bad_conn(ms, conn); 1683251876Speter return rv; 1684251876Speter } 1685251876Speter 1686251876Speter if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { 1687251876Speter rv = APR_SUCCESS; 1688251876Speter break; 1689251876Speter } 1690251876Speter else if (strncmp(MS_STAT, conn->buffer, MS_STAT_LEN) == 0) { 1691251876Speter update_stats(p, conn, ret); 1692251876Speter continue; 1693251876Speter } 1694251876Speter else { 1695251876Speter rv = APR_EGENERAL; 1696251876Speter break; 1697251876Speter } 1698251876Speter 1699251876Speter } while(1); 1700251876Speter 1701251876Speter ms_release_conn(ms, conn); 1702251876Speter 1703251876Speter if (stats) { 1704251876Speter *stats = ret; 1705251876Speter } 1706251876Speter 1707251876Speter return rv; 1708251876Speter} 1709251876Speter 1710