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