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