Merge with build trunk.
[awesomized/libmemcached] / example / interface_v1.cc
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 "config.h"
12 #include <assert.h>
13 #include <sys/types.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <libmemcachedprotocol-0.0/handler.h>
22 #include <example/byteorder.h>
23 #include "example/memcached_light.h"
24 #include "example/storage.h"
25
26 static protocol_binary_response_status add_handler(const void *cookie,
27 const void *key,
28 uint16_t keylen,
29 const void *data,
30 uint32_t datalen,
31 uint32_t flags,
32 uint32_t exptime,
33 uint64_t *cas)
34 {
35 (void)cookie;
36 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
37 struct item* item= get_item(key, keylen);
38 if (item == NULL)
39 {
40 item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
41 if (item == 0)
42 {
43 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
44 }
45 else
46 {
47 put_item(item);
48 *cas= item->cas;
49 release_item(item);
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 {
68 (void)cookie;
69 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
70
71 struct item *item= get_item(key, keylen);
72 struct item *nitem;
73
74 if (item == NULL)
75 {
76 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
77 }
78 else if (cas != 0 && cas != item->cas)
79 {
80 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
81 }
82 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
83 item->flags, item->exp)) == NULL)
84 {
85 release_item(item);
86 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
87 }
88 else
89 {
90 memcpy(nitem->data, item->data, item->size);
91 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
92 release_item(item);
93 delete_item(key, keylen);
94 put_item(nitem);
95 *result_cas= nitem->cas;
96 release_item(nitem);
97 }
98
99 return rval;
100 }
101
102 static protocol_binary_response_status decrement_handler(const void *cookie,
103 const void *key,
104 uint16_t keylen,
105 uint64_t delta,
106 uint64_t initial,
107 uint32_t expiration,
108 uint64_t *result,
109 uint64_t *result_cas) {
110 (void)cookie;
111 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
112 uint64_t val= initial;
113 struct item *item= get_item(key, keylen);
114
115 if (item != NULL)
116 {
117 if (delta > *(uint64_t*)item->data)
118 val= 0;
119 else
120 val= *(uint64_t*)item->data - delta;
121
122 expiration= (uint32_t)item->exp;
123 release_item(item);
124 delete_item(key, keylen);
125 }
126
127 item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
128 if (item == 0)
129 {
130 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
131 }
132 else
133 {
134 memcpy(item->data, &val, sizeof(val));
135 put_item(item);
136 *result= val;
137 *result_cas= item->cas;
138 release_item(item);
139 }
140
141 return rval;
142 }
143
144 static protocol_binary_response_status delete_handler(const void *, // cookie
145 const void *key,
146 uint16_t keylen,
147 uint64_t cas)
148 {
149 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
150
151 if (cas != 0)
152 {
153 struct item *item= get_item(key, keylen);
154 if (item != NULL)
155 {
156 if (item->cas != cas)
157 {
158 release_item(item);
159 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
160 }
161 release_item(item);
162 }
163 }
164
165 if (!delete_item(key, keylen))
166 {
167 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
168 }
169
170 return rval;
171 }
172
173
174 static protocol_binary_response_status flush_handler(const void * /* cookie */, uint32_t /* when */)
175 {
176 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
177 }
178
179 static protocol_binary_response_status get_handler(const void *cookie,
180 const void *key,
181 uint16_t keylen,
182 memcached_binary_protocol_get_response_handler response_handler) {
183 struct item *item= get_item(key, keylen);
184
185 if (item == NULL)
186 {
187 return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
188 }
189
190 protocol_binary_response_status rc;
191 rc= response_handler(cookie, key, (uint16_t)keylen,
192 item->data, (uint32_t)item->size, item->flags,
193 item->cas);
194 release_item(item);
195 return rc;
196 }
197
198 static protocol_binary_response_status increment_handler(const void *cookie,
199 const void *key,
200 uint16_t keylen,
201 uint64_t delta,
202 uint64_t initial,
203 uint32_t expiration,
204 uint64_t *result,
205 uint64_t *result_cas) {
206 (void)cookie;
207 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
208 uint64_t val= initial;
209 struct item *item= get_item(key, keylen);
210
211 if (item != NULL)
212 {
213 val= (*(uint64_t*)item->data) + delta;
214 expiration= (uint32_t)item->exp;
215 release_item(item);
216 delete_item(key, keylen);
217 }
218
219 item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
220 if (item == NULL)
221 {
222 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
223 }
224 else
225 {
226 char buffer[1024] = {0};
227 memcpy(buffer, key, keylen);
228 memcpy(item->data, &val, sizeof(val));
229 put_item(item);
230 *result= val;
231 *result_cas= item->cas;
232 release_item(item);
233 }
234
235 return rval;
236 }
237
238 static protocol_binary_response_status noop_handler(const void *cookie) {
239 (void)cookie;
240 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
241 }
242
243 static protocol_binary_response_status prepend_handler(const void *cookie,
244 const void *key,
245 uint16_t keylen,
246 const void* val,
247 uint32_t vallen,
248 uint64_t cas,
249 uint64_t *result_cas) {
250 (void)cookie;
251 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
252
253 struct item *item= get_item(key, keylen);
254 struct item *nitem= NULL;
255
256 if (item == NULL)
257 {
258 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
259 }
260 else if (cas != 0 && cas != item->cas)
261 {
262 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
263 }
264 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
265 item->flags, item->exp)) == NULL)
266 {
267 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
268 }
269 else
270 {
271 memcpy(nitem->data, val, vallen);
272 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
273 release_item(item);
274 item= NULL;
275 delete_item(key, keylen);
276 put_item(nitem);
277 *result_cas= nitem->cas;
278 }
279
280 if (item)
281 release_item(item);
282
283 if (nitem)
284 release_item(nitem);
285
286 return rval;
287 }
288
289 static protocol_binary_response_status quit_handler(const void *) //cookie
290 {
291 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
292 }
293
294 static protocol_binary_response_status replace_handler(const void *, // cookie
295 const void *key,
296 uint16_t keylen,
297 const void* data,
298 uint32_t datalen,
299 uint32_t flags,
300 uint32_t exptime,
301 uint64_t cas,
302 uint64_t *result_cas)
303 {
304 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
305 struct item* item= get_item(key, keylen);
306
307 if (item == NULL)
308 {
309 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
310 }
311 else if (cas == 0 || cas == item->cas)
312 {
313 release_item(item);
314 delete_item(key, keylen);
315 item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
316 if (item == 0)
317 {
318 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
319 }
320 else
321 {
322 put_item(item);
323 *result_cas= item->cas;
324 release_item(item);
325 }
326 }
327 else
328 {
329 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
330 release_item(item);
331 }
332
333 return rval;
334 }
335
336 static protocol_binary_response_status set_handler(const void *cookie,
337 const void *key,
338 uint16_t keylen,
339 const void* data,
340 uint32_t datalen,
341 uint32_t flags,
342 uint32_t exptime,
343 uint64_t cas,
344 uint64_t *result_cas) {
345 (void)cookie;
346 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
347
348 if (cas != 0)
349 {
350 struct item* item= get_item(key, keylen);
351 if (item != NULL && cas != item->cas)
352 {
353 /* Invalid CAS value */
354 release_item(item);
355 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
356 }
357 }
358
359 delete_item(key, keylen);
360 struct item* item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
361 if (item == 0)
362 {
363 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
364 }
365 else
366 {
367 put_item(item);
368 *result_cas= item->cas;
369 release_item(item);
370 }
371
372 return rval;
373 }
374
375 static protocol_binary_response_status stat_handler(const void *cookie,
376 const void *, // key
377 uint16_t, // keylen,
378 memcached_binary_protocol_stat_response_handler response_handler)
379 {
380 /* Just return an empty packet */
381 return response_handler(cookie, NULL, 0, NULL, 0);
382 }
383
384 static protocol_binary_response_status version_handler(const void *cookie,
385 memcached_binary_protocol_version_response_handler response_handler)
386 {
387 const char *version= "0.1.1";
388 return response_handler(cookie, version, (uint32_t)strlen(version));
389 }
390
391 memcached_binary_protocol_callback_st interface_v1_impl;
392
393 void initialize_interface_v1_handler(void)
394 {
395 memset(&interface_v1_impl, 0, sizeof(memcached_binary_protocol_callback_st));
396
397 interface_v1_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V1;
398 interface_v1_impl.interface.v1.add= add_handler;
399 interface_v1_impl.interface.v1.append= append_handler;
400 interface_v1_impl.interface.v1.decrement= decrement_handler;
401 interface_v1_impl.interface.v1.delete_object= delete_handler;
402 interface_v1_impl.interface.v1.flush_object= flush_handler;
403 interface_v1_impl.interface.v1.get= get_handler;
404 interface_v1_impl.interface.v1.increment= increment_handler;
405 interface_v1_impl.interface.v1.noop= noop_handler;
406 interface_v1_impl.interface.v1.prepend= prepend_handler;
407 interface_v1_impl.interface.v1.quit= quit_handler;
408 interface_v1_impl.interface.v1.replace= replace_handler;
409 interface_v1_impl.interface.v1.set= set_handler;
410 interface_v1_impl.interface.v1.stat= stat_handler;
411 interface_v1_impl.interface.v1.version= version_handler;
412 }