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