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