Update auto to use vector
[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 *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;
63 send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
64 if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
65 {
66 return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
67 memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
68 }
69
70 struct libmemcached_io_vector_st vector[]=
71 {
72 { memcached_literal_param("incr ") },
73 { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
74 { key, key_length },
75 { buffer, send_length },
76 { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
77 { memcached_literal_param("\r\n") }
78 };
79
80 if (is_incr == false)
81 {
82 vector[0].buffer= "decr ";
83 }
84
85 memcached_return_t rc= memcached_vdo(instance, vector, 6, true);
86 if (reply == false or memcached_failed(rc))
87 {
88 return rc;
89 }
90
91 rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
92
93 if (rc != MEMCACHED_SUCCESS)
94 {
95 return memcached_set_error(*instance, rc, MEMCACHED_AT);
96 }
97
98 /*
99 So why recheck responce? Because the protocol is brain dead :)
100 The number returned might end up equaling one of the string
101 values. Less chance of a mistake with strncmp() so we will
102 use it. We still called memcached_response() though since it
103 worked its magic for non-blocking IO.
104 */
105 if (not strncmp(buffer, memcached_literal_param("ERROR\r\n")))
106 {
107 *value= 0;
108 rc= MEMCACHED_PROTOCOL_ERROR;
109 }
110 else if (not strncmp(buffer, memcached_literal_param("CLIENT_ERROR\r\n")))
111 {
112 *value= 0;
113 rc= MEMCACHED_PROTOCOL_ERROR;
114 }
115 else if (not strncmp(buffer, memcached_literal_param("NOT_FOUND\r\n")))
116 {
117 *value= 0;
118 rc= MEMCACHED_NOTFOUND;
119 }
120 else
121 {
122 *value= strtoull(buffer, (char **)NULL, 10);
123 rc= MEMCACHED_SUCCESS;
124 }
125
126 return memcached_set_error(*instance, rc, MEMCACHED_AT);
127 }
128
129 static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
130 const char *group_key, size_t group_key_length,
131 const char *key, size_t key_length,
132 uint64_t offset, uint64_t initial,
133 uint32_t expiration,
134 uint64_t *value)
135 {
136 bool no_reply= ptr->flags.no_reply;
137
138 uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
139 memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);
140
141 if (no_reply)
142 {
143 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
144 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
145
146 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
147 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
148 }
149 protocol_binary_request_incr request= {}; // = {.bytes= {0}};
150
151 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
152 request.message.header.request.opcode= cmd;
153 request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
154 request.message.header.request.extlen= 20;
155 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
156 request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace) +request.message.header.request.extlen));
157 request.message.body.delta= memcached_htonll(offset);
158 request.message.body.initial= memcached_htonll(initial);
159 request.message.body.expiration= htonl((uint32_t) expiration);
160
161 struct libmemcached_io_vector_st vector[]=
162 {
163 { request.bytes, sizeof(request.bytes) },
164 { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
165 { key, key_length }
166 };
167
168 memcached_return_t rc;
169 if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
170 {
171 memcached_io_reset(instance);
172 return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
173 }
174
175 if (no_reply)
176 {
177 return MEMCACHED_SUCCESS;
178 }
179
180 return memcached_response(instance, (char*)value, sizeof(*value), NULL);
181 }
182
183 memcached_return_t memcached_increment(memcached_st *ptr,
184 const char *key, size_t key_length,
185 uint32_t offset,
186 uint64_t *value)
187 {
188 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
189 }
190
191 memcached_return_t memcached_decrement(memcached_st *ptr,
192 const char *key, size_t key_length,
193 uint32_t offset,
194 uint64_t *value)
195 {
196 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
197 }
198
199 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
200 const char *group_key, size_t group_key_length,
201 const char *key, size_t key_length,
202 uint64_t offset,
203 uint64_t *value)
204 {
205 memcached_return_t rc;
206 uint64_t local_value;
207 if (value == NULL)
208 {
209 value= &local_value;
210 }
211
212 if (memcached_failed(rc= initialize_query(ptr)))
213 {
214 return rc;
215 }
216
217 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
218 {
219 return rc;
220 }
221
222 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
223 if (ptr->flags.binary_protocol)
224 {
225 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
226 group_key, group_key_length, key, key_length,
227 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
228 value);
229 }
230 else
231 {
232 rc= text_incr_decr(ptr, true, group_key, group_key_length, key, key_length, offset, value);
233 }
234
235 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
236
237 return rc;
238 }
239
240 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
241 const char *group_key, size_t group_key_length,
242 const char *key, size_t key_length,
243 uint64_t offset,
244 uint64_t *value)
245 {
246 uint64_t local_value;
247 if (value == NULL)
248 {
249 value= &local_value;
250 }
251
252 memcached_return_t rc;
253 if (memcached_failed(rc= initialize_query(ptr)))
254 {
255 return rc;
256 }
257
258 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
259 {
260 return rc;
261 }
262
263
264 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
265 if (ptr->flags.binary_protocol)
266 {
267 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
268 group_key, group_key_length, key, key_length,
269 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
270 value);
271 }
272 else
273 {
274 rc= text_incr_decr(ptr, false, group_key, group_key_length, key, key_length, offset, value);
275 }
276
277 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
278
279 return rc;
280 }
281
282 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
283 const char *key,
284 size_t key_length,
285 uint64_t offset,
286 uint64_t initial,
287 time_t expiration,
288 uint64_t *value)
289 {
290 uint64_t local_value;
291 if (value == NULL)
292 {
293 value= &local_value;
294 }
295
296 return memcached_increment_with_initial_by_key(ptr, key, key_length,
297 key, key_length,
298 offset, initial, expiration, value);
299 }
300
301 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
302 const char *group_key,
303 size_t group_key_length,
304 const char *key,
305 size_t key_length,
306 uint64_t offset,
307 uint64_t initial,
308 time_t expiration,
309 uint64_t *value)
310 {
311 uint64_t local_value;
312 if (value == NULL)
313 {
314 value= &local_value;
315 }
316
317 memcached_return_t rc;
318 if (memcached_failed(rc= initialize_query(ptr)))
319 {
320 return rc;
321 }
322
323 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
324 {
325 return rc;
326 }
327
328 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
329 if (ptr->flags.binary_protocol)
330 {
331 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
332 group_key, group_key_length, key, key_length,
333 offset, initial, (uint32_t)expiration,
334 value);
335 }
336 else
337 {
338 rc= MEMCACHED_PROTOCOL_ERROR;
339 }
340
341 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
342
343 return rc;
344 }
345
346 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
347 const char *key,
348 size_t key_length,
349 uint64_t offset,
350 uint64_t initial,
351 time_t expiration,
352 uint64_t *value)
353 {
354 uint64_t local_value;
355 if (value == NULL)
356 {
357 value= &local_value;
358 }
359
360 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
361 key, key_length,
362 offset, initial, expiration, value);
363 }
364
365 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
366 const char *group_key,
367 size_t group_key_length,
368 const char *key,
369 size_t key_length,
370 uint64_t offset,
371 uint64_t initial,
372 time_t expiration,
373 uint64_t *value)
374 {
375 uint64_t local_value;
376 if (value == NULL)
377 {
378 value= &local_value;
379 }
380
381 memcached_return_t rc;
382 if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
383 {
384 return rc;
385 }
386
387 if (memcached_failed(rc= initialize_query(ptr)))
388 {
389 return rc;
390 }
391
392
393 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
394 if (ptr->flags.binary_protocol)
395 {
396 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
397 group_key, group_key_length, key, key_length,
398 offset, initial, (uint32_t)expiration,
399 value);
400 }
401 else
402 {
403 rc= MEMCACHED_PROTOCOL_ERROR;
404 }
405
406 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
407
408 return rc;
409 }
410