Fix from Charles Aylward for reuse of buffer.
[m6w6/libmemcached] / lib / memcached_storage.c
1 /*
2 Memcached library
3
4 memcached_set()
5 memcached_replace()
6 memcached_add()
7
8 */
9
10 #include "common.h"
11 #include "memcached_io.h"
12
13 typedef enum {
14 SET_OP,
15 REPLACE_OP,
16 ADD_OP,
17 PREPEND_OP,
18 APPEND_OP,
19 CAS_OP,
20 } memcached_storage_action;
21
22 /* Inline this */
23 static char *storage_op_string(memcached_storage_action verb)
24 {
25 switch (verb)
26 {
27 case SET_OP:
28 return "set";
29 case REPLACE_OP:
30 return "replace";
31 case ADD_OP:
32 return "add";
33 case PREPEND_OP:
34 return "prepend";
35 case APPEND_OP:
36 return "append";
37 case CAS_OP:
38 return "cas";
39 };
40
41 return SET_OP;
42 }
43
44 static inline memcached_return memcached_send(memcached_st *ptr,
45 char *master_key, size_t master_key_length,
46 char *key, size_t key_length,
47 char *value, size_t value_length,
48 time_t expiration,
49 uint32_t flags,
50 uint64_t cas,
51 memcached_storage_action verb)
52 {
53 char to_write;
54 size_t write_length;
55 ssize_t sent_length;
56 memcached_return rc[MEMCACHED_MAX_REPLICAS];
57 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
58 unsigned int server_key;
59 uint8_t replicas= 0;
60
61 unlikely (key_length == 0)
62 return MEMCACHED_NO_KEY_PROVIDED;
63
64 unlikely (ptr->number_of_hosts == 0)
65 return MEMCACHED_NO_SERVERS;
66
67 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test(&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
68 return MEMCACHED_BAD_KEY_PROVIDED;
69
70 server_key= memcached_generate_hash(ptr, master_key, master_key_length);
71
72 if (cas)
73 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
74 "%s %.*s %u %llu %zu %llu\r\n", storage_op_string(verb),
75 (int)key_length, key, flags,
76 (unsigned long long)expiration, value_length,
77 (unsigned long long)cas);
78 else
79 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
80 "%s %.*s %u %llu %zu\r\n", storage_op_string(verb),
81 (int)key_length, key, flags,
82 (unsigned long long)expiration, value_length);
83
84 if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
85 return MEMCACHED_WRITE_FAILURE;
86
87 if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
88 to_write= 0;
89 else
90 to_write= 1;
91
92 do
93 {
94 char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
95
96 rc[replicas]= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
97
98 if (rc[replicas] != MEMCACHED_SUCCESS)
99 goto error;
100
101 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
102 {
103 rc[replicas]= MEMCACHED_WRITE_FAILURE;
104 goto error;
105 }
106
107 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
108 {
109 rc[replicas]= MEMCACHED_WRITE_FAILURE;
110 goto error;
111 }
112
113 if (to_write == 0)
114 return MEMCACHED_BUFFERED;
115 else
116 rc[replicas]= memcached_response(&ptr->hosts[server_key],
117 response_buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
118
119 /* On error we just jump to the next potential server */
120 error:
121 if (replicas > 1 && ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT)
122 {
123 if (server_key == (ptr->number_of_hosts - 1))
124 server_key= 0;
125 else
126 server_key++;
127 }
128 } while ((++replicas) < ptr->number_of_replicas);
129
130 /* As long as one object gets stored, we count this as a success */
131 while (replicas--)
132 {
133 if (rc[replicas] == MEMCACHED_STORED)
134 return MEMCACHED_SUCCESS;
135 }
136
137 return rc[0];
138 }
139
140 memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length,
141 char *value, size_t value_length,
142 time_t expiration,
143 uint32_t flags)
144 {
145 memcached_return rc;
146 LIBMEMCACHED_MEMCACHED_SET_START();
147 rc= memcached_send(ptr, key, key_length,
148 key, key_length, value, value_length,
149 expiration, flags, 0, SET_OP);
150 LIBMEMCACHED_MEMCACHED_SET_END();
151 return rc;
152 }
153
154 memcached_return memcached_add(memcached_st *ptr,
155 char *key, size_t key_length,
156 char *value, size_t value_length,
157 time_t expiration,
158 uint32_t flags)
159 {
160 memcached_return rc;
161 LIBMEMCACHED_MEMCACHED_ADD_START();
162 rc= memcached_send(ptr, key, key_length,
163 key, key_length, value, value_length,
164 expiration, flags, 0, ADD_OP);
165 LIBMEMCACHED_MEMCACHED_ADD_END();
166 return rc;
167 }
168
169 memcached_return memcached_replace(memcached_st *ptr,
170 char *key, size_t key_length,
171 char *value, size_t value_length,
172 time_t expiration,
173 uint32_t flags)
174 {
175 memcached_return rc;
176 LIBMEMCACHED_MEMCACHED_REPLACE_START();
177 rc= memcached_send(ptr, key, key_length,
178 key, key_length, value, value_length,
179 expiration, flags, 0, REPLACE_OP);
180 LIBMEMCACHED_MEMCACHED_REPLACE_END();
181 return rc;
182 }
183
184 memcached_return memcached_prepend(memcached_st *ptr,
185 char *key, size_t key_length,
186 char *value, size_t value_length,
187 time_t expiration,
188 uint32_t flags)
189 {
190 memcached_return rc;
191 rc= memcached_send(ptr, key, key_length,
192 key, key_length, value, value_length,
193 expiration, flags, 0, PREPEND_OP);
194 return rc;
195 }
196
197 memcached_return memcached_append(memcached_st *ptr,
198 char *key, size_t key_length,
199 char *value, size_t value_length,
200 time_t expiration,
201 uint32_t flags)
202 {
203 memcached_return rc;
204 rc= memcached_send(ptr, key, key_length,
205 key, key_length, value, value_length,
206 expiration, flags, 0, APPEND_OP);
207 return rc;
208 }
209
210 memcached_return memcached_cas(memcached_st *ptr,
211 char *key, size_t key_length,
212 char *value, size_t value_length,
213 time_t expiration,
214 uint32_t flags,
215 uint64_t cas)
216 {
217 memcached_return rc;
218 rc= memcached_send(ptr, key, key_length,
219 key, key_length, value, value_length,
220 expiration, flags, cas, CAS_OP);
221 return rc;
222 }
223
224 memcached_return memcached_set_by_key(memcached_st *ptr,
225 char *master_key, size_t master_key_length,
226 char *key, size_t key_length,
227 char *value, size_t value_length,
228 time_t expiration,
229 uint32_t flags)
230 {
231 memcached_return rc;
232 LIBMEMCACHED_MEMCACHED_SET_START();
233 rc= memcached_send(ptr, key, key_length,
234 key, key_length, value, value_length,
235 expiration, flags, 0, SET_OP);
236 LIBMEMCACHED_MEMCACHED_SET_END();
237 return rc;
238 }
239
240 memcached_return memcached_add_by_key(memcached_st *ptr,
241 char *master_key, size_t master_key_length,
242 char *key, size_t key_length,
243 char *value, size_t value_length,
244 time_t expiration,
245 uint32_t flags)
246 {
247 memcached_return rc;
248 LIBMEMCACHED_MEMCACHED_ADD_START();
249 rc= memcached_send(ptr, key, key_length,
250 key, key_length, value, value_length,
251 expiration, flags, 0, ADD_OP);
252 LIBMEMCACHED_MEMCACHED_ADD_END();
253 return rc;
254 }
255
256 memcached_return memcached_replace_by_key(memcached_st *ptr,
257 char *master_key, size_t master_key_length,
258 char *key, size_t key_length,
259 char *value, size_t value_length,
260 time_t expiration,
261 uint32_t flags)
262 {
263 memcached_return rc;
264 LIBMEMCACHED_MEMCACHED_REPLACE_START();
265 rc= memcached_send(ptr, key, key_length,
266 key, key_length, value, value_length,
267 expiration, flags, 0, REPLACE_OP);
268 LIBMEMCACHED_MEMCACHED_REPLACE_END();
269 return rc;
270 }
271
272 memcached_return memcached_prepend_by_key(memcached_st *ptr,
273 char *master_key, size_t master_key_length,
274 char *key, size_t key_length,
275 char *value, size_t value_length,
276 time_t expiration,
277 uint32_t flags)
278 {
279 memcached_return rc;
280 rc= memcached_send(ptr, key, key_length,
281 key, key_length, value, value_length,
282 expiration, flags, 0, PREPEND_OP);
283 return rc;
284 }
285
286 memcached_return memcached_append_by_key(memcached_st *ptr,
287 char *master_key, size_t master_key_length,
288 char *key, size_t key_length,
289 char *value, size_t value_length,
290 time_t expiration,
291 uint32_t flags)
292 {
293 memcached_return rc;
294 rc= memcached_send(ptr, key, key_length,
295 key, key_length, value, value_length,
296 expiration, flags, 0, APPEND_OP);
297 return rc;
298 }
299
300 memcached_return memcached_cas_by_key(memcached_st *ptr,
301 char *master_key, size_t master_key_length,
302 char *key, size_t key_length,
303 char *value, size_t value_length,
304 time_t expiration,
305 uint32_t flags,
306 uint64_t cas)
307 {
308 memcached_return rc;
309 rc= memcached_send(ptr, key, key_length,
310 key, key_length, value, value_length,
311 expiration, flags, cas, CAS_OP);
312 return rc;
313 }