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