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