325ddb6b7d49721b1b34d4d955557045097a0ad7
[awesomized/libmemcached] / libmemcached / auto.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary: Methods for adding or decrementing values from an object in memcached
9 *
10 */
11
12 #include "libmemcached/common.h"
13
14 static memcached_return_t text_incr_decr(memcached_st *ptr,
15 const char *verb,
16 const char *group_key, size_t group_key_length,
17 const char *key, size_t key_length,
18 uint64_t offset,
19 uint64_t *value)
20 {
21 memcached_return_t rc;
22 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
23 uint32_t server_key;
24 memcached_server_write_instance_st instance;
25 bool no_reply= ptr->flags.no_reply;
26
27 if (memcached_server_count(ptr) == 0)
28 return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
29
30 if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
31 return MEMCACHED_BAD_KEY_PROVIDED;
32
33 server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
34 instance= memcached_server_instance_fetch(ptr, server_key);
35
36 int send_length;
37 send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
38 "%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
39 memcached_print_array(ptr->prefix_key),
40 (int)key_length, key,
41 offset, no_reply ? " noreply" : "");
42 if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
43 return MEMCACHED_WRITE_FAILURE;
44
45 rc= memcached_do(instance, buffer, (size_t)send_length, true);
46 if (no_reply || rc != MEMCACHED_SUCCESS)
47 return rc;
48
49 rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
50
51 /*
52 So why recheck responce? Because the protocol is brain dead :)
53 The number returned might end up equaling one of the string
54 values. Less chance of a mistake with strncmp() so we will
55 use it. We still called memcached_response() though since it
56 worked its magic for non-blocking IO.
57 */
58 if (! strncmp(buffer, "ERROR\r\n", 7))
59 {
60 *value= 0;
61 rc= MEMCACHED_PROTOCOL_ERROR;
62 }
63 else if (! strncmp(buffer, "CLIENT_ERROR\r\n", 14))
64 {
65 *value= 0;
66 rc= MEMCACHED_PROTOCOL_ERROR;
67 }
68 else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
69 {
70 *value= 0;
71 rc= MEMCACHED_NOTFOUND;
72 }
73 else
74 {
75 *value= strtoull(buffer, (char **)NULL, 10);
76 rc= MEMCACHED_SUCCESS;
77 }
78
79 return rc;
80 }
81
82 static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
83 const char *group_key, size_t group_key_length,
84 const char *key, size_t key_length,
85 uint64_t offset, uint64_t initial,
86 uint32_t expiration,
87 uint64_t *value)
88 {
89 uint32_t server_key;
90 memcached_server_write_instance_st instance;
91 bool no_reply= ptr->flags.no_reply;
92
93 if (memcached_server_count(ptr) == 0)
94 return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
95
96 server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
97 instance= memcached_server_instance_fetch(ptr, server_key);
98
99 if (no_reply)
100 {
101 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
102 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
103 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
104 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
105 }
106 protocol_binary_request_incr request= {.bytes= {0}};
107
108 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
109 request.message.header.request.opcode= cmd;
110 request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
111 request.message.header.request.extlen= 20;
112 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
113 request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen));
114 request.message.body.delta= htonll(offset);
115 request.message.body.initial= htonll(initial);
116 request.message.body.expiration= htonl((uint32_t) expiration);
117
118 struct libmemcached_io_vector_st vector[]=
119 {
120 { .length= sizeof(request.bytes), .buffer= request.bytes },
121 { .length= memcached_array_size(ptr->prefix_key), .buffer= ptr->prefix_key },
122 { .length= key_length, .buffer= key }
123 };
124
125 memcached_return_t rc;
126 if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS)
127 {
128 memcached_io_reset(instance);
129 return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
130 }
131
132 if (no_reply)
133 return MEMCACHED_SUCCESS;
134 return memcached_response(instance, (char*)value, sizeof(*value), NULL);
135 }
136
137 memcached_return_t memcached_increment(memcached_st *ptr,
138 const char *key, size_t key_length,
139 uint32_t offset,
140 uint64_t *value)
141 {
142 uint64_t local_value;
143 if (! value)
144 value= &local_value;
145
146 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
147 }
148
149 memcached_return_t memcached_decrement(memcached_st *ptr,
150 const char *key, size_t key_length,
151 uint32_t offset,
152 uint64_t *value)
153 {
154 uint64_t local_value;
155 if (! value)
156 value= &local_value;
157
158 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
159 }
160
161 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
162 const char *group_key, size_t group_key_length,
163 const char *key, size_t key_length,
164 uint64_t offset,
165 uint64_t *value)
166 {
167 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
168 unlikely (rc != MEMCACHED_SUCCESS)
169 return rc;
170
171 uint64_t local_value;
172 if (! value)
173 value= &local_value;
174
175 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
176 if (ptr->flags.binary_protocol)
177 {
178 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
179 group_key, group_key_length, key, key_length,
180 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
181 value);
182 }
183 else
184 {
185 rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value);
186 }
187
188 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
189
190 return rc;
191 }
192
193 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
194 const char *group_key, size_t group_key_length,
195 const char *key, size_t key_length,
196 uint64_t offset,
197 uint64_t *value)
198 {
199 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
200 unlikely (rc != MEMCACHED_SUCCESS)
201 return rc;
202
203 uint64_t local_value;
204 if (! value)
205 value= &local_value;
206
207 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
208 if (ptr->flags.binary_protocol)
209 {
210 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
211 group_key, group_key_length, key, key_length,
212 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
213 value);
214 }
215 else
216 {
217 rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value);
218 }
219
220 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
221
222 return rc;
223 }
224
225 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
226 const char *key,
227 size_t key_length,
228 uint64_t offset,
229 uint64_t initial,
230 time_t expiration,
231 uint64_t *value)
232 {
233 uint64_t local_value;
234 if (! value)
235 value= &local_value;
236
237 return memcached_increment_with_initial_by_key(ptr, key, key_length,
238 key, key_length,
239 offset, initial, expiration, value);
240 }
241
242 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
243 const char *group_key,
244 size_t group_key_length,
245 const char *key,
246 size_t key_length,
247 uint64_t offset,
248 uint64_t initial,
249 time_t expiration,
250 uint64_t *value)
251 {
252 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
253 unlikely (rc != MEMCACHED_SUCCESS)
254 return rc;
255
256 uint64_t local_value;
257 if (! value)
258 value= &local_value;
259
260 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
261 if (ptr->flags.binary_protocol)
262 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
263 group_key, group_key_length, key, key_length,
264 offset, initial, (uint32_t)expiration,
265 value);
266 else
267 rc= MEMCACHED_PROTOCOL_ERROR;
268
269 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
270
271 return rc;
272 }
273
274 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
275 const char *key,
276 size_t key_length,
277 uint64_t offset,
278 uint64_t initial,
279 time_t expiration,
280 uint64_t *value)
281 {
282 uint64_t local_value;
283 if (! value)
284 value= &local_value;
285
286 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
287 key, key_length,
288 offset, initial, expiration, value);
289 }
290
291 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
292 const char *group_key,
293 size_t group_key_length,
294 const char *key,
295 size_t key_length,
296 uint64_t offset,
297 uint64_t initial,
298 time_t expiration,
299 uint64_t *value)
300 {
301 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
302 unlikely (rc != MEMCACHED_SUCCESS)
303 return rc;
304
305 uint64_t local_value;
306 if (! value)
307 value= &local_value;
308
309 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
310 if (ptr->flags.binary_protocol)
311 {
312 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
313 group_key, group_key_length, key, key_length,
314 offset, initial, (uint32_t)expiration,
315 value);
316 }
317 else
318 {
319 rc= MEMCACHED_PROTOCOL_ERROR;
320 }
321
322 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
323
324 return rc;
325 }
326