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