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