Merge trunk
[awesomized/libmemcached] / example / interface_v1.c
1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /**
3 * This file contains an implementation of the callback interface for level 1
4 * in the protocol library. If you compare the implementation with the one
5 * in interface_v0.c you will see that this implementation is much easier and
6 * hides all of the protocol logic and let you focus on the application
7 * logic. One "problem" with this layer is that it is synchronous, so that
8 * you will not receive the next command before a answer to the previous
9 * command is being sent.
10 */
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netdb.h>
15 #include <netinet/tcp.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <libmemcached/protocol_handler.h>
24 #include "common.h"
25 #include "storage.h"
26
27 static protocol_binary_response_status add_handler(const void *cookie,
28 const void *key,
29 uint16_t keylen,
30 const void *data,
31 uint32_t datalen,
32 uint32_t flags,
33 uint32_t exptime,
34 uint64_t *cas)
35 {
36 (void)cookie;
37 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
38 struct item* item= get_item(key, keylen);
39 if (item == NULL)
40 {
41 item= create_item(key, keylen, data, datalen, flags, exptime);
42 if (item == 0)
43 {
44 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
45 }
46 else
47 {
48 put_item(item);
49 *cas= item->cas;
50 }
51 }
52 else
53 {
54 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
55 }
56
57 return rval;
58 }
59
60 static protocol_binary_response_status append_handler(const void *cookie,
61 const void *key,
62 uint16_t keylen,
63 const void* val,
64 uint32_t vallen,
65 uint64_t cas,
66 uint64_t *result_cas) {
67 (void)cookie;
68 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
69
70 struct item *item= get_item(key, keylen);
71 struct item *nitem;
72
73 if (item == NULL)
74 {
75 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
76 }
77 else if (cas != 0 && cas != item->cas)
78 {
79 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
80 }
81 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
82 item->flags, item->exp)) == NULL)
83 {
84 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
85 }
86 else
87 {
88 memcpy(nitem->data, item->data, item->size);
89 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
90 delete_item(key, keylen);
91 put_item(nitem);
92 *result_cas= nitem->cas;
93 }
94
95 return rval;
96 }
97
98 static protocol_binary_response_status decrement_handler(const void *cookie,
99 const void *key,
100 uint16_t keylen,
101 uint64_t delta,
102 uint64_t initial,
103 uint32_t expiration,
104 uint64_t *result,
105 uint64_t *result_cas) {
106 (void)cookie;
107 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
108 struct item *item= get_item(key, keylen);
109
110 if (item == NULL)
111 {
112 item= create_item(key, keylen, NULL, sizeof(initial), 0, expiration);
113 if (item == 0)
114 {
115 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
116 }
117 else
118 {
119 memcpy(item->data, &initial, sizeof(initial));
120 put_item(item);
121 *result= initial;
122 *result_cas= item->cas;
123 }
124 }
125 else
126 {
127 if (delta > *(uint64_t*)item->data)
128 {
129 *(uint64_t*)item->data= 0;
130 }
131 else
132 {
133 *(uint64_t*)item->data -= delta;
134 }
135 *result= (*(uint64_t*)item->data);
136 /* @todo fix cas */
137 }
138
139 return rval;
140 }
141
142 static protocol_binary_response_status delete_handler(const void *cookie,
143 const void *key,
144 uint16_t keylen,
145 uint64_t cas) {
146 (void)cookie;
147 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
148
149 if (cas != 0)
150 {
151 struct item *item= get_item(key, keylen);
152 if (item != NULL && item->cas != cas)
153 {
154 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
155 }
156 }
157
158 if (!delete_item(key, keylen))
159 {
160 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
161 }
162
163 return rval;
164 }
165
166
167 static protocol_binary_response_status flush_handler(const void *cookie,
168 uint32_t when) {
169
170 (void)cookie;
171 flush(when);
172 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
173 }
174
175 static protocol_binary_response_status get_handler(const void *cookie,
176 const void *key,
177 uint16_t keylen,
178 memcached_binary_protocol_get_response_handler response_handler) {
179 struct item *item= get_item(key, keylen);
180
181 if (item == NULL)
182 {
183 return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
184 }
185
186 return response_handler(cookie, key, (uint16_t)keylen,
187 item->data, (uint32_t)item->size, item->flags,
188 item->cas);
189 }
190
191 static protocol_binary_response_status increment_handler(const void *cookie,
192 const void *key,
193 uint16_t keylen,
194 uint64_t delta,
195 uint64_t initial,
196 uint32_t expiration,
197 uint64_t *result,
198 uint64_t *result_cas) {
199 (void)cookie;
200 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
201 struct item *item= get_item(key, keylen);
202
203 if (item == NULL)
204 {
205 item= create_item(key, keylen, NULL, sizeof(initial), 0, expiration);
206 if (item == 0)
207 {
208 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
209 }
210 else
211 {
212 memcpy(item->data, &initial, sizeof(initial));
213 put_item(item);
214 *result= initial;
215 *result_cas= item->cas;
216 }
217 }
218 else
219 {
220 (*(uint64_t*)item->data) += delta;
221 *result= (*(uint64_t*)item->data);
222 update_cas(item);
223 *result_cas= item->cas;
224 }
225
226 return rval;
227 }
228
229 static protocol_binary_response_status noop_handler(const void *cookie) {
230 (void)cookie;
231 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
232 }
233
234 static protocol_binary_response_status prepend_handler(const void *cookie,
235 const void *key,
236 uint16_t keylen,
237 const void* val,
238 uint32_t vallen,
239 uint64_t cas,
240 uint64_t *result_cas) {
241 (void)cookie;
242 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
243
244 struct item *item= get_item(key, keylen);
245 struct item *nitem;
246 if (item == NULL)
247 {
248 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
249 }
250 else if (cas != 0 && cas != item->cas)
251 {
252 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
253 }
254 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
255 item->flags, item->exp)) == NULL)
256 {
257 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
258 }
259 else
260 {
261 memcpy(nitem->data, val, vallen);
262 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
263 delete_item(key, keylen);
264 put_item(nitem);
265 *result_cas= nitem->cas;
266 }
267
268 return rval;
269 }
270
271 static protocol_binary_response_status quit_handler(const void *cookie) {
272 (void)cookie;
273 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
274 }
275
276 static protocol_binary_response_status replace_handler(const void *cookie,
277 const void *key,
278 uint16_t keylen,
279 const void* data,
280 uint32_t datalen,
281 uint32_t flags,
282 uint32_t exptime,
283 uint64_t cas,
284 uint64_t *result_cas) {
285 (void)cookie;
286 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
287 struct item* item= get_item(key, keylen);
288
289 if (item == NULL)
290 {
291 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
292 }
293 else if (cas == 0 || cas == item->cas)
294 {
295 delete_item(key, keylen);
296 item= create_item(key, keylen, data, datalen, flags, exptime);
297 if (item == 0)
298 {
299 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
300 }
301 else
302 {
303 put_item(item);
304 *result_cas= item->cas;
305 }
306 }
307 else
308 {
309 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
310 }
311
312 return rval;
313 }
314
315 static protocol_binary_response_status set_handler(const void *cookie,
316 const void *key,
317 uint16_t keylen,
318 const void* data,
319 uint32_t datalen,
320 uint32_t flags,
321 uint32_t exptime,
322 uint64_t cas,
323 uint64_t *result_cas) {
324 (void)cookie;
325 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
326
327 if (cas != 0)
328 {
329 struct item* item= get_item(key, keylen);
330 if (item != NULL && cas != item->cas)
331 {
332 /* Invalid CAS value */
333 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
334 }
335 }
336
337 delete_item(key, keylen);
338 struct item* item= create_item(key, keylen, data, datalen, flags, exptime);
339 if (item == 0)
340 {
341 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
342 }
343 else
344 {
345 put_item(item);
346 *result_cas= item->cas;
347 }
348
349 return rval;
350 }
351
352 static protocol_binary_response_status stat_handler(const void *cookie,
353 const void *key,
354 uint16_t keylen,
355 memcached_binary_protocol_stat_response_handler response_handler) {
356 (void)key;
357 (void)keylen;
358 /* Just return an empty packet */
359 return response_handler(cookie, NULL, 0, NULL, 0);
360 }
361
362 static protocol_binary_response_status version_handler(const void *cookie,
363 memcached_binary_protocol_version_response_handler response_handler) {
364 const char *version= "0.1.1";
365 return response_handler(cookie, version, (uint32_t)strlen(version));
366 }
367
368 struct memcached_binary_protocol_callback_st interface_v1_impl= {
369 .interface_version= 1,
370 .interface.v1= {
371 .add= add_handler,
372 .append= append_handler,
373 .decrement= decrement_handler,
374 .delete= delete_handler,
375 .flush= flush_handler,
376 .get= get_handler,
377 .increment= increment_handler,
378 .noop= noop_handler,
379 .prepend= prepend_handler,
380 .quit= quit_handler,
381 .replace= replace_handler,
382 .set= set_handler,
383 .stat= stat_handler,
384 .version= version_handler
385 }
386 };