Bugfix for memcached_connect() so that it will not always start up servers.
[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 (; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++)
38 {
39 *key= *string_ptr;
40 key++;
41 (*key_length)++;
42 }
43 }
44 else /* Skip characters */
45 for (; end_ptr > string_ptr && *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; end_ptr > string_ptr && *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; end_ptr > string_ptr && *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; end_ptr > string_ptr && *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
213 return memcached_string_c_copy(result_buffer);
214
215 error:
216 *value_length= 0;
217
218 LIBMEMCACHED_MEMCACHED_GET_END();
219
220 return NULL;
221 }
222
223 memcached_return memcached_mget(memcached_st *ptr,
224 char **keys, size_t *key_length,
225 unsigned int number_of_keys)
226 {
227 unsigned int x;
228 memcached_return rc= MEMCACHED_NOTFOUND;
229 char *get_command= "get ";
230 uint8_t get_command_length= 4
231
232 LIBMEMCACHED_MEMCACHED_MGET_START();
233 ptr->cursor_server= 0;
234
235 if (number_of_keys == 0)
236 return MEMCACHED_NOTFOUND;
237
238 if (ptr->number_of_hosts == 0)
239 return MEMCACHED_NO_SERVERS;
240
241 if (ptr->flags & MEM_SUPPORT_CAS)
242 {
243 get_command= "gets ";
244 get_command_length= 5;
245 }
246
247 for (x= 0; x < number_of_keys; x++)
248 {
249 unsigned int server_key;
250
251 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
252
253 if (ptr->hosts[server_key].cursor_active == 0)
254 {
255 rc= memcached_connect(ptr, server_key);
256
257 if ((memcached_io_write(ptr, server_key, get_command, get_command_length, 0)) == -1)
258 {
259 memcached_quit_server(ptr, server_key);
260 rc= MEMCACHED_SOME_ERRORS;
261 continue;
262 }
263 ptr->hosts[server_key].cursor_active= 1;
264 }
265
266 if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
267 {
268 ptr->hosts[server_key].cursor_active = 0;
269 memcached_quit_server(ptr, server_key);
270 rc= MEMCACHED_SOME_ERRORS;
271 continue;
272 }
273
274 if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
275 {
276 ptr->hosts[server_key].cursor_active = 0;
277 memcached_quit_server(ptr, server_key);
278 rc= MEMCACHED_SOME_ERRORS;
279 continue;
280 }
281 }
282
283
284 /*
285 Should we muddle on if some servers are dead?
286 */
287 for (x= 0; x < ptr->number_of_hosts; x++)
288 {
289 if (ptr->hosts[x].cursor_active == 1)
290 {
291 /* We need to doo something about non-connnected hosts in the future */
292 if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
293 {
294 memcached_quit_server(ptr, x);
295 rc= MEMCACHED_SOME_ERRORS;
296 }
297 }
298 }
299
300 LIBMEMCACHED_MEMCACHED_MGET_END();
301 return rc;
302 }
303
304 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
305 size_t *value_length,
306 uint16_t *flags,
307 memcached_return *error)
308 {
309 memcached_string_st *result_buffer;
310 result_buffer= &ptr->result_buffer;
311
312 while (ptr->cursor_server < ptr->number_of_hosts)
313 {
314 if (!ptr->hosts[ptr->cursor_server].cursor_active)
315 {
316 ptr->cursor_server++;
317 continue;
318 }
319
320 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
321 flags, NULL, 1, ptr->cursor_server);
322 *value_length= memcached_string_length(result_buffer);
323
324 if (*error == MEMCACHED_NOTFOUND)
325 {
326 ptr->hosts[ptr->cursor_server].cursor_active = 0;
327 ptr->cursor_server++;
328 }
329 else if (*error == MEMCACHED_END && *value_length == 0)
330 {
331 return NULL;
332 }
333 else if (*error == MEMCACHED_END)
334 {
335 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
336 *value_length= 0;
337 return NULL;
338 }
339 else if (*error != MEMCACHED_SUCCESS)
340 {
341 return NULL;
342 }
343 else
344 {
345 return memcached_string_c_copy(result_buffer);
346 }
347
348 }
349
350 *value_length= 0;
351 return NULL;
352 }
353
354 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
355 memcached_result_st *result,
356 memcached_return *error)
357 {
358 if (result == NULL)
359 result= memcached_result_create(ptr, NULL);
360
361 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
362
363 while (ptr->cursor_server < ptr->number_of_hosts)
364 {
365 if (!ptr->hosts[ptr->cursor_server].cursor_active)
366 {
367 ptr->cursor_server++;
368 continue;
369 }
370
371 result->cas= 0; /* We do this so we do not send in any junk */
372 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
373 &result->value,
374 &result->flags,
375 &result->cas,
376 1, ptr->cursor_server);
377
378 if (*error == MEMCACHED_NOTFOUND)
379 {
380 ptr->hosts[ptr->cursor_server].cursor_active = 0;
381 ptr->cursor_server++;
382 }
383 else if (*error == MEMCACHED_END && memcached_string_length((memcached_string_st *)(&result->value)) == 0)
384 {
385 goto error;
386 }
387 else if (*error == MEMCACHED_END)
388 {
389 WATCHPOINT_ASSERT(0); /* If this happens we have somehow messed up the fetch */
390 goto error;
391 }
392 else if (*error != MEMCACHED_SUCCESS)
393 {
394 goto error;
395 }
396 else
397 {
398 return result;
399 }
400 }
401
402 error:
403 memcached_string_reset(&result->value);
404
405 return NULL;
406 }