We didn't catch client_Error.
[awesomized/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 size_t send_length;
22 memcached_return_t rc;
23 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
24 uint32_t server_key;
25 memcached_server_write_instance_st instance;
26 bool no_reply= ptr->flags.no_reply;
27
28 unlikely (memcached_server_count(ptr) == 0)
29 return MEMCACHED_NO_SERVERS;
30
31 if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
32 return MEMCACHED_BAD_KEY_PROVIDED;
33
34 server_key= memcached_generate_hash_with_redistribution(ptr, master_key, master_key_length);
35 instance= memcached_server_instance_fetch(ptr, server_key);
36
37 send_length= (size_t)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 unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
44 return MEMCACHED_WRITE_FAILURE;
45
46 rc= memcached_do(instance, buffer, 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 unlikely (memcached_server_count(ptr) == 0)
95 return MEMCACHED_NO_SERVERS;
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);
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 + 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 memcached_return_t rc;
120 if (((rc= memcached_do(instance, request.bytes,
121 sizeof(request.bytes), false)) != MEMCACHED_SUCCESS) ||
122 (memcached_io_write(instance, key, key_length, true) == -1))
123 {
124 memcached_io_reset(instance);
125 return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
126 }
127
128 if (no_reply)
129 return MEMCACHED_SUCCESS;
130 return memcached_response(instance, (char*)value, sizeof(*value), NULL);
131 }
132
133 memcached_return_t memcached_increment(memcached_st *ptr,
134 const char *key, size_t key_length,
135 uint32_t offset,
136 uint64_t *value)
137 {
138 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
139 }
140
141 memcached_return_t memcached_decrement(memcached_st *ptr,
142 const char *key, size_t key_length,
143 uint32_t offset,
144 uint64_t *value)
145 {
146 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
147 }
148
149 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
150 const char *master_key, size_t master_key_length,
151 const char *key, size_t key_length,
152 uint64_t offset,
153 uint64_t *value)
154 {
155 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
156 unlikely (rc != MEMCACHED_SUCCESS)
157 return rc;
158
159 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
160 if (ptr->flags.binary_protocol)
161 {
162 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
163 master_key, master_key_length, key, key_length,
164 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
165 value);
166 }
167 else
168 {
169 rc= text_incr_decr(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
170 }
171
172 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
173
174 return rc;
175 }
176
177 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
178 const char *master_key, size_t master_key_length,
179 const char *key, size_t key_length,
180 uint64_t offset,
181 uint64_t *value)
182 {
183 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
184 unlikely (rc != MEMCACHED_SUCCESS)
185 return rc;
186
187 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
188 if (ptr->flags.binary_protocol)
189 {
190 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
191 master_key, master_key_length, key, key_length,
192 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
193 value);
194 }
195 else
196 {
197 rc= text_incr_decr(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
198 }
199
200 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
201
202 return rc;
203 }
204
205 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
206 const char *key,
207 size_t key_length,
208 uint64_t offset,
209 uint64_t initial,
210 time_t expiration,
211 uint64_t *value)
212 {
213 return memcached_increment_with_initial_by_key(ptr, key, key_length,
214 key, key_length,
215 offset, initial, expiration, value);
216 }
217
218 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
219 const char *master_key,
220 size_t master_key_length,
221 const char *key,
222 size_t key_length,
223 uint64_t offset,
224 uint64_t initial,
225 time_t expiration,
226 uint64_t *value)
227 {
228 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
229 unlikely (rc != MEMCACHED_SUCCESS)
230 return rc;
231
232 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
233 if (ptr->flags.binary_protocol)
234 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
235 master_key, master_key_length, key, key_length,
236 offset, initial, (uint32_t)expiration,
237 value);
238 else
239 rc= MEMCACHED_PROTOCOL_ERROR;
240
241 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
242
243 return rc;
244 }
245
246 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
247 const char *key,
248 size_t key_length,
249 uint64_t offset,
250 uint64_t initial,
251 time_t expiration,
252 uint64_t *value)
253 {
254 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
255 key, key_length,
256 offset, initial, expiration, value);
257 }
258
259 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
260 const char *master_key,
261 size_t master_key_length,
262 const char *key,
263 size_t key_length,
264 uint64_t offset,
265 uint64_t initial,
266 time_t expiration,
267 uint64_t *value)
268 {
269 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
270 unlikely (rc != MEMCACHED_SUCCESS)
271 return rc;
272
273 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
274 if (ptr->flags.binary_protocol)
275 {
276 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
277 master_key, master_key_length, key, key_length,
278 offset, initial, (uint32_t)expiration,
279 value);
280 }
281 else
282 {
283 rc= MEMCACHED_PROTOCOL_ERROR;
284 }
285
286 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
287
288 return rc;
289 }
290