ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/vendor/apache/apr-util/1.5.4/memcache/apr_memcache.c
Revision: 9277
Committed: Mon Feb 20 03:10:44 2017 UTC (7 years, 2 months ago) by laffer1
Content type: text/plain
File size: 48474 byte(s)
Log Message:
tag

File Contents

# Content
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
23 struct 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 */
103 struct 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
112 static 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
125 static 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
132 APU_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
146 static apr_status_t mc_version_ping(apr_memcache_server_t *ms);
147
148 APU_DECLARE(apr_memcache_server_t *)
149 apr_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
159 APU_DECLARE(apr_memcache_server_t *)
160 apr_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
210 APU_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
225 static 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
252 static 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
261 static 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
271 APU_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
283 APU_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
288 static 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
322 static apr_status_t
323 mc_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
375 static apr_status_t
376 mc_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
399 APU_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
448 APU_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
475 static 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
542 APU_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
556 APU_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
566 APU_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
578 static 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
601 static 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
685 APU_DECLARE(apr_status_t)
686 apr_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
700 APU_DECLARE(apr_status_t)
701 apr_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
715 APU_DECLARE(apr_status_t)
716 apr_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
731 APU_DECLARE(apr_status_t)
732 apr_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
866 APU_DECLARE(apr_status_t)
867 apr_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
933 static 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
1005 APU_DECLARE(apr_status_t)
1006 apr_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
1020 APU_DECLARE(apr_status_t)
1021 apr_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
1036 APU_DECLARE(apr_status_t)
1037 apr_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
1086 apr_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
1119 APU_DECLARE(void)
1120 apr_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
1141 static 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
1178 APU_DECLARE(apr_status_t)
1179 apr_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
1540 static 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
1546 static 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
1552 static 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
1558 static 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
1564 static 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
1618 static 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
1646 APU_DECLARE(apr_status_t)
1647 apr_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