Rollup merge.
[awesomized/libmemcached] / example / interface_v0.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 0
4 * in the protocol library. You might want to have your copy of the protocol
5 * specification next to your coffee ;-)
6 */
7 #include "config.h"
8 #include <assert.h>
9 #include <sys/types.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <libmemcached/protocol_handler.h>
18 #include <libmemcached/byteorder.h>
19 #include "storage.h"
20 #include "memcached_light.h"
21
22 static protocol_binary_response_status noop_command_handler(const void *cookie,
23 protocol_binary_request_header *header,
24 memcached_binary_protocol_raw_response_handler response_handler)
25 {
26 protocol_binary_response_no_extras response= {
27 .message.header.response= {
28 .magic= PROTOCOL_BINARY_RES,
29 .opcode= PROTOCOL_BINARY_CMD_NOOP,
30 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
31 .opaque= header->request.opaque
32 }
33 };
34
35 return response_handler(cookie, header, (void*)&response);
36 }
37
38 static protocol_binary_response_status quit_command_handler(const void *cookie,
39 protocol_binary_request_header *header,
40 memcached_binary_protocol_raw_response_handler response_handler)
41 {
42 protocol_binary_response_no_extras response= {
43 .message.header.response= {
44 .magic= PROTOCOL_BINARY_RES,
45 .opcode= PROTOCOL_BINARY_CMD_QUIT,
46 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
47 .opaque= header->request.opaque
48 }
49 };
50
51 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
52 response_handler(cookie, header, (void*)&response);
53
54 /* I need a better way to signal to close the connection */
55 return PROTOCOL_BINARY_RESPONSE_EIO;
56 }
57
58 static protocol_binary_response_status get_command_handler(const void *cookie,
59 protocol_binary_request_header *header,
60 memcached_binary_protocol_raw_response_handler response_handler)
61 {
62 uint8_t opcode= header->request.opcode;
63 union {
64 protocol_binary_response_get response;
65 char buffer[4096];
66 } msg= {
67 .response.message.header.response= {
68 .magic= PROTOCOL_BINARY_RES,
69 .opcode= opcode,
70 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
71 .opaque= header->request.opaque
72 }
73 };
74
75 struct item *item= get_item(header + 1, ntohs(header->request.keylen));
76 if (item)
77 {
78 msg.response.message.body.flags= htonl(item->flags);
79 char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
80 uint32_t bodysize= 4;
81 msg.response.message.header.response.cas= htonll(item->cas);
82 if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
83 {
84 memcpy(ptr, item->key, item->nkey);
85 msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
86 ptr += item->nkey;
87 bodysize += (uint32_t)item->nkey;
88 }
89 memcpy(ptr, item->data, item->size);
90 bodysize += (uint32_t)item->size;
91 msg.response.message.header.response.bodylen= htonl(bodysize);
92 msg.response.message.header.response.extlen= 4;
93
94 release_item(item);
95 return response_handler(cookie, header, (void*)&msg);
96 }
97 else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
98 {
99 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
100 return response_handler(cookie, header, (void*)&msg);
101 }
102
103 /* Q shouldn't report a miss ;-) */
104 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
105 }
106
107 static protocol_binary_response_status delete_command_handler(const void *cookie,
108 protocol_binary_request_header *header,
109 memcached_binary_protocol_raw_response_handler response_handler)
110 {
111 size_t keylen= ntohs(header->request.keylen);
112 char *key= ((char*)header) + sizeof(*header);
113 protocol_binary_response_no_extras response= {
114 .message.header.response= {
115 .magic= PROTOCOL_BINARY_RES,
116 .opcode= header->request.opcode,
117 .opaque= header->request.opaque
118 }
119 };
120
121 if (!delete_item(key, keylen))
122 {
123 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
124 return response_handler(cookie, header, (void*)&response);
125 }
126 else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
127 {
128 /* DELETEQ doesn't want success response */
129 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
130 return response_handler(cookie, header, (void*)&response);
131 }
132
133 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
134 }
135
136 static protocol_binary_response_status flush_command_handler(const void *cookie,
137 protocol_binary_request_header *header,
138 memcached_binary_protocol_raw_response_handler response_handler)
139 {
140 uint8_t opcode= header->request.opcode;
141
142 /* @fixme sett inn when! */
143 flush(0);
144
145 if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
146 {
147 protocol_binary_response_no_extras response= {
148 .message.header.response= {
149 .magic= PROTOCOL_BINARY_RES,
150 .opcode= opcode,
151 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
152 .opaque= header->request.opaque
153 }
154 };
155 return response_handler(cookie, header, (void*)&response);
156 }
157
158 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
159 }
160
161 static protocol_binary_response_status arithmetic_command_handler(const void *cookie,
162 protocol_binary_request_header *header,
163 memcached_binary_protocol_raw_response_handler response_handler)
164 {
165 protocol_binary_request_incr *req= (void*)header;
166 protocol_binary_response_incr response= {
167 .message.header.response= {
168 .magic= PROTOCOL_BINARY_RES,
169 .opcode= header->request.opcode,
170 .opaque= header->request.opaque,
171 },
172 };
173
174 uint16_t keylen= ntohs(header->request.keylen);
175 uint64_t initial= ntohll(req->message.body.initial);
176 uint64_t delta= ntohll(req->message.body.delta);
177 uint32_t expiration= ntohl(req->message.body.expiration);
178 uint32_t flags= 0;
179 void *key= req->bytes + sizeof(req->bytes);
180 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
181
182 uint64_t value= initial;
183
184 struct item *item= get_item(key, keylen);
185 if (item != NULL)
186 {
187 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
188 header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
189 {
190 value= (*(uint64_t*)item->data) + delta;
191 }
192 else
193 {
194 if (delta > *(uint64_t*)item->data)
195 {
196 value= 0;
197 }
198 else
199 {
200 value= *(uint64_t*)item->data - delta;
201 }
202 }
203 expiration= (uint32_t)item->exp;
204 flags= item->flags;
205
206 release_item(item);
207 delete_item(key, keylen);
208 }
209
210 item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
211 if (item == NULL)
212 {
213 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
214 }
215 else
216 {
217 memcpy(item->data, &value, sizeof(value));
218 put_item(item);
219 }
220
221 response.message.header.response.status= htons(rval);
222 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
223 {
224 response.message.header.response.bodylen= ntohl(8);
225 response.message.body.value= ntohll((*(uint64_t*)item->data));
226 response.message.header.response.cas= ntohll(item->cas);
227
228 release_item(item);
229 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
230 header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
231 {
232 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
233 }
234 }
235
236 return response_handler(cookie, header, (void*)&response);
237 }
238
239 static protocol_binary_response_status version_command_handler(const void *cookie,
240 protocol_binary_request_header *header,
241 memcached_binary_protocol_raw_response_handler response_handler)
242 {
243 const char *versionstring= "1.0.0";
244 union {
245 protocol_binary_response_header packet;
246 char buffer[256];
247 } response= {
248 .packet.response= {
249 .magic= PROTOCOL_BINARY_RES,
250 .opcode= PROTOCOL_BINARY_CMD_VERSION,
251 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
252 .opaque= header->request.opaque,
253 .bodylen= htonl((uint32_t)strlen(versionstring))
254 }
255 };
256
257 memcpy(response.buffer + sizeof(response.packet), versionstring, strlen(versionstring));
258
259 return response_handler(cookie, header, (void*)&response);
260 }
261
262 static protocol_binary_response_status concat_command_handler(const void *cookie,
263 protocol_binary_request_header *header,
264 memcached_binary_protocol_raw_response_handler response_handler)
265 {
266 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
267 uint16_t keylen= ntohs(header->request.keylen);
268 uint64_t cas= ntohll(header->request.cas);
269 void *key= header + 1;
270 uint32_t vallen= ntohl(header->request.bodylen) - keylen;
271 void *val= (char*)key + keylen;
272
273 struct item *item= get_item(key, keylen);
274 struct item *nitem= NULL;
275
276 if (item == NULL)
277 {
278 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
279 }
280 else if (cas != 0 && cas != item->cas)
281 {
282 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
283 }
284 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
285 item->flags, item->exp)) == NULL)
286 {
287 release_item(item);
288 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
289 }
290 else
291 {
292 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
293 header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
294 {
295 memcpy(nitem->data, item->data, item->size);
296 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
297 }
298 else
299 {
300 memcpy(nitem->data, val, vallen);
301 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
302 }
303 release_item(item);
304 delete_item(key, keylen);
305 put_item(nitem);
306 cas= nitem->cas;
307 release_item(nitem);
308
309 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
310 header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
311 {
312 protocol_binary_response_no_extras response= {
313 .message= {
314 .header.response= {
315 .magic= PROTOCOL_BINARY_RES,
316 .opcode= header->request.opcode,
317 .status= htons(rval),
318 .opaque= header->request.opaque,
319 .cas= htonll(cas),
320 }
321 }
322 };
323 return response_handler(cookie, header, (void*)&response);
324 }
325 }
326
327 return rval;
328 }
329
330 static protocol_binary_response_status set_command_handler(const void *cookie,
331 protocol_binary_request_header *header,
332 memcached_binary_protocol_raw_response_handler response_handler)
333 {
334 size_t keylen= ntohs(header->request.keylen);
335 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
336 protocol_binary_request_replace *request= (void*)header;
337 uint32_t flags= ntohl(request->message.body.flags);
338 time_t timeout= (time_t)ntohl(request->message.body.expiration);
339 char *key= ((char*)header) + sizeof(*header) + 8;
340 char *data= key + keylen;
341
342 protocol_binary_response_no_extras response= {
343 .message= {
344 .header.response= {
345 .magic= PROTOCOL_BINARY_RES,
346 .opcode= header->request.opcode,
347 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
348 .opaque= header->request.opaque
349 }
350 }
351 };
352
353 if (header->request.cas != 0)
354 {
355 /* validate cas */
356 struct item* item= get_item(key, keylen);
357 if (item != NULL)
358 {
359 if (item->cas != ntohll(header->request.cas))
360 {
361 release_item(item);
362 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
363 return response_handler(cookie, header, (void*)&response);
364 }
365 release_item(item);
366 }
367 }
368
369 delete_item(key, keylen);
370 struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
371 if (item == NULL)
372 {
373 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
374 }
375 else
376 {
377 put_item(item);
378 /* SETQ shouldn't return a message */
379 if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
380 {
381 response.message.header.response.cas= htonll(item->cas);
382 release_item(item);
383 return response_handler(cookie, header, (void*)&response);
384 }
385 release_item(item);
386
387 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
388 }
389
390 return response_handler(cookie, header, (void*)&response);
391 }
392
393 static protocol_binary_response_status add_command_handler(const void *cookie,
394 protocol_binary_request_header *header,
395 memcached_binary_protocol_raw_response_handler response_handler)
396 {
397 size_t keylen= ntohs(header->request.keylen);
398 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
399 protocol_binary_request_add *request= (void*)header;
400 uint32_t flags= ntohl(request->message.body.flags);
401 time_t timeout= (time_t)ntohl(request->message.body.expiration);
402 char *key= ((char*)header) + sizeof(*header) + 8;
403 char *data= key + keylen;
404
405 protocol_binary_response_no_extras response= {
406 .message= {
407 .header.response= {
408 .magic= PROTOCOL_BINARY_RES,
409 .opcode= header->request.opcode,
410 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
411 .opaque= header->request.opaque
412 }
413 }
414 };
415
416 struct item* item= get_item(key, keylen);
417 if (item == NULL)
418 {
419 item= create_item(key, keylen, data, datalen, flags, timeout);
420 if (item == NULL)
421 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
422 else
423 {
424 put_item(item);
425 /* ADDQ shouldn't return a message */
426 if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
427 {
428 response.message.header.response.cas= htonll(item->cas);
429 release_item(item);
430 return response_handler(cookie, header, (void*)&response);
431 }
432 release_item(item);
433 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
434 }
435 }
436 else
437 {
438 release_item(item);
439 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
440 }
441
442 return response_handler(cookie, header, (void*)&response);
443 }
444
445 static protocol_binary_response_status replace_command_handler(const void *cookie,
446 protocol_binary_request_header *header,
447 memcached_binary_protocol_raw_response_handler response_handler)
448 {
449 size_t keylen= ntohs(header->request.keylen);
450 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
451 protocol_binary_request_replace *request= (void*)header;
452 uint32_t flags= ntohl(request->message.body.flags);
453 time_t timeout= (time_t)ntohl(request->message.body.expiration);
454 char *key= ((char*)header) + sizeof(*header) + 8;
455 char *data= key + keylen;
456
457 protocol_binary_response_no_extras response= {
458 .message= {
459 .header.response= {
460 .magic= PROTOCOL_BINARY_RES,
461 .opcode= header->request.opcode,
462 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
463 .opaque= header->request.opaque
464 }
465 }
466 };
467
468 struct item* item= get_item(key, keylen);
469 if (item == NULL)
470 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
471 else if (header->request.cas == 0 || ntohll(header->request.cas) == item->cas)
472 {
473 release_item(item);
474 delete_item(key, keylen);
475 item= create_item(key, keylen, data, datalen, flags, timeout);
476 if (item == NULL)
477 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
478 else
479 {
480 put_item(item);
481 /* REPLACEQ shouldn't return a message */
482 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
483 {
484 response.message.header.response.cas= htonll(item->cas);
485 release_item(item);
486 return response_handler(cookie, header, (void*)&response);
487 }
488 release_item(item);
489 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
490 }
491 }
492 else
493 {
494 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
495 release_item(item);
496 }
497
498 return response_handler(cookie, header, (void*)&response);
499 }
500
501 static protocol_binary_response_status stat_command_handler(const void *cookie,
502 protocol_binary_request_header *header,
503 memcached_binary_protocol_raw_response_handler response_handler)
504 {
505 /* Just send the terminating packet*/
506 protocol_binary_response_no_extras response= {
507 .message= {
508 .header.response= {
509 .magic= PROTOCOL_BINARY_RES,
510 .opcode= PROTOCOL_BINARY_CMD_STAT,
511 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
512 .opaque= header->request.opaque
513 }
514 }
515 };
516
517 return response_handler(cookie, header, (void*)&response);
518 }
519
520 memcached_binary_protocol_callback_st interface_v0_impl= {
521 .interface_version= MEMCACHED_PROTOCOL_HANDLER_V0,
522 #ifdef FUTURE
523 /*
524 ** There is a number of bugs in the extra options for gcc causing
525 ** warning on these struct initializers. It hurts my heart to remove
526 ** it so I'll just leave it in here so that we can enable it when
527 ** we can drop support for the broken compilers
528 */
529 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler,
530 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler,
531 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
532 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
533 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
534 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler,
535 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler,
536 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
537 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
538 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
539 .interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
540 .interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
541 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
542 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
543 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler,
544 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler,
545 .interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
546 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
547 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
548 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
549 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
550 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler,
551 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler,
552 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
553 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
554 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler,
555 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler,
556 #endif
557 };
558
559 void initialize_interface_v0_handler(void)
560 {
561 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
562 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
563 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
564 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
565 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
566 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
567 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
568 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
569 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
570 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
571 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
572 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
573 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
574 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
575 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
576 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
577 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
578 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
579 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
580 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
581 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
582 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
583 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
584 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
585 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
586 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
587 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
588 }