Allocation fixes in string library (now we can run bigger tests!)
[awesomized/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 char *memcached_get(memcached_st *ptr, char *key, size_t key_length,
129 size_t *value_length,
130 uint16_t *flags,
131 memcached_return *error)
132 {
133 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
134 char *buf_ptr= buffer;
135 unsigned int server_key;
136 char *value;
137 LIBMEMCACHED_MEMCACHED_GET_START();
138
139 server_key= memcached_generate_hash(ptr, key, key_length);
140
141 *value_length= 0;
142 *error= memcached_connect(ptr, server_key);
143
144 if (*error != MEMCACHED_SUCCESS)
145 goto error;
146
147 memcpy(buf_ptr, "get ", 4);
148 buf_ptr+= 4;
149 memcpy(buf_ptr, key, key_length);
150 buf_ptr+= key_length;
151 memcpy(buf_ptr, "\r\n", 2);
152 buf_ptr+= 2;
153
154 if ((memcached_io_write(ptr, server_key, buffer, (size_t)(buf_ptr - buffer), 1)) == -1)
155 {
156 *error= MEMCACHED_WRITE_FAILURE;
157 goto error;
158 }
159
160 value= memcached_value_fetch(ptr, key, &key_length, value_length, flags,
161 error, 0, server_key);
162 if (*error == MEMCACHED_END && *value_length == 0)
163 {
164 *error= MEMCACHED_NOTFOUND;
165 goto error;
166 }
167 else if (*error == MEMCACHED_END)
168 assert(0); /* If this happens we have somehow messed up the fetch */
169 else if (*error == MEMCACHED_SUCCESS)
170 {
171 memcached_return rc;
172 /* We need to read END */
173 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
174
175 if (rc != MEMCACHED_END)
176 {
177 *error= MEMCACHED_PROTOCOL_ERROR;
178 goto error;
179 }
180 }
181 else
182 goto error;
183
184 LIBMEMCACHED_MEMCACHED_GET_END();
185
186 return value;
187
188 error:
189 free(value);
190 *value_length= 0;
191
192 LIBMEMCACHED_MEMCACHED_GET_END();
193
194 return NULL;
195 }
196
197 memcached_return memcached_mget(memcached_st *ptr,
198 char **keys, size_t *key_length,
199 unsigned int number_of_keys)
200 {
201 char buffer[HUGE_STRING_LEN];
202 unsigned int x;
203 memcached_return rc;
204 memcached_string_st **cursor_key_exec;
205 LIBMEMCACHED_MEMCACHED_MGET_START();
206
207 ptr->cursor_server= 0;
208 memset(buffer, 0, HUGE_STRING_LEN);
209
210 cursor_key_exec= (memcached_string_st **)malloc(sizeof(memcached_string_st *) * ptr->number_of_hosts);
211 memset(cursor_key_exec, 0, sizeof(memcached_string_st *) * ptr->number_of_hosts);
212
213
214 for (x= 0; x < number_of_keys; x++)
215 {
216 unsigned int server_key;
217
218 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
219
220 if (cursor_key_exec[server_key])
221 {
222 memcached_string_st *string= cursor_key_exec[server_key];
223
224 rc= memcached_string_append_character(ptr, string, ' ');
225
226 if (rc != MEMCACHED_SUCCESS)
227 assert(0);
228
229 rc= memcached_string_append(ptr, string, keys[x], key_length[x]);
230
231 if (rc != MEMCACHED_SUCCESS)
232 assert(0);
233 }
234 else
235 {
236 memcached_string_st *string= memcached_string_create(ptr, SMALL_STRING_LEN);
237
238 /* We need to figure out the correct way to error in case of this failure */
239 if (!string)
240 assert(0);
241
242 rc= memcached_string_append(ptr, string, "get ", 4);
243 if (rc != MEMCACHED_SUCCESS)
244 assert(0);
245
246 rc= memcached_string_append(ptr, string, keys[x], key_length[x]);
247 if (rc != MEMCACHED_SUCCESS)
248 assert(0);
249
250 cursor_key_exec[server_key]= string;
251 }
252 }
253
254
255 /*
256 Should we muddle on if some servers are dead?
257 */
258 for (x= 0; x < ptr->number_of_hosts; x++)
259 {
260 if (cursor_key_exec[x])
261 {
262 /* We need to doo something about non-connnected hosts in the future */
263 rc= memcached_connect(ptr, x);
264
265 memcached_string_st *string= cursor_key_exec[x];
266
267 rc= memcached_string_append(ptr, string, "\r\n", 2);
268 if (rc != MEMCACHED_SUCCESS)
269 assert(0);
270
271 if ((memcached_io_write(ptr, x, string->string,
272 memcached_string_length(ptr, string), 1)) == -1)
273 {
274 memcached_quit(ptr);
275 rc= MEMCACHED_SOME_ERRORS;
276 }
277 memcached_string_free(ptr, string);
278 cursor_key_exec[x]= NULL; /* Remove warning */
279 ptr->hosts[x].cursor_active= 1;
280 }
281 else
282 ptr->hosts[x].cursor_active= 0;
283 }
284
285 free(cursor_key_exec);
286
287 LIBMEMCACHED_MEMCACHED_MGET_END();
288 return rc;
289 }
290
291 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
292 size_t *value_length,
293 uint16_t *flags,
294 memcached_return *error)
295 {
296 char *value_check;
297
298 while (ptr->cursor_server < ptr->number_of_hosts)
299 {
300 if (!ptr->hosts[ptr->cursor_server].cursor_active)
301 {
302 ptr->cursor_server++;
303 continue;
304 }
305
306 value_check= memcached_value_fetch(ptr, key, key_length, value_length, flags,
307 error, 1, ptr->cursor_server);
308
309 if (*error == MEMCACHED_NOTFOUND)
310 ptr->cursor_server++;
311 else if (*error == MEMCACHED_END && *value_length == 0)
312 return NULL;
313 else if (*error == MEMCACHED_END)
314 assert(0); /* If this happens we have somehow messed up the fetch */
315 else if (*error != MEMCACHED_SUCCESS)
316 return NULL;
317 else
318 return value_check;
319
320 }
321
322 *value_length= 0;
323 return NULL;
324 }