770b27d4006a2a46137f89501b642750bce4643e
[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 /* Send command header */
110 rc= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
111 if (rc != MEMCACHED_SUCCESS)
112 goto error;
113
114 /* Send command body */
115 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
116 {
117 rc= MEMCACHED_WRITE_FAILURE;
118 goto error;
119 }
120
121 if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
122 to_write= 0;
123 else
124 to_write= 1;
125
126 if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
127 {
128 rc= MEMCACHED_WRITE_FAILURE;
129 goto error;
130 }
131
132 if (to_write == 0)
133 return MEMCACHED_BUFFERED;
134
135 rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
136
137 if (rc == MEMCACHED_STORED)
138 return MEMCACHED_SUCCESS;
139 else
140 return rc;
141
142 error:
143 memcached_io_reset(&ptr->hosts[server_key]);
144
145 return rc;
146 }
147
148
149 memcached_return memcached_set(memcached_st *ptr, const char *key, size_t key_length,
150 const char *value, size_t value_length,
151 time_t expiration,
152 uint32_t flags)
153 {
154 memcached_return rc;
155 LIBMEMCACHED_MEMCACHED_SET_START();
156 rc= memcached_send(ptr, key, key_length,
157 key, key_length, value, value_length,
158 expiration, flags, 0, SET_OP);
159 LIBMEMCACHED_MEMCACHED_SET_END();
160 return rc;
161 }
162
163 memcached_return memcached_add(memcached_st *ptr,
164 const char *key, size_t key_length,
165 const char *value, size_t value_length,
166 time_t expiration,
167 uint32_t flags)
168 {
169 memcached_return rc;
170 LIBMEMCACHED_MEMCACHED_ADD_START();
171 rc= memcached_send(ptr, key, key_length,
172 key, key_length, value, value_length,
173 expiration, flags, 0, ADD_OP);
174 LIBMEMCACHED_MEMCACHED_ADD_END();
175 return rc;
176 }
177
178 memcached_return memcached_replace(memcached_st *ptr,
179 const char *key, size_t key_length,
180 const char *value, size_t value_length,
181 time_t expiration,
182 uint32_t flags)
183 {
184 memcached_return rc;
185 LIBMEMCACHED_MEMCACHED_REPLACE_START();
186 rc= memcached_send(ptr, key, key_length,
187 key, key_length, value, value_length,
188 expiration, flags, 0, REPLACE_OP);
189 LIBMEMCACHED_MEMCACHED_REPLACE_END();
190 return rc;
191 }
192
193 memcached_return memcached_prepend(memcached_st *ptr,
194 const char *key, size_t key_length,
195 const char *value, size_t value_length,
196 time_t expiration,
197 uint32_t flags)
198 {
199 memcached_return rc;
200 rc= memcached_send(ptr, key, key_length,
201 key, key_length, value, value_length,
202 expiration, flags, 0, PREPEND_OP);
203 return rc;
204 }
205
206 memcached_return memcached_append(memcached_st *ptr,
207 const char *key, size_t key_length,
208 const char *value, size_t value_length,
209 time_t expiration,
210 uint32_t flags)
211 {
212 memcached_return rc;
213 rc= memcached_send(ptr, key, key_length,
214 key, key_length, value, value_length,
215 expiration, flags, 0, APPEND_OP);
216 return rc;
217 }
218
219 memcached_return memcached_cas(memcached_st *ptr,
220 const char *key, size_t key_length,
221 const char *value, size_t value_length,
222 time_t expiration,
223 uint32_t flags,
224 uint64_t cas)
225 {
226 memcached_return rc;
227 rc= memcached_send(ptr, key, key_length,
228 key, key_length, value, value_length,
229 expiration, flags, cas, CAS_OP);
230 return rc;
231 }
232
233 memcached_return memcached_set_by_key(memcached_st *ptr,
234 const char *master_key __attribute__((unused)),
235 size_t master_key_length __attribute__((unused)),
236 const char *key, size_t key_length,
237 const char *value, size_t value_length,
238 time_t expiration,
239 uint32_t flags)
240 {
241 memcached_return rc;
242 LIBMEMCACHED_MEMCACHED_SET_START();
243 rc= memcached_send(ptr, master_key, master_key_length,
244 key, key_length, value, value_length,
245 expiration, flags, 0, SET_OP);
246 LIBMEMCACHED_MEMCACHED_SET_END();
247 return rc;
248 }
249
250 memcached_return memcached_add_by_key(memcached_st *ptr,
251 const char *master_key, size_t master_key_length,
252 const char *key, size_t key_length,
253 const char *value, size_t value_length,
254 time_t expiration,
255 uint32_t flags)
256 {
257 memcached_return rc;
258 LIBMEMCACHED_MEMCACHED_ADD_START();
259 rc= memcached_send(ptr, master_key, master_key_length,
260 key, key_length, value, value_length,
261 expiration, flags, 0, ADD_OP);
262 LIBMEMCACHED_MEMCACHED_ADD_END();
263 return rc;
264 }
265
266 memcached_return memcached_replace_by_key(memcached_st *ptr,
267 const char *master_key, size_t master_key_length,
268 const char *key, size_t key_length,
269 const char *value, size_t value_length,
270 time_t expiration,
271 uint32_t flags)
272 {
273 memcached_return rc;
274 LIBMEMCACHED_MEMCACHED_REPLACE_START();
275 rc= memcached_send(ptr, master_key, master_key_length,
276 key, key_length, value, value_length,
277 expiration, flags, 0, REPLACE_OP);
278 LIBMEMCACHED_MEMCACHED_REPLACE_END();
279 return rc;
280 }
281
282 memcached_return memcached_prepend_by_key(memcached_st *ptr,
283 const char *master_key, size_t master_key_length,
284 const char *key, size_t key_length,
285 const char *value, size_t value_length,
286 time_t expiration,
287 uint32_t flags)
288 {
289 memcached_return rc;
290 rc= memcached_send(ptr, master_key, master_key_length,
291 key, key_length, value, value_length,
292 expiration, flags, 0, PREPEND_OP);
293 return rc;
294 }
295
296 memcached_return memcached_append_by_key(memcached_st *ptr,
297 const char *master_key, size_t master_key_length,
298 const char *key, size_t key_length,
299 const char *value, size_t value_length,
300 time_t expiration,
301 uint32_t flags)
302 {
303 memcached_return rc;
304 rc= memcached_send(ptr, master_key, master_key_length,
305 key, key_length, value, value_length,
306 expiration, flags, 0, APPEND_OP);
307 return rc;
308 }
309
310 memcached_return memcached_cas_by_key(memcached_st *ptr,
311 const char *master_key, size_t master_key_length,
312 const char *key, size_t key_length,
313 const char *value, size_t value_length,
314 time_t expiration,
315 uint32_t flags,
316 uint64_t cas)
317 {
318 memcached_return rc;
319 rc= memcached_send(ptr, master_key, master_key_length,
320 key, key_length, value, value_length,
321 expiration, flags, cas, CAS_OP);
322 return rc;
323 }
324
325 static memcached_return memcached_send_binary(memcached_server_st* server,
326 const char *key,
327 size_t key_length,
328 const char *value,
329 size_t value_length,
330 time_t expiration,
331 uint32_t flags,
332 uint64_t cas,
333 memcached_storage_action verb)
334 {
335 char flush;
336 protocol_binary_request_set request= {.bytes= {0}};
337 size_t send_length= sizeof(request.bytes);
338
339 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
340 switch (verb)
341 {
342 case SET_OP:
343 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
344 break;
345 case ADD_OP:
346 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_ADD;
347 break;
348 case REPLACE_OP:
349 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_REPLACE;
350 break;
351 case APPEND_OP:
352 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_APPEND;
353 break;
354 case PREPEND_OP:
355 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_PREPEND;
356 break;
357 case CAS_OP:
358 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_REPLACE;
359 break;
360 }
361
362 request.message.header.request.keylen= htons((uint16_t)key_length);
363 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
364 if (verb == APPEND_OP || verb == PREPEND_OP)
365 send_length -= 8; /* append & prepend does not contain extras! */
366 else
367 {
368 request.message.header.request.extlen= 8;
369 request.message.body.flags= htonl(flags);
370 request.message.body.expiration= htonl((uint32_t)expiration);
371 }
372
373 request.message.header.request.bodylen= htonl(key_length + value_length +
374 request.message.header.request.extlen);
375
376 if (cas)
377 request.message.header.request.cas= htonll(cas);
378
379 flush= ((server->root->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP) ? 0 : 1;
380 /* write the header */
381 if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
382 (memcached_io_write(server, key, key_length, 0) == -1) ||
383 (memcached_io_write(server, value, value_length, flush) == -1))
384 {
385 memcached_io_reset(server);
386 return MEMCACHED_WRITE_FAILURE;
387 }
388
389 if (flush == 0)
390 return MEMCACHED_BUFFERED;
391
392 return memcached_response(server, NULL, 0, NULL);
393 }
394