Add support for SASL
[m6w6/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, "NOT_FOUND\r\n", 11))
65 {
66 *value= 0;
67 rc= MEMCACHED_NOTFOUND;
68 }
69 else
70 {
71 *value= strtoull(buffer, (char **)NULL, 10);
72 rc= MEMCACHED_SUCCESS;
73 }
74
75 return rc;
76 }
77
78 static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
79 const char *master_key, size_t master_key_length,
80 const char *key, size_t key_length,
81 uint64_t offset, uint64_t initial,
82 uint32_t expiration,
83 uint64_t *value)
84 {
85 uint32_t server_key;
86 memcached_server_write_instance_st instance;
87 bool no_reply= ptr->flags.no_reply;
88
89 unlikely (memcached_server_count(ptr) == 0)
90 return MEMCACHED_NO_SERVERS;
91
92 server_key= memcached_generate_hash_with_redistribution(ptr, master_key, master_key_length);
93 instance= memcached_server_instance_fetch(ptr, server_key);
94
95 if (no_reply)
96 {
97 if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
98 cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
99 if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
100 cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
101 }
102 protocol_binary_request_incr request= {.bytes= {0}};
103
104 request.message.header.request.magic= PROTOCOL_BINARY_REQ;
105 request.message.header.request.opcode= cmd;
106 request.message.header.request.keylen= htons((uint16_t) key_length);
107 request.message.header.request.extlen= 20;
108 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
109 request.message.header.request.bodylen= htonl((uint32_t) (key_length + request.message.header.request.extlen));
110 request.message.body.delta= htonll(offset);
111 request.message.body.initial= htonll(initial);
112 request.message.body.expiration= htonl((uint32_t) expiration);
113
114 memcached_return_t rc;
115 if (((rc= memcached_do(instance, request.bytes,
116 sizeof(request.bytes), false)) != MEMCACHED_SUCCESS) ||
117 (memcached_io_write(instance, key, key_length, true) == -1))
118 {
119 memcached_io_reset(instance);
120 return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
121 }
122
123 if (no_reply)
124 return MEMCACHED_SUCCESS;
125 return memcached_response(instance, (char*)value, sizeof(*value), NULL);
126 }
127
128 memcached_return_t memcached_increment(memcached_st *ptr,
129 const char *key, size_t key_length,
130 uint32_t offset,
131 uint64_t *value)
132 {
133 return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
134 }
135
136 memcached_return_t memcached_decrement(memcached_st *ptr,
137 const char *key, size_t key_length,
138 uint32_t offset,
139 uint64_t *value)
140 {
141 return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
142 }
143
144 memcached_return_t memcached_increment_by_key(memcached_st *ptr,
145 const char *master_key, size_t master_key_length,
146 const char *key, size_t key_length,
147 uint64_t offset,
148 uint64_t *value)
149 {
150 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
151 unlikely (rc != MEMCACHED_SUCCESS)
152 return rc;
153
154 LIBMEMCACHED_MEMCACHED_INCREMENT_START();
155 if (ptr->flags.binary_protocol)
156 {
157 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
158 master_key, master_key_length, key, key_length,
159 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
160 value);
161 }
162 else
163 {
164 rc= text_incr_decr(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
165 }
166
167 LIBMEMCACHED_MEMCACHED_INCREMENT_END();
168
169 return rc;
170 }
171
172 memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
173 const char *master_key, size_t master_key_length,
174 const char *key, size_t key_length,
175 uint64_t offset,
176 uint64_t *value)
177 {
178 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
179 unlikely (rc != MEMCACHED_SUCCESS)
180 return rc;
181
182 LIBMEMCACHED_MEMCACHED_DECREMENT_START();
183 if (ptr->flags.binary_protocol)
184 {
185 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
186 master_key, master_key_length, key, key_length,
187 (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
188 value);
189 }
190 else
191 {
192 rc= text_incr_decr(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
193 }
194
195 LIBMEMCACHED_MEMCACHED_DECREMENT_END();
196
197 return rc;
198 }
199
200 memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
201 const char *key,
202 size_t key_length,
203 uint64_t offset,
204 uint64_t initial,
205 time_t expiration,
206 uint64_t *value)
207 {
208 return memcached_increment_with_initial_by_key(ptr, key, key_length,
209 key, key_length,
210 offset, initial, expiration, value);
211 }
212
213 memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
214 const char *master_key,
215 size_t master_key_length,
216 const char *key,
217 size_t key_length,
218 uint64_t offset,
219 uint64_t initial,
220 time_t expiration,
221 uint64_t *value)
222 {
223 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
224 unlikely (rc != MEMCACHED_SUCCESS)
225 return rc;
226
227 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
228 if (ptr->flags.binary_protocol)
229 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
230 master_key, master_key_length, key, key_length,
231 offset, initial, (uint32_t)expiration,
232 value);
233 else
234 rc= MEMCACHED_PROTOCOL_ERROR;
235
236 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
237
238 return rc;
239 }
240
241 memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
242 const char *key,
243 size_t key_length,
244 uint64_t offset,
245 uint64_t initial,
246 time_t expiration,
247 uint64_t *value)
248 {
249 return memcached_decrement_with_initial_by_key(ptr, key, key_length,
250 key, key_length,
251 offset, initial, expiration, value);
252 }
253
254 memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
255 const char *master_key,
256 size_t master_key_length,
257 const char *key,
258 size_t key_length,
259 uint64_t offset,
260 uint64_t initial,
261 time_t expiration,
262 uint64_t *value)
263 {
264 memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
265 unlikely (rc != MEMCACHED_SUCCESS)
266 return rc;
267
268 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
269 if (ptr->flags.binary_protocol)
270 {
271 rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
272 master_key, master_key_length, key, key_length,
273 offset, initial, (uint32_t)expiration,
274 value);
275 }
276 else
277 {
278 rc= MEMCACHED_PROTOCOL_ERROR;
279 }
280
281 LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
282
283 return rc;
284 }
285