517e5b96fb8faf96f23ee1c50a7ad2544206baad
[awesomized/libmemcached] / libmemcached / auto.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38 #include <libmemcached/common.h>
39
40 static memcached_return_t text_incr_decr(memcached_st *ptr,
41 const bool is_incr,
42 const char *group_key, size_t group_key_length,
43 const char *key, size_t key_length,
44 uint64_t offset,
45 uint64_t& numeric_value)
46 {
47 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
48 uint32_t server_key;
49 memcached_server_write_instance_st instance;
50
51 // Invert the logic to make it simpler to read the code
52 bool reply= (ptr->flags.no_reply) ? false : true;
53
54 if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
55 {
56 return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT);
57 }
58
59 server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
60 instance= memcached_server_instance_fetch(ptr, server_key);
61
62 int send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
63 if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
64 {
65 return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
66 memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
67 }
68
69 struct libmemcached_io_vector_st vector[]=
70 {
71 { memcached_literal_param("incr ") },
72 { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
73 { key, key_length },
74 { buffer, send_length },
75 { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
76 { memcached_literal_param("\r\n") }
77 };
78
79 if (is_incr == false)
80 {
81 vector[0].buffer= "decr ";
82 }
83
84 memcached_return_t rc= memcached_vdo(instance, vector, 6, true);
85 if (reply == false or memcached_failed(rc))
86 {
87 numeric_value= UINT64_MAX;
88 return rc;
89 }
90
91 rc= memcached_response(instance, buffer, sizeof(buffer), NULL, numeric_value);
92
93 return memcached_set_error(*instance, rc, MEMCACHED_AT);
94 }
95
96 static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
97 const char *group_key, size_t group_key_length,
98 const char *key, size_t key_length,
99 uint64_t offset, uint64_t initial,
100 uint32_t expiration,
101 uint64_t *value)
102 {
103 bool no_reply= ptr->flags.no_reply;
104
105 uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
106 memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);
107
108 if (no_reply)
109 {
110 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
111 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
112
113 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
114 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
115 }
116 protocol_binary_request_incr request= {}; // = {.bytes= {0}};
117
118 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
119 request.message.header.request.opcode= cmd;
120 request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
121 request.message.header.request.extlen= 20;
122 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
123 request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace) +request.message.header.request.extlen));
124 request.message.body.delta= memcached_htonll(offset);
125 request.message.body.initial= memcached_htonll(initial);
126 request.message.body.expiration= htonl((uint32_t) expiration);
127
128 struct libmemcached_io_vector_st vector[]=
129 {
130 { request.bytes, sizeof(request.bytes) },
131 { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
132 { key, key_length }
133 };
134
135 memcached_return_t rc;
136 if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
137 {
138 memcached_io_reset(instance);
139 return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
140 }
141
142 if (no_reply)
143 {
144 return MEMCACHED_SUCCESS;
145 }
146
147 return memcached_response(instance, (char*)value, sizeof(*value), NULL);
148 }
149
150 memcached_return_t memcached_increment(memcached_st *ptr,
151 const char *key, size_t key_length,
152 uint32_t offset,
153 uint64_t *value)
154 {
155 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
156 }
157
158 memcached_return_t memcached_decrement(memcached_st *ptr,
159 const char *key, size_t key_length,
160 uint32_t offset,
161 uint64_t *value)
162 {
163 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
164 }
165
166 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
167 const char *group_key, size_t group_key_length,
168 const char *key, size_t key_length,
169 uint64_t offset,
170 uint64_t *value)
171 {
172 memcached_return_t rc;
173 uint64_t local_value;
174 if (value == NULL)
175 {
176 value= &local_value;
177 }
178
179 if (memcached_failed(rc= initialize_query(ptr)))
180 {
181 return rc;
182 }
183
184 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
185 {
186 return rc;
187 }
188
189 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
190 if (ptr->flags.binary_protocol)
191 {
192 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
193 group_key, group_key_length, key, key_length,
194 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
195 value);
196 }
197 else
198 {
199 rc= text_incr_decr(ptr, true, group_key, group_key_length, key, key_length, offset, *value);
200 }
201
202 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
203
204 return rc;
205 }
206
207 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
208 const char *group_key, size_t group_key_length,
209 const char *key, size_t key_length,
210 uint64_t offset,
211 uint64_t *value)
212 {
213 uint64_t local_value;
214 if (value == NULL)
215 {
216 value= &local_value;
217 }
218
219 memcached_return_t rc;
220 if (memcached_failed(rc= initialize_query(ptr)))
221 {
222 return rc;
223 }
224
225 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
226 {
227 return rc;
228 }
229
230
231 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
232 if (ptr->flags.binary_protocol)
233 {
234 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
235 group_key, group_key_length, key, key_length,
236 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
237 value);
238 }
239 else
240 {
241 rc= text_incr_decr(ptr, false, group_key, group_key_length, key, key_length, offset, *value);
242 }
243
244 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
245
246 return rc;
247 }
248
249 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
250 const char *key,
251 size_t key_length,
252 uint64_t offset,
253 uint64_t initial,
254 time_t expiration,
255 uint64_t *value)
256 {
257 uint64_t local_value;
258 if (value == NULL)
259 {
260 value= &local_value;
261 }
262
263 return memcached_increment_with_initial_by_key(ptr, key, key_length,
264 key, key_length,
265 offset, initial, expiration, value);
266 }
267
268 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
269 const char *group_key,
270 size_t group_key_length,
271 const char *key,
272 size_t key_length,
273 uint64_t offset,
274 uint64_t initial,
275 time_t expiration,
276 uint64_t *value)
277 {
278 uint64_t local_value;
279 if (value == NULL)
280 {
281 value= &local_value;
282 }
283
284 memcached_return_t rc;
285 if (memcached_failed(rc= initialize_query(ptr)))
286 {
287 return rc;
288 }
289
290 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
291 {
292 return rc;
293 }
294
295 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
296 if (ptr->flags.binary_protocol)
297 {
298 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
299 group_key, group_key_length, key, key_length,
300 offset, initial, (uint32_t)expiration,
301 value);
302 }
303 else
304 {
305 rc= MEMCACHED_PROTOCOL_ERROR;
306 }
307
308 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
309
310 return rc;
311 }
312
313 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
314 const char *key,
315 size_t key_length,
316 uint64_t offset,
317 uint64_t initial,
318 time_t expiration,
319 uint64_t *value)
320 {
321 uint64_t local_value;
322 if (value == NULL)
323 {
324 value= &local_value;
325 }
326
327 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
328 key, key_length,
329 offset, initial, expiration, value);
330 }
331
332 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
333 const char *group_key,
334 size_t group_key_length,
335 const char *key,
336 size_t key_length,
337 uint64_t offset,
338 uint64_t initial,
339 time_t expiration,
340 uint64_t *value)
341 {
342 uint64_t local_value;
343 if (value == NULL)
344 {
345 value= &local_value;
346 }
347
348 memcached_return_t rc;
349 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
350 {
351 return rc;
352 }
353
354 if (memcached_failed(rc= initialize_query(ptr)))
355 {
356 return rc;
357 }
358
359
360 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
361 if (ptr->flags.binary_protocol)
362 {
363 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
364 group_key, group_key_length, key, key_length,
365 offset, initial, (uint32_t)expiration,
366 value);
367 }
368 else
369 {
370 rc= MEMCACHED_PROTOCOL_ERROR;
371 }
372
373 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
374
375 return rc;
376 }
377