eef8f40141b6715dabd6db21709a2f4f69011cbc
[awesomized/libmemcached] / src / libmemcached / fetch.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - 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 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 char *memcached_fetch(memcached_st *shell, char *key, size_t *key_length, size_t *value_length,
19 uint32_t *flags, memcached_return_t *error) {
20 Memcached *ptr = memcached2Memcached(shell);
21 memcached_return_t unused;
22 if (error == NULL) {
23 error = &unused;
24 }
25
26 if (memcached_is_udp(ptr)) {
27 if (value_length) {
28 *value_length = 0;
29 }
30
31 if (key_length) {
32 *key_length = 0;
33 }
34
35 if (flags) {
36 *flags = 0;
37 }
38
39 if (key) {
40 *key = 0;
41 }
42
43 *error = MEMCACHED_NOT_SUPPORTED;
44 return NULL;
45 }
46
47 memcached_result_st *result_buffer = &ptr->result;
48 result_buffer = memcached_fetch_result(ptr, result_buffer, error);
49 if (result_buffer == NULL or memcached_failed(*error)) {
50 WATCHPOINT_ASSERT(result_buffer == NULL);
51 if (value_length) {
52 *value_length = 0;
53 }
54
55 if (key_length) {
56 *key_length = 0;
57 }
58
59 if (flags) {
60 *flags = 0;
61 }
62
63 if (key) {
64 *key = 0;
65 }
66
67 return NULL;
68 }
69
70 if (value_length) {
71 *value_length = memcached_string_length(&result_buffer->value);
72 }
73
74 if (key) {
75 if (result_buffer->key_length > MEMCACHED_MAX_KEY) {
76 *error = MEMCACHED_KEY_TOO_BIG;
77 if (value_length) {
78 *value_length = 0;
79 }
80
81 if (key_length) {
82 *key_length = 0;
83 }
84
85 if (flags) {
86 *flags = 0;
87 }
88
89 if (key) {
90 *key = 0;
91 }
92
93 return NULL;
94 }
95
96 strncpy(key, result_buffer->item_key,
97 result_buffer->key_length); // For the binary protocol we will cut off the key :(
98 if (key_length) {
99 *key_length = result_buffer->key_length;
100 }
101 }
102
103 if (flags) {
104 *flags = result_buffer->item_flags;
105 }
106
107 return memcached_string_take_value(&result_buffer->value);
108 }
109
110 memcached_result_st *memcached_fetch_result(memcached_st *ptr, memcached_result_st *result,
111 memcached_return_t *error) {
112 memcached_return_t unused;
113 if (error == NULL) {
114 error = &unused;
115 }
116
117 if (ptr == NULL) {
118 *error = MEMCACHED_INVALID_ARGUMENTS;
119 return NULL;
120 }
121
122 if (memcached_is_udp(ptr)) {
123 *error = MEMCACHED_NOT_SUPPORTED;
124 return NULL;
125 }
126
127 if (result == NULL) {
128 // If we have already initialized (ie it is in use) our internal, we
129 // create one.
130 if (memcached_is_initialized(&ptr->result)) {
131 if ((result = memcached_result_create(ptr, NULL)) == NULL) {
132 *error = MEMCACHED_MEMORY_ALLOCATION_FAILURE;
133 return NULL;
134 }
135 } else {
136 result = memcached_result_create(ptr, &ptr->result);
137 }
138 }
139
140 *error = MEMCACHED_MAXIMUM_RETURN; // We use this to see if we ever go into the loop
141 memcached_instance_st *server;
142 memcached_return_t read_ret = MEMCACHED_SUCCESS;
143 bool connection_failures = false;
144 while ((server = memcached_io_get_readable_server(ptr, read_ret))) {
145 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
146 *error = memcached_response(server, buffer, sizeof(buffer), result);
147
148 if (*error == MEMCACHED_IN_PROGRESS) {
149 continue;
150 } else if (*error == MEMCACHED_CONNECTION_FAILURE) {
151 connection_failures = true;
152 continue;
153 } else if (*error == MEMCACHED_SUCCESS) {
154 result->count++;
155 return result;
156 } else if (*error == MEMCACHED_END) {
157 memcached_server_response_reset(server);
158 } else if (*error != MEMCACHED_NOTFOUND) {
159 break;
160 }
161 }
162
163 if (*error == MEMCACHED_NOTFOUND and result->count) {
164 *error = MEMCACHED_END;
165 } else if (*error == MEMCACHED_MAXIMUM_RETURN and result->count) {
166 *error = MEMCACHED_END;
167 } else if (*error == MEMCACHED_MAXIMUM_RETURN) // while() loop was never entered
168 {
169 *error = MEMCACHED_NOTFOUND;
170 } else if (connection_failures) {
171 /*
172 If we have a connection failure to some servers, the caller may
173 wish to treat that differently to getting a definitive NOT_FOUND
174 from all servers, so return MEMCACHED_CONNECTION_FAILURE to allow
175 that.
176 */
177 *error = MEMCACHED_CONNECTION_FAILURE;
178 } else if (*error == MEMCACHED_SUCCESS) {
179 *error = MEMCACHED_END;
180 } else if (result->count == 0) {
181 *error = MEMCACHED_NOTFOUND;
182 }
183
184 /* We have completed reading data */
185 if (memcached_is_allocated(result)) {
186 memcached_result_free(result);
187 } else {
188 result->count = 0;
189 memcached_string_reset(&result->value);
190 }
191
192 return NULL;
193 }
194
195 memcached_return_t memcached_fetch_execute(memcached_st *shell, memcached_execute_fn *callback,
196 void *context, uint32_t number_of_callbacks) {
197 Memcached *ptr = memcached2Memcached(shell);
198 memcached_result_st *result = &ptr->result;
199 memcached_return_t rc;
200 bool some_errors = false;
201
202 while ((result = memcached_fetch_result(ptr, result, &rc))) {
203 if (memcached_failed(rc) and rc == MEMCACHED_NOTFOUND) {
204 continue;
205 } else if (memcached_failed(rc)) {
206 memcached_set_error(*ptr, rc, MEMCACHED_AT);
207 some_errors = true;
208 continue;
209 }
210
211 for (uint32_t x = 0; x < number_of_callbacks; x++) {
212 memcached_return_t ret = (*callback[x])(ptr, result, context);
213 if (memcached_failed(ret)) {
214 some_errors = true;
215 memcached_set_error(*ptr, ret, MEMCACHED_AT);
216 break;
217 }
218 }
219 }
220
221 if (some_errors) {
222 return MEMCACHED_SOME_ERRORS;
223 }
224
225 // If we were able to run all keys without issue we return
226 // MEMCACHED_SUCCESS
227 if (memcached_success(rc)) {
228 return MEMCACHED_SUCCESS;
229 }
230
231 return rc;
232 }