Fix for minor rewrite in clone method of number of hosts.
[m6w6/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 (; isalnum(*string_ptr); string_ptr++)
39 {
40 *key= *string_ptr;
41 key++;
42 (*key_length)++;
43 }
44 }
45 else /* Skip characters */
46 for (; isalnum(*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 while (ptr->cursor_server < ptr->number_of_hosts)
151 {
152 if (!ptr->hosts[ptr->cursor_server].cursor_active)
153 {
154 ptr->cursor_server++;
155 continue;
156 }
157
158 *error = memcached_value_fetch(ptr, key, key_length, result_buffer,
159 flags, NULL, ptr->cursor_server);
160 *value_length= memcached_string_length(result_buffer);
161
162 if (*error == MEMCACHED_END) /* END means that we move on to the next */
163 {
164 ptr->hosts[ptr->cursor_server].cursor_active= 0;
165 ptr->cursor_server++;
166 continue;
167 }
168 else if (*error == MEMCACHED_SUCCESS)
169 return memcached_string_c_copy(result_buffer);
170 else
171 return NULL;
172 }
173
174 ptr->cursor_server= 0;
175 *value_length= 0;
176 return NULL;
177 }
178
179 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
180 memcached_result_st *result,
181 memcached_return *error)
182 {
183 if (result == NULL)
184 result= memcached_result_create(ptr, NULL);
185
186 WATCHPOINT_ASSERT(result->value.is_allocated != MEMCACHED_USED);
187
188 while (ptr->cursor_server < ptr->number_of_hosts)
189 {
190 if (!ptr->hosts[ptr->cursor_server].cursor_active)
191 {
192 ptr->cursor_server++;
193 continue;
194 }
195
196 result->cas= 0; /* We do this so we do not send in any junk */
197 *error= memcached_value_fetch(ptr, result->key, &result->key_length,
198 &result->value,
199 &result->flags,
200 &result->cas,
201 ptr->cursor_server);
202
203 if (*error == MEMCACHED_END) /* END means that we move on to the next */
204 {
205 ptr->hosts[ptr->cursor_server].cursor_active= 0;
206 ptr->cursor_server++;
207 continue;
208 }
209 else if (*error == MEMCACHED_SUCCESS)
210 return result;
211 else
212 return NULL;
213 }
214
215 /* We have completed reading data */
216 if (result->is_allocated == MEMCACHED_ALLOCATED)
217 memcached_result_free(result);
218 else
219 memcached_string_reset(&result->value);
220
221 ptr->cursor_server= 0;
222 return NULL;
223 }
224
225 memcached_return memcached_finish_server(memcached_st *ptr, unsigned int server_key)
226 {
227 memcached_return rc;
228 memcached_string_st *result_buffer;
229
230 result_buffer= &ptr->result_buffer;
231
232 rc= MEMCACHED_SUCCESS;
233 while (rc == MEMCACHED_SUCCESS)
234 {
235 rc= memcached_value_fetch(ptr, NULL, NULL, result_buffer,
236 NULL, NULL, server_key);
237 }
238 ptr->hosts[server_key].cursor_active= 0;
239
240 return rc;
241 }
242
243 void memcached_finish(memcached_st *ptr)
244 {
245 unsigned int x;
246
247 for (x= 0; x < ptr->number_of_hosts; x++)
248 {
249 if (ptr->hosts[x].cursor_active)
250 (void)memcached_finish_server(ptr, x);
251 }
252
253 ptr->cursor_server= 0;
254 }