Standardize the snprintf() failure messages, and add tests for libmemcached_util_getpid()
[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 <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_EINTERNAL;
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= memcached_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= memcached_ntohll(req->message.body.initial);
176 uint64_t delta= memcached_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= memcached_ntohll((*(uint64_t*)item->data));
226 response.message.header.response.cas= memcached_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 .cas= 0,
254 .bodylen= htonl((uint32_t)strlen(versionstring))
255 }
256 };
257
258 memcpy(response.buffer + sizeof(response.packet), versionstring, strlen(versionstring));
259
260 return response_handler(cookie, header, (void*)&response);
261 }
262
263 static protocol_binary_response_status concat_command_handler(const void *cookie,
264 protocol_binary_request_header *header,
265 memcached_binary_protocol_raw_response_handler response_handler)
266 {
267 protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
268 uint16_t keylen= ntohs(header->request.keylen);
269 uint64_t cas= memcached_ntohll(header->request.cas);
270 void *key= header + 1;
271 uint32_t vallen= ntohl(header->request.bodylen) - keylen;
272 void *val= (char*)key + keylen;
273
274 struct item *item= get_item(key, keylen);
275 struct item *nitem= NULL;
276
277 if (item == NULL)
278 {
279 rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
280 }
281 else if (cas != 0 && cas != item->cas)
282 {
283 rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
284 }
285 else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
286 item->flags, item->exp)) == NULL)
287 {
288 release_item(item);
289 rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
290 }
291 else
292 {
293 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
294 header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
295 {
296 memcpy(nitem->data, item->data, item->size);
297 memcpy(((char*)(nitem->data)) + item->size, val, vallen);
298 }
299 else
300 {
301 memcpy(nitem->data, val, vallen);
302 memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
303 }
304 release_item(item);
305 delete_item(key, keylen);
306 put_item(nitem);
307 cas= nitem->cas;
308 release_item(nitem);
309
310 if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
311 header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
312 {
313 protocol_binary_response_no_extras response= {
314 .message= {
315 .header.response= {
316 .magic= PROTOCOL_BINARY_RES,
317 .opcode= header->request.opcode,
318 .status= htons(rval),
319 .opaque= header->request.opaque,
320 .cas= memcached_htonll(cas),
321 }
322 }
323 };
324 return response_handler(cookie, header, (void*)&response);
325 }
326 }
327
328 return rval;
329 }
330
331 static protocol_binary_response_status set_command_handler(const void *cookie,
332 protocol_binary_request_header *header,
333 memcached_binary_protocol_raw_response_handler response_handler)
334 {
335 size_t keylen= ntohs(header->request.keylen);
336 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
337 protocol_binary_request_replace *request= (void*)header;
338 uint32_t flags= ntohl(request->message.body.flags);
339 time_t timeout= (time_t)ntohl(request->message.body.expiration);
340 char *key= ((char*)header) + sizeof(*header) + 8;
341 char *data= key + keylen;
342
343 protocol_binary_response_no_extras response= {
344 .message= {
345 .header.response= {
346 .magic= PROTOCOL_BINARY_RES,
347 .opcode= header->request.opcode,
348 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
349 .opaque= header->request.opaque
350 }
351 }
352 };
353
354 if (header->request.cas != 0)
355 {
356 /* validate cas */
357 struct item* item= get_item(key, keylen);
358 if (item != NULL)
359 {
360 if (item->cas != memcached_ntohll(header->request.cas))
361 {
362 release_item(item);
363 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
364 return response_handler(cookie, header, (void*)&response);
365 }
366 release_item(item);
367 }
368 }
369
370 delete_item(key, keylen);
371 struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
372 if (item == NULL)
373 {
374 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
375 }
376 else
377 {
378 put_item(item);
379 /* SETQ shouldn't return a message */
380 if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
381 {
382 response.message.header.response.cas= memcached_htonll(item->cas);
383 release_item(item);
384 return response_handler(cookie, header, (void*)&response);
385 }
386 release_item(item);
387
388 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
389 }
390
391 return response_handler(cookie, header, (void*)&response);
392 }
393
394 static protocol_binary_response_status add_command_handler(const void *cookie,
395 protocol_binary_request_header *header,
396 memcached_binary_protocol_raw_response_handler response_handler)
397 {
398 size_t keylen= ntohs(header->request.keylen);
399 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
400 protocol_binary_request_add *request= (void*)header;
401 uint32_t flags= ntohl(request->message.body.flags);
402 time_t timeout= (time_t)ntohl(request->message.body.expiration);
403 char *key= ((char*)header) + sizeof(*header) + 8;
404 char *data= key + keylen;
405
406 protocol_binary_response_no_extras response= {
407 .message= {
408 .header.response= {
409 .magic= PROTOCOL_BINARY_RES,
410 .opcode= header->request.opcode,
411 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
412 .opaque= header->request.opaque
413 }
414 }
415 };
416
417 struct item* item= get_item(key, keylen);
418 if (item == NULL)
419 {
420 item= create_item(key, keylen, data, datalen, flags, timeout);
421 if (item == NULL)
422 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
423 else
424 {
425 put_item(item);
426 /* ADDQ shouldn't return a message */
427 if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
428 {
429 response.message.header.response.cas= memcached_htonll(item->cas);
430 release_item(item);
431 return response_handler(cookie, header, (void*)&response);
432 }
433 release_item(item);
434 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
435 }
436 }
437 else
438 {
439 release_item(item);
440 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
441 }
442
443 return response_handler(cookie, header, (void*)&response);
444 }
445
446 static protocol_binary_response_status replace_command_handler(const void *cookie,
447 protocol_binary_request_header *header,
448 memcached_binary_protocol_raw_response_handler response_handler)
449 {
450 size_t keylen= ntohs(header->request.keylen);
451 size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
452 protocol_binary_request_replace *request= (void*)header;
453 uint32_t flags= ntohl(request->message.body.flags);
454 time_t timeout= (time_t)ntohl(request->message.body.expiration);
455 char *key= ((char*)header) + sizeof(*header) + 8;
456 char *data= key + keylen;
457
458 protocol_binary_response_no_extras response= {
459 .message= {
460 .header.response= {
461 .magic= PROTOCOL_BINARY_RES,
462 .opcode= header->request.opcode,
463 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
464 .opaque= header->request.opaque
465 }
466 }
467 };
468
469 struct item* item= get_item(key, keylen);
470 if (item == NULL)
471 {
472 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
473 }
474 else if (header->request.cas == 0 || memcached_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
480 if (item == NULL)
481 {
482 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
483 }
484 else
485 {
486 put_item(item);
487 /* REPLACEQ shouldn't return a message */
488 if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
489 {
490 response.message.header.response.cas= memcached_htonll(item->cas);
491 release_item(item);
492 return response_handler(cookie, header, (void*)&response);
493 }
494 release_item(item);
495 return PROTOCOL_BINARY_RESPONSE_SUCCESS;
496 }
497 }
498 else
499 {
500 response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
501 release_item(item);
502 }
503
504 return response_handler(cookie, header, (void*)&response);
505 }
506
507 static protocol_binary_response_status stat_command_handler(const void *cookie,
508 protocol_binary_request_header *header,
509 memcached_binary_protocol_raw_response_handler response_handler)
510 {
511 /* Just send the terminating packet*/
512 protocol_binary_response_no_extras response= {
513 .message= {
514 .header.response= {
515 .magic= PROTOCOL_BINARY_RES,
516 .opcode= PROTOCOL_BINARY_CMD_STAT,
517 .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
518 .opaque= header->request.opaque
519 }
520 }
521 };
522
523 return response_handler(cookie, header, (void*)&response);
524 }
525
526 memcached_binary_protocol_callback_st interface_v0_impl= {
527 .interface_version= MEMCACHED_PROTOCOL_HANDLER_V0,
528 #ifdef FUTURE
529 /*
530 ** There is a number of bugs in the extra options for gcc causing
531 ** warning on these struct initializers. It hurts my heart to remove
532 ** it so I'll just leave it in here so that we can enable it when
533 ** we can drop support for the broken compilers
534 */
535 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler,
536 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler,
537 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
538 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
539 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
540 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler,
541 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler,
542 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
543 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
544 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
545 .interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
546 .interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
547 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
548 .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
549 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler,
550 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler,
551 .interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
552 .interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
553 .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
554 .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
555 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
556 .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler,
557 .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler,
558 .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
559 .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
560 .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler,
561 .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler,
562 #endif
563 };
564
565 void initialize_interface_v0_handler(void)
566 {
567 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
568 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
569 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
570 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
571 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
572 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
573 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
574 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
575 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
576 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
577 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
578 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
579 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
580 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
581 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
582 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
583 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
584 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
585 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
586 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
587 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
588 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
589 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
590 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
591 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
592 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
593 interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
594 }