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