Updated to build on OSX (will now require updated autoconf)
[m6w6/libmemcached] / lib / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 static char *memcached_value_fetch(memcached_st *ptr, char *key, size_t *key_length,
5 size_t *value_length,
6 uint16_t *flags,
7 memcached_return *error,
8 char load_key,
9 unsigned int server_key)
10 {
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 *value_length= 0;
19 *flags= 0;
20
21 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
22
23 if (*error == MEMCACHED_SUCCESS)
24 {
25 char *next_ptr;
26
27 string_ptr= buffer;
28 string_ptr+= 6; /* "VALUE " */
29
30 /* We load the key */
31 if (load_key)
32 {
33 memset(key, 0, MEMCACHED_MAX_KEY);
34 *key_length= 0;
35
36 for (; end_ptr > string_ptr && *string_ptr != ' '; string_ptr++)
37 {
38 *key= *string_ptr;
39 key++;
40 (*key_length)++;
41 }
42 }
43 else /* Skip characters */
44 for (; end_ptr > string_ptr && *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; end_ptr > string_ptr && *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; end_ptr > string_ptr && *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 past the \r\n */
71 string_ptr+= 2;
72
73 if (end_ptr < string_ptr)
74 goto read_error;
75
76 if (*value_length)
77 {
78 size_t read_length;
79 size_t to_read;
80 char *value;
81 char *value_ptr;
82
83 /* We add two bytes so that we can walk the \r\n */
84 value= (char *)malloc(((*value_length) +2) * sizeof(char));
85 if (!value)
86 {
87 *value_length= 0;
88 *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
89 return NULL;
90 }
91 memset(value, 0, ((*value_length) +2) * sizeof(char));
92
93 value_ptr= value;
94 read_length= 0;
95 /*
96 We read the \r\n into the string since not doing so is more
97 cycles then the waster of memory to do so.
98
99 We are null terminating through, which will most likely make
100 some people lazy about using the return length.
101 */
102 to_read= (*value_length) + 2;
103
104 read_length= memcached_io_read(ptr, server_key,
105 value_ptr, to_read);
106
107 if (read_length != (size_t)(*value_length + 2))
108 {
109 free(value);
110 goto read_error;
111 }
112
113 value[*value_length]= 0;
114 value[(*value_length) + 1]= 0;
115
116 return value;
117 }
118 }
119 else if (*error == MEMCACHED_END)
120 *error= MEMCACHED_NOTFOUND;
121
122 return NULL;
123 read_error:
124 *error= MEMCACHED_PARTIAL_READ;
125 return NULL;
126 }
127
128 /*
129 What happens if no servers exist?
130 */
131 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
132 size_t *value_length,
133 uint16_t *flags,
134 memcached_return *error)
135 {
136 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
137 char *buf_ptr= buffer;
138 unsigned int server_key;
139 char *value= NULL;
140 LIBMEMCACHED_MEMCACHED_GET_START();
141
142 server_key= memcached_generate_hash(ptr, key, key_length);
143
144 *value_length= 0;
145 *error= memcached_connect(ptr, server_key);
146
147 if (*error != MEMCACHED_SUCCESS)
148 goto error;
149
150 memcpy(buf_ptr, "get ", 4);
151 buf_ptr+= 4;
152 memcpy(buf_ptr, key, key_length);
153 buf_ptr+= key_length;
154 memcpy(buf_ptr, "\r\n", 2);
155 buf_ptr+= 2;
156
157 if ((memcached_io_write(ptr, server_key, buffer, (size_t)(buf_ptr - buffer), 1)) == -1)
158 {
159 *error= MEMCACHED_WRITE_FAILURE;
160 goto error;
161 }
162
163 value= memcached_value_fetch(ptr, key, &key_length, value_length, flags,
164 error, 0, server_key);
165 if (*error == MEMCACHED_END && *value_length == 0)
166 {
167 *error= MEMCACHED_NOTFOUND;
168 goto error;
169 }
170 else if (*error == MEMCACHED_END)
171 assert(0); /* If this happens we have somehow messed up the fetch */
172 else if (*error == MEMCACHED_SUCCESS)
173 {
174 memcached_return rc;
175 /* We need to read END */
176 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
177
178 if (rc != MEMCACHED_END)
179 {
180 *error= MEMCACHED_PROTOCOL_ERROR;
181 goto error;
182 }
183 }
184 else
185 goto error;
186
187 LIBMEMCACHED_MEMCACHED_GET_END();
188
189 return value;
190
191 error:
192 free(value);
193 *value_length= 0;
194
195 LIBMEMCACHED_MEMCACHED_GET_END();
196
197 return NULL;
198 }
199
200 memcached_return memcached_mget(memcached_st *ptr,
201 char **keys, size_t *key_length,
202 unsigned int number_of_keys)
203 {
204 unsigned int x;
205 memcached_return rc= MEMCACHED_NOTFOUND;
206 char *cursor_key_exec;
207 LIBMEMCACHED_MEMCACHED_MGET_START();
208 ptr->cursor_server= 0;
209
210 if (number_of_keys == 0)
211 return MEMCACHED_NOTFOUND;
212
213 cursor_key_exec= (char *)malloc(sizeof(char) * ptr->number_of_hosts);
214 memset(cursor_key_exec, 0, sizeof(char) * ptr->number_of_hosts);
215
216 for (x= 0; x < number_of_keys; x++)
217 {
218 unsigned int server_key;
219
220 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
221
222 if (cursor_key_exec[server_key] == 0)
223 {
224 rc= memcached_connect(ptr, server_key);
225
226 if ((memcached_io_write(ptr, server_key, "get ", 4, 0)) == -1)
227 {
228 memcached_quit(ptr);
229 rc= MEMCACHED_SOME_ERRORS;
230 break;
231 }
232 }
233
234 if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
235 {
236 memcached_quit(ptr);
237 rc= MEMCACHED_SOME_ERRORS;
238 break;
239 }
240
241 if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
242 {
243 memcached_quit(ptr);
244 rc= MEMCACHED_SOME_ERRORS;
245 break;
246 }
247 cursor_key_exec[server_key]= 1;
248 }
249
250
251 /*
252 Should we muddle on if some servers are dead?
253 */
254 for (x= 0; x < ptr->number_of_hosts; x++)
255 {
256 if (cursor_key_exec[x])
257 {
258 /* We need to doo something about non-connnected hosts in the future */
259 if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
260 {
261 memcached_quit(ptr);
262 rc= MEMCACHED_SOME_ERRORS;
263 break;
264 }
265
266 ptr->hosts[x].cursor_active= 1;
267 }
268 else
269 ptr->hosts[x].cursor_active= 0;
270 }
271
272 free(cursor_key_exec);
273
274 LIBMEMCACHED_MEMCACHED_MGET_END();
275 return rc;
276 }
277
278 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
279 size_t *value_length,
280 uint16_t *flags,
281 memcached_return *error)
282 {
283 char *value_check;
284
285 while (ptr->cursor_server < ptr->number_of_hosts)
286 {
287 if (!ptr->hosts[ptr->cursor_server].cursor_active)
288 {
289 ptr->cursor_server++;
290 continue;
291 }
292
293 value_check= memcached_value_fetch(ptr, key, key_length, value_length, flags,
294 error, 1, ptr->cursor_server);
295
296 if (*error == MEMCACHED_NOTFOUND)
297 ptr->cursor_server++;
298 else if (*error == MEMCACHED_END && *value_length == 0)
299 return NULL;
300 else if (*error == MEMCACHED_END)
301 assert(0); /* If this happens we have somehow messed up the fetch */
302 else if (*error != MEMCACHED_SUCCESS)
303 return NULL;
304 else
305 return value_check;
306
307 }
308
309 *value_length= 0;
310 return NULL;
311 }