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