Big fix for async mode to make sure all data has been pushed through socket
[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 *value;
150 char *dummy_value;
151 size_t dummy_length;
152 uint16_t dummy_flags;
153 memcached_return dummy_error;
154
155 /* Request the key */
156 *error= memcached_mget(ptr, &key, &key_length, 1);
157
158 value= memcached_fetch(ptr, NULL, NULL,
159 value_length, flags, error);
160
161 if (value == NULL)
162 return NULL;
163
164 /* We do a second read to clean the cursor */
165 dummy_value= memcached_fetch(ptr, NULL, NULL,
166 &dummy_length, &dummy_flags,
167 &dummy_error);
168
169 /* Something is really wrong if this happens */
170 WATCHPOINT_ASSERT(dummy_value == NULL);
171 if (dummy_value)
172 free(dummy_value);
173
174 return value;
175 }
176
177 memcached_return memcached_mget(memcached_st *ptr,
178 char **keys, size_t *key_length,
179 unsigned int number_of_keys)
180 {
181 unsigned int x;
182 memcached_return rc= MEMCACHED_NOTFOUND;
183 char *get_command= "get ";
184 uint8_t get_command_length= 4
185
186 LIBMEMCACHED_MEMCACHED_MGET_START();
187 ptr->cursor_server= 0;
188
189 if (number_of_keys == 0)
190 return MEMCACHED_NOTFOUND;
191
192 if (ptr->number_of_hosts == 0)
193 return MEMCACHED_NO_SERVERS;
194
195 if (ptr->flags & MEM_SUPPORT_CAS)
196 {
197 get_command= "gets ";
198 get_command_length= 5;
199 }
200
201 for (x= 0; x < number_of_keys; x++)
202 {
203 unsigned int server_key;
204
205 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
206
207 if (ptr->hosts[server_key].cursor_active == 0)
208 {
209 rc= memcached_connect(ptr, server_key);
210
211 if ((memcached_io_write(ptr, server_key, get_command, get_command_length, 0)) == -1)
212 {
213 memcached_quit_server(ptr, server_key);
214 rc= MEMCACHED_SOME_ERRORS;
215 continue;
216 }
217 ptr->hosts[server_key].cursor_active= 1;
218 }
219
220 if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
221 {
222 ptr->hosts[server_key].cursor_active = 0;
223 memcached_quit_server(ptr, server_key);
224 rc= MEMCACHED_SOME_ERRORS;
225 continue;
226 }
227
228 if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
229 {
230 ptr->hosts[server_key].cursor_active = 0;
231 memcached_quit_server(ptr, server_key);
232 rc= MEMCACHED_SOME_ERRORS;
233 continue;
234 }
235 }
236
237
238 /*
239 Should we muddle on if some servers are dead?
240 */
241 for (x= 0; x < ptr->number_of_hosts; x++)
242 {
243 if (ptr->hosts[x].cursor_active == 1)
244 {
245 /* We need to doo something about non-connnected hosts in the future */
246 if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
247 {
248 memcached_quit_server(ptr, x);
249 rc= MEMCACHED_SOME_ERRORS;
250 }
251 }
252 }
253
254 LIBMEMCACHED_MEMCACHED_MGET_END();
255 return rc;
256 }
257
258 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
259 size_t *value_length,
260 uint16_t *flags,
261 memcached_return *error)
262 {
263 memcached_string_st *result_buffer;
264 result_buffer= &ptr->result_buffer;
265
266 while (ptr->cursor_server < ptr->number_of_hosts)
267 {
268 if (!ptr->hosts[ptr->cursor_server].cursor_active)
269 {
270 ptr->cursor_server++;
271 continue;
272 }
273
274 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
275 flags, NULL, ptr->cursor_server);
276 *value_length= memcached_string_length(result_buffer);
277
278 if (*error == MEMCACHED_NOTFOUND)
279 {
280 ptr->hosts[ptr->cursor_server].cursor_active = 0;
281 ptr->cursor_server++;
282 }
283 else if (*error == MEMCACHED_END && *value_length == 0)
284 {
285 return NULL;
286 }
287 else if (*error == MEMCACHED_END)
288 {
289 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
290 *value_length= 0;
291 return NULL;
292 }
293 else if (*error != MEMCACHED_SUCCESS)
294 {
295 return NULL;
296 }
297 else
298 {
299 return memcached_string_c_copy(result_buffer);
300 }
301
302 }
303
304 *value_length= 0;
305 return NULL;
306 }
307
308 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
309 memcached_result_st *result,
310 memcached_return *error)
311 {
312 if (result == NULL)
313 result= memcached_result_create(ptr, NULL);
314
315 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
316
317 while (ptr->cursor_server < ptr->number_of_hosts)
318 {
319 if (!ptr->hosts[ptr->cursor_server].cursor_active)
320 {
321 ptr->cursor_server++;
322 continue;
323 }
324
325 result->cas= 0; /* We do this so we do not send in any junk */
326 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
327 &result->value,
328 &result->flags,
329 &result->cas,
330 ptr->cursor_server);
331
332 if (*error == MEMCACHED_NOTFOUND)
333 {
334 ptr->hosts[ptr->cursor_server].cursor_active = 0;
335 ptr->cursor_server++;
336 }
337 else if (*error == MEMCACHED_END && memcached_string_length((memcached_string_st *)(&result->value)) == 0)
338 {
339 break;
340 }
341 else if (*error == MEMCACHED_END)
342 {
343 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
344 break;
345 }
346 else if (*error != MEMCACHED_SUCCESS)
347 {
348 break;
349 }
350 else
351 {
352 return result;
353 }
354 }
355
356 /* An error has occurred */
357 if (result->is_allocated == MEMCACHED_ALLOCATED)
358 memcached_result_free(result);
359 else
360 memcached_string_reset(&result->value);
361
362 return NULL;
363 }