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