First merge of Trond's patches (cherry picking).
[m6w6/libmemcached] / libmemcached / memcached_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 memcached_auto(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 unsigned int server_key;
25 bool no_reply= ptr->flags.no_reply;
26
27 unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
28 return MEMCACHED_NO_SERVERS;
29
30 if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
31 return MEMCACHED_BAD_KEY_PROVIDED;
32
33 server_key= memcached_generate_hash(ptr, master_key, master_key_length);
34
35 send_length= (size_t)snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
36 "%s %s%.*s %" PRIu64 "%s\r\n", verb,
37 ptr->prefix_key,
38 (int)key_length, key,
39 offset, no_reply ? " noreply" : "");
40 unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
41 return MEMCACHED_WRITE_FAILURE;
42
43 rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
44 if (no_reply || rc != MEMCACHED_SUCCESS)
45 return rc;
46
47 rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
48
49 /*
50 So why recheck responce? Because the protocol is brain dead :)
51 The number returned might end up equaling one of the string
52 values. Less chance of a mistake with strncmp() so we will
53 use it. We still called memcached_response() though since it
54 worked its magic for non-blocking IO.
55 */
56 if (!strncmp(buffer, "ERROR\r\n", 7))
57 {
58 *value= 0;
59 rc= MEMCACHED_PROTOCOL_ERROR;
60 }
61 else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
62 {
63 *value= 0;
64 rc= MEMCACHED_NOTFOUND;
65 }
66 else
67 {
68 *value= strtoull(buffer, (char **)NULL, 10);
69 rc= MEMCACHED_SUCCESS;
70 }
71
72 return rc;
73 }
74
75 static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
76 const char *master_key, size_t master_key_length,
77 const char *key, size_t key_length,
78 uint64_t offset, uint64_t initial,
79 uint32_t expiration,
80 uint64_t *value)
81 {
82 unsigned int server_key;
83 bool no_reply= ptr->flags.no_reply;
84
85 unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
86 return MEMCACHED_NO_SERVERS;
87
88 server_key= memcached_generate_hash(ptr, master_key, master_key_length);
89
90 if (no_reply)
91 {
92 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
93 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
94 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
95 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
96 }
97 protocol_binary_request_incr request= {.bytes= {0}};
98
99 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
100 request.message.header.request.opcode= cmd;
101 request.message.header.request.keylen= htons((uint16_t) key_length);
102 request.message.header.request.extlen= 20;
103 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
104 request.message.header.request.bodylen= htonl((uint32_t) (key_length + request.message.header.request.extlen));
105 request.message.body.delta= htonll(offset);
106 request.message.body.initial= htonll(initial);
107 request.message.body.expiration= htonl((uint32_t) expiration);
108
109 if ((memcached_do(&ptr->hosts[server_key], request.bytes,
110 sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
111 (memcached_io_write(&ptr->hosts[server_key], key, key_length, 1) == -1))
112 {
113 memcached_io_reset(&ptr->hosts[server_key]);
114 return MEMCACHED_WRITE_FAILURE;
115 }
116
117 if (no_reply)
118 return MEMCACHED_SUCCESS;
119 return memcached_response(&ptr->hosts[server_key], (char*)value, sizeof(*value), NULL);
120 }
121
122 memcached_return_t memcached_increment(memcached_st *ptr,
123 const char *key, size_t key_length,
124 uint32_t offset,
125 uint64_t *value)
126 {
127 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
128 }
129
130 memcached_return_t memcached_decrement(memcached_st *ptr,
131 const char *key, size_t key_length,
132 uint32_t offset,
133 uint64_t *value)
134 {
135 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
136 }
137
138 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
139 const char *master_key, size_t master_key_length,
140 const char *key, size_t key_length,
141 uint64_t offset,
142 uint64_t *value)
143 {
144 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
145 unlikely (rc != MEMCACHED_SUCCESS)
146 return rc;
147
148 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
149 if (ptr->flags.binary_protocol)
150 {
151 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
152 master_key, master_key_length, key, key_length,
153 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
154 value);
155 }
156 else
157 {
158 rc= memcached_auto(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
159 }
160
161 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
162
163 return rc;
164 }
165
166 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
167 const char *master_key, size_t master_key_length,
168 const char *key, size_t key_length,
169 uint64_t offset,
170 uint64_t *value)
171 {
172 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
173 unlikely (rc != MEMCACHED_SUCCESS)
174 return rc;
175
176 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
177 if (ptr->flags.binary_protocol)
178 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
179 master_key, master_key_length, key, key_length,
180 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
181 value);
182 else
183 rc= memcached_auto(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
184
185 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
186
187 return rc;
188 }
189
190 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
191 const char *key,
192 size_t key_length,
193 uint64_t offset,
194 uint64_t initial,
195 time_t expiration,
196 uint64_t *value)
197 {
198 return memcached_increment_with_initial_by_key(ptr, key, key_length,
199 key, key_length,
200 offset, initial, expiration, value);
201 }
202
203 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
204 const char *master_key,
205 size_t master_key_length,
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 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
214 unlikely (rc != MEMCACHED_SUCCESS)
215 return rc;
216
217 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
218 if (ptr->flags.binary_protocol)
219 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
220 master_key, master_key_length, key, key_length,
221 offset, initial, (uint32_t)expiration,
222 value);
223 else
224 rc= MEMCACHED_PROTOCOL_ERROR;
225
226 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
227
228 return rc;
229 }
230
231 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
232 const char *key,
233 size_t key_length,
234 uint64_t offset,
235 uint64_t initial,
236 time_t expiration,
237 uint64_t *value)
238 {
239 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
240 key, key_length,
241 offset, initial, expiration, value);
242 }
243
244 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
245 const char *master_key,
246 size_t master_key_length,
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 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
255 unlikely (rc != MEMCACHED_SUCCESS)
256 return rc;
257
258 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
259 if (ptr->flags.binary_protocol)
260 {
261 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
262 master_key, master_key_length, key, key_length,
263 offset, initial, (uint32_t)expiration,
264 value);
265 }
266 else
267 {
268 rc= MEMCACHED_PROTOCOL_ERROR;
269 }
270
271 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
272
273 return rc;
274 }
275