memcached_quit should clear internal server variables
[m6w6/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 <sys/socket.h>
11 #include <netdb.h>
12 #include <netinet/tcp.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <libmemcached/protocol_handler.h>
21 #include <libmemcached/byteorder.h>
22 #include "storage.h"
23 #include "memcached_light.h"
24
25 static protocol_binary_response_status noop_command_handler(const void *cookie,
26 protocol_binary_request_header *header,
27 memcached_binary_protocol_raw_response_handler response_handler)
28 {
29 protocol_binary_response_no_extras response= {
30 .message.header.response= {
31 .magic= PROTOCOL_BINARY_RES,
32 .opcode= PROTOCOL_BINARY_CMD_NOOP,
33 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
34 .opaque= header->request.opaque
35 }
36 };
37
38 return response_handler(cookie, header, (void*)&response);
39 }
40
41 static protocol_binary_response_status quit_command_handler(const void *cookie,
42 protocol_binary_request_header *header,
43 memcached_binary_protocol_raw_response_handler response_handler)
44 {
45 protocol_binary_response_no_extras response= {
46 .message.header.response= {
47 .magic= PROTOCOL_BINARY_RES,
48 .opcode= PROTOCOL_BINARY_CMD_QUIT,
49 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
50 .opaque= header->request.opaque
51 }
52 };
53
54 if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
55 response_handler(cookie, header, (void*)&response);
56
57 /* I need a better way to signal to close the connection */
58 return PROTOCOL_BINARY_RESPONSE_EIO;
59 }
60
61 static protocol_binary_response_status get_command_handler(const void *cookie,
62 protocol_binary_request_header *header,
63 memcached_binary_protocol_raw_response_handler response_handler)
64 {
65 uint8_t opcode= header->request.opcode;
66 union {
67 protocol_binary_response_get response;
68 char buffer[4096];
69 } msg= {
70 .response.message.header.response= {
71 .magic= PROTOCOL_BINARY_RES,
72 .opcode= opcode,
73 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
74 .opaque= header->request.opaque
75 }
76 };
77
78 struct item *item= get_item(header + 1, ntohs(header->request.keylen));
79 if (item)
80 {
81 msg.response.message.body.flags= htonl(item->flags);
82 char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
83 uint32_t bodysize= 4;
84 msg.response.message.header.response.cas= htonll(item->cas);
85 if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
86 {
87 memcpy(ptr, item->key, item->nkey);
88 msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
89 ptr += item->nkey;
90 bodysize += (uint32_t)item->nkey;
91 }
92 memcpy(ptr, item->data, item->size);
93 bodysize += (uint32_t)item->size;
94 msg.response.message.header.response.bodylen= htonl(bodysize);
95 msg.response.message.header.response.extlen= 4;
96
97 release_item(item);
98 return response_handler(cookie, header, (void*)&msg);
99 }
100 else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
101 {
102 msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
103 return response_handler(cookie, header, (void*)&msg);
104 }
105
106 /* Q shouldn't report a miss ;-) */
107 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
108 }
109
110 static protocol_binary_response_status delete_command_handler(const void *cookie,
111 protocol_binary_request_header *header,
112 memcached_binary_protocol_raw_response_handler response_handler)
113 {
114 size_t keylen= ntohs(header->request.keylen);
115 char *key= ((char*)header) + sizeof(*header);
116 protocol_binary_response_no_extras response= {
117 .message.header.response= {
118 .magic= PROTOCOL_BINARY_RES,
119 .opcode= header->request.opcode,
120 .opaque= header->request.opaque
121 }
122 };
123
124 if (!delete_item(key, keylen))
125 {
126 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
127 return response_handler(cookie, header, (void*)&response);
128 }
129 else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
130 {
131 /* DELETEQ doesn't want success response */
132 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
133 return response_handler(cookie, header, (void*)&response);
134 }
135
136 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
137 }
138
139 static protocol_binary_response_status flush_command_handler(const void *cookie,
140 protocol_binary_request_header *header,
141 memcached_binary_protocol_raw_response_handler response_handler)
142 {
143 uint8_t opcode= header->request.opcode;
144
145 /* @fixme sett inn when! */
146 flush(0);
147
148 if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
149 {
150 protocol_binary_response_no_extras response= {
151 .message.header.response= {
152 .magic= PROTOCOL_BINARY_RES,
153 .opcode= opcode,
154 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
155 .opaque= header->request.opaque
156 }
157 };
158 return response_handler(cookie, header, (void*)&response);
159 }
160
161 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
162 }
163
164 static protocol_binary_response_status arithmetic_command_handler(const void *cookie,
165 protocol_binary_request_header *header,
166 memcached_binary_protocol_raw_response_handler response_handler)
167 {
168 protocol_binary_request_incr *req= (void*)header;
169 protocol_binary_response_incr response= {
170 .message.header.response= {
171 .magic= PROTOCOL_BINARY_RES,
172 .opcode= header->request.opcode,
173 .opaque= header->request.opaque,
174 },
175 };
176
177 uint16_t keylen= ntohs(header->request.keylen);
178 uint64_t initial= ntohll(req->message.body.initial);
179 uint64_t delta= ntohll(req->message.body.delta);
180 uint32_t expiration= ntohl(req->message.body.expiration);
181 uint32_t flags= 0;
182 void *key= req->bytes + sizeof(req->bytes);
183 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
184
185 uint64_t value= initial;
186
187 struct item *item= get_item(key, keylen);
188 if (item != NULL)
189 {
190 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
191 header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
192 {
193 value= (*(uint64_t*)item->data) + delta;
194 }
195 else
196 {
197 if (delta > *(uint64_t*)item->data)
198 {
199 value= 0;
200 }
201 else
202 {
203 value= *(uint64_t*)item->data - delta;
204 }
205 }
206 expiration= (uint32_t)item->exp;
207 flags= item->flags;
208
209 release_item(item);
210 delete_item(key, keylen);
211 }
212
213 item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
214 if (item == NULL)
215 {
216 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
217 }
218 else
219 {
220 memcpy(item->data, &value, sizeof(value));
221 put_item(item);
222 }
223
224 response.message.header.response.status= htons(rval);
225 if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
226 {
227 response.message.header.response.bodylen= ntohl(8);
228 response.message.body.value= ntohll((*(uint64_t*)item->data));
229 response.message.header.response.cas= ntohll(item->cas);
230
231 release_item(item);
232 if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
233 header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
234 {
235 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
236 }
237 }
238
239 return response_handler(cookie, header, (void*)&response);
240 }
241
242 static protocol_binary_response_status version_command_handler(const void *cookie,
243 protocol_binary_request_header *header,
244 memcached_binary_protocol_raw_response_handler response_handler)
245 {
246 const char *versionstring= "1.0.0";
247 union {
248 protocol_binary_response_header packet;
249 char buffer[256];
250 } response= {
251 .packet.response= {
252 .magic= PROTOCOL_BINARY_RES,
253 .opcode= PROTOCOL_BINARY_CMD_VERSION,
254 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
255 .opaque= header->request.opaque,
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= 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= 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 != 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= 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= 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 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
474 else if (header->request.cas == 0 || ntohll(header->request.cas) == item->cas)
475 {
476 release_item(item);
477 delete_item(key, keylen);
478 item= create_item(key, keylen, data, datalen, flags, timeout);
479 if (item == NULL)
480 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
481 else
482 {
483 put_item(item);
484 /* REPLACEQ shouldn't return a message */
485 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
486 {
487 response.message.header.response.cas= htonll(item->cas);
488 release_item(item);
489 return response_handler(cookie, header, (void*)&response);
490 }
491 release_item(item);
492 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
493 }
494 }
495 else
496 {
497 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
498 release_item(item);
499 }
500
501 return response_handler(cookie, header, (void*)&response);
502 }
503
504 static protocol_binary_response_status stat_command_handler(const void *cookie,
505 protocol_binary_request_header *header,
506 memcached_binary_protocol_raw_response_handler response_handler)
507 {
508 /* Just send the terminating packet*/
509 protocol_binary_response_no_extras response= {
510 .message= {
511 .header.response= {
512 .magic= PROTOCOL_BINARY_RES,
513 .opcode= PROTOCOL_BINARY_CMD_STAT,
514 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
515 .opaque= header->request.opaque
516 }
517 }
518 };
519
520 return response_handler(cookie, header, (void*)&response);
521 }
522
523 memcached_binary_protocol_callback_st interface_v0_impl= {
524 .interface_version= MEMCACHED_PROTOCOL_HANDLER_V0,
525 #ifdef FUTURE
526 /*
527 ** There is a number of bugs in the extra options for gcc causing
528 ** warning on these struct initializers. It hurts my heart to remove
529 ** it so I'll just leave it in here so that we can enable it when
530 ** we can drop support for the broken compilers
531 */
532 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler,
533 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler,
534 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
535 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
536 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
537 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler,
538 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler,
539 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
540 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
541 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
542 .interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
543 .interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
544 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
545 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
546 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler,
547 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler,
548 .interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
549 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
550 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
551 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
552 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
553 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler,
554 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler,
555 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
556 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
557 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler,
558 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler,
559 #endif
560 };
561
562 void initialize_interface_v0_handler(void)
563 {
564 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
565 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
566 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
567 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
568 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
569 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
570 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
571 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
572 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
573 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
574 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
575 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
576 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
577 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
578 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
579 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
580 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
581 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
582 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
583 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
584 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
585 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
586 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
587 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
588 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
589 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
590 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
591 }