a2f7716d485d3e190b694899ef8074a487229c92
[m6w6/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 uint8_t latch; /* We use latch to track the state of the original socket */
55
56 if (rc == MEMCACHED_BUFFERED)
57 {
58 latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
59 if (latch == 0)
60 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
61 }
62
63 rc= memcached_set(ptr, key, key_length,
64 memcached_result_value(&ptr->result),
65 memcached_result_length(&ptr->result),
66 0, memcached_result_flags(&ptr->result));
67
68 if (rc == MEMCACHED_BUFFERED && latch == 0)
69 memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
70
71 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
72 {
73 *error= rc;
74 *value_length= memcached_result_length(&ptr->result);
75 *flags= memcached_result_flags(&ptr->result);
76 return memcached_string_c_copy(&ptr->result.value);
77 }
78 }
79 }
80
81 return NULL;
82 }
83
84 (void)memcached_fetch(ptr, NULL, NULL,
85 &dummy_length, &dummy_flags,
86 &dummy_error);
87 WATCHPOINT_ASSERT(dummy_length == 0);
88
89 return value;
90 }
91
92 memcached_return memcached_mget(memcached_st *ptr,
93 char **keys, size_t *key_length,
94 unsigned int number_of_keys)
95 {
96 return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
97 }
98
99 memcached_return memcached_mget_by_key(memcached_st *ptr,
100 const char *master_key,
101 size_t master_key_length,
102 char **keys,
103 size_t *key_length,
104 unsigned int number_of_keys)
105 {
106 unsigned int x;
107 memcached_return rc= MEMCACHED_NOTFOUND;
108 char *get_command= "get ";
109 uint8_t get_command_length= 4;
110 unsigned int master_server_key= 0;
111
112 LIBMEMCACHED_MEMCACHED_MGET_START();
113 ptr->cursor_server= 0;
114
115 if (number_of_keys == 0)
116 return MEMCACHED_NOTFOUND;
117
118 if (ptr->number_of_hosts == 0)
119 return MEMCACHED_NO_SERVERS;
120
121 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
122 return MEMCACHED_BAD_KEY_PROVIDED;
123
124 if (ptr->flags & MEM_SUPPORT_CAS)
125 {
126 get_command= "gets ";
127 get_command_length= 5;
128 }
129
130 if (master_key && master_key_length)
131 master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
132
133 /*
134 Here is where we pay for the non-block API. We need to remove any data sitting
135 in the queue before we start our get.
136
137 It might be optimum to bounce the connection if count > some number.
138 */
139 for (x= 0; x < ptr->number_of_hosts; x++)
140 {
141 if (memcached_server_response_count(&ptr->hosts[x]))
142 {
143 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
144
145 if (ptr->flags & MEM_NO_BLOCK)
146 (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
147
148 while(memcached_server_response_count(&ptr->hosts[x]))
149 (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
150 }
151 }
152
153 /*
154 If a server fails we warn about errors and start all over with sending keys
155 to the server.
156 */
157 for (x= 0; x < number_of_keys; x++)
158 {
159 unsigned int server_key;
160
161 if (master_server_key)
162 server_key= master_server_key;
163 else
164 server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
165
166 if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
167 {
168 rc= memcached_connect(&ptr->hosts[server_key]);
169
170 if (rc != MEMCACHED_SUCCESS)
171 continue;
172
173 if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
174 {
175 rc= MEMCACHED_SOME_ERRORS;
176 continue;
177 }
178 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
179 memcached_server_response_increment(&ptr->hosts[server_key]);
180 WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
181 }
182
183 if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
184 {
185 memcached_server_response_reset(&ptr->hosts[server_key]);
186 rc= MEMCACHED_SOME_ERRORS;
187 continue;
188 }
189
190 if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
191 {
192 memcached_server_response_reset(&ptr->hosts[server_key]);
193 rc= MEMCACHED_SOME_ERRORS;
194 continue;
195 }
196 }
197
198 /*
199 Should we muddle on if some servers are dead?
200 */
201 for (x= 0; x < ptr->number_of_hosts; x++)
202 {
203 if (memcached_server_response_count(&ptr->hosts[x]))
204 {
205 /* We need to do something about non-connnected hosts in the future */
206 if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
207 {
208 rc= MEMCACHED_SOME_ERRORS;
209 }
210 }
211 }
212
213 LIBMEMCACHED_MEMCACHED_MGET_END();
214 return rc;
215 }