WIP
[m6w6/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.cc 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 "mem_config.h"
12
13 #include <cassert>
14 #include <cerrno>
15 #include <cstdio>
16 #include <cstdlib>
17 #include <cstring>
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #if HAVE_UNISTD_H
21 # include <unistd.h>
22 #endif
23 #include <libmemcachedprotocol-0.0/handler.h>
24 #include <example/byteorder.h>
25 #include "example/memcached_light.h"
26 #include "example/storage.h"
27 #include "util/log.hpp"
28
29 static datadifferential::util::log_info_st *log_file= NULL;
30
31 static protocol_binary_response_status add_handler(const void *cookie,
32 const void *key,
33 uint16_t keylen,
34 const void *data,
35 uint32_t datalen,
36 uint32_t flags,
37 uint32_t exptime,
38 uint64_t *cas)
39 {
40 (void)cookie;
41 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
42 struct item* item= get_item(key, keylen);
43 if (item == NULL)
44 {
45 item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
46 if (item == 0)
47 {
48 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
49 }
50 else
51 {
52 put_item(item);
53 *cas= item->cas;
54 release_item(item);
55 }
56 }
57 else
58 {
59 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
60 }
61
62 return rval;
63 }
64
65 static protocol_binary_response_status append_handler(const void *cookie,
66 const void *key,
67 uint16_t keylen,
68 const void* val,
69 uint32_t vallen,
70 uint64_t cas,
71 uint64_t *result_cas)
72 {
73 (void)cookie;
74 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
75
76 struct item *item= get_item(key, keylen);
77 struct item *nitem;
78
79 if (item == NULL)
80 {
81 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
82 }
83 else if (cas != 0 && cas != item->cas)
84 {
85 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
86 }
87 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
88 item->flags, item->exp)) == NULL)
89 {
90 release_item(item);
91 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
92 }
93 else
94 {
95 memcpy(nitem->data, item->data, item->size);
96 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
97 release_item(item);
98 delete_item(key, keylen);
99 put_item(nitem);
100 *result_cas= nitem->cas;
101 release_item(nitem);
102 }
103
104 return rval;
105 }
106
107 static protocol_binary_response_status decrement_handler(const void *cookie,
108 const void *key,
109 uint16_t keylen,
110 uint64_t delta,
111 uint64_t initial,
112 uint32_t expiration,
113 uint64_t *result,
114 uint64_t *result_cas) {
115 (void)cookie;
116 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
117 uint64_t val= initial;
118 struct item *item= get_item(key, keylen);
119
120 if (item != NULL)
121 {
122 if (delta > *(uint64_t*)item->data)
123 val= 0;
124 else
125 val= *(uint64_t*)item->data - delta;
126
127 expiration= (uint32_t)item->exp;
128 release_item(item);
129 delete_item(key, keylen);
130 }
131
132 item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
133 if (item == 0)
134 {
135 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
136 }
137 else
138 {
139 memcpy(item->data, &val, sizeof(val));
140 put_item(item);
141 *result= val;
142 *result_cas= item->cas;
143 release_item(item);
144 }
145
146 return rval;
147 }
148
149 static protocol_binary_response_status delete_handler(const void *, // cookie
150 const void *key,
151 uint16_t keylen,
152 uint64_t cas)
153 {
154 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
155
156 if (cas != 0)
157 {
158 struct item *item= get_item(key, keylen);
159 if (item != NULL)
160 {
161 if (item->cas != cas)
162 {
163 release_item(item);
164 return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
165 }
166 release_item(item);
167 }
168 }
169
170 if (!delete_item(key, keylen))
171 {
172 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
173 }
174
175 return rval;
176 }
177
178
179 static protocol_binary_response_status flush_handler(const void * /* cookie */, uint32_t /* when */)
180 {
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 {
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 {
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 {
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 {
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
398 void initialize_interface_v1_handler(datadifferential::util::log_info_st& arg)
399 {
400 log_file= &arg;
401 memset(&interface_v1_impl, 0, sizeof(memcached_binary_protocol_callback_st));
402
403 interface_v1_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V1;
404 interface_v1_impl.interface.v1.add= add_handler;
405 interface_v1_impl.interface.v1.append= append_handler;
406 interface_v1_impl.interface.v1.decrement= decrement_handler;
407 interface_v1_impl.interface.v1.delete_object= delete_handler;
408 interface_v1_impl.interface.v1.flush_object= flush_handler;
409 interface_v1_impl.interface.v1.get= get_handler;
410 interface_v1_impl.interface.v1.increment= increment_handler;
411 interface_v1_impl.interface.v1.noop= noop_handler;
412 interface_v1_impl.interface.v1.prepend= prepend_handler;
413 interface_v1_impl.interface.v1.quit= quit_handler;
414 interface_v1_impl.interface.v1.replace= replace_handler;
415 interface_v1_impl.interface.v1.set= set_handler;
416 interface_v1_impl.interface.v1.stat= stat_handler;
417 interface_v1_impl.interface.v1.version= version_handler;
418 }