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