First merge of Trond's patches (cherry picking).
[m6w6/libmemcached] / libmemcached / memcached_dump.c
1 /*
2 We use this to dump all keys.
3
4 At this point we only support a callback method. This could be optimized by first
5 calling items and finding active slabs. For the moment though we just loop through
6 all slabs on servers and "grab" the keys.
7 */
8
9 #include "common.h"
10 static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
11 {
12 memcached_return_t rc= 0;
13 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
14 size_t send_length;
15 uint32_t server_key;
16 uint32_t x;
17
18 unlikely (ptr->number_of_hosts == 0)
19 return MEMCACHED_NO_SERVERS;
20
21 for (server_key= 0; server_key < ptr->number_of_hosts; server_key++)
22 {
23 /* 256 I BELIEVE is the upper limit of slabs */
24 for (x= 0; x < 256; x++)
25 {
26 send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
27 "stats cachedump %u 0 0\r\n", x);
28
29 rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
30
31 unlikely (rc != MEMCACHED_SUCCESS)
32 goto error;
33
34 while (1)
35 {
36 uint32_t callback_counter;
37 rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
38
39 if (rc == MEMCACHED_ITEM)
40 {
41 char *string_ptr, *end_ptr;
42 char *key;
43
44 string_ptr= buffer;
45 string_ptr+= 5; /* Move past ITEM */
46 for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
47 key= string_ptr;
48 key[(size_t)(end_ptr-string_ptr)]= 0;
49 for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
50 {
51 rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context);
52 if (rc != MEMCACHED_SUCCESS)
53 break;
54 }
55 }
56 else if (rc == MEMCACHED_END)
57 break;
58 else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR)
59 {
60 /* If we try to request stats cachedump for a slab class that is too big
61 * the server will return an incorrect error message:
62 * "MEMCACHED_SERVER_ERROR failed to allocate memory"
63 * This isn't really a fatal error, so let's just skip it. I want to
64 * fix the return value from the memcached server to a CLIENT_ERROR,
65 * so let's add support for that as well right now.
66 */
67 rc= MEMCACHED_END;
68 break;
69 }
70 else
71 goto error;
72 }
73 }
74 }
75
76 error:
77 if (rc == MEMCACHED_END)
78 return MEMCACHED_SUCCESS;
79 else
80 return rc;
81 }
82
83 memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
84 {
85 /* No support for Binary protocol yet */
86 if (ptr->flags.binary_protocol)
87 return MEMCACHED_FAILURE;
88
89 return ascii_dump(ptr, callback, context, number_of_callbacks);
90 }
91