Initial support for the binary protocol
[awesomized/libmemcached] / libmemcached / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 /*
5 What happens if no servers exist?
6 */
7 char *memcached_get(memcached_st *ptr, const char *key,
8 size_t key_length,
9 size_t *value_length,
10 uint32_t *flags,
11 memcached_return *error)
12 {
13 return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
14 flags, error);
15 }
16
17 char *memcached_get_by_key(memcached_st *ptr,
18 const char *master_key,
19 size_t master_key_length,
20 const char *key, size_t key_length,
21 size_t *value_length,
22 uint32_t *flags,
23 memcached_return *error)
24 {
25 char *value;
26 size_t dummy_length;
27 uint32_t dummy_flags;
28 memcached_return dummy_error;
29
30 /* Request the key */
31 *error= memcached_mget_by_key(ptr,
32 master_key,
33 master_key_length,
34 (char **)&key, &key_length, 1);
35
36 value= memcached_fetch(ptr, NULL, NULL,
37 value_length, flags, error);
38 /* This is for historical reasons */
39 if (*error == MEMCACHED_END)
40 *error= MEMCACHED_NOTFOUND;
41
42 if (value == NULL)
43 {
44 if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
45 {
46 memcached_return rc;
47
48 memcached_result_reset(&ptr->result);
49 rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
50
51 /* On all failure drop to returning NULL */
52 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
53 {
54 if (rc == MEMCACHED_BUFFERED)
55 {
56 uint8_t latch; /* We use latch to track the state of the original socket */
57 latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
58 if (latch == 0)
59 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
60
61 rc= memcached_set(ptr, key, key_length,
62 memcached_result_value(&ptr->result),
63 memcached_result_length(&ptr->result),
64 0, memcached_result_flags(&ptr->result));
65
66 if (rc == MEMCACHED_BUFFERED && latch == 0)
67 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
68 }
69 else
70 {
71 rc= memcached_set(ptr, key, key_length,
72 memcached_result_value(&ptr->result),
73 memcached_result_length(&ptr->result),
74 0, memcached_result_flags(&ptr->result));
75 }
76
77 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
78 {
79 *error= rc;
80 *value_length= memcached_result_length(&ptr->result);
81 *flags= memcached_result_flags(&ptr->result);
82 return memcached_string_c_copy(&ptr->result.value);
83 }
84 }
85 }
86
87 return NULL;
88 }
89
90 (void)memcached_fetch(ptr, NULL, NULL,
91 &dummy_length, &dummy_flags,
92 &dummy_error);
93 WATCHPOINT_ASSERT(dummy_length == 0);
94
95 return value;
96 }
97
98 memcached_return memcached_mget(memcached_st *ptr,
99 char **keys, size_t *key_length,
100 unsigned int number_of_keys)
101 {
102 return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
103 }
104
105 static memcached_return binary_mget_by_key(memcached_st *ptr,
106 unsigned int master_server_key,
107 char **keys, size_t *key_length,
108 unsigned int number_of_keys);
109
110 memcached_return memcached_mget_by_key(memcached_st *ptr,
111 const char *master_key,
112 size_t master_key_length,
113 char **keys,
114 size_t *key_length,
115 unsigned int number_of_keys)
116 {
117 unsigned int x;
118 memcached_return rc= MEMCACHED_NOTFOUND;
119 char *get_command= "get ";
120 uint8_t get_command_length= 4;
121 unsigned int master_server_key= 0;
122
123 LIBMEMCACHED_MEMCACHED_MGET_START();
124 ptr->cursor_server= 0;
125
126 if (number_of_keys == 0)
127 return MEMCACHED_NOTFOUND;
128
129 if (ptr->number_of_hosts == 0)
130 return MEMCACHED_NO_SERVERS;
131
132 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
133 return MEMCACHED_BAD_KEY_PROVIDED;
134
135 if (ptr->flags & MEM_SUPPORT_CAS)
136 {
137 get_command= "gets ";
138 get_command_length= 5;
139 }
140
141 if (master_key && master_key_length)
142 {
143 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test((char **)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
144 return MEMCACHED_BAD_KEY_PROVIDED;
145 master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
146 }
147
148 /*
149 Here is where we pay for the non-block API. We need to remove any data sitting
150 in the queue before we start our get.
151
152 It might be optimum to bounce the connection if count > some number.
153 */
154 for (x= 0; x < ptr->number_of_hosts; x++)
155 {
156 if (memcached_server_response_count(&ptr->hosts[x]))
157 {
158 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
159
160 if (ptr->flags & MEM_NO_BLOCK)
161 (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
162
163 while(memcached_server_response_count(&ptr->hosts[x]))
164 (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
165 }
166 }
167
168 if (ptr->flags & MEM_BINARY_PROTOCOL)
169 return binary_mget_by_key(ptr, master_server_key, keys,
170 key_length, number_of_keys);
171
172 /*
173 If a server fails we warn about errors and start all over with sending keys
174 to the server.
175 */
176 for (x= 0; x < number_of_keys; x++)
177 {
178 unsigned int server_key;
179
180 if (master_server_key)
181 server_key= master_server_key;
182 else
183 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
184
185 if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
186 {
187 rc= memcached_connect(&ptr->hosts[server_key]);
188
189 if (rc != MEMCACHED_SUCCESS)
190 continue;
191
192 if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
193 {
194 rc= MEMCACHED_SOME_ERRORS;
195 continue;
196 }
197 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
198 memcached_server_response_increment(&ptr->hosts[server_key]);
199 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
200 }
201
202 /* Only called when we have a prefix key */
203 if (ptr->prefix_key[0] != 0)
204 {
205 if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
206 {
207 memcached_server_response_reset(&ptr->hosts[server_key]);
208 rc= MEMCACHED_SOME_ERRORS;
209 continue;
210 }
211 }
212
213 if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
214 {
215 memcached_server_response_reset(&ptr->hosts[server_key]);
216 rc= MEMCACHED_SOME_ERRORS;
217 continue;
218 }
219
220 if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
221 {
222 memcached_server_response_reset(&ptr->hosts[server_key]);
223 rc= MEMCACHED_SOME_ERRORS;
224 continue;
225 }
226 }
227
228 /*
229 Should we muddle on if some servers are dead?
230 */
231 for (x= 0; x < ptr->number_of_hosts; x++)
232 {
233 if (memcached_server_response_count(&ptr->hosts[x]))
234 {
235 /* We need to do something about non-connnected hosts in the future */
236 if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
237 {
238 rc= MEMCACHED_SOME_ERRORS;
239 }
240 }
241 }
242
243 LIBMEMCACHED_MEMCACHED_MGET_END();
244 return rc;
245 }
246
247 static memcached_return binary_mget_by_key(memcached_st *ptr,
248 unsigned int master_server_key,
249 char **keys, size_t *key_length,
250 unsigned int number_of_keys)
251 {
252 memcached_return rc= MEMCACHED_NOTFOUND;
253
254 int flush= number_of_keys == 1;
255
256 /*
257 If a server fails we warn about errors and start all over with sending keys
258 to the server.
259 */
260 for (int x= 0; x < number_of_keys; x++)
261 {
262 unsigned int server_key;
263
264 if (master_server_key)
265 server_key= master_server_key;
266 else
267 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
268
269 if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
270 {
271 rc= memcached_connect(&ptr->hosts[server_key]);
272 if (rc != MEMCACHED_SUCCESS)
273 continue;
274 }
275
276 protocol_binary_request_getk request= {0};
277 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
278 if (number_of_keys == 1)
279 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
280 else
281 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
282
283 request.message.header.request.keylen= htons((uint16_t)key_length[x]);
284 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
285 request.message.header.request.bodylen= htonl(key_length[x]);
286
287 if ((memcached_io_write(&ptr->hosts[server_key], request.bytes,
288 sizeof(request.bytes), 0) == -1) ||
289 (memcached_io_write(&ptr->hosts[server_key], keys[x],
290 key_length[x], flush) == -1))
291 {
292 memcached_server_response_reset(&ptr->hosts[server_key]);
293 rc= MEMCACHED_SOME_ERRORS;
294 continue;
295 }
296 memcached_server_response_increment(&ptr->hosts[server_key]);
297 }
298
299 if (number_of_keys > 1)
300 {
301 /*
302 * Send a noop command to flush the buffers
303 */
304 protocol_binary_request_noop request= {0};
305 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
306 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
307 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
308
309 for (int x= 0; x < ptr->number_of_hosts; x++)
310 if (memcached_server_response_count(&ptr->hosts[x]))
311 {
312 if (memcached_io_write(&ptr->hosts[x], NULL, 0, 1) == -1)
313 {
314 memcached_server_response_reset(&ptr->hosts[x]);
315 memcached_io_reset(&ptr->hosts[x]);
316 rc= MEMCACHED_SOME_ERRORS;
317 }
318
319 if (memcached_io_write(&ptr->hosts[x], request.bytes,
320 sizeof(request.bytes), 1) == -1)
321 {
322 memcached_server_response_reset(&ptr->hosts[x]);
323 memcached_io_reset(&ptr->hosts[x]);
324 rc= MEMCACHED_SOME_ERRORS;
325 }
326 memcached_server_response_increment(&ptr->hosts[x]);
327 }
328 }
329
330
331 return rc;
332 }