Merge pull request #140 from hussainnaqvee/patch-1
[awesomized/libmemcached] / src / libmemcached / dump.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 static memcached_return_t ascii_dump(Memcached *memc, memcached_dump_fn *callback, void *context,
19 uint32_t number_of_callbacks) {
20 memcached_version(memc);
21 /* MAX_NUMBER_OF_SLAB_CLASSES is defined to 200 in Memcached 1.4.10 */
22 for (uint32_t x = 0; x < 200; x++) {
23 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
24 int buffer_length = snprintf(buffer, sizeof(buffer), "%u", x);
25 if (size_t(buffer_length) >= sizeof(buffer) or buffer_length < 0) {
26 return memcached_set_error(
27 *memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
28 memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
29 }
30
31 // @NOTE the hard coded zero means "no limit"
32 libmemcached_io_vector_st vector[] = {{memcached_literal_param("stats cachedump ")},
33 {buffer, size_t(buffer_length)},
34 {memcached_literal_param(" 0\r\n")}};
35
36 // Send message to all servers
37 for (uint32_t server_key = 0; server_key < memcached_server_count(memc); server_key++) {
38 memcached_instance_st *instance = memcached_instance_fetch(memc, server_key);
39
40 // skip slabs >63 for server versions >= 1.4.23
41 if (x < 64 || memcached_version_instance_cmp(instance, 1, 4, 23) < 0) {
42 memcached_return_t vdo_rc;
43 if (memcached_failed((vdo_rc = memcached_vdo(instance, vector, 3, true)))) {
44 return vdo_rc;
45 }
46 }
47 }
48
49 // Collect the returned items
50 memcached_instance_st *instance;
51 memcached_return_t read_ret = MEMCACHED_SUCCESS;
52 while ((instance = memcached_io_get_readable_server(memc, read_ret))) {
53 memcached_return_t response_rc =
54 memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
55 if (response_rc == MEMCACHED_ITEM) {
56 char *string_ptr, *end_ptr;
57
58 string_ptr = buffer;
59 string_ptr += 5; /* Move past ITEM */
60
61 for (end_ptr = string_ptr; isgraph(*end_ptr); end_ptr++) {
62 };
63
64 char *key = string_ptr;
65 key[(size_t)(end_ptr - string_ptr)] = 0;
66
67 for (uint32_t callback_counter = 0; callback_counter < number_of_callbacks;
68 callback_counter++) {
69 memcached_return_t callback_rc =
70 (*callback[callback_counter])(memc, key, (size_t)(end_ptr - string_ptr), context);
71 if (callback_rc != MEMCACHED_SUCCESS) {
72 // @todo build up a message for the error from the value
73 memcached_set_error(*instance, callback_rc, MEMCACHED_AT);
74 break;
75 }
76 }
77 } else if (response_rc == MEMCACHED_END) {
78 // All items have been returned
79 } else if (response_rc == MEMCACHED_SERVER_ERROR) {
80 /* If we try to request stats cachedump for a slab class that is too big
81 * the server will return an incorrect error message:
82 * "MEMCACHED_SERVER_ERROR failed to allocate memory"
83 * This isn't really a fatal error, so let's just skip it. I want to
84 * fix the return value from the memcached server to a CLIENT_ERROR,
85 * so let's add support for that as well right now.
86 */
87 assert(response_rc == MEMCACHED_SUCCESS); // Just fail
88 return response_rc;
89 } else if (response_rc == MEMCACHED_CLIENT_ERROR) {
90 /* The maximum number of slabs has changed in the past (currently 1<<6-1),
91 * so ignore any client errors complaining about an illegal slab id.
92 */
93 if (0
94 == strncmp(buffer, "CLIENT_ERROR Illegal slab id",
95 sizeof("CLIENT_ERROR Illegal slab id") - 1))
96 {
97 memcached_error_free(*instance);
98 memcached_error_free(*memc);
99 } else {
100 return response_rc;
101 }
102 } else {
103 // IO error of some sort must have occurred
104 return response_rc;
105 }
106 }
107 }
108
109 return memcached_has_current_error(*memc) ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
110 }
111
112 memcached_return_t memcached_dump(memcached_st *shell, memcached_dump_fn *callback, void *context,
113 uint32_t number_of_callbacks) {
114 Memcached *ptr = memcached2Memcached(shell);
115 memcached_return_t rc;
116 if (memcached_failed(rc = initialize_query(ptr, true))) {
117 return rc;
118 }
119
120 /*
121 No support for Binary protocol yet
122 @todo Fix this so that we just flush, switch to ascii, and then go back to binary.
123 */
124 if (memcached_is_binary(ptr)) {
125 return memcached_set_error(
126 *ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
127 memcached_literal_param("Binary protocol is not supported for memcached_dump()"));
128 }
129
130 return ascii_dump(ptr, callback, context, number_of_callbacks);
131 }