Refactored call, removed abort() call (we should never cause the parent
[awesomized/libmemcached] / libmemcached / memcached_storage.c
1 /*
2 Memcached library
3
4 memcached_set()
5 memcached_replace()
6 memcached_add()
7
8 */
9 #include "common.h"
10 #include "memcached_io.h"
11
12 typedef enum {
13 SET_OP,
14 REPLACE_OP,
15 ADD_OP,
16 PREPEND_OP,
17 APPEND_OP,
18 CAS_OP,
19 } memcached_storage_action;
20
21 /* Inline this */
22 static char *storage_op_string(memcached_storage_action verb)
23 {
24 switch (verb)
25 {
26 case SET_OP:
27 return "set";
28 case REPLACE_OP:
29 return "replace";
30 case ADD_OP:
31 return "add";
32 case PREPEND_OP:
33 return "prepend";
34 case APPEND_OP:
35 return "append";
36 case CAS_OP:
37 return "cas";
38 default:
39 return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */
40 };
41
42 return SET_OP;
43 }
44
45 static memcached_return memcached_send_binary(memcached_server_st* server,
46 const char *key,
47 size_t key_length,
48 const char *value,
49 size_t value_length,
50 time_t expiration,
51 uint32_t flags,
52 uint64_t cas,
53 memcached_storage_action verb);
54
55 static inline memcached_return memcached_send(memcached_st *ptr,
56 const char *master_key, size_t master_key_length,
57 const char *key, size_t key_length,
58 const char *value, size_t value_length,
59 time_t expiration,
60 uint32_t flags,
61 uint64_t cas,
62 memcached_storage_action verb)
63 {
64 char to_write;
65 size_t write_length;
66 ssize_t sent_length;
67 memcached_return rc;
68 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
69 unsigned int server_key;
70
71 WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
72
73 unlikely (key_length == 0)
74 return MEMCACHED_NO_KEY_PROVIDED;
75
76 unlikely (ptr->number_of_hosts == 0)
77 return MEMCACHED_NO_SERVERS;
78
79 if ((ptr->flags & MEM_VERIFY_KEY) && (memcachd_key_test((char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
80 return MEMCACHED_BAD_KEY_PROVIDED;
81
82 server_key= memcached_generate_hash(ptr, master_key, master_key_length);
83
84 if (ptr->flags & MEM_BINARY_PROTOCOL)
85 return memcached_send_binary(&ptr->hosts[server_key], key, key_length,
86 value, value_length, expiration,
87 flags, cas, verb);
88
89 if (cas)
90 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
91 "%s %s%.*s %u %llu %zu %llu\r\n", storage_op_string(verb),
92 ptr->prefix_key,
93 (int)key_length, key, flags,
94 (unsigned long long)expiration, value_length,
95 (unsigned long long)cas);
96 else
97 write_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
98 "%s %s%.*s %u %llu %zu\r\n", storage_op_string(verb),
99 ptr->prefix_key,
100 (int)key_length, key, flags,
101 (unsigned long long)expiration, value_length);
102
103 if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
104 {
105 rc= MEMCACHED_WRITE_FAILURE;
106 goto error;
107 }
108
109 rc= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
110 if (rc != MEMCACHED_SUCCESS)
111 goto error;
112
113 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
114 {
115 rc= MEMCACHED_WRITE_FAILURE;
116 goto error;
117 }
118
119 if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
120 to_write= 0;
121 else
122 to_write= 1;
123
124 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
125 {
126 rc= MEMCACHED_WRITE_FAILURE;
127 goto error;
128 }
129
130 if (to_write == 0)
131 return MEMCACHED_BUFFERED;
132
133 rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
134
135 if (rc == MEMCACHED_STORED)
136 return MEMCACHED_SUCCESS;
137 else
138 return rc;
139
140 error:
141 memcached_io_reset(&ptr->hosts[server_key]);
142
143 return rc;
144 }
145
146
147 memcached_return memcached_set(memcached_st *ptr, const char *key, size_t key_length,
148 const char *value, size_t value_length,
149 time_t expiration,
150 uint32_t flags)
151 {
152 memcached_return rc;
153 LIBMEMCACHED_MEMCACHED_SET_START();
154 rc= memcached_send(ptr, key, key_length,
155 key, key_length, value, value_length,
156 expiration, flags, 0, SET_OP);
157 LIBMEMCACHED_MEMCACHED_SET_END();
158 return rc;
159 }
160
161 memcached_return memcached_add(memcached_st *ptr,
162 const char *key, size_t key_length,
163 const char *value, size_t value_length,
164 time_t expiration,
165 uint32_t flags)
166 {
167 memcached_return rc;
168 LIBMEMCACHED_MEMCACHED_ADD_START();
169 rc= memcached_send(ptr, key, key_length,
170 key, key_length, value, value_length,
171 expiration, flags, 0, ADD_OP);
172 LIBMEMCACHED_MEMCACHED_ADD_END();
173 return rc;
174 }
175
176 memcached_return memcached_replace(memcached_st *ptr,
177 const char *key, size_t key_length,
178 const char *value, size_t value_length,
179 time_t expiration,
180 uint32_t flags)
181 {
182 memcached_return rc;
183 LIBMEMCACHED_MEMCACHED_REPLACE_START();
184 rc= memcached_send(ptr, key, key_length,
185 key, key_length, value, value_length,
186 expiration, flags, 0, REPLACE_OP);
187 LIBMEMCACHED_MEMCACHED_REPLACE_END();
188 return rc;
189 }
190
191 memcached_return memcached_prepend(memcached_st *ptr,
192 const char *key, size_t key_length,
193 const char *value, size_t value_length,
194 time_t expiration,
195 uint32_t flags)
196 {
197 memcached_return rc;
198 rc= memcached_send(ptr, key, key_length,
199 key, key_length, value, value_length,
200 expiration, flags, 0, PREPEND_OP);
201 return rc;
202 }
203
204 memcached_return memcached_append(memcached_st *ptr,
205 const char *key, size_t key_length,
206 const char *value, size_t value_length,
207 time_t expiration,
208 uint32_t flags)
209 {
210 memcached_return rc;
211 rc= memcached_send(ptr, key, key_length,
212 key, key_length, value, value_length,
213 expiration, flags, 0, APPEND_OP);
214 return rc;
215 }
216
217 memcached_return memcached_cas(memcached_st *ptr,
218 const char *key, size_t key_length,
219 const char *value, size_t value_length,
220 time_t expiration,
221 uint32_t flags,
222 uint64_t cas)
223 {
224 memcached_return rc;
225 rc= memcached_send(ptr, key, key_length,
226 key, key_length, value, value_length,
227 expiration, flags, cas, CAS_OP);
228 return rc;
229 }
230
231 memcached_return memcached_set_by_key(memcached_st *ptr,
232 const char *master_key __attribute__((unused)),
233 size_t master_key_length __attribute__((unused)),
234 const char *key, size_t key_length,
235 const char *value, size_t value_length,
236 time_t expiration,
237 uint32_t flags)
238 {
239 memcached_return rc;
240 LIBMEMCACHED_MEMCACHED_SET_START();
241 rc= memcached_send(ptr, master_key, master_key_length,
242 key, key_length, value, value_length,
243 expiration, flags, 0, SET_OP);
244 LIBMEMCACHED_MEMCACHED_SET_END();
245 return rc;
246 }
247
248 memcached_return memcached_add_by_key(memcached_st *ptr,
249 const char *master_key, size_t master_key_length,
250 const char *key, size_t key_length,
251 const char *value, size_t value_length,
252 time_t expiration,
253 uint32_t flags)
254 {
255 memcached_return rc;
256 LIBMEMCACHED_MEMCACHED_ADD_START();
257 rc= memcached_send(ptr, master_key, master_key_length,
258 key, key_length, value, value_length,
259 expiration, flags, 0, ADD_OP);
260 LIBMEMCACHED_MEMCACHED_ADD_END();
261 return rc;
262 }
263
264 memcached_return memcached_replace_by_key(memcached_st *ptr,
265 const char *master_key, size_t master_key_length,
266 const char *key, size_t key_length,
267 const char *value, size_t value_length,
268 time_t expiration,
269 uint32_t flags)
270 {
271 memcached_return rc;
272 LIBMEMCACHED_MEMCACHED_REPLACE_START();
273 rc= memcached_send(ptr, master_key, master_key_length,
274 key, key_length, value, value_length,
275 expiration, flags, 0, REPLACE_OP);
276 LIBMEMCACHED_MEMCACHED_REPLACE_END();
277 return rc;
278 }
279
280 memcached_return memcached_prepend_by_key(memcached_st *ptr,
281 const char *master_key, size_t master_key_length,
282 const char *key, size_t key_length,
283 const char *value, size_t value_length,
284 time_t expiration,
285 uint32_t flags)
286 {
287 memcached_return rc;
288 rc= memcached_send(ptr, master_key, master_key_length,
289 key, key_length, value, value_length,
290 expiration, flags, 0, PREPEND_OP);
291 return rc;
292 }
293
294 memcached_return memcached_append_by_key(memcached_st *ptr,
295 const char *master_key, size_t master_key_length,
296 const char *key, size_t key_length,
297 const char *value, size_t value_length,
298 time_t expiration,
299 uint32_t flags)
300 {
301 memcached_return rc;
302 rc= memcached_send(ptr, master_key, master_key_length,
303 key, key_length, value, value_length,
304 expiration, flags, 0, APPEND_OP);
305 return rc;
306 }
307
308 memcached_return memcached_cas_by_key(memcached_st *ptr,
309 const char *master_key, size_t master_key_length,
310 const char *key, size_t key_length,
311 const char *value, size_t value_length,
312 time_t expiration,
313 uint32_t flags,
314 uint64_t cas)
315 {
316 memcached_return rc;
317 rc= memcached_send(ptr, master_key, master_key_length,
318 key, key_length, value, value_length,
319 expiration, flags, cas, CAS_OP);
320 return rc;
321 }
322
323 static memcached_return memcached_send_binary(memcached_server_st* server,
324 const char *key,
325 size_t key_length,
326 const char *value,
327 size_t value_length,
328 time_t expiration,
329 uint32_t flags,
330 uint64_t cas,
331 memcached_storage_action verb)
332 {
333 char flush;
334 protocol_binary_request_set request= {.bytes= {0}};
335 size_t send_length= sizeof(request.bytes);
336
337 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
338 switch (verb)
339 {
340 case SET_OP:
341 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
342 break;
343 case ADD_OP:
344 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_ADD;
345 break;
346 case REPLACE_OP:
347 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_REPLACE;
348 break;
349 case APPEND_OP:
350 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_APPEND;
351 break;
352 case PREPEND_OP:
353 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_PREPEND;
354 break;
355 case CAS_OP:
356 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_REPLACE;
357 break;
358 }
359
360 request.message.header.request.keylen= htons((uint16_t)key_length);
361 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
362 if (verb == APPEND_OP || verb == PREPEND_OP)
363 send_length -= 8; /* append & prepend does not contain extras! */
364 else
365 {
366 request.message.header.request.extlen= 8;
367 request.message.body.flags= htonl(flags);
368 request.message.body.expiration= htonl((uint32_t)expiration);
369 }
370
371 request.message.header.request.bodylen= htonl(key_length + value_length +
372 request.message.header.request.extlen);
373
374 if (cas)
375 request.message.header.request.cas= htonll(cas);
376
377 flush= ((server->root->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP) ? 0 : 1;
378 /* write the header */
379 if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
380 (memcached_io_write(server, key, key_length, 0) == -1) ||
381 (memcached_io_write(server, value, value_length, flush) == -1))
382 {
383 memcached_io_reset(server);
384 return MEMCACHED_WRITE_FAILURE;
385 }
386
387 if (flush == 0)
388 return MEMCACHED_BUFFERED;
389
390 return memcached_response(server, NULL, 0, NULL);
391 }
392