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