Merge in trunk
[m6w6/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 void auto_response(memcached_server_write_instance_st instance, const bool reply, memcached_return_t& rc, uint64_t* value)
41 {
42 // If the message was successfully sent, then get the response, otherwise
43 // fail.
44 if (memcached_success(rc))
45 {
46 if (reply == false)
47 {
48 *value= UINT64_MAX;
49 return;
50 }
51
52 rc= memcached_response(instance, &instance->root->result);
53 }
54
55 if (memcached_success(rc))
56 {
57 *value= instance->root->result.numeric_value;
58 }
59 else
60 {
61 *value= UINT64_MAX;
62 }
63 }
64
65 static memcached_return_t text_incr_decr(memcached_server_write_instance_st instance,
66 const bool is_incr,
67 const char *key, size_t key_length,
68 const uint64_t offset,
69 const bool reply)
70 {
71 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
72
73 int send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
74 if (size_t(send_length) >= sizeof(buffer) or send_length < 0)
75 {
76 return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
77 memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
78 }
79
80 libmemcached_io_vector_st vector[]=
81 {
82 { NULL, 0 },
83 { memcached_literal_param("incr ") },
84 { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
85 { key, key_length },
86 { buffer, size_t(send_length) },
87 { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
88 { memcached_literal_param("\r\n") }
89 };
90
91 if (is_incr == false)
92 {
93 vector[1].buffer= "decr ";
94 }
95
96 return memcached_vdo(instance, vector, 7, true);
97 }
98
99 static memcached_return_t binary_incr_decr(memcached_server_write_instance_st instance,
100 protocol_binary_command cmd,
101 const char *key, const size_t key_length,
102 const uint64_t offset,
103 const uint64_t initial,
104 const uint32_t expiration,
105 const bool reply)
106 {
107 if (reply == false)
108 {
109 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
110 {
111 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
112 }
113
114 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
115 {
116 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
117 }
118 }
119 protocol_binary_request_incr request= {}; // = {.bytes= {0}};
120
121 initialize_binary_request(instance, request.message.header);
122
123 request.message.header.request.opcode= cmd;
124 request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(instance->root->_namespace)));
125 request.message.header.request.extlen= 20;
126 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
127 request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
128 request.message.body.delta= memcached_htonll(offset);
129 request.message.body.initial= memcached_htonll(initial);
130 request.message.body.expiration= htonl((uint32_t) expiration);
131
132 libmemcached_io_vector_st vector[]=
133 {
134 { NULL, 0 },
135 { request.bytes, sizeof(request.bytes) },
136 { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
137 { key, key_length }
138 };
139
140 return memcached_vdo(instance, vector, 4, true);
141 }
142
143 memcached_return_t memcached_increment(memcached_st *memc,
144 const char *key, size_t key_length,
145 uint32_t offset,
146 uint64_t *value)
147 {
148 return memcached_increment_by_key(memc, key, key_length, key, key_length, offset, value);
149 }
150
151 static memcached_return_t increment_decrement_by_key(const protocol_binary_command command,
152 memcached_st *memc,
153 const char *group_key, size_t group_key_length,
154 const char *key, size_t key_length,
155 uint64_t offset,
156 uint64_t *value)
157 {
158 uint64_t local_value;
159 if (value == NULL)
160 {
161 value= &local_value;
162 }
163
164 memcached_return_t rc;
165 if (memcached_failed(rc= initialize_query(memc, true)))
166 {
167 return rc;
168 }
169
170 if (memcached_is_encrypted(memc))
171 {
172 return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
173 memcached_literal_param("Operation not allowed while encyrption is enabled"));
174 }
175
176 if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
177 {
178 return memcached_last_error(memc);
179 }
180
181 uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
182 memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, server_key);
183
184 bool reply= memcached_is_replying(instance->root);
185
186 if (memcached_is_binary(memc))
187 {
188 rc= binary_incr_decr(instance, command,
189 key, key_length,
190 uint64_t(offset), 0, MEMCACHED_EXPIRATION_NOT_ADD,
191 reply);
192 }
193 else
194 {
195 rc= text_incr_decr(instance,
196 command == PROTOCOL_BINARY_CMD_INCREMENT ? true : false,
197 key, key_length,
198 offset, reply);
199 }
200
201 auto_response(instance, reply, rc, value);
202
203 return rc;
204 }
205
206 static memcached_return_t increment_decrement_with_initial_by_key(const protocol_binary_command command,
207 memcached_st *memc,
208 const char *group_key,
209 size_t group_key_length,
210 const char *key,
211 size_t key_length,
212 uint64_t offset,
213 uint64_t initial,
214 time_t expiration,
215 uint64_t *value)
216 {
217 uint64_t local_value;
218 if (value == NULL)
219 {
220 value= &local_value;
221 }
222
223 memcached_return_t rc;
224 if (memcached_failed(rc= initialize_query(memc, true)))
225 {
226 return rc;
227 }
228
229 if (memcached_is_encrypted(memc))
230 {
231 return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
232 memcached_literal_param("Operation not allowed while encyrption is enabled"));
233 }
234
235 if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
236 {
237 return memcached_last_error(memc);
238 }
239
240 uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
241 memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, server_key);
242
243 bool reply= memcached_is_replying(instance->root);
244
245 if (memcached_is_binary(memc))
246 {
247 rc= binary_incr_decr(instance, command,
248 key, key_length,
249 offset, initial, uint32_t(expiration),
250 reply);
251
252 }
253 else
254 {
255 rc= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
256 memcached_literal_param("memcached_increment_with_initial_by_key() is not supported via the ASCII protocol"));
257 }
258
259 auto_response(instance, reply, rc, value);
260
261 return rc;
262 }
263
264 memcached_return_t memcached_decrement(memcached_st *memc,
265 const char *key, size_t key_length,
266 uint32_t offset,
267 uint64_t *value)
268 {
269 return memcached_decrement_by_key(memc, key, key_length, key, key_length, offset, value);
270 }
271
272
273 memcached_return_t memcached_increment_by_key(memcached_st *memc,
274 const char *group_key, size_t group_key_length,
275 const char *key, size_t key_length,
276 uint64_t offset,
277 uint64_t *value)
278 {
279 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
280 memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
281 memc,
282 group_key, group_key_length,
283 key, key_length,
284 offset, value);
285
286 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
287
288 return rc;
289 }
290
291 memcached_return_t memcached_decrement_by_key(memcached_st *memc,
292 const char *group_key, size_t group_key_length,
293 const char *key, size_t key_length,
294 uint64_t offset,
295 uint64_t *value)
296 {
297 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
298 memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
299 memc,
300 group_key, group_key_length,
301 key, key_length,
302 offset, value);
303 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
304
305 return rc;
306 }
307
308 memcached_return_t memcached_increment_with_initial(memcached_st *memc,
309 const char *key,
310 size_t key_length,
311 uint64_t offset,
312 uint64_t initial,
313 time_t expiration,
314 uint64_t *value)
315 {
316 return memcached_increment_with_initial_by_key(memc, key, key_length,
317 key, key_length,
318 offset, initial, expiration, value);
319 }
320
321 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *memc,
322 const char *group_key,
323 size_t group_key_length,
324 const char *key,
325 size_t key_length,
326 uint64_t offset,
327 uint64_t initial,
328 time_t expiration,
329 uint64_t *value)
330 {
331 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
332 memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
333 memc,
334 group_key, group_key_length,
335 key, key_length,
336 offset, initial, expiration, value);
337 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
338
339 return rc;
340 }
341
342 memcached_return_t memcached_decrement_with_initial(memcached_st *memc,
343 const char *key,
344 size_t key_length,
345 uint64_t offset,
346 uint64_t initial,
347 time_t expiration,
348 uint64_t *value)
349 {
350 return memcached_decrement_with_initial_by_key(memc, key, key_length,
351 key, key_length,
352 offset, initial, expiration, value);
353 }
354
355 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *memc,
356 const char *group_key,
357 size_t group_key_length,
358 const char *key,
359 size_t key_length,
360 uint64_t offset,
361 uint64_t initial,
362 time_t expiration,
363 uint64_t *value)
364 {
365 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
366 memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
367 memc,
368 group_key, group_key_length,
369 key, key_length,
370 offset, initial, expiration, value);
371
372 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
373
374 return rc;
375 }