Use poll() to determine next readable server
[awesomized/libmemcached] / libmemcached / memcached_fetch.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 memcached_return value_fetch(memcached_server_st *ptr,
5 char *buffer,
6 memcached_result_st *result)
7 {
8 memcached_return rc= MEMCACHED_SUCCESS;
9 char *string_ptr;
10 char *end_ptr;
11 char *next_ptr;
12 size_t value_length;
13 size_t read_length;
14 size_t to_read;
15 char *value_ptr;
16
17 if (ptr->root->flags & MEM_USE_UDP)
18 return MEMCACHED_NOT_SUPPORTED;
19
20 WATCHPOINT_ASSERT(ptr->root);
21 end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
22
23 memcached_result_reset(result);
24
25 string_ptr= buffer;
26 string_ptr+= 6; /* "VALUE " */
27
28
29 /* We load the key */
30 {
31 char *key;
32 size_t prefix_length;
33
34 key= result->key;
35 result->key_length= 0;
36
37 for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
38 {
39 if (prefix_length == 0)
40 {
41 *key= *string_ptr;
42 key++;
43 result->key_length++;
44 }
45 else
46 prefix_length--;
47 }
48 result->key[result->key_length]= 0;
49 }
50
51 if (end_ptr == string_ptr)
52 goto read_error;
53
54 /* Flags fetch move past space */
55 string_ptr++;
56 if (end_ptr == string_ptr)
57 goto read_error;
58 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
59 result->flags= strtoul(next_ptr, &string_ptr, 10);
60
61 if (end_ptr == string_ptr)
62 goto read_error;
63
64 /* Length fetch move past space*/
65 string_ptr++;
66 if (end_ptr == string_ptr)
67 goto read_error;
68
69 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
70 value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
71
72 if (end_ptr == string_ptr)
73 goto read_error;
74
75 /* Skip spaces */
76 if (*string_ptr == '\r')
77 {
78 /* Skip past the \r\n */
79 string_ptr+= 2;
80 }
81 else
82 {
83 string_ptr++;
84 for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
85 result->cas= strtoull(next_ptr, &string_ptr, 10);
86 }
87
88 if (end_ptr < string_ptr)
89 goto read_error;
90
91 /* We add two bytes so that we can walk the \r\n */
92 rc= memcached_string_check(&result->value, value_length+2);
93 if (rc != MEMCACHED_SUCCESS)
94 {
95 value_length= 0;
96 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
97 }
98
99 value_ptr= memcached_string_value(&result->value);
100 read_length= 0;
101 /*
102 We read the \r\n into the string since not doing so is more
103 cycles then the waster of memory to do so.
104
105 We are null terminating through, which will most likely make
106 some people lazy about using the return length.
107 */
108 to_read= (value_length) + 2;
109 read_length= memcached_io_read(ptr, value_ptr, to_read);
110 if (read_length != (size_t)(value_length + 2))
111 {
112 goto read_error;
113 }
114
115 /* This next bit blows the API, but this is internal....*/
116 {
117 char *char_ptr;
118 char_ptr= memcached_string_value(&result->value);;
119 char_ptr[value_length]= 0;
120 char_ptr[value_length + 1]= 0;
121 memcached_string_set_length(&result->value, value_length);
122 }
123
124 return MEMCACHED_SUCCESS;
125
126 read_error:
127 memcached_io_reset(ptr);
128
129 return MEMCACHED_PARTIAL_READ;
130 }
131
132 char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
133 size_t *value_length,
134 uint32_t *flags,
135 memcached_return *error)
136 {
137 memcached_result_st *result_buffer= &ptr->result;
138
139 if (ptr->flags & MEM_USE_UDP)
140 {
141 *error= MEMCACHED_NOT_SUPPORTED;
142 return NULL;
143 }
144
145 while (ptr->cursor_server < ptr->number_of_hosts)
146 {
147 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
148
149 if (memcached_server_response_count(&ptr->hosts[ptr->cursor_server]) == 0)
150 {
151 ptr->cursor_server++;
152 continue;
153 }
154
155 *error= memcached_response(&ptr->hosts[ptr->cursor_server], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, result_buffer);
156
157 if (*error == MEMCACHED_END) /* END means that we move on to the next */
158 {
159 memcached_server_response_reset(&ptr->hosts[ptr->cursor_server]);
160 ptr->cursor_server++;
161 continue;
162 }
163 else if (*error == MEMCACHED_SUCCESS)
164 {
165 *value_length= memcached_string_length(&result_buffer->value);
166
167 if (key)
168 {
169 strncpy(key, result_buffer->key, result_buffer->key_length);
170 *key_length= result_buffer->key_length;
171 }
172
173 if (result_buffer->flags)
174 *flags= result_buffer->flags;
175 else
176 *flags= 0;
177
178 return memcached_string_c_copy(&result_buffer->value);
179 }
180 else
181 {
182 *value_length= 0;
183 return NULL;
184 }
185 }
186
187 ptr->cursor_server= 0;
188 *value_length= 0;
189 return NULL;
190 }
191
192 memcached_result_st *memcached_fetch_result(memcached_st *ptr,
193 memcached_result_st *result,
194 memcached_return *error)
195 {
196 memcached_server_st *server;
197
198 if (ptr->flags & MEM_USE_UDP)
199 {
200 *error= MEMCACHED_NOT_SUPPORTED;
201 return NULL;
202 }
203
204 if (result == NULL)
205 if ((result= memcached_result_create(ptr, NULL)) == NULL)
206 return NULL;
207
208 while ((server = memcached_io_get_readable_server(ptr)) != NULL) {
209 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
210 *error= memcached_response(server, buffer, sizeof(buffer), result);
211
212 if (*error == MEMCACHED_SUCCESS)
213 return result;
214 else if (*error == MEMCACHED_END)
215 memcached_server_response_reset(server);
216 else
217 break;
218 }
219
220 /* We have completed reading data */
221 if (result->is_allocated)
222 memcached_result_free(result);
223 else
224 memcached_string_reset(&result->value);
225
226 return NULL;
227 }
228