Created a bigger buffer for write/read.
[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 assert(value_length);
16 assert(flags);
17 assert(error);
18
19 memset(buffer, 0, MEMCACHED_DEFAULT_COMMAND_SIZE);
20 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
21
22 *value_length= 0;
23
24 *error= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
25
26 if (*error == MEMCACHED_SUCCESS)
27 {
28 char *next_ptr;
29
30 string_ptr= buffer;
31 string_ptr+= 6; /* "VALUE " */
32
33 /* We load the key */
34 if (load_key)
35 {
36 memset(key, 0, MEMCACHED_MAX_KEY);
37 *key_length= 0;
38
39 for (; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++)
40 {
41 *key= *string_ptr;
42 key++;
43 (*key_length)++;
44 }
45 }
46 else /* Skip characters */
47 for (; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
48
49 if (end_ptr == string_ptr)
50 goto read_error;
51
52 /* Flags fetch move past space */
53 string_ptr++;
54 if (end_ptr == string_ptr)
55 goto read_error;
56 for (next_ptr= string_ptr; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
57 *flags= (uint16_t)strtol(next_ptr, &string_ptr, 10);
58
59 if (end_ptr == string_ptr)
60 goto read_error;
61
62 /* Length fetch move past space*/
63 string_ptr++;
64 if (end_ptr == string_ptr)
65 goto read_error;
66
67 for (next_ptr= string_ptr; end_ptr == string_ptr || *string_ptr != ' '; string_ptr++);
68 *value_length= (size_t)strtoll(next_ptr, &string_ptr, 10);
69
70 if (end_ptr == string_ptr)
71 goto read_error;
72
73 /* Skip past the \r\n */
74 string_ptr+= 2;
75
76 if (end_ptr < string_ptr)
77 goto read_error;
78
79 if (*value_length)
80 {
81 size_t read_length;
82 size_t to_read;
83 char *value;
84 char *value_ptr;
85
86 /* We add two bytes so that we can walk the \r\n */
87 value= (char *)malloc(((*value_length) +2) * sizeof(char));
88 if (!value)
89 {
90 *value_length= 0;
91 *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
92 return NULL;
93 }
94 memset(value, 0, ((*value_length) +2) * sizeof(char));
95
96 value_ptr= value;
97 read_length= 0;
98 /*
99 We read the \r\n into the string since not doing so is more
100 cycles then the waster of memory to do so.
101
102 We are null terminating through, which will most likely make
103 some people lazy about using the return length.
104 */
105 to_read= (*value_length) + 2;
106
107 read_length= memcached_io_read(ptr, server_key,
108 value_ptr, to_read);
109
110 if (read_length != (size_t)(*value_length + 2))
111 {
112 free(value);
113 goto read_error;
114 }
115
116 value[*value_length]= 0;
117 value[(*value_length) + 1]= 0;
118
119 return value;
120 }
121 }
122 else if (*error == MEMCACHED_END)
123 *error= MEMCACHED_NOTFOUND;
124
125 return NULL;
126 read_error:
127 *error= MEMCACHED_PARTIAL_READ;
128 return NULL;
129 }
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 size_t send_length;
137 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
138 unsigned int server_key;
139 char *value;
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 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "get %.*s\r\n",
151 (int)key_length, key);
152
153 if ((memcached_io_write(ptr, server_key, buffer, send_length, 1)) == -1)
154 {
155 *error= MEMCACHED_WRITE_FAILURE;
156 goto error;
157 }
158
159 value= memcached_value_fetch(ptr, key, &key_length, value_length, flags,
160 error, 0, server_key);
161 if (*error == MEMCACHED_END && *value_length == 0)
162 {
163 *error= MEMCACHED_NOTFOUND;
164 goto error;
165 }
166 else if (*error == MEMCACHED_END)
167 assert(0); /* If this happens we have somehow messed up the fetch */
168 else if (*error == MEMCACHED_SUCCESS)
169 {
170 memcached_return rc;
171 /* We need to read END */
172 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
173
174 if (rc != MEMCACHED_END)
175 {
176 *error= MEMCACHED_PROTOCOL_ERROR;
177 goto error;
178 }
179 }
180 else
181 goto error;
182
183 LIBMEMCACHED_MEMCACHED_GET_END();
184
185 return value;
186
187 error:
188 free(value);
189 *value_length= 0;
190
191 LIBMEMCACHED_MEMCACHED_GET_END();
192
193 return NULL;
194 }
195
196 memcached_return memcached_mget(memcached_st *ptr,
197 char **keys, size_t *key_length,
198 unsigned int number_of_keys)
199 {
200 char buffer[HUGE_STRING_LEN];
201 unsigned int x;
202 memcached_return rc;
203 memcached_string_st **cursor_key_exec;
204 LIBMEMCACHED_MEMCACHED_MGET_START();
205
206 ptr->cursor_server= 0;
207 memset(buffer, 0, HUGE_STRING_LEN);
208
209 cursor_key_exec= (memcached_string_st **)malloc(sizeof(memcached_string_st *) * ptr->number_of_hosts);
210 memset(cursor_key_exec, 0, sizeof(memcached_string_st *) * ptr->number_of_hosts);
211
212
213 for (x= 0; x < number_of_keys; x++)
214 {
215 unsigned int server_key;
216
217 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
218
219 if (cursor_key_exec[server_key])
220 {
221 memcached_string_st *string= cursor_key_exec[server_key];
222
223 memcached_string_append_character(ptr, string, ' ');
224 memcached_string_append(ptr, string, keys[x], key_length[x]);
225 }
226 else
227 {
228 memcached_string_st *string= memcached_string_create(ptr, SMALL_STRING_LEN);
229
230 /* We need to figure out the correct way to error in case of this failure */
231 if (!string)
232 assert(0);
233
234 memcached_string_append(ptr, string, "get ", 4);
235 memcached_string_append(ptr, string, keys[x], key_length[x]);
236
237 cursor_key_exec[server_key]= string;
238 }
239 }
240
241
242 /*
243 Should we muddle on if some servers are dead?
244 */
245 for (x= 0; x < ptr->number_of_hosts; x++)
246 {
247 if (cursor_key_exec[x])
248 {
249 /* We need to doo something about non-connnected hosts in the future */
250 rc= memcached_connect(ptr, x);
251
252 memcached_string_st *string= cursor_key_exec[x];
253 memcached_string_append(ptr, string, "\r\n", 2);
254
255 if ((memcached_io_write(ptr, x, string->string,
256 memcached_string_length(ptr, string), 1)) == -1)
257 {
258 memcached_quit(ptr);
259 rc= MEMCACHED_SOME_ERRORS;
260 }
261 memcached_string_free(ptr, string);
262 cursor_key_exec[x]= NULL; /* Remove warning */
263 ptr->hosts[x].cursor_active= 1;
264 }
265 else
266 ptr->hosts[x].cursor_active= 0;
267 }
268
269 free(cursor_key_exec);
270
271 LIBMEMCACHED_MEMCACHED_MGET_END();
272 return rc;
273 }
274
275 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
276 size_t *value_length,
277 uint16_t *flags,
278 memcached_return *error)
279 {
280 char *value_check;
281
282 while (ptr->cursor_server < ptr->number_of_hosts)
283 {
284 if (!ptr->hosts[ptr->cursor_server].cursor_active)
285 {
286 ptr->cursor_server++;
287 continue;
288 }
289
290 value_check= memcached_value_fetch(ptr, key, key_length, value_length, flags,
291 error, 1, ptr->cursor_server);
292
293 if (*error == MEMCACHED_NOTFOUND)
294 ptr->cursor_server++;
295 else if (*error == MEMCACHED_END && *value_length == 0)
296 return NULL;
297 else if (*error == MEMCACHED_END)
298 assert(0); /* If this happens we have somehow messed up the fetch */
299 else if (*error != MEMCACHED_SUCCESS)
300 return NULL;
301 else
302 return value_check;
303
304 }
305
306 *value_length= 0;
307 return NULL;
308 }