Fix for bad key on master
[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 {
138 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test((char **)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
139 return MEMCACHED_BAD_KEY_PROVIDED;
140 master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
141 }
142
143 /*
144 Here is where we pay for the non-block API. We need to remove any data sitting
145 in the queue before we start our get.
146
147 It might be optimum to bounce the connection if count > some number.
148 */
149 for (x= 0; x < ptr->number_of_hosts; x++)
150 {
151 if (memcached_server_response_count(&ptr->hosts[x]))
152 {
153 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
154
155 if (ptr->flags & MEM_NO_BLOCK)
156 (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
157
158 while(memcached_server_response_count(&ptr->hosts[x]))
159 (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
160 }
161 }
162
163 /*
164 If a server fails we warn about errors and start all over with sending keys
165 to the server.
166 */
167 for (x= 0; x < number_of_keys; x++)
168 {
169 unsigned int server_key;
170
171 if (master_server_key)
172 server_key= master_server_key;
173 else
174 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
175
176 if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
177 {
178 rc= memcached_connect(&ptr->hosts[server_key]);
179
180 if (rc != MEMCACHED_SUCCESS)
181 continue;
182
183 if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
184 {
185 rc= MEMCACHED_SOME_ERRORS;
186 continue;
187 }
188 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
189 memcached_server_response_increment(&ptr->hosts[server_key]);
190 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
191 }
192
193 /* Only called when we have a prefix key */
194 if (ptr->prefix_key[0] != 0)
195 {
196 if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
197 {
198 memcached_server_response_reset(&ptr->hosts[server_key]);
199 rc= MEMCACHED_SOME_ERRORS;
200 continue;
201 }
202 }
203
204 if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
205 {
206 memcached_server_response_reset(&ptr->hosts[server_key]);
207 rc= MEMCACHED_SOME_ERRORS;
208 continue;
209 }
210
211 if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
212 {
213 memcached_server_response_reset(&ptr->hosts[server_key]);
214 rc= MEMCACHED_SOME_ERRORS;
215 continue;
216 }
217 }
218
219 /*
220 Should we muddle on if some servers are dead?
221 */
222 for (x= 0; x < ptr->number_of_hosts; x++)
223 {
224 if (memcached_server_response_count(&ptr->hosts[x]))
225 {
226 /* We need to do something about non-connnected hosts in the future */
227 if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
228 {
229 rc= MEMCACHED_SOME_ERRORS;
230 }
231 }
232 }
233
234 LIBMEMCACHED_MEMCACHED_MGET_END();
235 return rc;
236 }