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