Abstract out ptr->hosts[server_key] references.
[m6w6/libmemcached] / libmemcached / get.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary: Get functions for libmemcached
9 *
10 */
11
12 #include "common.h"
13
14 /*
15 What happens if no servers exist?
16 */
17 char *memcached_get(memcached_st *ptr, const char *key,
18 size_t key_length,
19 size_t *value_length,
20 uint32_t *flags,
21 memcached_return_t *error)
22 {
23 return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
24 flags, error);
25 }
26
27 static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
28 const char *master_key,
29 size_t master_key_length,
30 const char * const *keys,
31 const size_t *key_length,
32 size_t number_of_keys,
33 bool mget_mode);
34
35 char *memcached_get_by_key(memcached_st *ptr,
36 const char *master_key,
37 size_t master_key_length,
38 const char *key, size_t key_length,
39 size_t *value_length,
40 uint32_t *flags,
41 memcached_return_t *error)
42 {
43 char *value;
44 size_t dummy_length;
45 uint32_t dummy_flags;
46 memcached_return_t dummy_error;
47
48 unlikely (ptr->flags.use_udp)
49 {
50 *error= MEMCACHED_NOT_SUPPORTED;
51 return NULL;
52 }
53
54 /* Request the key */
55 *error= memcached_mget_by_key_real(ptr, master_key, master_key_length,
56 (const char * const *)&key,
57 &key_length, 1, false);
58
59 value= memcached_fetch(ptr, NULL, NULL,
60 value_length, flags, error);
61 /* This is for historical reasons */
62 if (*error == MEMCACHED_END)
63 *error= MEMCACHED_NOTFOUND;
64
65 if (value == NULL)
66 {
67 if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
68 {
69 memcached_return_t rc;
70
71 memcached_result_reset(&ptr->result);
72 rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
73
74 /* On all failure drop to returning NULL */
75 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
76 {
77 if (rc == MEMCACHED_BUFFERED)
78 {
79 uint64_t latch; /* We use latch to track the state of the original socket */
80 latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
81 if (latch == 0)
82 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
83
84 rc= memcached_set(ptr, key, key_length,
85 (memcached_result_value(&ptr->result)),
86 (memcached_result_length(&ptr->result)),
87 0,
88 (memcached_result_flags(&ptr->result)));
89
90 if (rc == MEMCACHED_BUFFERED && latch == 0)
91 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
92 }
93 else
94 {
95 rc= memcached_set(ptr, key, key_length,
96 (memcached_result_value(&ptr->result)),
97 (memcached_result_length(&ptr->result)),
98 0,
99 (memcached_result_flags(&ptr->result)));
100 }
101
102 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
103 {
104 *error= rc;
105 *value_length= memcached_result_length(&ptr->result);
106 *flags= memcached_result_flags(&ptr->result);
107 return memcached_string_c_copy(&ptr->result.value);
108 }
109 }
110 }
111
112 return NULL;
113 }
114
115 (void)memcached_fetch(ptr, NULL, NULL,
116 &dummy_length, &dummy_flags,
117 &dummy_error);
118 WATCHPOINT_ASSERT(dummy_length == 0);
119
120 return value;
121 }
122
123 memcached_return_t memcached_mget(memcached_st *ptr,
124 const char * const *keys,
125 const size_t *key_length,
126 size_t number_of_keys)
127 {
128 return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
129 }
130
131 static memcached_return_t binary_mget_by_key(memcached_st *ptr,
132 uint32_t master_server_key,
133 bool is_master_key_set,
134 const char * const *keys,
135 const size_t *key_length,
136 size_t number_of_keys,
137 bool mget_mode);
138
139 static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
140 const char *master_key,
141 size_t master_key_length,
142 const char * const *keys,
143 const size_t *key_length,
144 size_t number_of_keys,
145 bool mget_mode)
146 {
147 unsigned int x;
148 memcached_return_t rc= MEMCACHED_NOTFOUND;
149 const char *get_command= "get ";
150 uint8_t get_command_length= 4;
151 unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
152 bool is_master_key_set= false;
153
154 unlikely (ptr->flags.use_udp)
155 return MEMCACHED_NOT_SUPPORTED;
156
157 LIBMEMCACHED_MEMCACHED_MGET_START();
158
159 if (number_of_keys == 0)
160 return MEMCACHED_NOTFOUND;
161
162 if (memcached_server_count(ptr) == 0)
163 return MEMCACHED_NO_SERVERS;
164
165 if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
166 return MEMCACHED_BAD_KEY_PROVIDED;
167
168 if (master_key && master_key_length)
169 {
170 if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
171 return MEMCACHED_BAD_KEY_PROVIDED;
172 master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
173 is_master_key_set= true;
174 }
175
176 /*
177 Here is where we pay for the non-block API. We need to remove any data sitting
178 in the queue before we start our get.
179
180 It might be optimum to bounce the connection if count > some number.
181 */
182 for (x= 0; x < memcached_server_count(ptr); x++)
183 {
184 if (memcached_server_response_count(&ptr->hosts[x]))
185 {
186 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
187
188 if (ptr->flags.no_block)
189 (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
190
191 while(memcached_server_response_count(&ptr->hosts[x]))
192 (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
193 }
194 }
195
196 if (ptr->flags.binary_protocol)
197 return binary_mget_by_key(ptr, master_server_key, is_master_key_set, keys,
198 key_length, number_of_keys, mget_mode);
199
200 if (ptr->flags.support_cas)
201 {
202 get_command= "gets ";
203 get_command_length= 5;
204 }
205
206 /*
207 If a server fails we warn about errors and start all over with sending keys
208 to the server.
209 */
210 for (x= 0; x < number_of_keys; x++)
211 {
212 memcached_server_instance_st *instance;
213 uint32_t server_key;
214
215 if (is_master_key_set)
216 {
217 server_key= master_server_key;
218 }
219 else
220 {
221 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
222 }
223
224 instance= memcached_server_instance_fetch(ptr, server_key);
225
226 if (memcached_server_response_count(instance) == 0)
227 {
228 rc= memcached_connect(instance);
229
230 if (rc != MEMCACHED_SUCCESS)
231 continue;
232
233 if ((memcached_io_write(instance, get_command, get_command_length, 0)) == -1)
234 {
235 rc= MEMCACHED_SOME_ERRORS;
236 continue;
237 }
238 WATCHPOINT_ASSERT(instance->cursor_active == 0);
239 memcached_server_response_increment(instance);
240 WATCHPOINT_ASSERT(instance->cursor_active == 1);
241 }
242
243 /* Only called when we have a prefix key */
244 if (ptr->prefix_key[0] != 0)
245 {
246 if ((memcached_io_write(instance, ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
247 {
248 memcached_server_response_reset(instance);
249 rc= MEMCACHED_SOME_ERRORS;
250 continue;
251 }
252 }
253
254 if ((memcached_io_write(instance, keys[x], key_length[x], 0)) == -1)
255 {
256 memcached_server_response_reset(instance);
257 rc= MEMCACHED_SOME_ERRORS;
258 continue;
259 }
260
261 if ((memcached_io_write(instance, " ", 1, 0)) == -1)
262 {
263 memcached_server_response_reset(instance);
264 rc= MEMCACHED_SOME_ERRORS;
265 continue;
266 }
267 }
268
269 /*
270 Should we muddle on if some servers are dead?
271 */
272 for (x= 0; x < memcached_server_count(ptr); x++)
273 {
274 if (memcached_server_response_count(&ptr->hosts[x]))
275 {
276 /* We need to do something about non-connnected hosts in the future */
277 if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
278 {
279 rc= MEMCACHED_SOME_ERRORS;
280 }
281 }
282 }
283
284 LIBMEMCACHED_MEMCACHED_MGET_END();
285 return rc;
286 }
287
288 memcached_return_t memcached_mget_by_key(memcached_st *ptr,
289 const char *master_key,
290 size_t master_key_length,
291 const char * const *keys,
292 const size_t *key_length,
293 size_t number_of_keys)
294 {
295 return memcached_mget_by_key_real(ptr, master_key, master_key_length, keys,
296 key_length, number_of_keys, true);
297 }
298
299 memcached_return_t memcached_mget_execute(memcached_st *ptr,
300 const char * const *keys,
301 const size_t *key_length,
302 size_t number_of_keys,
303 memcached_execute_fn *callback,
304 void *context,
305 unsigned int number_of_callbacks)
306 {
307 return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
308 number_of_keys, callback,
309 context, number_of_callbacks);
310 }
311
312 memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
313 const char *master_key,
314 size_t master_key_length,
315 const char * const *keys,
316 const size_t *key_length,
317 size_t number_of_keys,
318 memcached_execute_fn *callback,
319 void *context,
320 unsigned int number_of_callbacks)
321 {
322 if ((ptr->flags.binary_protocol) == 0)
323 return MEMCACHED_NOT_SUPPORTED;
324
325 memcached_return_t rc;
326 memcached_callback_st *original_callbacks= ptr->callbacks;
327 memcached_callback_st cb= {
328 .callback= callback,
329 .context= context,
330 .number_of_callback= number_of_callbacks
331 };
332
333 ptr->callbacks= &cb;
334 rc= memcached_mget_by_key(ptr, master_key, master_key_length, keys,
335 key_length, number_of_keys);
336 ptr->callbacks= original_callbacks;
337 return rc;
338 }
339
340 static memcached_return_t simple_binary_mget(memcached_st *ptr,
341 uint32_t master_server_key,
342 bool is_master_key_set,
343 const char * const *keys,
344 const size_t *key_length,
345 size_t number_of_keys, bool mget_mode)
346 {
347 memcached_return_t rc= MEMCACHED_NOTFOUND;
348 uint32_t x;
349
350 int flush= number_of_keys == 1;
351
352 /*
353 If a server fails we warn about errors and start all over with sending keys
354 to the server.
355 */
356 for (x= 0; x < number_of_keys; x++)
357 {
358 uint32_t server_key;
359 memcached_server_instance_st *instance;
360
361 if (is_master_key_set)
362 {
363 server_key= master_server_key;
364 }
365 else
366 {
367 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
368 }
369
370 instance= memcached_server_instance_fetch(ptr, server_key);
371
372 if (memcached_server_response_count(instance) == 0)
373 {
374 rc= memcached_connect(instance);
375 if (rc != MEMCACHED_SUCCESS)
376 continue;
377 }
378
379 protocol_binary_request_getk request= {.bytes= {0}};
380 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
381 if (mget_mode)
382 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
383 else
384 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
385
386 memcached_return_t vk;
387 vk= memcached_validate_key_length(key_length[x],
388 ptr->flags.binary_protocol);
389 unlikely (vk != MEMCACHED_SUCCESS)
390 {
391 if (x > 0)
392 {
393 memcached_io_reset(instance);
394 }
395
396 return vk;
397 }
398
399 request.message.header.request.keylen= htons((uint16_t)key_length[x]);
400 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
401 request.message.header.request.bodylen= htonl((uint32_t) key_length[x]);
402
403 if ((memcached_io_write(instance, request.bytes,
404 sizeof(request.bytes), 0) == -1) ||
405 (memcached_io_write(instance, keys[x],
406 key_length[x], (char) flush) == -1))
407 {
408 memcached_server_response_reset(instance);
409 rc= MEMCACHED_SOME_ERRORS;
410 continue;
411 }
412
413 /* We just want one pending response per server */
414 memcached_server_response_reset(instance);
415 memcached_server_response_increment(instance);
416 if ((x > 0 && x == ptr->io_key_prefetch) &&
417 memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
418 rc= MEMCACHED_SOME_ERRORS;
419 }
420
421 if (mget_mode)
422 {
423 /*
424 * Send a noop command to flush the buffers
425 */
426 protocol_binary_request_noop request= {.bytes= {0}};
427 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
428 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
429 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
430
431 for (x= 0; x < memcached_server_count(ptr); x++)
432 if (memcached_server_response_count(&ptr->hosts[x]))
433 {
434 if (memcached_io_write(&ptr->hosts[x], NULL, 0, 1) == -1)
435 {
436 memcached_server_response_reset(&ptr->hosts[x]);
437 memcached_io_reset(&ptr->hosts[x]);
438 rc= MEMCACHED_SOME_ERRORS;
439 }
440
441 if (memcached_io_write(&ptr->hosts[x], request.bytes,
442 sizeof(request.bytes), 1) == -1)
443 {
444 memcached_server_response_reset(&ptr->hosts[x]);
445 memcached_io_reset(&ptr->hosts[x]);
446 rc= MEMCACHED_SOME_ERRORS;
447 }
448 }
449 }
450
451
452 return rc;
453 }
454
455 static memcached_return_t replication_binary_mget(memcached_st *ptr,
456 uint32_t* hash,
457 bool* dead_servers,
458 const char *const *keys,
459 const size_t *key_length,
460 size_t number_of_keys)
461 {
462 memcached_return_t rc= MEMCACHED_NOTFOUND;
463 uint32_t x, start= 0;
464 uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
465
466 if (randomize_read)
467 start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
468
469 /* Loop for each replica */
470 for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
471 {
472 bool success= true;
473
474 for (x= 0; x < number_of_keys; ++x)
475 {
476 if (hash[x] == memcached_server_count(ptr))
477 continue; /* Already successfully sent */
478
479 uint32_t server= hash[x] + replica;
480
481 /* In case of randomized reads */
482 if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas)))
483 server += start;
484
485 while (server >= memcached_server_count(ptr))
486 server -= memcached_server_count(ptr);
487
488 if (dead_servers[server])
489 continue;
490
491 if (memcached_server_response_count(&ptr->hosts[server]) == 0)
492 {
493 rc= memcached_connect(&ptr->hosts[server]);
494 if (rc != MEMCACHED_SUCCESS)
495 {
496 memcached_io_reset(&ptr->hosts[server]);
497 dead_servers[server]= true;
498 success= false;
499 continue;
500 }
501 }
502
503 protocol_binary_request_getk request= {
504 .message.header.request= {
505 .magic= PROTOCOL_BINARY_REQ,
506 .opcode= PROTOCOL_BINARY_CMD_GETK,
507 .keylen= htons((uint16_t)key_length[x]),
508 .datatype= PROTOCOL_BINARY_RAW_BYTES,
509 .bodylen= htonl((uint32_t)key_length[x])
510 }
511 };
512
513 /*
514 * We need to disable buffering to actually know that the request was
515 * successfully sent to the server (so that we should expect a result
516 * back). It would be nice to do this in buffered mode, but then it
517 * would be complex to handle all error situations if we got to send
518 * some of the messages, and then we failed on writing out some others
519 * and we used the callback interface from memcached_mget_execute so
520 * that we might have processed some of the responses etc. For now,
521 * just make sure we work _correctly_
522 */
523 if ((memcached_io_write(&ptr->hosts[server], request.bytes,
524 sizeof(request.bytes), 0) == -1) ||
525 (memcached_io_write(&ptr->hosts[server], keys[x],
526 key_length[x], 1) == -1))
527 {
528 memcached_io_reset(&ptr->hosts[server]);
529 dead_servers[server]= true;
530 success= false;
531 continue;
532 }
533
534 memcached_server_response_increment(&ptr->hosts[server]);
535 hash[x]= memcached_server_count(ptr);
536 }
537
538 if (success)
539 break;
540 }
541
542 return rc;
543 }
544
545 static memcached_return_t binary_mget_by_key(memcached_st *ptr,
546 uint32_t master_server_key,
547 bool is_master_key_set,
548 const char * const *keys,
549 const size_t *key_length,
550 size_t number_of_keys,
551 bool mget_mode)
552 {
553 memcached_return_t rc;
554
555 if (ptr->number_of_replicas == 0)
556 {
557 rc= simple_binary_mget(ptr, master_server_key, is_master_key_set,
558 keys, key_length, number_of_keys, mget_mode);
559 }
560 else
561 {
562 uint32_t* hash;
563 bool* dead_servers;
564
565 hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
566 dead_servers= ptr->call_calloc(ptr, memcached_server_count(ptr), sizeof(bool));
567
568 if (hash == NULL || dead_servers == NULL)
569 {
570 ptr->call_free(ptr, hash);
571 ptr->call_free(ptr, dead_servers);
572 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
573 }
574
575 if (is_master_key_set)
576 for (unsigned int x= 0; x < number_of_keys; x++)
577 hash[x]= master_server_key;
578 else
579 for (unsigned int x= 0; x < number_of_keys; x++)
580 hash[x]= memcached_generate_hash(ptr, keys[x], key_length[x]);
581
582 rc= replication_binary_mget(ptr, hash, dead_servers, keys,
583 key_length, number_of_keys);
584
585 ptr->call_free(ptr, hash);
586 ptr->call_free(ptr, dead_servers);
587
588 return MEMCACHED_SUCCESS;
589 }
590
591 return rc;
592 }