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