8d281f35d182dd0758df03425cad4c7b24cdea0d
[awesomized/libmemcached] / lib / memcached_fetch.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 uint64_t *cas,
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 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
16
17 if (flags)
18 *flags= 0;
19
20 memcached_string_reset(value);
21
22 rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
23
24
25 if (rc == MEMCACHED_SUCCESS)
26 {
27 char *next_ptr;
28 size_t value_length;
29
30 string_ptr= buffer;
31 string_ptr+= 6; /* "VALUE " */
32
33 /* We load the key */
34 if (key)
35 {
36 *key_length= 0;
37
38 for (; isgraph(*string_ptr); string_ptr++)
39 {
40 *key= *string_ptr;
41 key++;
42 (*key_length)++;
43 }
44 }
45 else /* Skip characters */
46 for (; isgraph(*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; isdigit(*string_ptr); string_ptr++);
56 if (flags)
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; isdigit(*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 spaces */
74 if (*string_ptr == '\r')
75 {
76 /* Skip past the \r\n */
77 string_ptr+= 2;
78 }
79 else
80 {
81 string_ptr++;
82 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
83 if (cas)
84 *cas= (size_t)strtoll(next_ptr, &string_ptr, 10);
85 }
86
87 if (end_ptr < string_ptr)
88 goto read_error;
89
90 if (value_length)
91 {
92 size_t read_length;
93 size_t to_read;
94 char *value_ptr;
95
96 /* We add two bytes so that we can walk the \r\n */
97 rc= memcached_string_check(value, value_length+2);
98 if (rc != MEMCACHED_SUCCESS)
99 {
100 value_length= 0;
101 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
102 }
103
104 value_ptr= memcached_string_value(value);
105 read_length= 0;
106 /*
107 We read the \r\n into the string since not doing so is more
108 cycles then the waster of memory to do so.
109
110 We are null terminating through, which will most likely make
111 some people lazy about using the return length.
112 */
113 to_read= (value_length) + 2;
114
115 read_length= memcached_io_read(ptr, server_key,
116 value_ptr, to_read);
117
118 if (read_length != (size_t)(value_length + 2))
119 {
120 goto read_error;
121 }
122
123 /* This next bit blows the API, but this is internal....*/
124 {
125 char *char_ptr;
126 char_ptr= memcached_string_value(value);;
127 char_ptr[value_length]= 0;
128 char_ptr[value_length + 1]= 0;
129 memcached_string_set_length(value, value_length);
130 }
131
132 return MEMCACHED_SUCCESS;
133 }
134 }
135
136 return rc;
137
138 read_error:
139 return MEMCACHED_PARTIAL_READ;
140 }
141
142 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
143 size_t *value_length,
144 uint16_t *flags,
145 memcached_return *error)
146 {
147 memcached_string_st *result_buffer;
148 result_buffer= &ptr->result_buffer;
149
150 if (ptr->flags & MEM_NO_BLOCK)
151 memcached_io_preread(ptr);
152
153 while (ptr->cursor_server < ptr->number_of_hosts)
154 {
155 if (!ptr->hosts[ptr->cursor_server].cursor_active)
156 {
157 ptr->cursor_server++;
158 continue;
159 }
160
161 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
162 flags, NULL, ptr->cursor_server);
163 *value_length= memcached_string_length(result_buffer);
164
165 if (*error == MEMCACHED_END) /* END means that we move on to the next */
166 {
167 ptr->hosts[ptr->cursor_server].cursor_active= 0;
168 ptr->cursor_server++;
169 continue;
170 }
171 else if (*error == MEMCACHED_SUCCESS)
172 return memcached_string_c_copy(result_buffer);
173 else
174 return NULL;
175 }
176
177 ptr->cursor_server= 0;
178 *value_length= 0;
179 return NULL;
180 }
181
182 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
183 memcached_result_st *result,
184 memcached_return *error)
185 {
186 if (result == NULL)
187 result= memcached_result_create(ptr, NULL);
188
189 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
190
191 if (ptr->flags & MEM_NO_BLOCK)
192 memcached_io_preread(ptr);
193
194 while (ptr->cursor_server < ptr->number_of_hosts)
195 {
196 if (!ptr->hosts[ptr->cursor_server].cursor_active)
197 {
198 ptr->cursor_server++;
199 continue;
200 }
201
202 result->cas= 0; /* We do this so we do not send in any junk */
203 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
204 &result->value,
205 &result->flags,
206 &result->cas,
207 ptr->cursor_server);
208
209 if (*error == MEMCACHED_END) /* END means that we move on to the next */
210 {
211 ptr->hosts[ptr->cursor_server].cursor_active= 0;
212 ptr->cursor_server++;
213 continue;
214 }
215 else if (*error == MEMCACHED_SUCCESS)
216 return result;
217 else
218 return NULL;
219 }
220
221 /* We have completed reading data */
222 if (result->is_allocated == MEMCACHED_ALLOCATED)
223 memcached_result_free(result);
224 else
225 memcached_string_reset(&result->value);
226
227 ptr->cursor_server= 0;
228 return NULL;
229 }
230
231 memcached_return memcached_finish_server(memcached_st *ptr, unsigned int server_key)
232 {
233 memcached_return rc;
234 memcached_string_st *result_buffer;
235
236 result_buffer= &ptr->result_buffer;
237
238 rc= MEMCACHED_SUCCESS;
239 while (rc == MEMCACHED_SUCCESS)
240 {
241 rc= memcached_value_fetch(ptr, NULL, NULL, result_buffer,
242 NULL, NULL, server_key);
243 }
244 ptr->hosts[server_key].cursor_active= 0;
245
246 return rc;
247 }
248
249 void memcached_finish(memcached_st *ptr)
250 {
251 unsigned int x;
252
253 for (x= 0; x < ptr->number_of_hosts; x++)
254 {
255 if (ptr->hosts[x].cursor_active)
256 (void)memcached_finish_server(ptr, x);
257 }
258
259 ptr->cursor_server= 0;
260 }