Simple fix in stats.
[awesomized/libmemcached] / libmemcached / memcached_get.c
1 #include "common.h"
2 #include "memcached_io.h"
3
4 /*
5 What happens if no servers exist?
6 */
7 char *memcached_get(memcached_st *ptr, const char *key,
8 size_t key_length,
9 size_t *value_length,
10 uint32_t *flags,
11 memcached_return *error)
12 {
13 return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
14 flags, error);
15 }
16
17 char *memcached_get_by_key(memcached_st *ptr,
18 const char *master_key,
19 size_t master_key_length,
20 const char *key, size_t key_length,
21 size_t *value_length,
22 uint32_t *flags,
23 memcached_return *error)
24 {
25 char *value;
26 size_t dummy_length;
27 uint32_t dummy_flags;
28 memcached_return dummy_error;
29
30 /* Request the key */
31 *error= memcached_mget_by_key(ptr,
32 master_key,
33 master_key_length,
34 (char **)&key, &key_length, 1);
35
36 value= memcached_fetch(ptr, NULL, NULL,
37 value_length, flags, error);
38 /* This is for historical reasons */
39 if (*error == MEMCACHED_END)
40 *error= MEMCACHED_NOTFOUND;
41
42 if (value == NULL)
43 {
44 if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
45 {
46 memcached_return rc;
47
48 memcached_result_reset(&ptr->result);
49 rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
50
51 /* On all failure drop to returning NULL */
52 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
53 {
54 if (rc == MEMCACHED_BUFFERED)
55 {
56 uint8_t latch; /* We use latch to track the state of the original socket */
57 latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
58 if (latch == 0)
59 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
60
61 rc= memcached_set(ptr, key, key_length,
62 memcached_result_value(&ptr->result),
63 memcached_result_length(&ptr->result),
64 0, memcached_result_flags(&ptr->result));
65
66 if (rc == MEMCACHED_BUFFERED && latch == 0)
67 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
68 }
69 else
70 {
71 rc= memcached_set(ptr, key, key_length,
72 memcached_result_value(&ptr->result),
73 memcached_result_length(&ptr->result),
74 0, memcached_result_flags(&ptr->result));
75 }
76
77 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
78 {
79 *error= rc;
80 *value_length= memcached_result_length(&ptr->result);
81 *flags= memcached_result_flags(&ptr->result);
82 return memcached_string_c_copy(&ptr->result.value);
83 }
84 }
85 }
86
87 return NULL;
88 }
89
90 (void)memcached_fetch(ptr, NULL, NULL,
91 &dummy_length, &dummy_flags,
92 &dummy_error);
93 WATCHPOINT_ASSERT(dummy_length == 0);
94
95 return value;
96 }
97
98 memcached_return memcached_mget(memcached_st *ptr,
99 char **keys, size_t *key_length,
100 unsigned int number_of_keys)
101 {
102 return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
103 }
104
105 memcached_return memcached_mget_by_key(memcached_st *ptr,
106 const char *master_key,
107 size_t master_key_length,
108 char **keys,
109 size_t *key_length,
110 unsigned int number_of_keys)
111 {
112 unsigned int x;
113 memcached_return rc= MEMCACHED_NOTFOUND;
114 char *get_command= "get ";
115 uint8_t get_command_length= 4;
116 unsigned int master_server_key= 0;
117
118 LIBMEMCACHED_MEMCACHED_MGET_START();
119 ptr->cursor_server= 0;
120
121 if (number_of_keys == 0)
122 return MEMCACHED_NOTFOUND;
123
124 if (ptr->number_of_hosts == 0)
125 return MEMCACHED_NO_SERVERS;
126
127 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
128 return MEMCACHED_BAD_KEY_PROVIDED;
129
130 if (ptr->flags & MEM_SUPPORT_CAS)
131 {
132 get_command= "gets ";
133 get_command_length= 5;
134 }
135
136 if (master_key && master_key_length)
137 master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
138
139 /*
140 Here is where we pay for the non-block API. We need to remove any data sitting
141 in the queue before we start our get.
142
143 It might be optimum to bounce the connection if count > some number.
144 */
145 for (x= 0; x < ptr->number_of_hosts; x++)
146 {
147 if (memcached_server_response_count(&ptr->hosts[x]))
148 {
149 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
150
151 if (ptr->flags & MEM_NO_BLOCK)
152 (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
153
154 while(memcached_server_response_count(&ptr->hosts[x]))
155 (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
156 }
157 }
158
159 /*
160 If a server fails we warn about errors and start all over with sending keys
161 to the server.
162 */
163 for (x= 0; x < number_of_keys; x++)
164 {
165 unsigned int server_key;
166
167 if (master_server_key)
168 server_key= master_server_key;
169 else
170 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
171
172 if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
173 {
174 rc= memcached_connect(&ptr->hosts[server_key]);
175
176 if (rc != MEMCACHED_SUCCESS)
177 continue;
178
179 if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
180 {
181 rc= MEMCACHED_SOME_ERRORS;
182 continue;
183 }
184 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
185 memcached_server_response_increment(&ptr->hosts[server_key]);
186 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
187 }
188
189 /* Only called when we have a prefix key */
190 if (ptr->prefix_key[0] != 0)
191 {
192 if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
193 {
194 memcached_server_response_reset(&ptr->hosts[server_key]);
195 rc= MEMCACHED_SOME_ERRORS;
196 continue;
197 }
198 }
199
200 if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
201 {
202 memcached_server_response_reset(&ptr->hosts[server_key]);
203 rc= MEMCACHED_SOME_ERRORS;
204 continue;
205 }
206
207 if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
208 {
209 memcached_server_response_reset(&ptr->hosts[server_key]);
210 rc= MEMCACHED_SOME_ERRORS;
211 continue;
212 }
213 }
214
215 /*
216 Should we muddle on if some servers are dead?
217 */
218 for (x= 0; x < ptr->number_of_hosts; x++)
219 {
220 if (memcached_server_response_count(&ptr->hosts[x]))
221 {
222 /* We need to do something about non-connnected hosts in the future */
223 if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
224 {
225 rc= MEMCACHED_SOME_ERRORS;
226 }
227 }
228 }
229
230 LIBMEMCACHED_MEMCACHED_MGET_END();
231 return rc;
232 }