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