Refactored out param
[awesomized/libmemcached] / lib / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 static memcached_return memcached_value_fetch(memcached_st *ptr, char *key, size_t *key_length,
5 memcached_string_st *value,
6 uint16_t *flags,
7 uint64_t *cas,
8 unsigned int server_key)
9 {
10 memcached_return rc;
11 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
12 char *string_ptr;
13 char *end_ptr;
14
15 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
16
17 *flags= 0;
18
19 memcached_string_reset(value);
20
21 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
22
23 if (rc == MEMCACHED_SUCCESS)
24 {
25 char *next_ptr;
26 size_t value_length;
27
28 string_ptr= buffer;
29 string_ptr+= 6; /* "VALUE " */
30
31 /* We load the key */
32 if (key)
33 {
34 *key_length= 0;
35
36 for (; isalnum(*string_ptr); string_ptr++)
37 {
38 *key= *string_ptr;
39 key++;
40 (*key_length)++;
41 }
42 }
43 else /* Skip characters */
44 for (; isalnum(*string_ptr); string_ptr++);
45
46 if (end_ptr == string_ptr)
47 goto read_error;
48
49 /* Flags fetch move past space */
50 string_ptr++;
51 if (end_ptr == string_ptr)
52 goto read_error;
53 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
54 *flags= (uint16_t)strtol(next_ptr, &string_ptr, 10);
55
56 if (end_ptr == string_ptr)
57 goto read_error;
58
59 /* Length fetch move past space*/
60 string_ptr++;
61 if (end_ptr == string_ptr)
62 goto read_error;
63
64 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
65 value_length= (size_t)strtoll(next_ptr, &string_ptr, 10);
66
67 if (end_ptr == string_ptr)
68 goto read_error;
69
70 /* Skip spaces */
71 if (*string_ptr == '\r')
72 {
73 /* Skip past the \r\n */
74 string_ptr+= 2;
75 }
76 else
77 {
78 string_ptr++;
79 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
80 if (cas)
81 *cas= (size_t)strtoll(next_ptr, &string_ptr, 10);
82 }
83
84 if (end_ptr < string_ptr)
85 goto read_error;
86
87 if (value_length)
88 {
89 size_t read_length;
90 size_t to_read;
91 char *value_ptr;
92
93 /* We add two bytes so that we can walk the \r\n */
94 rc= memcached_string_check(value, value_length+2);
95 if (rc != MEMCACHED_SUCCESS)
96 {
97 value_length= 0;
98 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
99 }
100
101 value_ptr= memcached_string_value(value);
102 read_length= 0;
103 /*
104 We read the \r\n into the string since not doing so is more
105 cycles then the waster of memory to do so.
106
107 We are null terminating through, which will most likely make
108 some people lazy about using the return length.
109 */
110 to_read= (value_length) + 2;
111
112 read_length= memcached_io_read(ptr, server_key,
113 value_ptr, to_read);
114
115 if (read_length != (size_t)(value_length + 2))
116 {
117 goto read_error;
118 }
119
120 /* This next bit blows the API, but this is internal....*/
121 {
122 char *char_ptr;
123 char_ptr= memcached_string_value(value);;
124 char_ptr[value_length]= 0;
125 char_ptr[value_length + 1]= 0;
126 memcached_string_set_length(value, value_length);
127 }
128
129 return MEMCACHED_SUCCESS;
130 }
131 }
132 else if (rc == MEMCACHED_END)
133 rc= MEMCACHED_NOTFOUND;
134
135 return rc;
136
137 read_error:
138 return MEMCACHED_PARTIAL_READ;
139 }
140
141 /*
142 What happens if no servers exist?
143 */
144 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
145 size_t *value_length,
146 uint16_t *flags,
147 memcached_return *error)
148 {
149 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
150 char *buf_ptr= buffer;
151 unsigned int server_key;
152 memcached_string_st *result_buffer;
153 LIBMEMCACHED_MEMCACHED_GET_START();
154
155 if (key_length == 0)
156 {
157 *error= MEMCACHED_NO_KEY_PROVIDED;
158 return NULL;
159 }
160
161 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
162 {
163 *error= MEMCACHED_NO_SERVERS;
164 return NULL;
165 }
166
167 server_key= memcached_generate_hash(ptr, key, key_length);
168 result_buffer= &ptr->result_buffer;
169
170 *value_length= 0;
171 memcpy(buf_ptr, "get ", 4);
172 buf_ptr+= 4;
173 memcpy(buf_ptr, key, key_length);
174 buf_ptr+= key_length;
175 memcpy(buf_ptr, "\r\n", 2);
176 buf_ptr+= 2;
177
178 *error= memcached_do(ptr, server_key, buffer, (size_t)(buf_ptr - buffer), 1);
179 if (*error != MEMCACHED_SUCCESS)
180 goto error;
181
182 *error= memcached_value_fetch(ptr, NULL, NULL, result_buffer,
183 flags, NULL, server_key);
184 *value_length= memcached_string_length(result_buffer);
185 if (*error == MEMCACHED_END && *value_length == 0)
186 {
187 *error= MEMCACHED_NOTFOUND;
188 goto error;
189 }
190 else if (*error == MEMCACHED_END)
191 {
192 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
193 }
194 else if (*error == MEMCACHED_SUCCESS)
195 {
196 memcached_return rc;
197 /* We need to read END */
198 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
199
200 if (rc != MEMCACHED_END)
201 {
202 *error= MEMCACHED_PROTOCOL_ERROR;
203 goto error;
204 }
205 }
206 else
207 goto error;
208
209 LIBMEMCACHED_MEMCACHED_GET_END();
210
211 return memcached_string_c_copy(result_buffer);
212
213 error:
214 *value_length= 0;
215
216 LIBMEMCACHED_MEMCACHED_GET_END();
217
218 return NULL;
219 }
220
221 memcached_return memcached_mget(memcached_st *ptr,
222 char **keys, size_t *key_length,
223 unsigned int number_of_keys)
224 {
225 unsigned int x;
226 memcached_return rc= MEMCACHED_NOTFOUND;
227 char *get_command= "get ";
228 uint8_t get_command_length= 4
229
230 LIBMEMCACHED_MEMCACHED_MGET_START();
231 ptr->cursor_server= 0;
232
233 if (number_of_keys == 0)
234 return MEMCACHED_NOTFOUND;
235
236 if (ptr->number_of_hosts == 0)
237 return MEMCACHED_NO_SERVERS;
238
239 if (ptr->flags & MEM_SUPPORT_CAS)
240 {
241 get_command= "gets ";
242 get_command_length= 5;
243 }
244
245 for (x= 0; x < number_of_keys; x++)
246 {
247 unsigned int server_key;
248
249 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
250
251 if (ptr->hosts[server_key].cursor_active == 0)
252 {
253 rc= memcached_connect(ptr, server_key);
254
255 if ((memcached_io_write(ptr, server_key, get_command, get_command_length, 0)) == -1)
256 {
257 memcached_quit_server(ptr, server_key);
258 rc= MEMCACHED_SOME_ERRORS;
259 continue;
260 }
261 ptr->hosts[server_key].cursor_active= 1;
262 }
263
264 if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
265 {
266 ptr->hosts[server_key].cursor_active = 0;
267 memcached_quit_server(ptr, server_key);
268 rc= MEMCACHED_SOME_ERRORS;
269 continue;
270 }
271
272 if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
273 {
274 ptr->hosts[server_key].cursor_active = 0;
275 memcached_quit_server(ptr, server_key);
276 rc= MEMCACHED_SOME_ERRORS;
277 continue;
278 }
279 }
280
281
282 /*
283 Should we muddle on if some servers are dead?
284 */
285 for (x= 0; x < ptr->number_of_hosts; x++)
286 {
287 if (ptr->hosts[x].cursor_active == 1)
288 {
289 /* We need to doo something about non-connnected hosts in the future */
290 if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
291 {
292 memcached_quit_server(ptr, x);
293 rc= MEMCACHED_SOME_ERRORS;
294 }
295 }
296 }
297
298 LIBMEMCACHED_MEMCACHED_MGET_END();
299 return rc;
300 }
301
302 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
303 size_t *value_length,
304 uint16_t *flags,
305 memcached_return *error)
306 {
307 memcached_string_st *result_buffer;
308 result_buffer= &ptr->result_buffer;
309
310 while (ptr->cursor_server < ptr->number_of_hosts)
311 {
312 if (!ptr->hosts[ptr->cursor_server].cursor_active)
313 {
314 ptr->cursor_server++;
315 continue;
316 }
317
318 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
319 flags, NULL, ptr->cursor_server);
320 *value_length= memcached_string_length(result_buffer);
321
322 if (*error == MEMCACHED_NOTFOUND)
323 {
324 ptr->hosts[ptr->cursor_server].cursor_active = 0;
325 ptr->cursor_server++;
326 }
327 else if (*error == MEMCACHED_END && *value_length == 0)
328 {
329 return NULL;
330 }
331 else if (*error == MEMCACHED_END)
332 {
333 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
334 *value_length= 0;
335 return NULL;
336 }
337 else if (*error != MEMCACHED_SUCCESS)
338 {
339 return NULL;
340 }
341 else
342 {
343 return memcached_string_c_copy(result_buffer);
344 }
345
346 }
347
348 *value_length= 0;
349 return NULL;
350 }
351
352 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
353 memcached_result_st *result,
354 memcached_return *error)
355 {
356 if (result == NULL)
357 result= memcached_result_create(ptr, NULL);
358
359 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
360
361 while (ptr->cursor_server < ptr->number_of_hosts)
362 {
363 if (!ptr->hosts[ptr->cursor_server].cursor_active)
364 {
365 ptr->cursor_server++;
366 continue;
367 }
368
369 result->cas= 0; /* We do this so we do not send in any junk */
370 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
371 &result->value,
372 &result->flags,
373 &result->cas,
374 ptr->cursor_server);
375
376 if (*error == MEMCACHED_NOTFOUND)
377 {
378 ptr->hosts[ptr->cursor_server].cursor_active = 0;
379 ptr->cursor_server++;
380 }
381 else if (*error == MEMCACHED_END && memcached_string_length((memcached_string_st *)(&result->value)) == 0)
382 {
383 break;
384 }
385 else if (*error == MEMCACHED_END)
386 {
387 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
388 break;
389 }
390 else if (*error != MEMCACHED_SUCCESS)
391 {
392 break;
393 }
394 else
395 {
396 return result;
397 }
398 }
399
400 /* An error has occurred */
401 if (result->is_allocated == MEMCACHED_ALLOCATED)
402 memcached_result_free(result);
403 else
404 memcached_string_reset(&result->value);
405
406 return NULL;
407 }