tmp_chroot
unittests/unittests
tests/libmemcached-1.0/testsocket
+example/t/memcached_light
void options_parse(int argc, char *argv[])
{
int option_index= 0;
- int option_rv;
memcached_programs_help_st help_options[]=
{
while (1)
{
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
if (option_rv == -1) break;
switch (option_rv)
{
if (memcached_failed(rc))
{
- std::cerr << "Error occrrured during operation: " << memcached_last_error_message(memc) << std::endl;
+ std::cerr << "Error occrrured during memcached_set(): " << memcached_last_error_message(memc) << std::endl;
exit_code= EXIT_FAILURE;
}
optind++;
}
+ if (opt_verbose)
+ {
+ std::cout << "Calling memcached_free()" << std::endl;
+ }
+
memcached_free(memc);
if (opt_servers)
std::cerr << "Could not find key \"" << argv[optind] << "\"" << std::endl;
}
}
- else if (memcached_failed(rc))
+ else if (memcached_fatal(rc))
{
if (opt_verbose)
{
AC_DEFINE([HAVE_LIBPQ], [0], [Support for Postgres])
AC_DEFINE([HAVE_LIBCURL], [0], [Support for libcurl])
+AC_DEFINE([HAVE_MEMCACHED_LIGHT_BINARY], [1], [Support for memcached_light])
+AC_DEFINE([MEMCACHED_LIGHT_BINARY], ["example/memcached_light"], [Support for memcached_light])
+
AC_CHECK_HEADERS_ONCE(winsock2.h poll.h sys/wait.h fnmatch.h)
AM_CONDITIONAL(BUILD_POLL, test "x$ac_cv_header_poll_h" = "xno")
AM_CONDITIONAL(BUILD_WIN32_WRAPPERS, test "x$ac_cv_header_winsock2_h" = "xyes")
example_memcached_light_SOURCES= \
example/byteorder.cc \
- example/interface_v0.c \
- example/interface_v1.c \
- example/memcached_light.c
+ example/interface_v0.cc \
+ example/interface_v1.cc \
+ example/memcached_light.cc \
+ util/daemon.cc \
+ util/pidfile.cc
example_memcached_light_LDADD= libmemcached/libmemcachedprotocol.la \
$(LIBEVENT_LDFLAGS)
-example_memcached_light_SOURCES+= example/storage.c
+example_memcached_light_SOURCES+= example/storage.cc
+
+include example/t/include.am
+++ /dev/null
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-/**
- * This file contains an implementation of the callback interface for level 0
- * in the protocol library. You might want to have your copy of the protocol
- * specification next to your coffee ;-)
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libmemcachedprotocol-0.0/handler.h>
-#include <example/byteorder.h>
-#include "example/storage.h"
-#include "example/memcached_light.h"
-
-static protocol_binary_response_status noop_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_NOOP,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- };
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status quit_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_QUIT,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- };
-
- if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
- response_handler(cookie, header, (void*)&response);
-
- /* I need a better way to signal to close the connection */
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
-}
-
-static protocol_binary_response_status get_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- uint8_t opcode= header->request.opcode;
- union {
- protocol_binary_response_get response;
- char buffer[4096];
- } msg= {
- .response.message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- };
-
- struct item *item= get_item(header + 1, ntohs(header->request.keylen));
- if (item)
- {
- msg.response.message.body.flags= htonl(item->flags);
- char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
- uint32_t bodysize= 4;
- msg.response.message.header.response.cas= example_htonll(item->cas);
- if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
- {
- memcpy(ptr, item->key, item->nkey);
- msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
- ptr += item->nkey;
- bodysize += (uint32_t)item->nkey;
- }
- memcpy(ptr, item->data, item->size);
- bodysize += (uint32_t)item->size;
- msg.response.message.header.response.bodylen= htonl(bodysize);
- msg.response.message.header.response.extlen= 4;
-
- release_item(item);
- return response_handler(cookie, header, (void*)&msg);
- }
- else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
- {
- msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
- return response_handler(cookie, header, (void*)&msg);
- }
-
- /* Q shouldn't report a miss ;-) */
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status delete_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- size_t keylen= ntohs(header->request.keylen);
- char *key= ((char*)header) + sizeof(*header);
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .opaque= header->request.opaque
- }
- };
-
- if (!delete_item(key, keylen))
- {
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
- return response_handler(cookie, header, (void*)&response);
- }
- else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
- {
- /* DELETEQ doesn't want success response */
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
- return response_handler(cookie, header, (void*)&response);
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status flush_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- uint8_t opcode= header->request.opcode;
-
- /* @fixme sett inn when! */
- flush(0);
-
- if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
- {
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- };
- return response_handler(cookie, header, (void*)&response);
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status arithmetic_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_request_incr *req= (void*)header;
- protocol_binary_response_incr response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .opaque= header->request.opaque,
- },
- };
-
- uint16_t keylen= ntohs(header->request.keylen);
- uint64_t initial= example_ntohll(req->message.body.initial);
- uint64_t delta= example_ntohll(req->message.body.delta);
- uint32_t expiration= ntohl(req->message.body.expiration);
- uint32_t flags= 0;
- void *key= req->bytes + sizeof(req->bytes);
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- uint64_t value= initial;
-
- struct item *item= get_item(key, keylen);
- if (item != NULL)
- {
- if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
- header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
- {
- value= (*(uint64_t*)item->data) + delta;
- }
- else
- {
- if (delta > *(uint64_t*)item->data)
- {
- value= 0;
- }
- else
- {
- value= *(uint64_t*)item->data - delta;
- }
- }
- expiration= (uint32_t)item->exp;
- flags= item->flags;
-
- release_item(item);
- delete_item(key, keylen);
- }
-
- item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- memcpy(item->data, &value, sizeof(value));
- put_item(item);
- }
-
- response.message.header.response.status= htons(rval);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- response.message.header.response.bodylen= ntohl(8);
- response.message.body.value= example_ntohll((*(uint64_t*)item->data));
- response.message.header.response.cas= example_ntohll(item->cas);
-
- release_item(item);
- if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
- header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
- {
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
- }
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status version_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- const char *versionstring= "1.0.0";
- union {
- protocol_binary_response_header packet;
- char buffer[256];
- } response= {
- .packet.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_VERSION,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= 0,
- .bodylen= htonl((uint32_t)strlen(versionstring))
- }
- };
-
- memcpy(response.buffer + sizeof(response.packet), versionstring, strlen(versionstring));
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status concat_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- uint16_t keylen= ntohs(header->request.keylen);
- uint64_t cas= example_ntohll(header->request.cas);
- void *key= header + 1;
- uint32_t vallen= ntohl(header->request.bodylen) - keylen;
- void *val= (char*)key + keylen;
-
- struct item *item= get_item(key, keylen);
- struct item *nitem= NULL;
-
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
- else if (cas != 0 && cas != item->cas)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
- else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
- item->flags, item->exp)) == NULL)
- {
- release_item(item);
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
- header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
- {
- memcpy(nitem->data, item->data, item->size);
- memcpy(((char*)(nitem->data)) + item->size, val, vallen);
- }
- else
- {
- memcpy(nitem->data, val, vallen);
- memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
- }
- release_item(item);
- delete_item(key, keylen);
- put_item(nitem);
- cas= nitem->cas;
- release_item(nitem);
-
- if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
- header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
- {
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .status= htons(rval),
- .opaque= header->request.opaque,
- .cas= example_htonll(cas),
- }
- }
- };
- return response_handler(cookie, header, (void*)&response);
- }
- }
-
- return rval;
-}
-
-static protocol_binary_response_status set_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- size_t keylen= ntohs(header->request.keylen);
- size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_replace *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- time_t timeout= (time_t)ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
-
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- }
- };
-
- if (header->request.cas != 0)
- {
- /* validate cas */
- struct item* item= get_item(key, keylen);
- if (item != NULL)
- {
- if (item->cas != example_ntohll(header->request.cas))
- {
- release_item(item);
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
- return response_handler(cookie, header, (void*)&response);
- }
- release_item(item);
- }
- }
-
- delete_item(key, keylen);
- struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
- if (item == NULL)
- {
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
- }
- else
- {
- put_item(item);
- /* SETQ shouldn't return a message */
- if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
- {
- response.message.header.response.cas= example_htonll(item->cas);
- release_item(item);
- return response_handler(cookie, header, (void*)&response);
- }
- release_item(item);
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status add_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- size_t keylen= ntohs(header->request.keylen);
- size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_add *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- time_t timeout= (time_t)ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
-
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- }
- };
-
- struct item* item= get_item(key, keylen);
- if (item == NULL)
- {
- item= create_item(key, keylen, data, datalen, flags, timeout);
- if (item == NULL)
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
- else
- {
- put_item(item);
- /* ADDQ shouldn't return a message */
- if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
- {
- response.message.header.response.cas= example_htonll(item->cas);
- release_item(item);
- return response_handler(cookie, header, (void*)&response);
- }
- release_item(item);
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
- }
- else
- {
- release_item(item);
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
- }
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status replace_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- size_t keylen= ntohs(header->request.keylen);
- size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_replace *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- time_t timeout= (time_t)ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
-
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- }
- };
-
- struct item* item= get_item(key, keylen);
- if (item == NULL)
- {
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
- }
- else if (header->request.cas == 0 || example_ntohll(header->request.cas) == item->cas)
- {
- release_item(item);
- delete_item(key, keylen);
- item= create_item(key, keylen, data, datalen, flags, timeout);
-
- if (item == NULL)
- {
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
- }
- else
- {
- put_item(item);
- /* REPLACEQ shouldn't return a message */
- if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
- {
- response.message.header.response.cas= example_htonll(item->cas);
- release_item(item);
- return response_handler(cookie, header, (void*)&response);
- }
- release_item(item);
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
- }
- else
- {
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
- release_item(item);
- }
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-static protocol_binary_response_status stat_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- /* Just send the terminating packet*/
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_STAT,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- }
- };
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-memcached_binary_protocol_callback_st interface_v0_impl= {
- .interface_version= MEMCACHED_PROTOCOL_HANDLER_V0,
-#ifdef FUTURE
- /*
- ** There is a number of bugs in the extra options for gcc causing
- ** warning on these struct initializers. It hurts my heart to remove
- ** it so I'll just leave it in here so that we can enable it when
- ** we can drop support for the broken compilers
- */
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler,
- .interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler,
-#endif
-};
-
-void initialize_interface_v0_handler(void)
-{
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
- interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
-}
--- /dev/null
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/**
+ * This file contains an implementation of the callback interface for level 0
+ * in the protocol library. You might want to have your copy of the protocol
+ * specification next to your coffee ;-)
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libmemcachedprotocol-0.0/handler.h>
+#include <example/byteorder.h>
+#include "example/memcached_light.h"
+#include "example/storage.h"
+
+static protocol_binary_response_status noop_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= PROTOCOL_BINARY_CMD_NOOP;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status quit_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= PROTOCOL_BINARY_CMD_QUIT;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
+ {
+ response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+
+ /* I need a better way to signal to close the connection */
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+}
+
+static protocol_binary_response_status get_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ uint8_t opcode= header->request.opcode;
+ union protocol_binary_response_get_un {
+ protocol_binary_response_get response;
+ char buffer[4096];
+ };
+
+ protocol_binary_response_get_un msg;
+ memset(&msg, 0, sizeof(protocol_binary_response_get_un));
+
+ msg.response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ msg.response.message.header.response.opcode= opcode;
+ msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ msg.response.message.header.response.opaque= header->request.opaque;
+
+ struct item *item= get_item(header + 1, ntohs(header->request.keylen));
+ if (item)
+ {
+ msg.response.message.body.flags= htonl(item->flags);
+ char *ptr= (char*)(msg.response.bytes + sizeof(*header) + 4);
+ uint32_t bodysize= 4;
+ msg.response.message.header.response.cas= example_htonll(item->cas);
+ if (opcode == PROTOCOL_BINARY_CMD_GETK || opcode == PROTOCOL_BINARY_CMD_GETKQ)
+ {
+ memcpy(ptr, item->key, item->nkey);
+ msg.response.message.header.response.keylen= htons((uint16_t)item->nkey);
+ ptr += item->nkey;
+ bodysize += (uint32_t)item->nkey;
+ }
+ memcpy(ptr, item->data, item->size);
+ bodysize += (uint32_t)item->size;
+ msg.response.message.header.response.bodylen= htonl(bodysize);
+ msg.response.message.header.response.extlen= 4;
+
+ release_item(item);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
+ }
+ else if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETK)
+ {
+ msg.response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&msg);
+ }
+
+ /* Q shouldn't report a miss ;-) */
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status delete_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ size_t keylen= ntohs(header->request.keylen);
+
+ char *key= ((char*)header) + sizeof(*header);
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.opaque= header->request.opaque;
+
+ if (!delete_item(key, keylen))
+ {
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ else if (header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
+ {
+ /* DELETEQ doesn't want success response */
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status flush_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ uint8_t opcode= header->request.opcode;
+
+ /* @fixme sett inn when! */
+ flush(0);
+
+ if (opcode == PROTOCOL_BINARY_CMD_FLUSH)
+ {
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= opcode;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status arithmetic_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_request_incr *req= (protocol_binary_request_incr*)header;
+ protocol_binary_response_incr response;
+ memset(&response, 0, sizeof(protocol_binary_response_incr));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.opaque= header->request.opaque;
+
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint64_t initial= example_ntohll(req->message.body.initial);
+ uint64_t delta= example_ntohll(req->message.body.delta);
+ uint32_t expiration= ntohl(req->message.body.expiration);
+ uint32_t flags= 0;
+ void *key= req->bytes + sizeof(req->bytes);
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ uint64_t value= initial;
+
+ struct item *item= get_item(key, keylen);
+ if (item != NULL)
+ {
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
+ header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
+ {
+ value= (*(uint64_t*)item->data) + delta;
+ }
+ else
+ {
+ if (delta > *(uint64_t*)item->data)
+ {
+ value= 0;
+ }
+ else
+ {
+ value= *(uint64_t*)item->data - delta;
+ }
+ }
+ expiration= (uint32_t)item->exp;
+ flags= item->flags;
+
+ release_item(item);
+ delete_item(key, keylen);
+ }
+
+ item= create_item(key, keylen, NULL, sizeof(value), flags, (time_t)expiration);
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ memcpy(item->data, &value, sizeof(value));
+ put_item(item);
+ }
+
+ response.message.header.response.status= htons(rval);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ response.message.header.response.bodylen= ntohl(8);
+ response.message.body.value= example_ntohll((*(uint64_t*)item->data));
+ response.message.header.response.cas= example_ntohll(item->cas);
+
+ release_item(item);
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
+ header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
+ {
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+ }
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status version_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ const char *versionstring= "1.0.0";
+ union protocol_binary_response_header_un
+ {
+ protocol_binary_response_header packet;
+ char buffer[256];
+ };
+
+ protocol_binary_response_header_un response;
+ memset(&response, 0, sizeof(protocol_binary_response_header_un));
+
+ response.packet.response.magic= PROTOCOL_BINARY_RES;
+ response.packet.response.opcode= PROTOCOL_BINARY_CMD_VERSION;
+ response.packet.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.packet.response.opaque= header->request.opaque;
+ response.packet.response.cas= 0;
+ response.packet.response.bodylen= htonl((uint32_t)strlen(versionstring));
+
+ assert(sizeof(protocol_binary_response_header) +strlen(versionstring) <= 256);
+ memcpy(response.buffer + sizeof(protocol_binary_response_header), versionstring, strlen(versionstring));
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status concat_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint64_t cas= example_ntohll(header->request.cas);
+ void *key= header + 1;
+ uint32_t vallen= ntohl(header->request.bodylen) - keylen;
+ void *val= (char*)key + keylen;
+
+ struct item *item= get_item(key, keylen);
+ struct item *nitem= NULL;
+
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+ else if (cas != 0 && cas != item->cas)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+ else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
+ item->flags, item->exp)) == NULL)
+ {
+ release_item(item);
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
+ header->request.opcode == PROTOCOL_BINARY_CMD_APPENDQ)
+ {
+ memcpy(nitem->data, item->data, item->size);
+ memcpy(((char*)(nitem->data)) + item->size, val, vallen);
+ }
+ else
+ {
+ memcpy(nitem->data, val, vallen);
+ memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
+ }
+ release_item(item);
+ delete_item(key, keylen);
+ put_item(nitem);
+ cas= nitem->cas;
+ release_item(nitem);
+
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_APPEND ||
+ header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
+ {
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.status= htons(rval);
+ response.message.header.response.opaque= header->request.opaque;
+ response.message.header.response.cas= example_htonll(cas);
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status set_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ size_t keylen= ntohs(header->request.keylen);
+ size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_replace *request= (protocol_binary_request_replace*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ time_t timeout= (time_t)ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ if (header->request.cas != 0)
+ {
+ /* validate cas */
+ struct item* item= get_item(key, keylen);
+ if (item != NULL)
+ {
+ if (item->cas != example_ntohll(header->request.cas))
+ {
+ release_item(item);
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ release_item(item);
+ }
+ }
+
+ delete_item(key, keylen);
+ struct item* item= create_item(key, keylen, data, datalen, flags, timeout);
+ if (item == NULL)
+ {
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
+ }
+ else
+ {
+ put_item(item);
+ /* SETQ shouldn't return a message */
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
+ {
+ response.message.header.response.cas= example_htonll(item->cas);
+ release_item(item);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ release_item(item);
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status add_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ size_t keylen= ntohs(header->request.keylen);
+ size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_add *request= (protocol_binary_request_add*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ time_t timeout= (time_t)ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ struct item* item= get_item(key, keylen);
+ if (item == NULL)
+ {
+ item= create_item(key, keylen, data, datalen, flags, timeout);
+ if (item == NULL)
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
+ else
+ {
+ put_item(item);
+ /* ADDQ shouldn't return a message */
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
+ {
+ response.message.header.response.cas= example_htonll(item->cas);
+ release_item(item);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ release_item(item);
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+ }
+ else
+ {
+ release_item(item);
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
+ }
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status replace_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ size_t keylen= ntohs(header->request.keylen);
+ size_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_replace *request= (protocol_binary_request_replace*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ time_t timeout= (time_t)ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ struct item* item= get_item(key, keylen);
+ if (item == NULL)
+ {
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
+ }
+ else if (header->request.cas == 0 || example_ntohll(header->request.cas) == item->cas)
+ {
+ release_item(item);
+ delete_item(key, keylen);
+ item= create_item(key, keylen, data, datalen, flags, timeout);
+
+ if (item == NULL)
+ {
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
+ }
+ else
+ {
+ put_item(item);
+ /* REPLACEQ shouldn't return a message */
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
+ {
+ response.message.header.response.cas= example_htonll(item->cas);
+ release_item(item);
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+ }
+ release_item(item);
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+ }
+ else
+ {
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
+ release_item(item);
+ }
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+static protocol_binary_response_status stat_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ /* Just send the terminating packet*/
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= PROTOCOL_BINARY_CMD_STAT;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS);
+ response.message.header.response.opaque= header->request.opaque;
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+memcached_binary_protocol_callback_st interface_v0_impl;
+
+void initialize_interface_v0_handler(void)
+{
+ interface_v0_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V0;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADD]= add_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENT]= arithmetic_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENT]= arithmetic_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETQ]= get_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_VERSION]= version_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETK]= get_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPEND]= concat_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPEND]= concat_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_STAT]= stat_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_SETQ]= set_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_INCREMENTQ]= arithmetic_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_DECREMENTQ]= arithmetic_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_APPENDQ]= concat_command_handler;
+ interface_v0_impl.interface.v0.comcode[PROTOCOL_BINARY_CMD_PREPENDQ]= concat_command_handler;
+}
+++ /dev/null
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-/**
- * This file contains an implementation of the callback interface for level 1
- * in the protocol library. If you compare the implementation with the one
- * in interface_v0.c you will see that this implementation is much easier and
- * hides all of the protocol logic and let you focus on the application
- * logic. One "problem" with this layer is that it is synchronous, so that
- * you will not receive the next command before a answer to the previous
- * command is being sent.
- */
-#include "config.h"
-#include <assert.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libmemcachedprotocol-0.0/handler.h>
-#include <example/byteorder.h>
-#include "storage.h"
-
-static protocol_binary_response_status add_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *data,
- uint32_t datalen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t *cas)
-{
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- struct item* item= get_item(key, keylen);
- if (item == NULL)
- {
- item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
- if (item == 0)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- put_item(item);
- *cas= item->cas;
- release_item(item);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
-
- return rval;
-}
-
-static protocol_binary_response_status append_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint64_t cas,
- uint64_t *result_cas)
-{
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- struct item *item= get_item(key, keylen);
- struct item *nitem;
-
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
- else if (cas != 0 && cas != item->cas)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
- else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
- item->flags, item->exp)) == NULL)
- {
- release_item(item);
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- memcpy(nitem->data, item->data, item->size);
- memcpy(((char*)(nitem->data)) + item->size, val, vallen);
- release_item(item);
- delete_item(key, keylen);
- put_item(nitem);
- *result_cas= nitem->cas;
- release_item(nitem);
- }
-
- return rval;
-}
-
-static protocol_binary_response_status decrement_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t expiration,
- uint64_t *result,
- uint64_t *result_cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- uint64_t val= initial;
- struct item *item= get_item(key, keylen);
-
- if (item != NULL)
- {
- if (delta > *(uint64_t*)item->data)
- val= 0;
- else
- val= *(uint64_t*)item->data - delta;
-
- expiration= (uint32_t)item->exp;
- release_item(item);
- delete_item(key, keylen);
- }
-
- item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
- if (item == 0)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- memcpy(item->data, &val, sizeof(val));
- put_item(item);
- *result= val;
- *result_cas= item->cas;
- release_item(item);
- }
-
- return rval;
-}
-
-static protocol_binary_response_status delete_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- if (cas != 0)
- {
- struct item *item= get_item(key, keylen);
- if (item != NULL)
- {
- if (item->cas != cas)
- {
- release_item(item);
- return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
- release_item(item);
- }
- }
-
- if (!delete_item(key, keylen))
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
-
- return rval;
-}
-
-
-static protocol_binary_response_status flush_handler(const void *cookie,
- uint32_t when) {
-
- (void)cookie;
- flush(when);
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status get_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- memcached_binary_protocol_get_response_handler response_handler) {
- struct item *item= get_item(key, keylen);
-
- if (item == NULL)
- {
- return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
-
- protocol_binary_response_status rc;
- rc= response_handler(cookie, key, (uint16_t)keylen,
- item->data, (uint32_t)item->size, item->flags,
- item->cas);
- release_item(item);
- return rc;
-}
-
-static protocol_binary_response_status increment_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t expiration,
- uint64_t *result,
- uint64_t *result_cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- uint64_t val= initial;
- struct item *item= get_item(key, keylen);
-
- if (item != NULL)
- {
- val= (*(uint64_t*)item->data) + delta;
- expiration= (uint32_t)item->exp;
- release_item(item);
- delete_item(key, keylen);
- }
-
- item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- char buffer[1024] = {0};
- memcpy(buffer, key, keylen);
- memcpy(item->data, &val, sizeof(val));
- put_item(item);
- *result= val;
- *result_cas= item->cas;
- release_item(item);
- }
-
- return rval;
-}
-
-static protocol_binary_response_status noop_handler(const void *cookie) {
- (void)cookie;
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status prepend_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint64_t cas,
- uint64_t *result_cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- struct item *item= get_item(key, keylen);
- struct item *nitem= NULL;
-
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
- else if (cas != 0 && cas != item->cas)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
- else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
- item->flags, item->exp)) == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- memcpy(nitem->data, val, vallen);
- memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
- release_item(item);
- item= NULL;
- delete_item(key, keylen);
- put_item(nitem);
- *result_cas= nitem->cas;
- }
-
- if (item)
- release_item(item);
-
- if (nitem)
- release_item(nitem);
-
- return rval;
-}
-
-static protocol_binary_response_status quit_handler(const void *cookie) {
- (void)cookie;
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-static protocol_binary_response_status replace_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* data,
- uint32_t datalen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t cas,
- uint64_t *result_cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- struct item* item= get_item(key, keylen);
-
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
- else if (cas == 0 || cas == item->cas)
- {
- release_item(item);
- delete_item(key, keylen);
- item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
- if (item == 0)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- put_item(item);
- *result_cas= item->cas;
- release_item(item);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- release_item(item);
- }
-
- return rval;
-}
-
-static protocol_binary_response_status set_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* data,
- uint32_t datalen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t cas,
- uint64_t *result_cas) {
- (void)cookie;
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- if (cas != 0)
- {
- struct item* item= get_item(key, keylen);
- if (item != NULL && cas != item->cas)
- {
- /* Invalid CAS value */
- release_item(item);
- return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
- }
- }
-
- delete_item(key, keylen);
- struct item* item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
- if (item == 0)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- put_item(item);
- *result_cas= item->cas;
- release_item(item);
- }
-
- return rval;
-}
-
-static protocol_binary_response_status stat_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- memcached_binary_protocol_stat_response_handler response_handler) {
- (void)key;
- (void)keylen;
- /* Just return an empty packet */
- return response_handler(cookie, NULL, 0, NULL, 0);
-}
-
-static protocol_binary_response_status version_handler(const void *cookie,
- memcached_binary_protocol_version_response_handler response_handler) {
- const char *version= "0.1.1";
- return response_handler(cookie, version, (uint32_t)strlen(version));
-}
-
-memcached_binary_protocol_callback_st interface_v1_impl= {
- .interface_version= MEMCACHED_PROTOCOL_HANDLER_V1,
- .interface.v1= {
- .add= add_handler,
- .append= append_handler,
- .decrement= decrement_handler,
- .delete= delete_handler,
- .flush= flush_handler,
- .get= get_handler,
- .increment= increment_handler,
- .noop= noop_handler,
- .prepend= prepend_handler,
- .quit= quit_handler,
- .replace= replace_handler,
- .set= set_handler,
- .stat= stat_handler,
- .version= version_handler
- }
-};
--- /dev/null
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/**
+ * This file contains an implementation of the callback interface for level 1
+ * in the protocol library. If you compare the implementation with the one
+ * in interface_v0.c you will see that this implementation is much easier and
+ * hides all of the protocol logic and let you focus on the application
+ * logic. One "problem" with this layer is that it is synchronous, so that
+ * you will not receive the next command before a answer to the previous
+ * command is being sent.
+ */
+#include "config.h"
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libmemcachedprotocol-0.0/handler.h>
+#include <example/byteorder.h>
+#include "example/memcached_light.h"
+#include "example/storage.h"
+
+static protocol_binary_response_status add_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *data,
+ uint32_t datalen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t *cas)
+{
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ struct item* item= get_item(key, keylen);
+ if (item == NULL)
+ {
+ item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
+ if (item == 0)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ put_item(item);
+ *cas= item->cas;
+ release_item(item);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status append_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint64_t cas,
+ uint64_t *result_cas)
+{
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ struct item *item= get_item(key, keylen);
+ struct item *nitem;
+
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+ else if (cas != 0 && cas != item->cas)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+ else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
+ item->flags, item->exp)) == NULL)
+ {
+ release_item(item);
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ memcpy(nitem->data, item->data, item->size);
+ memcpy(((char*)(nitem->data)) + item->size, val, vallen);
+ release_item(item);
+ delete_item(key, keylen);
+ put_item(nitem);
+ *result_cas= nitem->cas;
+ release_item(nitem);
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status decrement_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t expiration,
+ uint64_t *result,
+ uint64_t *result_cas) {
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ uint64_t val= initial;
+ struct item *item= get_item(key, keylen);
+
+ if (item != NULL)
+ {
+ if (delta > *(uint64_t*)item->data)
+ val= 0;
+ else
+ val= *(uint64_t*)item->data - delta;
+
+ expiration= (uint32_t)item->exp;
+ release_item(item);
+ delete_item(key, keylen);
+ }
+
+ item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
+ if (item == 0)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ memcpy(item->data, &val, sizeof(val));
+ put_item(item);
+ *result= val;
+ *result_cas= item->cas;
+ release_item(item);
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status delete_handler(const void *, // cookie
+ const void *key,
+ uint16_t keylen,
+ uint64_t cas)
+{
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ if (cas != 0)
+ {
+ struct item *item= get_item(key, keylen);
+ if (item != NULL)
+ {
+ if (item->cas != cas)
+ {
+ release_item(item);
+ return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+ release_item(item);
+ }
+ }
+
+ if (!delete_item(key, keylen))
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+
+ return rval;
+}
+
+
+static protocol_binary_response_status flush_handler(const void * /* cookie */, uint32_t /* when */)
+{
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status get_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ memcached_binary_protocol_get_response_handler response_handler) {
+ struct item *item= get_item(key, keylen);
+
+ if (item == NULL)
+ {
+ return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+
+ protocol_binary_response_status rc;
+ rc= response_handler(cookie, key, (uint16_t)keylen,
+ item->data, (uint32_t)item->size, item->flags,
+ item->cas);
+ release_item(item);
+ return rc;
+}
+
+static protocol_binary_response_status increment_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t expiration,
+ uint64_t *result,
+ uint64_t *result_cas) {
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ uint64_t val= initial;
+ struct item *item= get_item(key, keylen);
+
+ if (item != NULL)
+ {
+ val= (*(uint64_t*)item->data) + delta;
+ expiration= (uint32_t)item->exp;
+ release_item(item);
+ delete_item(key, keylen);
+ }
+
+ item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ char buffer[1024] = {0};
+ memcpy(buffer, key, keylen);
+ memcpy(item->data, &val, sizeof(val));
+ put_item(item);
+ *result= val;
+ *result_cas= item->cas;
+ release_item(item);
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status noop_handler(const void *cookie) {
+ (void)cookie;
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status prepend_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint64_t cas,
+ uint64_t *result_cas) {
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ struct item *item= get_item(key, keylen);
+ struct item *nitem= NULL;
+
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+ else if (cas != 0 && cas != item->cas)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+ else if ((nitem= create_item(key, keylen, NULL, item->size + vallen,
+ item->flags, item->exp)) == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ memcpy(nitem->data, val, vallen);
+ memcpy(((char*)(nitem->data)) + vallen, item->data, item->size);
+ release_item(item);
+ item= NULL;
+ delete_item(key, keylen);
+ put_item(nitem);
+ *result_cas= nitem->cas;
+ }
+
+ if (item)
+ release_item(item);
+
+ if (nitem)
+ release_item(nitem);
+
+ return rval;
+}
+
+static protocol_binary_response_status quit_handler(const void *) //cookie
+{
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+static protocol_binary_response_status replace_handler(const void *, // cookie
+ const void *key,
+ uint16_t keylen,
+ const void* data,
+ uint32_t datalen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t cas,
+ uint64_t *result_cas)
+{
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ struct item* item= get_item(key, keylen);
+
+ if (item == NULL)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+ else if (cas == 0 || cas == item->cas)
+ {
+ release_item(item);
+ delete_item(key, keylen);
+ item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
+ if (item == 0)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ put_item(item);
+ *result_cas= item->cas;
+ release_item(item);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ release_item(item);
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status set_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* data,
+ uint32_t datalen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t cas,
+ uint64_t *result_cas) {
+ (void)cookie;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ if (cas != 0)
+ {
+ struct item* item= get_item(key, keylen);
+ if (item != NULL && cas != item->cas)
+ {
+ /* Invalid CAS value */
+ release_item(item);
+ return PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+ }
+ }
+
+ delete_item(key, keylen);
+ struct item* item= create_item(key, keylen, data, datalen, flags, (time_t)exptime);
+ if (item == 0)
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ else
+ {
+ put_item(item);
+ *result_cas= item->cas;
+ release_item(item);
+ }
+
+ return rval;
+}
+
+static protocol_binary_response_status stat_handler(const void *cookie,
+ const void *, // key
+ uint16_t, // keylen,
+ memcached_binary_protocol_stat_response_handler response_handler)
+{
+ /* Just return an empty packet */
+ return response_handler(cookie, NULL, 0, NULL, 0);
+}
+
+static protocol_binary_response_status version_handler(const void *cookie,
+ memcached_binary_protocol_version_response_handler response_handler)
+{
+ const char *version= "0.1.1";
+ return response_handler(cookie, version, (uint32_t)strlen(version));
+}
+
+memcached_binary_protocol_callback_st interface_v1_impl;
+
+void initialize_interface_v1_handler(void)
+{
+ memset(&interface_v1_impl, 0, sizeof(memcached_binary_protocol_callback_st));
+
+ interface_v1_impl.interface_version= MEMCACHED_PROTOCOL_HANDLER_V1;
+ interface_v1_impl.interface.v1.add= add_handler;
+ interface_v1_impl.interface.v1.append= append_handler;
+ interface_v1_impl.interface.v1.decrement= decrement_handler;
+ interface_v1_impl.interface.v1.delete_object= delete_handler;
+ interface_v1_impl.interface.v1.flush_object= flush_handler;
+ interface_v1_impl.interface.v1.get= get_handler;
+ interface_v1_impl.interface.v1.increment= increment_handler;
+ interface_v1_impl.interface.v1.noop= noop_handler;
+ interface_v1_impl.interface.v1.prepend= prepend_handler;
+ interface_v1_impl.interface.v1.quit= quit_handler;
+ interface_v1_impl.interface.v1.replace= replace_handler;
+ interface_v1_impl.interface.v1.set= set_handler;
+ interface_v1_impl.interface.v1.stat= stat_handler;
+ interface_v1_impl.interface.v1.version= version_handler;
+}
+++ /dev/null
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-/**
- * What is a library without an example to show you how to use the library?
- * This example use both interfaces to implement a small memcached server.
- * Please note that this is an exemple on how to use the library, not
- * an implementation of a scalable memcached server. If you look closely
- * at the example it isn't even multithreaded ;-)
- *
- * With that in mind, let me give you some pointers into the source:
- * storage.c/h - Implements the item store for this server and not really
- * interesting for this example.
- * interface_v0.c - Shows an implementation of the memcached server by using
- * the "raw" access to the packets as they arrive
- * interface_v1.c - Shows an implementation of the memcached server by using
- * the more "logical" interface.
- * memcached_light.c - This file sets up all of the sockets and run the main
- * message loop.
- *
- *
- * config.h is included so that I can use the ntohll/htonll on platforms that
- * doesn't have that (this is a private function inside libmemcached, so you
- * cannot use it directly from libmemcached without special modifications to
- * the library)
- */
-
-#include "config.h"
-#include <assert.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <event.h>
-
-#include <libmemcachedprotocol-0.0/handler.h>
-#include <libmemcached/socket.hpp>
-#include <example/byteorder.h>
-#include "example/storage.h"
-#include "example/memcached_light.h"
-
-extern memcached_binary_protocol_callback_st interface_v0_impl;
-extern memcached_binary_protocol_callback_st interface_v1_impl;
-
-static memcached_socket_t server_sockets[1024];
-static int num_server_sockets= 0;
-
-struct connection
-{
- void *userdata;
- struct event event;
-};
-
-/* The default maximum number of connections... (change with -c) */
-static int maxconns = 1024;
-
-static struct connection *socket_userdata_map;
-static bool verbose= false;
-static struct event_base *event_base;
-
-struct options_st {
- char *pid_file;
- bool has_port;
- in_port_t port;
-} global_options;
-
-typedef struct options_st options_st;
-
-/**
- * Callback for driving a client connection
- * @param fd the socket for the client socket
- * @param which identifying the event that occurred (not used)
- * @param arg the connection structure for the client
- */
-static void drive_client(memcached_socket_t fd, short which, void *arg)
-{
- (void)which;
- struct connection *client= arg;
- struct memcached_protocol_client_st* c= client->userdata;
- assert(c != NULL);
-
- memcached_protocol_event_t events= memcached_protocol_client_work(c);
- if (events & MEMCACHED_PROTOCOL_ERROR_EVENT)
- {
- memcached_protocol_client_destroy(c);
- closesocket(fd);
- } else {
- short flags = 0;
- if (events & MEMCACHED_PROTOCOL_WRITE_EVENT)
- {
- flags= EV_WRITE;
- }
-
- if (events & MEMCACHED_PROTOCOL_READ_EVENT)
- {
- flags|= EV_READ;
- }
-
- event_set(&client->event, (intptr_t)fd, flags, drive_client, client);
- event_base_set(event_base, &client->event);
-
- if (event_add(&client->event, 0) == -1)
- {
- (void)fprintf(stderr, "Failed to add event for %d\n", fd);
- memcached_protocol_client_destroy(c);
- closesocket(fd);
- }
- }
-}
-
-/**
- * Callback for accepting new connections
- * @param fd the socket for the server socket
- * @param which identifying the event that occurred (not used)
- * @param arg the connection structure for the server
- */
-static void accept_handler(memcached_socket_t fd, short which, void *arg)
-{
- (void)which;
- struct connection *server= arg;
- /* accept new client */
- struct sockaddr_storage addr;
- socklen_t addrlen= sizeof(addr);
- memcached_socket_t sock= accept(fd, (struct sockaddr *)&addr, &addrlen);
-
- if (sock == INVALID_SOCKET)
- {
- perror("Failed to accept client");
- return ;
- }
-
-#ifndef WIN32
- if (sock >= maxconns)
- {
- (void)fprintf(stderr, "Client outside socket range (specified with -c)\n");
- closesocket(sock);
- return ;
- }
-#endif
-
- struct memcached_protocol_client_st* c;
- c= memcached_protocol_create_client(server->userdata, sock);
- if (c == NULL)
- {
- (void)fprintf(stderr, "Failed to create client\n");
- closesocket(sock);
- }
- else
- {
- struct connection *client = &socket_userdata_map[sock];
- client->userdata= c;
-
- event_set(&client->event, (intptr_t)sock, EV_READ, drive_client, client);
- event_base_set(event_base, &client->event);
- if (event_add(&client->event, 0) == -1)
- {
- (void)fprintf(stderr, "Failed to add event for %d\n", sock);
- memcached_protocol_client_destroy(c);
- closesocket(sock);
- }
- }
-}
-
-/**
- * Create a socket and bind it to a specific port number
- * @param port the port number to bind to
- */
-static int server_socket(const char *port)
-{
- struct addrinfo *ai;
- struct addrinfo hints= { .ai_flags= AI_PASSIVE,
- .ai_family= AF_UNSPEC,
- .ai_socktype= SOCK_STREAM };
-
- int error= getaddrinfo("127.0.0.1", port, &hints, &ai);
- if (error != 0)
- {
- if (error != EAI_SYSTEM)
- fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
- else
- perror("getaddrinfo()");
-
- return 0;
- }
-
- struct linger ling= {0, 0};
-
- for (struct addrinfo *next= ai; next; next= next->ai_next)
- {
- memcached_socket_t sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (sock == INVALID_SOCKET)
- {
- perror("Failed to create socket");
- continue;
- }
-
- int flags;
-#ifdef WIN32
- u_long arg = 1;
- if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
- {
- perror("Failed to set nonblocking io");
- closesocket(sock);
- continue;
- }
-#else
- flags= fcntl(sock, F_GETFL, 0);
- if (flags == -1)
- {
- perror("Failed to get socket flags");
- closesocket(sock);
- continue;
- }
-
- if ((flags & O_NONBLOCK) != O_NONBLOCK)
- {
- if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
- {
- perror("Failed to set socket to nonblocking mode");
- closesocket(sock);
- continue;
- }
- }
-#endif
-
- flags= 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)) != 0)
- perror("Failed to set SO_REUSEADDR");
-
- if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) != 0)
- perror("Failed to set SO_KEEPALIVE");
-
- if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling)) != 0)
- perror("Failed to set SO_LINGER");
-
- if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) != 0)
- perror("Failed to set TCP_NODELAY");
-
- if (bind(sock, next->ai_addr, next->ai_addrlen) == SOCKET_ERROR)
- {
- if (get_socket_errno() != EADDRINUSE)
- {
- perror("bind()");
- freeaddrinfo(ai);
- }
- closesocket(sock);
- continue;
- }
-
- if (listen(sock, 1024) == SOCKET_ERROR)
- {
- perror("listen()");
- closesocket(sock);
- continue;
- }
-
- server_sockets[num_server_sockets++]= sock;
- }
-
- freeaddrinfo(ai);
-
- return (num_server_sockets > 0) ? 0 : 1;
-}
-
-/**
- * Convert a command code to a textual string
- * @param cmd the comcode to convert
- * @return a textual string with the command or NULL for unknown commands
- */
-static const char* comcode2str(uint8_t cmd)
-{
- static const char * const text[] = {
- "GET", "SET", "ADD", "REPLACE", "DELETE",
- "INCREMENT", "DECREMENT", "QUIT", "FLUSH",
- "GETQ", "NOOP", "VERSION", "GETK", "GETKQ",
- "APPEND", "PREPEND", "STAT", "SETQ", "ADDQ",
- "REPLACEQ", "DELETEQ", "INCREMENTQ", "DECREMENTQ",
- "QUITQ", "FLUSHQ", "APPENDQ", "PREPENDQ"
- };
-
- if (cmd <= PROTOCOL_BINARY_CMD_PREPENDQ)
- return text[cmd];
-
- return NULL;
-}
-
-/**
- * Print out the command we are about to execute
- */
-static void pre_execute(const void *cookie,
- protocol_binary_request_header *header)
-{
- if (verbose)
- {
- const char *cmd= comcode2str(header->request.opcode);
- if (cmd != NULL)
- fprintf(stderr, "pre_execute from %p: %s\n", cookie, cmd);
- else
- fprintf(stderr, "pre_execute from %p: 0x%02x\n", cookie, header->request.opcode);
- }
-}
-
-/**
- * Print out the command we just executed
- */
-static void post_execute(const void *cookie,
- protocol_binary_request_header *header)
-{
- if (verbose)
- {
- const char *cmd= comcode2str(header->request.opcode);
- if (cmd != NULL)
- fprintf(stderr, "post_execute from %p: %s\n", cookie, cmd);
- else
- fprintf(stderr, "post_execute from %p: 0x%02x\n", cookie, header->request.opcode);
- }
-}
-
-/**
- * Callback handler for all unknown commands.
- * Send an unknown command back to the client
- */
-static protocol_binary_response_status unknown(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= header->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND),
- .opaque= header->request.opaque
- }
- }
- };
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-/**
- * Program entry point. Bind to the specified port(s) and serve clients
- *
- * @param argc number of items in the argument vector
- * @param argv argument vector
- * @return EXIT_SUCCESS on success, 1 otherwise
- */
-int main(int argc, char **argv)
-{
- int cmd;
- memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
-
- memset(&global_options, 0, sizeof(global_options));
-
- event_base= event_init();
- if (event_base == NULL)
- {
- fprintf(stderr, "Failed to create an instance of libevent\n");
- return EXIT_FAILURE;
- }
-
- /*
- * We need to initialize the handlers manually due to a bug in the
- * warnings generated by struct initialization in gcc (all the way up to 4.4)
- */
- initialize_interface_v0_handler();
-
- while ((cmd= getopt(argc, argv, "v1p:P:?hc:")) != EOF)
- {
- switch (cmd) {
- case '1':
- interface= &interface_v1_impl;
- break;
- case 'P':
- global_options.pid_file= strdup(optarg);
- break;
- case 'p':
- global_options.has_port= true;
- (void)server_socket(optarg);
- break;
- case 'v':
- verbose= true;
- break;
- case 'c':
- maxconns= atoi(optarg);
- break;
- case 'h': /* FALLTHROUGH */
- case '?': /* FALLTHROUGH */
- default:
- (void)fprintf(stderr, "Usage: %s [-p port] [-v] [-1] [-c #clients] [-P pidfile]\n",
- argv[0]);
- return EXIT_FAILURE;
- }
- }
-
- if (! initialize_storage())
- {
- /* Error message already printed */
- return EXIT_FAILURE;
- }
-
- if (! global_options.has_port)
- (void)server_socket("9999");
-
- if (global_options.pid_file)
- {
- FILE *pid_file;
- uint32_t pid;
-
- pid_file= fopen(global_options.pid_file, "w+");
-
- if (pid_file == NULL)
- {
- perror(strerror(get_socket_errno()));
- abort();
- }
-
- pid= (uint32_t)getpid();
- fprintf(pid_file, "%u\n", pid);
- fclose(pid_file);
- }
-
- if (num_server_sockets == 0)
- {
- fprintf(stderr, "I don't have any server sockets\n");
- return EXIT_FAILURE;
- }
-
- /*
- * Create and initialize the handles to the protocol handlers. I want
- * to be able to trace the traffic throught the pre/post handlers, and
- * set up a common handler for unknown messages
- */
- interface->pre_execute= pre_execute;
- interface->post_execute= post_execute;
- interface->unknown= unknown;
-
- struct memcached_protocol_st *protocol_handle;
- if ((protocol_handle= memcached_protocol_create_instance()) == NULL)
- {
- fprintf(stderr, "Failed to allocate protocol handle\n");
- return EXIT_FAILURE;
- }
-
- socket_userdata_map= calloc((size_t)(maxconns), sizeof(struct connection));
- if (socket_userdata_map == NULL)
- {
- fprintf(stderr, "Failed to allocate room for connections\n");
- return EXIT_FAILURE;
- }
-
- memcached_binary_protocol_set_callbacks(protocol_handle, interface);
- memcached_binary_protocol_set_pedantic(protocol_handle, true);
-
- for (int xx= 0; xx < num_server_sockets; ++xx)
- {
- struct connection *conn= &socket_userdata_map[server_sockets[xx]];
- conn->userdata= protocol_handle;
- event_set(&conn->event, (intptr_t)server_sockets[xx], EV_READ | EV_PERSIST,
- accept_handler, conn);
- event_base_set(event_base, &conn->event);
- if (event_add(&conn->event, 0) == -1)
- {
- fprintf(stderr, "Failed to add event for %d\n", server_sockets[xx]);
- closesocket(server_sockets[xx]);
- }
- }
-
- /* Serve all of the clients */
- event_base_loop(event_base, 0);
-
- /* NOTREACHED */
- return EXIT_SUCCESS;
-}
--- /dev/null
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/**
+ * What is a library without an example to show you how to use the library?
+ * This example use both interfaces to implement a small memcached server.
+ * Please note that this is an exemple on how to use the library, not
+ * an implementation of a scalable memcached server. If you look closely
+ * at the example it isn't even multithreaded ;-)
+ *
+ * With that in mind, let me give you some pointers into the source:
+ * storage.c/h - Implements the item store for this server and not really
+ * interesting for this example.
+ * interface_v0.c - Shows an implementation of the memcached server by using
+ * the "raw" access to the packets as they arrive
+ * interface_v1.c - Shows an implementation of the memcached server by using
+ * the more "logical" interface.
+ * memcached_light.c - This file sets up all of the sockets and run the main
+ * message loop.
+ *
+ *
+ * config.h is included so that I can use the ntohll/htonll on platforms that
+ * doesn't have that (this is a private function inside libmemcached, so you
+ * cannot use it directly from libmemcached without special modifications to
+ * the library)
+ */
+
+#include "config.h"
+
+#include <libmemcachedprotocol-0.0/handler.h>
+#include <libmemcached/socket.hpp>
+#include <example/byteorder.h>
+#include "example/storage.h"
+#include "example/memcached_light.h"
+
+#include "util/daemon.hpp"
+#include "util/log.hpp"
+#include "util/pidfile.hpp"
+
+using namespace datadifferential;
+
+#include <event.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <getopt.h>
+#include <iostream>
+#include <sys/types.h>
+#include <unistd.h>
+
+extern memcached_binary_protocol_callback_st interface_v0_impl;
+extern memcached_binary_protocol_callback_st interface_v1_impl;
+
+static memcached_socket_t server_sockets[1024];
+static int num_server_sockets= 0;
+
+struct connection
+{
+ void *userdata;
+ struct event event;
+};
+
+/* The default maximum number of connections... (change with -c) */
+static int maxconns= 1024;
+
+static struct connection *socket_userdata_map;
+static struct event_base *event_base= NULL;
+
+struct options_st {
+ std::string pid_file;
+ std::string service;
+ std::string log_file;
+ bool is_verbose;
+ bool opt_daemon;
+
+ options_st() :
+ service("9999"),
+ is_verbose(false)
+ {
+ }
+};
+
+static options_st global_options;
+
+/**
+ * Callback for driving a client connection
+ * @param fd the socket for the client socket
+ * @param which identifying the event that occurred (not used)
+ * @param arg the connection structure for the client
+ */
+static void drive_client(memcached_socket_t fd, short, void *arg)
+{
+ struct connection *client= (struct connection*)arg;
+ struct memcached_protocol_client_st* c= (struct memcached_protocol_client_st*)client->userdata;
+ assert(c != NULL);
+
+ memcached_protocol_event_t events= memcached_protocol_client_work(c);
+ if (events & MEMCACHED_PROTOCOL_ERROR_EVENT)
+ {
+ if (global_options.is_verbose)
+ {
+ struct sockaddr_in sin;
+ socklen_t addrlen= sizeof(sin);
+
+ if (getsockname(fd, (struct sockaddr *)&sin, &addrlen) != -1)
+ {
+ std::cout << __FILE__ << ":" << __LINE__
+ << " close(MEMCACHED_PROTOCOL_ERROR_EVENT)"
+ << " " << inet_ntoa(sin.sin_addr) << ":" << sin.sin_port
+ << " fd:" << fd
+ << std::endl;
+ }
+ else
+ {
+ std::cout << __FILE__ << ":" << __LINE__ << "close() MEMCACHED_PROTOCOL_ERROR_EVENT" << std::endl;
+ }
+ }
+
+ memcached_protocol_client_destroy(c);
+ closesocket(fd);
+ }
+ else
+ {
+ short flags = 0;
+ if (events & MEMCACHED_PROTOCOL_WRITE_EVENT)
+ {
+ flags= EV_WRITE;
+ }
+
+ if (events & MEMCACHED_PROTOCOL_READ_EVENT)
+ {
+ flags|= EV_READ;
+ }
+
+ event_set(&client->event, (intptr_t)fd, flags, drive_client, client);
+ event_base_set(event_base, &client->event);
+
+ if (event_add(&client->event, 0) == -1)
+ {
+ memcached_protocol_client_destroy(c);
+ closesocket(fd);
+ }
+ }
+}
+
+/**
+ * Callback for accepting new connections
+ * @param fd the socket for the server socket
+ * @param which identifying the event that occurred (not used)
+ * @param arg the connection structure for the server
+ */
+static void accept_handler(memcached_socket_t fd, short, void *arg)
+{
+ struct connection *server= (struct connection *)arg;
+ /* accept new client */
+ struct sockaddr_storage addr;
+ socklen_t addrlen= sizeof(addr);
+ memcached_socket_t sock= accept(fd, (struct sockaddr *)&addr, &addrlen);
+
+ if (sock == INVALID_SOCKET)
+ {
+ perror("Failed to accept client");
+ }
+
+#ifndef WIN32
+ if (sock >= maxconns)
+ {
+ closesocket(sock);
+ return ;
+ }
+#endif
+
+ struct memcached_protocol_client_st* c= memcached_protocol_create_client((memcached_protocol_st*)server->userdata, sock);
+ if (c == NULL)
+ {
+ closesocket(sock);
+ }
+ else
+ {
+ memcached_protocol_client_set_verbose(c, global_options.is_verbose);
+ struct connection *client = &socket_userdata_map[sock];
+ client->userdata= c;
+
+ event_set(&client->event, (intptr_t)sock, EV_READ, drive_client, client);
+ event_base_set(event_base, &client->event);
+ if (event_add(&client->event, 0) == -1)
+ {
+ std::cerr << "Failed to add event for " << sock << std::endl;
+ memcached_protocol_client_destroy(c);
+ closesocket(sock);
+ }
+ }
+}
+
+static bool server_socket(util::log_info_st& log_file, const std::string& service)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+
+ hints.ai_flags= AI_PASSIVE;
+ hints.ai_family= AF_UNSPEC;
+ hints.ai_socktype= SOCK_STREAM;
+
+ int error= getaddrinfo("127.0.0.1", service.c_str(), &hints, &ai);
+ if (error != 0)
+ {
+ if (error != EAI_SYSTEM)
+ {
+ std::string buffer("getaddrinfo: ");
+ buffer+= gai_strerror(error);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ }
+ else
+ {
+ std::string buffer("getaddrinfo: ");
+ buffer+= strerror(errno);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ }
+
+ return false;
+ }
+
+ struct linger ling= {0, 0};
+
+ for (struct addrinfo *next= ai; next; next= next->ai_next)
+ {
+ memcached_socket_t sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock == INVALID_SOCKET)
+ {
+ std::string buffer("Failed to create socket: ");
+ buffer+= strerror(errno);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ continue;
+ }
+
+ int flags;
+#ifdef WIN32
+ u_long arg = 1;
+ if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ std::cerr << "Failed to set nonblocking io: " << strerror(errno) << std::endl;
+ closesocket(sock);
+ continue;
+ }
+#else
+ flags= fcntl(sock, F_GETFL, 0);
+ if (flags == -1)
+ {
+ std::string buffer("Failed to get socket flags: ");
+ buffer+= strerror(errno);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ closesocket(sock);
+ continue;
+ }
+
+ if ((flags & O_NONBLOCK) != O_NONBLOCK)
+ {
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ std::string buffer("Failed to set socket to nonblocking mode: ");
+ buffer+= strerror(errno);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ closesocket(sock);
+ continue;
+ }
+ }
+#endif
+
+ flags= 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)) != 0)
+ {
+ std::cerr << "Failed to set SO_REUSEADDR: " << strerror(errno) << std::endl;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)) != 0)
+ {
+ std::cerr << "Failed to set SO_KEEPALIVE: " << strerror(errno) << std::endl;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling)) != 0)
+ {
+ std::cerr << "Failed to set SO_LINGER: " << strerror(errno) << std::endl;
+ }
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) != 0)
+ {
+ std::cerr << "Failed to set TCP_NODELAY: " << strerror(errno) << std::endl;
+ }
+
+ if (bind(sock, next->ai_addr, next->ai_addrlen) == SOCKET_ERROR)
+ {
+ if (get_socket_errno() != EADDRINUSE)
+ {
+ std::cerr << "bind(): " << strerror(errno) << std::endl;
+ freeaddrinfo(ai);
+ }
+ closesocket(sock);
+ continue;
+ }
+
+ if (listen(sock, 1024) == SOCKET_ERROR)
+ {
+ std::string buffer("listen(): ");
+ buffer+= strerror(errno);
+ log_file.write(util::VERBOSE_ERROR, buffer.c_str());
+ closesocket(sock);
+ continue;
+ }
+
+ if (global_options.is_verbose)
+ {
+ std::string buffer("Listening to: ");
+ buffer+= global_options.service;
+ log_file.write(util::VERBOSE_NOTICE, buffer.c_str());
+ }
+
+ server_sockets[num_server_sockets++]= sock;
+ }
+
+ freeaddrinfo(ai);
+
+ return (num_server_sockets > 0) ? true : false;
+}
+
+/**
+ * Convert a command code to a textual string
+ * @param cmd the comcode to convert
+ * @return a textual string with the command or NULL for unknown commands
+ */
+static const char* comcode2str(uint8_t cmd)
+{
+ static const char * const text[] = {
+ "GET", "SET", "ADD", "REPLACE", "DELETE",
+ "INCREMENT", "DECREMENT", "QUIT", "FLUSH",
+ "GETQ", "NOOP", "VERSION", "GETK", "GETKQ",
+ "APPEND", "PREPEND", "STAT", "SETQ", "ADDQ",
+ "REPLACEQ", "DELETEQ", "INCREMENTQ", "DECREMENTQ",
+ "QUITQ", "FLUSHQ", "APPENDQ", "PREPENDQ"
+ };
+
+ if (cmd <= PROTOCOL_BINARY_CMD_PREPENDQ)
+ {
+ return text[cmd];
+ }
+
+ return NULL;
+}
+
+/**
+ * Print out the command we are about to execute
+ */
+static void pre_execute(const void *cookie,
+ protocol_binary_request_header *header)
+{
+ if (global_options.is_verbose)
+ {
+ if (header)
+ {
+ const char *cmd= comcode2str(header->request.opcode);
+ if (cmd != NULL)
+ {
+ std::cout << "pre_execute from " << cookie << ": " << cmd << std::endl;
+ }
+ else
+ {
+ std::cout << "pre_execute from " << cookie << ": " << header->request.opcode << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "pre_execute from " << cookie << std::endl;
+ }
+ }
+}
+
+/**
+ * Print out the command we just executed
+ */
+static void post_execute(const void *cookie,
+ protocol_binary_request_header *header)
+{
+ if (global_options.is_verbose)
+ {
+ if (header)
+ {
+ const char *cmd= comcode2str(header->request.opcode);
+ if (cmd != NULL)
+ {
+ std::cout << "post_execute from " << cookie << ": " << cmd << std::endl;
+ }
+ else
+ {
+ std::cout << "post_execute from " << cookie << ": " << header->request.opcode << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "post_execute from " << cookie << std::endl;
+ }
+ }
+}
+
+/**
+ * Callback handler for all unknown commands.
+ * Send an unknown command back to the client
+ */
+static protocol_binary_response_status unknown(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_response_no_extras response;
+ memset(&response, 0, sizeof(protocol_binary_response_no_extras));
+
+ response.message.header.response.magic= PROTOCOL_BINARY_RES;
+ response.message.header.response.opcode= header->request.opcode;
+ response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND);
+ response.message.header.response.opaque= header->request.opaque;
+
+ return response_handler(cookie, header, (protocol_binary_response_header*)&response);
+}
+
+/**
+ * Program entry point. Bind to the specified port(s) and serve clients
+ *
+ * @param argc number of items in the argument vector
+ * @param argv argument vector
+ * @return EXIT_SUCCESS on success, 1 otherwise
+ */
+int main(int argc, char **argv)
+{
+ memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
+
+ /*
+ * We need to initialize the handlers manually due to a bug in the
+ * warnings generated by struct initialization in gcc (all the way up to 4.4)
+ */
+ initialize_interface_v0_handler();
+ initialize_interface_v1_handler();
+
+ {
+ enum long_option_t {
+ OPT_HELP,
+ OPT_VERBOSE,
+ OPT_DAEMON,
+ OPT_PROTOCOL_VERSION,
+ OPT_VERSION,
+ OPT_PORT,
+ OPT_MAX_CONNECTIONS,
+ OPT_LOGFILE,
+ OPT_PIDFILE
+ };
+
+ static struct option long_options[]=
+ {
+ { "help", no_argument, NULL, OPT_HELP },
+ { "port", required_argument, NULL, OPT_PORT },
+ { "verbose", no_argument, NULL, OPT_VERBOSE },
+ { "daemon", no_argument, NULL, OPT_DAEMON },
+ { "protocol", no_argument, NULL, OPT_PROTOCOL_VERSION },
+ { "version", no_argument, NULL, OPT_VERSION },
+ { "max-connections", required_argument, NULL, OPT_MAX_CONNECTIONS },
+ { "pid-file", required_argument, NULL, OPT_PIDFILE },
+ { "log-file", required_argument, NULL, OPT_LOGFILE },
+ {0, 0, 0, 0}
+ };
+
+ bool opt_help= false;
+ int option_index;
+ bool done= false;
+ while (done == false)
+ {
+ switch (getopt_long(argc, argv, "", long_options, &option_index))
+ {
+ case -1:
+ done= true;
+ break;
+
+ case OPT_PROTOCOL_VERSION:
+ interface= &interface_v1_impl;
+ break;
+
+ case OPT_PIDFILE:
+ global_options.pid_file= optarg;
+ break;
+
+ case OPT_LOGFILE:
+ global_options.log_file= optarg;
+ break;
+
+ case OPT_VERBOSE:
+ global_options.is_verbose= true;
+ break;
+
+ case OPT_VERSION:
+ break;
+
+ case OPT_DAEMON:
+ global_options.opt_daemon= true;
+ break;
+
+ case OPT_PORT:
+ global_options.service= optarg;
+ break;
+
+ case OPT_MAX_CONNECTIONS:
+ maxconns= atoi(optarg);
+ break;
+
+ case OPT_HELP: /* FALLTHROUGH */
+ opt_help= true;
+ break;
+
+ default:
+ {
+ std::cerr << "Unknown option: " << optarg << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ if (opt_help)
+ {
+ std::cout << "Usage: " << argv[0] << std::endl;
+ for (struct option *ptr_option= long_options; ptr_option->name; ptr_option++)
+ {
+ std::cout << "\t" << ptr_option->name << std::endl;
+ }
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if (global_options.opt_daemon)
+ {
+ util::daemonize(false, true);
+ }
+
+ if (initialize_storage() == false)
+ {
+ /* Error message already printed */
+ return EXIT_FAILURE;
+ }
+
+ util::Pidfile _pid_file(global_options.pid_file);
+
+ if (_pid_file.create() == false)
+ {
+ std::cerr << "Failed to create pid-file" << _pid_file.error_message() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ util::log_info_st log_file(argv[0], global_options.log_file, false);
+ log_file.write(util::VERBOSE_NOTICE, "starting log");
+
+ if (server_socket(log_file, global_options.service) == false)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if (num_server_sockets == 0)
+ {
+ log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Create and initialize the handles to the protocol handlers. I want
+ * to be able to trace the traffic throught the pre/post handlers, and
+ * set up a common handler for unknown messages
+ */
+ interface->pre_execute= pre_execute;
+ interface->post_execute= post_execute;
+ interface->unknown= unknown;
+
+ struct memcached_protocol_st *protocol_handle;
+ if ((protocol_handle= memcached_protocol_create_instance()) == NULL)
+ {
+ log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
+ return EXIT_FAILURE;
+ }
+
+ socket_userdata_map= (struct connection*)calloc((size_t)(maxconns), sizeof(struct connection));
+ if (socket_userdata_map == NULL)
+ {
+ log_file.write(util::VERBOSE_ERROR, "Failed to allocate room for connections");
+ return EXIT_FAILURE;
+ }
+
+ memcached_binary_protocol_set_callbacks(protocol_handle, interface);
+ memcached_binary_protocol_set_pedantic(protocol_handle, true);
+
+ event_base= event_init();
+ if (event_base == NULL)
+ {
+ std::cerr << "Failed to create an instance of libevent" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ for (int xx= 0; xx < num_server_sockets; ++xx)
+ {
+ struct connection *conn= &socket_userdata_map[server_sockets[xx]];
+ conn->userdata= protocol_handle;
+
+ event_set(&conn->event, (intptr_t)server_sockets[xx], EV_READ | EV_PERSIST, accept_handler, conn);
+
+ event_base_set(event_base, &conn->event);
+ if (event_add(&conn->event, 0) == -1)
+ {
+ log_file.write(util::VERBOSE_ERROR, "Failed to add event");
+ closesocket(server_sockets[xx]);
+ }
+ }
+
+ if (global_options.opt_daemon)
+ {
+ if (util::daemon_is_ready(true) == false)
+ {
+ log_file.write(util::VERBOSE_ERROR, "Failed for util::daemon_is_ready()");
+ return EXIT_FAILURE;
+ }
+ }
+
+
+ /* Serve all of the clients */
+ switch (event_base_loop(event_base, 0))
+ {
+ case -1:
+ log_file.write(util::VERBOSE_ERROR, "event_base_loop() failed");
+ break;
+
+ case 1:
+ log_file.write(util::VERBOSE_ERROR, "event_base_loop(), no events were registered");
+ break;
+
+ default:
+ break;
+ }
+ log_file.write(util::VERBOSE_NOTICE, "exiting");
+
+ /* NOTREACHED */
+ return EXIT_SUCCESS;
+}
/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#ifndef MEMCACHED_LIGHT_H
-#define MEMCACHED_LIGHT_H
+#pragma once
extern void initialize_interface_v0_handler(void);
-
-#endif
+extern void initialize_interface_v1_handler(void);
+++ /dev/null
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "config.h"
-#include <stdlib.h>
-#include <inttypes.h>
-#include <time.h>
-#include <stdbool.h>
-#include <string.h>
-#include "storage.h"
-
-struct list_entry {
- struct item item;
- struct list_entry *next;
- struct list_entry *prev;
-};
-
-static struct list_entry *root;
-static uint64_t cas;
-
-bool initialize_storage(void)
-{
- return true;
-}
-
-void shutdown_storage(void)
-{
- /* Do nothing */
-}
-
-void put_item(struct item* item)
-{
- struct list_entry* entry= (void*)item;
-
- update_cas(item);
-
- if (root == NULL)
- {
- entry->next= entry->prev= entry;
- }
- else
- {
- entry->prev= root->prev;
- entry->next= root;
- entry->prev->next= entry;
- entry->next->prev= entry;
- }
-
- root= entry;
-}
-
-struct item* get_item(const void* key, size_t nkey)
-{
- struct list_entry *walker= root;
-
- if (root == NULL)
- {
- return NULL;
- }
-
- do
- {
- if (((struct item*)walker)->nkey == nkey &&
- memcmp(((struct item*)walker)->key, key, nkey) == 0)
- {
- return (struct item*)walker;
- }
- walker= walker->next;
- } while (walker != root);
-
- return NULL;
-}
-
-struct item* create_item(const void* key, size_t nkey, const void* data,
- size_t size, uint32_t flags, time_t exp)
-{
- struct item* ret= calloc(1, sizeof(struct list_entry));
-
- if (ret != NULL)
- {
- ret->key= malloc(nkey);
- if (size > 0)
- {
- ret->data= malloc(size);
- }
-
- if (ret->key == NULL || (size > 0 && ret->data == NULL))
- {
- free(ret->key);
- free(ret->data);
- free(ret);
- return NULL;
- }
-
- memcpy(ret->key, key, nkey);
- if (data != NULL)
- {
- memcpy(ret->data, data, size);
- }
-
- ret->nkey= nkey;
- ret->size= size;
- ret->flags= flags;
- ret->exp= exp;
- }
-
- return ret;
-}
-
-bool delete_item(const void* key, size_t nkey)
-{
- struct item* item= get_item(key, nkey);
- bool ret= false;
-
- if (item)
- {
- /* remove from linked list */
- struct list_entry *entry= (void*)item;
-
- if (entry->next == entry)
- {
- /* Only one object in the list */
- root= NULL;
- }
- else
- {
- /* ensure that we don't loose track of the root, and this will
- * change the start position for the next search ;-) */
- root= entry->next;
- entry->prev->next= entry->next;
- entry->next->prev= entry->prev;
- }
-
- free(item->key);
- free(item->data);
- free(item);
- ret= true;
- }
-
- return ret;
-}
-
-void flush(uint32_t when)
-{
- /* FIXME */
- (void)when;
- /* remove the complete linked list */
- if (root == NULL)
- {
- return;
- }
-
- root->prev->next= NULL;
- while (root != NULL)
- {
- struct item* tmp= (void*)root;
- root= root->next;
-
- free(tmp->key);
- free(tmp->data);
- free(tmp);
- }
-}
-
-void update_cas(struct item* item)
-{
- item->cas= ++cas;
-}
-
-void release_item(struct item* item)
-{
- (void)item;
- /* EMPTY */
-}
--- /dev/null
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#include "config.h"
+#include <stdlib.h>
+#include <inttypes.h>
+#include <time.h>
+#include <stdbool.h>
+#include <string.h>
+#include "storage.h"
+
+struct list_entry {
+ struct item item;
+ struct list_entry *next;
+ struct list_entry *prev;
+};
+
+static struct list_entry *root;
+static uint64_t cas;
+
+bool initialize_storage(void)
+{
+ return true;
+}
+
+void shutdown_storage(void)
+{
+ /* Do nothing */
+}
+
+void put_item(struct item* item)
+{
+ struct list_entry* entry= (struct list_entry*)item;
+
+ update_cas(item);
+
+ if (root == NULL)
+ {
+ entry->next= entry->prev= entry;
+ }
+ else
+ {
+ entry->prev= root->prev;
+ entry->next= root;
+ entry->prev->next= entry;
+ entry->next->prev= entry;
+ }
+
+ root= entry;
+}
+
+struct item* get_item(const void* key, size_t nkey)
+{
+ struct list_entry *walker= root;
+
+ if (root == NULL)
+ {
+ return NULL;
+ }
+
+ do
+ {
+ if (((struct item*)walker)->nkey == nkey &&
+ memcmp(((struct item*)walker)->key, key, nkey) == 0)
+ {
+ return (struct item*)walker;
+ }
+ walker= walker->next;
+ } while (walker != root);
+
+ return NULL;
+}
+
+struct item* create_item(const void* key, size_t nkey, const void* data,
+ size_t size, uint32_t flags, time_t exp)
+{
+ struct item* ret= (struct item*)calloc(1, sizeof(struct list_entry));
+
+ if (ret != NULL)
+ {
+ ret->key= malloc(nkey);
+ if (size > 0)
+ {
+ ret->data= malloc(size);
+ }
+
+ if (ret->key == NULL || (size > 0 && ret->data == NULL))
+ {
+ free(ret->key);
+ free(ret->data);
+ free(ret);
+ return NULL;
+ }
+
+ memcpy(ret->key, key, nkey);
+ if (data != NULL)
+ {
+ memcpy(ret->data, data, size);
+ }
+
+ ret->nkey= nkey;
+ ret->size= size;
+ ret->flags= flags;
+ ret->exp= exp;
+ }
+
+ return ret;
+}
+
+bool delete_item(const void* key, size_t nkey)
+{
+ struct item* item= get_item(key, nkey);
+ bool ret= false;
+
+ if (item)
+ {
+ /* remove from linked list */
+ struct list_entry *entry= (struct list_entry*)item;
+
+ if (entry->next == entry)
+ {
+ /* Only one object in the list */
+ root= NULL;
+ }
+ else
+ {
+ /* ensure that we don't loose track of the root, and this will
+ * change the start position for the next search ;-) */
+ root= entry->next;
+ entry->prev->next= entry->next;
+ entry->next->prev= entry->prev;
+ }
+
+ free(item->key);
+ free(item->data);
+ free(item);
+ ret= true;
+ }
+
+ return ret;
+}
+
+void flush(uint32_t /* when */)
+{
+ /* remove the complete linked list */
+ if (root == NULL)
+ {
+ return;
+ }
+
+ root->prev->next= NULL;
+ while (root != NULL)
+ {
+ struct item* tmp= (struct item*)root;
+ root= root->next;
+
+ free(tmp->key);
+ free(tmp->data);
+ free(tmp);
+ }
+}
+
+void update_cas(struct item* item)
+{
+ item->cas= ++cas;
+}
+
+void release_item(struct item* /* item */)
+{
+}
--- /dev/null
+# vim:ft=automake
+# Copyright (C) 2012 Data Differential
+# All rights reserved.
+#
+# Use and distribution licensed under the BSD license. See
+# the COPYING file in the parent directory for full text.
+#
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+MEMCACHED_LIGHT_TESTS_LDADDS= \
+ libmemcached/libmemcached.la \
+ libmemcached/libmemcachedutil.la \
+ libtest/libtest.la
+example_t_memcached_light_SOURCES= example/t/memcached_light.cc
+example_t_memcached_light_CXXFLAGS = $(AM_CXXFLAGS)
+example_t_memcached_light_DEPENDENCIES= $(MEMCACHED_LIGHT_TESTS_LDADDS) example/memcached_light
+example_t_memcached_light_LDADD= $(MEMCACHED_LIGHT_TESTS_LDADDS)
+check_PROGRAMS+= example/t/memcached_light
+noinst_PROGRAMS+= example/t/memcached_light
+
+test-memcached_light: example/t/memcached_light
+ @example/t/memcached_light
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Test memcat
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ Test that we are cycling the servers we are creating during testing.
+*/
+
+#include <config.h>
+
+#include <libtest/test.hpp>
+#include <libmemcached/memcached.h>
+
+using namespace libtest;
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+static std::string executable("example/memcached_light");
+
+static test_return_t help_TEST(void *)
+{
+ const char *args[]= { "--help", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t verbose_TEST(void *)
+{
+ const char *args[]= { "--help", "--verbose", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t daemon_TEST(void *)
+{
+ const char *args[]= { "--help", "--daemon", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t protocol_TEST(void *)
+{
+ const char *args[]= { "--help", "--protocol", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t version_TEST(void *)
+{
+ const char *args[]= { "--help", "--version", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t port_TEST(void *)
+{
+ const char *args[]= { "--help", "--port=9090", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t pid_file_TEST(void *)
+{
+ const char *args[]= { "--help", "--pid-file=/tmp/foo.pid", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t log_file_TEST(void *)
+{
+ const char *args[]= { "--help", "--log-file=/tmp/foo.log", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t max_connections_file_TEST(void *)
+{
+ const char *args[]= { "--help", "--max-connections=/tmp/foo.max_connections", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
+test_st cmdline_option_TESTS[] ={
+ {"--help", true, help_TEST },
+ {"--verbose", true, verbose_TEST },
+ {"--daemon", true, daemon_TEST },
+ {"--protocol", true, protocol_TEST },
+ {"--version", true, version_TEST },
+ {"--port", true, port_TEST },
+ {"--pid-file", true, pid_file_TEST },
+ {"--log-file", true, log_file_TEST },
+ {"--max-connections", true, max_connections_file_TEST },
+ {0, 0, 0}
+};
+
+collection_st collection[] ={
+ {"command line options", 0, 0, cmdline_option_TESTS },
+ {0, 0, 0, 0}
+};
+
+static void *world_create(server_startup_st& servers, test_return_t& error)
+{
+ if (HAVE_MEMCACHED_LIGHT_BINARY == 0)
+ {
+ error= TEST_SKIPPED;
+ return NULL;
+ }
+
+ if (server_startup(servers, "memcached-light", libtest::default_port(), 0, NULL) == 0)
+ {
+ error= TEST_FAILURE;
+ }
+
+ return &servers;
+}
+
+
+void get_world(Framework *world)
+{
+ world->collections= collection;
+ world->_create= world_create;
+}
+
#include "win32/wrappers.h"
#define get_socket_errno() WSAGetLastError()
#else
+#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(a) close(a)
* Delete an existing key
*
* @param cookie id of the client receiving the command
- * @param key the key to delete
+ * @param key the key to delete_object
* @param len the length of the key
* @param cas the CAS in the request
*/
- protocol_binary_response_status (*delete)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t cas);
+ protocol_binary_response_status (*delete_object)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t cas);
/**
* @param cookie id of the client receiving the command
* @param when when the cache should be flushed (0 == immediately)
*/
- protocol_binary_response_status (*flush)(const void *cookie,
- uint32_t when);
+ protocol_binary_response_status (*flush_object)(const void *cookie,
+ uint32_t when);
* Version 1 abstracts more of the protocol details, and let you work at
* a logical level
*/
- MEMCACHED_PROTOCOL_HANDLER_V1= 1,
+ MEMCACHED_PROTOCOL_HANDLER_V1= 1
} memcached_protocol_interface_version_t;
/**
LIBMEMCACHED_API
void memcached_protocol_client_destroy(memcached_protocol_client_st *client);
+LIBMEMCACHED_API
+void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg);
+
/**
* Error event means that the client encountered an error with the
* connection so you should shut it down
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+
+
+static void print_ascii_command(memcached_protocol_client_st *client)
+{
+ if (client->is_verbose)
+ {
+ switch (client->ascii_command)
+ {
+ case SET_CMD:
+ fprintf(stderr, "%s:%d SET_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case ADD_CMD:
+ fprintf(stderr, "%s:%d ADD_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case REPLACE_CMD:
+ fprintf(stderr, "%s:%d REPLACE_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case CAS_CMD:
+ fprintf(stderr, "%s:%d CAS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case APPEND_CMD:
+ fprintf(stderr, "%s:%d APPEND_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case PREPEND_CMD:
+ fprintf(stderr, "%s:%d PREPEND_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case DELETE_CMD:
+ fprintf(stderr, "%s:%d DELETE_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case INCR_CMD: /* FALLTHROUGH */
+ fprintf(stderr, "%s:%d INCR_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case DECR_CMD:
+ fprintf(stderr, "%s:%d DECR_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case STATS_CMD:
+ fprintf(stderr, "%s:%d STATS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case FLUSH_ALL_CMD:
+ fprintf(stderr, "%s:%d FLUSH_ALL_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case VERSION_CMD:
+ fprintf(stderr, "%s:%d VERSION_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case QUIT_CMD:
+ fprintf(stderr, "%s:%d QUIT_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case VERBOSITY_CMD:
+ fprintf(stderr, "%s:%d VERBOSITY_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case GET_CMD:
+ fprintf(stderr, "%s:%d GET_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case GETS_CMD:
+ fprintf(stderr, "%s:%d GETS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ default:
+ case UNKNOWN_CMD:
+ fprintf(stderr, "%s:%d UNKNOWN_CMD\n", __FILE__, __LINE__);
+ break;
+
+ }
+ }
+}
/**
* Try to parse a key from the string.
* @param text the text to spool
* @return status of the spool operation
*/
-static protocol_binary_response_status
-spool_string(memcached_protocol_client_st *client, const char *text)
+static protocol_binary_response_status raw_response_handler(memcached_protocol_client_st *client, const char *text)
{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, text);
+ }
+
+ if (client->root->drain(client) == false)
+ {
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+
+ assert(client->output != NULL);
+#if 0
+ if (client->output == NULL)
+ {
+ /* I can write directly to the socket.... */
+ do
+ {
+ size_t num_bytes= len -offset;
+ ssize_t nw= client->root->send(client,
+ client->sock,
+ ptr + offset,
+ num_bytes);
+ if (nw == -1)
+ {
+ if (get_socket_errno() == EWOULDBLOCK)
+ {
+ break;
+ }
+ else if (get_socket_errno() != EINTR)
+ {
+ client->error= errno;
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+ }
+ else
+ {
+ offset += (size_t)nw;
+ }
+ } while (offset < len);
+ }
+#endif
+
return client->root->spool(client, text, strlen(text));
}
[CAS_CMD]= "CLIENT_ERROR: Syntax error: cas <key> <flags> <exptime> <bytes> <casid> [noreply]\r\n",
[APPEND_CMD]= "CLIENT_ERROR: Syntax error: append <key> <flags> <exptime> <bytes> [noreply]\r\n",
[PREPEND_CMD]= "CLIENT_ERROR: Syntax error: prepend <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [DELETE_CMD]= "CLIENT_ERROR: Syntax error: delete <key> [noreply]\r\n",
+ [DELETE_CMD]= "CLIENT_ERROR: Syntax error: delete_object <key> [noreply]\r\n",
[INCR_CMD]= "CLIENT_ERROR: Syntax error: incr <key> <value> [noreply]\r\n",
[DECR_CMD]= "CLIENT_ERROR: Syntax error: decr <key> <value> [noreply]\r\n",
[STATS_CMD]= "CLIENT_ERROR: Syntax error: stats [key]\r\n",
};
client->mute = false;
- spool_string(client, errmsg[client->ascii_command]);
+ raw_response_handler(client, errmsg[client->ascii_command]);
}
/**
* @param text the length of the body
* @param textlen the length of the body
*/
-static protocol_binary_response_status
-ascii_version_response_handler(const void *cookie,
- const void *text,
- uint32_t textlen)
+static protocol_binary_response_status ascii_version_response_handler(const void *cookie,
+ const void *text,
+ uint32_t textlen)
{
memcached_protocol_client_st *client= (memcached_protocol_client_st*)cookie;
- spool_string(client, "VERSION ");
+ raw_response_handler(client, "VERSION ");
client->root->spool(client, text, textlen);
- spool_string(client, "\r\n");
+ raw_response_handler(client, "\r\n");
return PROTOCOL_BINARY_RESPONSE_SUCCESS;
}
* @param body the length of the body
* @param bodylen the length of the body
*/
-static protocol_binary_response_status
-ascii_stat_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen)
+static protocol_binary_response_status ascii_stat_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen)
{
memcached_protocol_client_st *client= (void*)cookie;
if (key != NULL)
{
- spool_string(client, "STAT ");
+ raw_response_handler(client, "STAT ");
client->root->spool(client, key, keylen);
- spool_string(client, " ");
+ raw_response_handler(client, " ");
client->root->spool(client, body, bodylen);
- spool_string(client, "\r\n");
+ raw_response_handler(client, "\r\n");
}
else
{
- spool_string(client, "END\r\n");
+ raw_response_handler(client, "END\r\n");
}
return PROTOCOL_BINARY_RESPONSE_SUCCESS;
send_command_usage(client);
}
else
+ {
client->root->spool(client, "END\r\n", 5);
+ }
}
/**
{ .cmd= "cas", .len= 3, .cc= CAS_CMD },
{ .cmd= "append", .len= 6, .cc= APPEND_CMD },
{ .cmd= "prepend", .len= 7, .cc= PREPEND_CMD },
- { .cmd= "delete", .len= 6, .cc= DELETE_CMD },
+ { .cmd= "delete_object", .len= 6, .cc= DELETE_CMD },
{ .cmd= "incr", .len= 4, .cc= INCR_CMD },
{ .cmd= "decr", .len= 4, .cc= DECR_CMD },
{ .cmd= "stats", .len= 5, .cc= STATS_CMD },
}
/**
- * Perform a delete operation.
+ * Perform a delete_object operation.
*
* @param client client requesting the deletion
* @param tokens the command as a vector
return;
}
- if (client->root->callback->interface.v1.delete == NULL)
+ if (client->root->callback->interface.v1.delete_object == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
- protocol_binary_response_status rval;
- rval= client->root->callback->interface.v1.delete(client, key, nkey, 0);
+ protocol_binary_response_status rval= client->root->callback->interface.v1.delete_object(client, key, nkey, 0);
if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
{
- spool_string(client, "DELETED\r\n");
+ raw_response_handler(client, "DELETED\r\n");
}
else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
{
- spool_string(client, "NOT_FOUND\r\n");
+ raw_response_handler(client, "NOT_FOUND\r\n");
}
else
{
char msg[80];
- snprintf(msg, sizeof(msg), "SERVER_ERROR: delete failed %u\r\n",(uint32_t)rval);
- spool_string(client, msg);
+ snprintf(msg, sizeof(msg), "SERVER_ERROR: delete_object failed %u\r\n",(uint32_t)rval);
+ raw_response_handler(client, msg);
}
}
{
if (client->root->callback->interface.v1.increment == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
rval= client->root->callback->interface.v1.increment(client,
{
if (client->root->callback->interface.v1.decrement == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
rval= client->root->callback->interface.v1.decrement(client,
{
char buffer[80];
snprintf(buffer, sizeof(buffer), "%"PRIu64"\r\n", result);
- spool_string(client, buffer);
+ raw_response_handler(client, buffer);
}
else
{
- spool_string(client, "NOT_FOUND\r\n");
+ raw_response_handler(client, "NOT_FOUND\r\n");
}
}
{
if (client->root->callback->interface.v1.stat == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
while (isspace(*key))
+ {
key++;
+ }
uint16_t nkey= (uint16_t)(end - key);
(void)client->root->callback->interface.v1.stat(client, key, nkey,
if (client->root->callback->interface.v1.version == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
return;
}
- if (client->root->callback->interface.v1.flush == NULL)
+ if (client->root->callback->interface.v1.flush_object == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return;
}
}
protocol_binary_response_status rval;
- rval= client->root->callback->interface.v1.flush(client, timeout);
+ rval= client->root->callback->interface.v1.flush_object(client, timeout);
if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- spool_string(client, "OK\r\n");
+ raw_response_handler(client, "OK\r\n");
else
- spool_string(client, "SERVER_ERROR: internal error\r\n");
+ raw_response_handler(client, "SERVER_ERROR: internal error\r\n");
}
/**
* 1 We need more data, so just go ahead and wait for more!
*/
static inline int process_storage_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
{
(void)ntokens; /* already checked */
char *key= tokens[1];
if (nkey == 0)
{
/* return error */
- spool_string(client, "CLIENT_ERROR: bad key\r\n");
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
return -1;
}
if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
{
- spool_string(client, "STORED\r\n");
+ raw_response_handler(client, "STORED\r\n");
}
else
{
{
if (rval == PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)
{
- spool_string(client, "EXISTS\r\n");
+ raw_response_handler(client, "EXISTS\r\n");
}
else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
{
- spool_string(client, "NOT_FOUND\r\n");
+ raw_response_handler(client, "NOT_FOUND\r\n");
}
else
{
- spool_string(client, "NOT_STORED\r\n");
+ raw_response_handler(client, "NOT_STORED\r\n");
}
}
else
{
- spool_string(client, "NOT_STORED\r\n");
+ raw_response_handler(client, "NOT_STORED\r\n");
}
}
if (client->root->callback->interface.v1.replace == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
if (client->root->callback->interface.v1.set == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
if (client->root->callback->interface.v1.add == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
if (client->root->callback->interface.v1.replace == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
if (client->root->callback->interface.v1.append == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
if (client->root->callback->interface.v1.prepend == NULL)
{
- spool_string(client, "SERVER_ERROR: callback not implemented\r\n");
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
return false;
}
client->ascii_command= ascii_to_cmd(ptr, (size_t)(*length));
+ /* we got all data available, execute the callback! */
+ if (client->root->callback->pre_execute != NULL)
+ {
+ client->root->callback->pre_execute(client, NULL);
+ }
+
+
/* A multiget lists all of the keys, and I don't want to have an
* avector of let's say 512 pointers to tokenize all of them, so let's
* just handle them immediately
*/
if (client->ascii_command == GET_CMD ||
- client->ascii_command == GETS_CMD) {
+ client->ascii_command == GETS_CMD)
+ {
if (client->root->callback->interface.v1.get != NULL)
+ {
ascii_process_gets(client, ptr, end);
+ }
else
- spool_string(client, "SERVER_ERROR: Command not implemented\n");
- } else {
+ {
+ raw_response_handler(client, "SERVER_ERROR: Command not implemented\n");
+ }
+ }
+ else
+ {
/* None of the defined commands takes 10 parameters, so lets just use
* that as a maximum limit.
- */
+ */
char *tokens[10];
int ntokens= ascii_tokenize_command(ptr, end, tokens, 10);
{
client->mute= strcmp(tokens[ntokens - 1], "noreply") == 0;
if (client->mute)
+ {
--ntokens; /* processed noreply token*/
+ }
}
int error= 0;
- switch (client->ascii_command) {
+ print_ascii_command(client);
+ switch (client->ascii_command)
+ {
case SET_CMD:
error= process_set_command(client, tokens, ntokens, ptr, &end, *length);
break;
+
case ADD_CMD:
error= process_add_command(client, tokens, ntokens, ptr, &end, *length);
break;
+
case REPLACE_CMD:
- error= process_replace_command(client, tokens, ntokens,
- ptr, &end, *length);
+ error= process_replace_command(client, tokens, ntokens, ptr, &end, *length);
break;
+
case CAS_CMD:
error= process_cas_command(client, tokens, ntokens, ptr, &end, *length);
break;
+
case APPEND_CMD:
- error= process_append_command(client, tokens, ntokens,
- ptr, &end, *length);
+ error= process_append_command(client, tokens, ntokens, ptr, &end, *length);
break;
+
case PREPEND_CMD:
- error= process_prepend_command(client, tokens, ntokens,
- ptr, &end, *length);
- break;
+ error= process_prepend_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
case DELETE_CMD:
process_delete(client, tokens, ntokens);
break;
case DECR_CMD:
process_arithmetic(client, tokens, ntokens);
break;
+
case STATS_CMD:
if (client->mute)
{
process_stats(client, ptr + 6, end);
}
break;
+
case FLUSH_ALL_CMD:
process_flush(client, tokens, ntokens);
break;
+
case VERSION_CMD:
if (client->mute)
{
process_version(client, tokens, ntokens);
}
break;
+
case QUIT_CMD:
if (ntokens != 1 || client->mute)
{
else
{
if (client->root->callback->interface.v1.quit != NULL)
+ {
client->root->callback->interface.v1.quit(client);
+ }
return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
case VERBOSITY_CMD:
if (ntokens != 2)
+ {
send_command_usage(client);
+ }
else
- spool_string(client, "OK\r\n");
+ {
+ raw_response_handler(client, "OK\r\n");
+ }
break;
case UNKNOWN_CMD:
}
if (error == -1)
+ {
return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
else if (error == 1)
+ {
return MEMCACHED_PROTOCOL_READ_EVENT;
+ }
+ }
+
+ if (client->root->callback->post_execute != NULL)
+ {
+ client->root->callback->post_execute(client, NULL);
}
/* Move past \n */
* @param response the packet to send
* @return The status of the operation
*/
-static protocol_binary_response_status
-raw_response_handler(const void *cookie,
- protocol_binary_request_header *request,
- protocol_binary_response_header *response)
+static protocol_binary_response_status raw_response_handler(const void *cookie,
+ protocol_binary_request_header *request,
+ protocol_binary_response_header *response)
{
memcached_protocol_client_st *client= (void*)cookie;
return PROTOCOL_BINARY_RESPONSE_EINVAL;
}
- if (!client->root->drain(client))
+ if (client->root->drain(client) == false)
{
return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
}
- size_t len= sizeof(*response) + htonl(response->response.bodylen);
+ size_t len= sizeof(protocol_binary_response_header) + htonl(response->response.bodylen);
size_t offset= 0;
char *ptr= (void*)response;
return client->root->spool(client, ptr, len - offset);
}
+static void print_cmd(protocol_binary_command cmd)
+{
+ switch (cmd)
+ {
+ case PROTOCOL_BINARY_CMD_GET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_ADD: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_REPLACE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_INCREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DECREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_QUIT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_NOOP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_VERSION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETK: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETKQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_APPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_PREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_STAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_ADDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_REPLACEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_INCREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DECREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_QUITQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_FLUSHQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_APPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_PREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_VERBOSITY: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TOUCH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GATQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_AUTH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_STEP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RGET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RSET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RSETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RAPPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RAPPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RPREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RPREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RINCR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RINCRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDECR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDECRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DEL_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CONNECT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_MUTATION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_OPAQUE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_LAST_RESERVED: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SCRUB: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__, __LINE__); return;
+ default:
+ abort();
+ }
+}
+
/*
* Version 0 of the interface is really low level and protocol specific,
* while the version 1 of the interface is more API focused. We need a
* @param flags the flags for the item
* @param cas the CAS id for the item
*/
-static protocol_binary_response_status
-get_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen,
- uint32_t flags,
- uint64_t cas) {
-
+static protocol_binary_response_status get_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen,
+ uint32_t flags,
+ uint64_t cas)
+{
memcached_protocol_client_st *client= (void*)cookie;
uint8_t opcode= client->current_command->request.opcode;
* @param text the length of the body
* @param textlen the length of the body
*/
-static protocol_binary_response_status
-version_response_handler(const void *cookie,
- const void *text,
- uint32_t textlen) {
+static protocol_binary_response_status version_response_handler(const void *cookie,
+ const void *text,
+ uint32_t textlen)
+{
memcached_protocol_client_st *client= (void*)cookie;
* @param response_handler not used
* @return the result of the operation
*/
-static protocol_binary_response_status
-delete_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
+static protocol_binary_response_status delete_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
{
(void)response_handler;
protocol_binary_response_status rval;
memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.delete != NULL)
+ if (client->root->callback->interface.v1.delete_object != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
void *key= (header +1);
uint64_t cas= memcached_ntohll(header->request.cas);
- rval= client->root->callback->interface.v1.delete(cookie, key, keylen, cas);
+ rval= client->root->callback->interface.v1.delete_object(cookie, key, keylen, cas);
if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
{
protocol_binary_response_status rval;
memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.flush != NULL)
+ if (client->root->callback->interface.v1.flush_object != NULL)
{
- protocol_binary_request_flush *flush= (void*)header;
+ protocol_binary_request_flush *flush_object= (void*)header;
uint32_t timeout= 0;
if (htonl(header->request.bodylen) == 4)
{
- timeout= ntohl(flush->message.body.expiration);
+ timeout= ntohl(flush_object->message.body.expiration);
}
- rval= client->root->callback->interface.v1.flush(cookie, timeout);
+ rval= client->root->callback->interface.v1.flush_object(cookie, timeout);
if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
header->request.opcode == PROTOCOL_BINARY_CMD_FLUSH)
{
* @param response_handler not used
* @return the result of the operation
*/
-static protocol_binary_response_status
-set_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
+static protocol_binary_response_status set_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
{
(void)response_handler;
protocol_binary_response_status rval;
client->root->callback->pre_execute(client, header);
}
- protocol_binary_response_status rval;
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
uint8_t cc= header->request.opcode;
+ if (client->is_verbose)
+ {
+ print_cmd(cc);
+ }
+
switch (client->root->callback->interface_version)
{
case 0:
- if (client->root->callback->interface.v0.comcode[cc] != NULL) {
+ if (client->root->callback->interface.v0.comcode[cc] != NULL)
+ {
rval= client->root->callback->interface.v0.comcode[cc](client, header, raw_response_handler);
}
break;
+
case 1:
- if (comcode_v0_v1_remap[cc] != NULL) {
+ if (comcode_v0_v1_remap[cc] != NULL)
+ {
rval= comcode_v0_v1_remap[cc](client, header, raw_response_handler);
}
break;
+
default:
/* Unknown interface.
* It should be impossible to get here so I'll just call abort
*length= len;
*endptr= (void*)header;
return MEMCACHED_PROTOCOL_ERROR_EVENT;
- } else if (rv == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
+ }
+ else if (rv == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
+ {
return MEMCACHED_PROTOCOL_PAUSE_EVENT;
+ }
ssize_t total= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen));
len -= total;
};
struct memcached_protocol_client_st {
+ bool is_verbose;
memcached_protocol_st *root;
memcached_socket_t sock;
int error;
size_t nbytes)
{
(void)cookie;
- return send(fd, buf, nbytes, 0);
+ return send(fd, buf, nbytes, MSG_NOSIGNAL);
}
/**
*/
static bool drain_output(struct memcached_protocol_client_st *client)
{
- ssize_t len;
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s mute:%d output:%s length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute,
+ client->output ? "yes" : "no",
+ client->output ? (int)(client->output->nbytes - client->output->offset) : 0);
+ }
/* Do we have pending data to send? */
while (client->output != NULL)
{
- len= client->root->send(client,
+ ssize_t len= client->root->send(client,
client->sock,
client->output->data + client->output->offset,
client->output->nbytes - client->output->offset);
const void *data,
size_t length)
{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s mute:%d length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute, (int)length);
+ }
+
if (client->mute)
{
return PROTOCOL_BINARY_RESPONSE_SUCCESS;
{
if (*client->root->input_buffer == (uint8_t)PROTOCOL_BINARY_REQ)
{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: memcached_binary_protocol_process_data\n", __FILE__, __LINE__);
+ }
client->work= memcached_binary_protocol_process_data;
}
else if (client->root->callback->interface_version == 1)
{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: memcached_ascii_protocol_process_data\n", __FILE__, __LINE__);
+ }
+
/*
* The ASCII protocol can only be used if the implementors provide
* an implementation for the version 1 of the interface..
}
else
{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: Unsupported protocol\n", __FILE__, __LINE__);
+ }
+
/* Let's just output a warning the way it is supposed to look like
* in the ASCII protocol...
*/
const char *err= "CLIENT_ERROR: Unsupported protocol\r\n";
client->root->spool(client, err, strlen(err));
client->root->drain(client);
+
return MEMCACHED_PROTOCOL_ERROR_EVENT; /* Unsupported protocol */
}
{
free(ret);
ret= NULL;
+
return NULL;
}
struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, memcached_socket_t sock)
{
- struct memcached_protocol_client_st *ret= calloc(1, sizeof(*ret));
+ struct memcached_protocol_client_st *ret= calloc(1, sizeof(memcached_protocol_client_st));
if (ret != NULL)
{
ret->root= instance;
free(client);
}
+void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg)
+{
+ if (client)
+ {
+ client->is_verbose= arg;
+ }
+}
+
memcached_protocol_event_t memcached_protocol_client_work(struct memcached_protocol_client_st *client)
{
/* Try to send data and read from the socket */
memcached_protocol_event_t ret= MEMCACHED_PROTOCOL_READ_EVENT;
if (client->output)
+ {
ret|= MEMCACHED_PROTOCOL_READ_EVENT;
+ }
return ret;
}
return "benchmark/blobslap_worker";
}
- const char *pid_file_option()
- {
- return "--pid-file=";
- }
-
const char *daemon_file_option()
{
return "--daemon";
}
- const char *log_file_option()
+ bool has_port_option() const
{
- return "--log-file=";
+ return true;
}
- const char *port_option()
+ bool has_log_file_option() const
{
- return "--port=";
+ return true;
}
bool is_libtool()
return true;
}
- bool build(int argc, const char *argv[]);
+ bool build(size_t argc, const char *argv[]);
};
#include <sstream>
-bool BlobslapWorker::build(int argc, const char *argv[])
+bool BlobslapWorker::build(size_t argc, const char *argv[])
{
std::stringstream arg_buffer;
- for (int x= 1 ; x < argc ; x++)
+ for (size_t x= 0 ; x < argc ; x++)
{
- arg_buffer << " " << argv[x] << " ";
+ add_option(argv[x]);
}
- set_extra_args(arg_buffer.str());
-
return true;
}
return arg_buffer.str();
}
+ static Application::error_t int_to_error_t(int arg)
+ {
+ switch (arg)
+ {
+ case 127:
+ return Application::INVALID;
+
+ case 0:
+ return Application::SUCCESS;
+
+ default:
+ case 1:
+ return Application::FAILURE;
+ }
+ }
}
namespace libtest {
}
else
{
- assert(waited_pid == _pid);
- exit_code= error_t(exited_successfully(status));
+ if (waited_pid != _pid)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Pid mismatch, %d != %d", int(waited_pid), int(_pid));
+ }
+ exit_code= int_to_error_t(exited_successfully(status));
}
}
if (exit_code == Application::INVALID)
{
-#if 0
Error << print_argv(built_argv, _argc, _pid);
-#endif
}
return exit_code;
{
return int(ret);
}
- ret= app.wait();
- return int(ret);
+ return int(app.wait());
}
const char *gearmand_binary()
case Application::INVALID:
output << "127";
break;
+
+ default:
+ output << "EXIT_UNKNOWN";
}
return output;
enum test_return_t {
TEST_SUCCESS,
TEST_FAILURE,
- TEST_MEMORY_ALLOCATION_FAILURE,
- TEST_SKIPPED,
- TEST_FATAL // Collection should not be continued
+ TEST_SKIPPED
};
} // namespace libtest
#define fatal_message(__mesg) libtest::fatal(LIBYATL_DEFAULT_PARAM, __mesg)
+#define fatal_assert(__assert) if((__assert)) {} else { libtest::fatal(LIBYATL_DEFAULT_PARAM, #__assert); }
return GEARMAND_BINARY;
}
- const char *pid_file_option()
- {
- return "--pid-file=";
- }
-
const char *daemon_file_option()
{
return "--daemon";
}
- const char *log_file_option()
+ void log_file_option(Application& app, const std::string& arg)
{
- return "--verbose=DEBUG --log-file=";
+ if (arg.empty() == false)
+ {
+ std::string buffer("--log-file=");
+ buffer+= arg;
+ app.add_option("--verbose=DEBUG");
+ app.add_option(buffer);
+ }
}
- const char *port_option()
+ bool has_log_file_option() const
{
- return "--port=";
+ return true;
}
bool is_libtool()
return true;
}
- bool build(int argc, const char *argv[]);
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ bool build(size_t argc, const char *argv[]);
};
-bool Gearmand::build(int argc, const char *argv[])
+bool Gearmand::build(size_t argc, const char *argv[])
{
std::stringstream arg_buffer;
if (getuid() == 0 or geteuid() == 0)
{
- arg_buffer << " -u root ";
+ add_option("-u", "root");
}
- arg_buffer << " --listen=localhost ";
+ add_option("--listen=localhost");
- for (int x= 1 ; x < argc ; x++)
+ for (size_t x= 0 ; x < argc ; x++)
{
- arg_buffer << " " << argv[x] << " ";
+ add_option(argv[x]);
}
- set_extra_args(arg_buffer.str());
-
return true;
}
pid_t get_pid(bool error_is_ok)
{
// Memcached is slow to start, so we need to do this
- if (not pid_file().empty())
+ if (pid_file().empty() == false)
{
if (error_is_ok and not wait_for_pidfile())
{
return MEMCACHED_BINARY;
}
- const char *pid_file_option()
+ virtual void pid_file_option(Application& app, const std::string& arg)
{
- return "-P ";
+ if (arg.empty() == false)
+ {
+ app.add_option("-P", arg);
+ }
}
const char *socket_file_option() const
return "-d";
}
- const char *log_file_option()
+ virtual void port_option(Application& app, in_port_t arg)
{
- return NULL;
+ char buffer[30];
+ snprintf(buffer, sizeof(buffer), "%d", int(arg));
+ app.add_option("-p", buffer);
}
- const char *port_option()
+ bool has_port_option() const
{
- return "-p ";
+ return true;
+ }
+
+ bool has_socket_file_option() const
+ {
+ return has_socket();
+ }
+
+ void socket_file_option(Application& app, const std::string& socket_arg)
+ {
+ if (socket_arg.empty() == false)
+ {
+ app.add_option("-s", socket_arg);
+ }
}
bool is_libtool()
return true;
}
- bool build(int argc, const char *argv[]);
+ bool build(size_t argc, const char *argv[]);
+};
+
+class MemcachedLight : public libtest::Server
+{
+
+public:
+ MemcachedLight(const std::string& host_arg, const in_port_t port_arg):
+ libtest::Server(host_arg, port_arg)
+ {
+ set_pid_file();
+ }
+
+ pid_t get_pid(bool error_is_ok)
+ {
+ // Memcached is slow to start, so we need to do this
+ if (not pid_file().empty())
+ {
+ if (error_is_ok and not wait_for_pidfile())
+ {
+ Error << "Pidfile was not found:" << pid_file();
+ return -1;
+ }
+ }
+
+ bool success= false;
+ std::stringstream error_message;
+ pid_t local_pid= get_pid_from_file(pid_file(), error_message);
+ if (local_pid > 0)
+ {
+ if (::kill(local_pid, 0) > 0)
+ {
+ success= true;
+ }
+ }
+
+ if (error_is_ok and ((success or not is_pid_valid(local_pid))))
+ {
+ Error << "kill(" << " pid: " << local_pid << " errno:" << strerror(errno) << " for:" << *this;
+ }
+
+ return local_pid;
+ }
+
+ bool ping()
+ {
+ // Memcached is slow to start, so we need to do this
+ if (not pid_file().empty())
+ {
+ if (not wait_for_pidfile())
+ {
+ Error << "Pidfile was not found:" << pid_file();
+ return false;
+ }
+ }
+
+ std::stringstream error_message;
+ pid_t local_pid= get_pid_from_file(pid_file(), error_message);
+ if (local_pid > 0)
+ {
+ if (::kill(local_pid, 0) == 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ const char *name()
+ {
+ return "memcached_light";
+ };
+
+ const char *executable()
+ {
+ return MEMCACHED_LIGHT_BINARY;
+ }
+
+ const char *daemon_file_option()
+ {
+ return "--daemon";
+ }
+
+ virtual void port_option(Application& app, in_port_t arg)
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
+ app.add_option(buffer);
+ }
+
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ bool is_libtool()
+ {
+ return true;
+ }
+
+ bool build(size_t argc, const char *argv[]);
};
class MemcachedSaSL : public Memcached
#include <sstream>
-bool Memcached::build(int argc, const char *argv[])
+bool Memcached::build(size_t argc, const char *argv[])
{
std::stringstream arg_buffer;
if (getuid() == 0 or geteuid() == 0)
{
- arg_buffer << " -u root ";
+ add_option("-u", "root");
}
- arg_buffer << " -l localhost ";
- arg_buffer << " -m 128 ";
- arg_buffer << " -M ";
+ add_option("-l", "localhost");
+ add_option("-m", "128");
+ add_option("-M");
if (sasl())
{
- arg_buffer << sasl();
+ add_option(sasl());
}
- for (int x= 1 ; x < argc ; x++)
+ for (int x= 0 ; x < argc ; x++)
{
- arg_buffer << " " << argv[x] << " ";
+ add_option(argv[x]);
}
- set_extra_args(arg_buffer.str());
+ return true;
+}
+
+bool MemcachedLight::build(size_t argc, const char *argv[])
+{
+ for (int x= 0 ; x < argc ; x++)
+ {
+ add_option(argv[x]);
+ }
return true;
}
return new Memcached(socket_file, try_port, true);
}
+libtest::Server *build_memcached_light(const std::string& hostname, const in_port_t try_port)
+{
+ return new MemcachedLight(hostname, try_port);
+}
+
libtest::Server *build_memcached_sasl(const std::string& hostname, const in_port_t try_port, const std::string& username, const std::string &password)
{
libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port);
+libtest::Server *build_memcached_light(const std::string& socket_file, const in_port_t try_port);
+
libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port);
libtest::Server *build_memcached_sasl(const std::string& hostname, const in_port_t try_port, const std::string& username, const std::string& password);
#include <libtest/stream.h>
#include <libtest/killpid.h>
-extern "C" {
- static bool exited_successfully(int status, const std::string &command)
- {
- if (status == 0)
- {
- return true;
- }
-
- if (WIFEXITED(status) == true)
- {
- int ret= WEXITSTATUS(status);
-
- if (ret == 0)
- {
- return true;
- }
- else if (ret == EXIT_FAILURE)
- {
- libtest::Error << "Command executed, but returned EXIT_FAILURE: " << command;
- }
- else
- {
- libtest::Error << "Command executed, but returned " << ret;
- }
- }
- else if (WIFSIGNALED(status) == true)
- {
- int ret_signal= WTERMSIG(status);
- libtest::Error << "Died from signal " << strsignal(ret_signal);
- }
-
- return false;
- }
-}
-
-
namespace libtest {
std::ostream& operator<<(std::ostream& output, const Server &arg)
output << " Exec:" << arg.running();
}
-
return output; // for multiple << operators
}
return true;
}
-// Grab a one off command
-bool Server::command(std::string& command_arg)
-{
- rebuild_base_command();
-
- command_arg+= _base_command;
-
- if (args(command_arg))
- {
- return true;
- }
-
- return false;
-}
-
bool Server::wait_for_pidfile() const
{
Wait wait(pid_file(), 4);
Error << "Could not kill() existing server during start() pid:" << _pid;
return false;
}
- assert(not has_pid());
- _running.clear();
- if (command(_running) == false)
+ if (has_pid() == false)
+ {
+ fatal_message("has_pid() failed, programer error");
+ }
+
+ Application app(executable(), is_libtool());
+ if (args(app) == false)
{
Error << "Could not build command()";
return false;
}
- if (is_valgrind() or is_helgrind())
+ Application::error_t ret;
+ if (Application::SUCCESS != (ret= app.run()))
{
- _running+= " &";
+ Error << "Application::run() " << ret;
+ return false;
}
+ _running= app.print();
- int ret= system(_running.c_str());
- if (exited_successfully(ret, _running) == false)
+ if (Application::SUCCESS != (ret= app.wait()))
{
- Error << "system(" << _running << ") failed: " << strerror(errno);
- _running.clear();
+ Error << "Application::wait() " << app.print() << " " << ret;
return false;
}
dream(5, 50000);
}
- if (pid_file_option() and pid_file().empty() == false)
+ if (pid_file().empty() == false)
{
Wait wait(pid_file(), 8);
if (pinged == false)
{
// If we happen to have a pid file, lets try to kill it
- if (pid_file_option() and pid_file().empty() == false)
+ if (pid_file().empty() == false)
+ {
+ if (kill_file(pid_file()) == false)
+ {
+ fatal_message("Failed to kill off server after startup occurred, when pinging failed");
+ }
+ Error << "Failed to ping() server started, having pid_file. exec:" << _running;
+ }
+ else
{
- Error << "We are going to kill it off";
- kill_file(pid_file());
+ Error << "Failed to ping() server started. exec:" << _running;
}
- Error << "Failed to ping() server started with:" << _running;
_running.clear();
return false;
}
return _pid;
}
+void Server::add_option(const std::string& arg)
+{
+ _options.push_back(std::make_pair(arg, std::string()));
+}
+
+void Server::add_option(const std::string& name, const std::string& value)
+{
+ _options.push_back(std::make_pair(name, value));
+}
+
bool Server::set_socket_file()
{
char file_buffer[FILENAME_MAX];
return true;
}
-void Server::rebuild_base_command()
+bool Server::args(Application& app)
{
- _base_command.clear();
- if (is_libtool())
- {
- _base_command+= libtool();
- _base_command+= " --mode=execute ";
- }
-
- if (is_debug() and getenv("GDB_COMMAND"))
- {
- _base_command+= getenv("GDB_COMMAND");
- _base_command+= " ";
- }
- else if (is_valgrind() and getenv("VALGRIND_COMMAND"))
- {
- _base_command+= getenv("VALGRIND_COMMAND");
- _base_command+= " ";
- }
- else if (is_helgrind() and getenv("HELGRIND_COMMAND"))
- {
- _base_command+= getenv("HELGRIND_COMMAND");
- _base_command+= " ";
- }
-
- if (is_libtool())
- {
- if (getenv("PWD"))
- {
- _base_command+= getenv("PWD");
- _base_command+= "/";
- }
- }
-
- _base_command+= executable();
-}
-
-void Server::set_extra_args(const std::string &arg)
-{
- _extra_args= arg;
-}
-
-bool Server::args(std::string& options)
-{
- std::stringstream arg_buffer;
// Set a log file if it was requested (and we can)
- if (getenv("LIBTEST_LOG") and log_file_option())
+ if (getenv("LIBTEST_LOG") and has_log_file_option())
{
if (not set_log_file())
{
return false;
}
- arg_buffer << " " << log_file_option() << _log_file;
+ log_file_option(app, _log_file);
}
if (getenv("LIBTEST_SYSLOG") and has_syslog())
{
- arg_buffer << " --syslog";
+ app.add_option("--syslog");
}
// Update pid_file
- if (pid_file_option())
{
if (_pid_file.empty() and set_pid_file() == false)
{
return false;
}
- arg_buffer << " " << pid_file_option() << pid_file();
+ pid_file_option(app, pid_file());
}
assert(daemon_file_option());
if (daemon_file_option() and not is_valgrind() and not is_helgrind())
{
- arg_buffer << " " << daemon_file_option();
+ app.add_option(daemon_file_option());
}
- if (_is_socket and socket_file_option())
+ if (has_socket_file_option())
{
- if (not set_socket_file())
+ if (set_socket_file() == false)
{
return false;
}
- arg_buffer << " " << socket_file_option() << "\"" << _socket << "\"";
+ socket_file_option(app, _socket);
}
- assert(port_option());
- if (port_option() and _port > 0)
+ if (has_port_option())
{
- arg_buffer << " " << port_option() << _port;
+ port_option(app, _port);
}
- options+= arg_buffer.str();
-
- if (not _extra_args.empty())
+ for (Options::const_iterator iter= _options.begin(); iter != _options.end(); iter++)
{
- options+= _extra_args;
+ if ((*iter).second.empty() == false)
+ {
+ app.add_option((*iter).first, (*iter).second);
+ }
+ else
+ {
+ app.add_option((*iter).first);
+ }
}
return true;
#pragma once
+#include <libtest/cmdline.h>
+
#include <cassert>
#include <cstdio>
#include <cstring>
namespace libtest {
struct Server {
+private:
+ typedef std::vector< std::pair<std::string, std::string> > Options;
+
private:
bool _is_socket;
std::string _socket;
virtual const char *name()= 0;
virtual const char *executable()= 0;
- virtual const char *port_option()= 0;
- virtual const char *pid_file_option()= 0;
virtual const char *daemon_file_option()= 0;
- virtual const char *log_file_option()= 0;
virtual bool is_libtool()= 0;
- virtual bool broken_socket_cleanup()
+ virtual bool has_socket_file_option() const
+ {
+ return false;
+ }
+
+ virtual void socket_file_option(Application& app, const std::string& socket_arg)
+ {
+ if (socket_arg.empty() == false)
+ {
+ std::string buffer("--socket=");
+ buffer+= socket_arg;
+ app.add_option(buffer);
+ }
+ }
+
+ bool has_log_file_option() const
+ {
+ return false;
+ }
+
+ virtual void log_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ std::string buffer("--log-file=");
+ buffer+= arg;
+ app.add_option(buffer);
+ }
+ }
+
+ virtual void pid_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ std::string buffer("--pid-file=");
+ buffer+= arg;
+ app.add_option(buffer);
+ }
+ }
+
+ virtual bool has_port_option() const
{
return false;
}
- virtual const char *socket_file_option() const
+ virtual void port_option(Application& app, in_port_t arg)
{
- return NULL;
+ if (arg > 0)
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
+ app.add_option(buffer);
+ }
+ }
+
+ virtual bool broken_socket_cleanup()
+ {
+ return false;
}
virtual bool broken_pid_file()
virtual pid_t get_pid(bool error_is_ok= false)= 0;
- virtual bool build(int argc, const char *argv[])= 0;
+ virtual bool build(size_t argc, const char *argv[])= 0;
+
+ void add_option(const std::string&);
+ void add_option(const std::string&, const std::string&);
in_port_t port() const
{
_log_file.clear();
}
- void set_extra_args(const std::string &arg);
-
- bool args(std::string& options);
+ bool args(Application&);
pid_t pid();
bool kill(pid_t pid_arg);
bool start();
- bool command(std::string& command_arg);
+ bool command(libtest::Application& app);
protected:
bool set_pid_file();
+ Options _options;
private:
bool is_helgrind() const;
bool is_debug() const;
bool set_log_file();
bool set_socket_file();
- void rebuild_base_command();
void reset_pid();
};
bool server_startup(server_startup_st& construct, const std::string& server_type, in_port_t try_port, int argc, const char *argv[])
{
Outn();
- (void)try_port;
+ if (try_port <= 0)
+ {
+ libtest::fatal(LIBYATL_DEFAULT_PARAM, "was passed the invalid port number %d", int(try_port));
+ }
libtest::Server *server= NULL;
if (0)
}
}
}
+ else if (server_type.compare("memcached-light") == 0)
+ {
+ if (MEMCACHED_LIGHT_BINARY)
+ {
+ if (HAVE_LIBMEMCACHED)
+ {
+ server= build_memcached_light("localhost", try_port);
+ }
+ }
+ }
if (server == NULL)
{
- Error << "Failure occured while creating server: " << server_type;
- return false;
+ fatal_message("Launching of an unknown server was attempted");
}
/*
Out << "Pausing for startup, hit return when ready.";
std::string gdb_command= server->base_command();
std::string options;
+#if 0
Out << "run " << server->args(options);
+#endif
getchar();
}
else if (server->start() == false)
Out << "Pausing for startup, hit return when ready.";
std::string gdb_command= server->base_command();
std::string options;
+#if 0
Out << "run " << server->args(options);
+#endif
getchar();
}
else if (not server->start())
case TEST_FAILURE:
return "failed";
- case TEST_MEMORY_ALLOCATION_FAILURE:
- return "memory allocation";
-
case TEST_SKIPPED:
return "skipped";
-
- case TEST_FATAL:
- break;
}
- return "failed";
+ throw fatal_message("No port could be found");
}
} // namespace libtest
delete world;
return EXIT_SUCCESS;
- case TEST_FATAL:
case TEST_FAILURE:
- case TEST_MEMORY_ALLOCATION_FAILURE:
delete world;
return EXIT_FAILURE;
}
case TEST_SUCCESS:
break;
- case TEST_FATAL:
case TEST_FAILURE:
Out << next->name << " [ failed ]";
failed= true;
skipped= true;
goto cleanup;
- case TEST_MEMORY_ALLOCATION_FAILURE:
- test_assert(0, "Allocation failure, or unknown return");
+ default:
+ throw fatal_message("invalid return code");
}
Out << "Collection: " << next->name;
stats.success++;
break;
- case TEST_FATAL:
case TEST_FAILURE:
stats.failed++;
failed= true;
Out << "\tTesting " << run->name << "\t\t\t\t\t" << "[ " << test_strerror(return_code) << " ]";
break;
- case TEST_MEMORY_ALLOCATION_FAILURE:
- test_assert(0, "Memory Allocation Error");
+ default:
+ throw fatal_message("invalid return code");
}
if (test_failed(world->on_error(return_code, creators_ptr)))
{
std::cerr << e.what() << std::endl;
}
+ catch (std::bad_alloc& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
catch (...)
{
std::cerr << "Unknown exception halted execution" << std::endl;
#include <cstdio>
#include <cstdlib>
-#include <stdint.h>
#include <arpa/inet.h>
#include <libtest/visibility.h>
test_skip(true, has_gearmand_binary());
#endif
- const char *argv[1]= { "cycle_gearmand" };
- test_true(server_startup(*servers, "gearmand", get_free_port(), 1, argv));
+ test_true(server_startup(*servers, "gearmand", get_free_port(), 0, NULL));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t memcached_light_cycle_TEST(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+
+ test_skip(true, bool(HAVE_MEMCACHED_LIGHT_BINARY));
+
+ test_true(server_startup(*servers, "memcached-light", get_free_port(), 0, NULL));
return TEST_SUCCESS;
}
if (MEMCACHED_BINARY and HAVE_LIBMEMCACHED)
{
test_true(has_memcached_binary());
- const char *argv[1]= { "cycle_memcached" };
- test_true(server_startup(*servers, "memcached", get_free_port(), 1, argv));
+ test_true(server_startup(*servers, "memcached", get_free_port(), 0, NULL));
return TEST_SUCCESS;
}
if (HAVE_LIBMEMCACHED)
{
test_true(has_memcached_binary());
- const char *argv[1]= { "cycle_memcached" };
- test_true(servers->start_socket_server("memcached", get_free_port(), 1, argv));
+ test_true(servers->start_socket_server("memcached", get_free_port(), 0, NULL));
return TEST_SUCCESS;
}
if (HAVE_LIBMEMCACHED)
{
test_true(has_memcached_sasl_binary());
- const char *argv[1]= { "cycle_memcached_sasl" };
- test_true(server_startup(*servers, "memcached-sasl", get_free_port(), 1, argv));
+ test_true(server_startup(*servers, "memcached-sasl", get_free_port(), 0, NULL));
return TEST_SUCCESS;
}
test_st memcached_tests[] ={
{"memcached startup-shutdown", 0, memcached_cycle_test },
+ {"memcached-light startup-shutdown", 0, memcached_light_cycle_TEST },
{"memcached(socket file) startup-shutdown", 0, memcached_socket_cycle_test },
{"memcached_sasl() startup-shutdown", 0, memcached_sasl_test },
{"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test },
AS_IF([test "$]AS_TR_SH([ax_cv_have_]$1)[" = "yes"],
AC_DEFINE([HAVE_]$1, [1], [Define to 1 if ]$1[ is found])
- m4_ifnblank([$4], [$4]),
- m4_ifnblank([$5], [$5]))
+ m4_ifval( m4_normalize([$4]), [$4]),
+ m4_ifval( m4_normalize([$5]), [$5]))
])
check_PROGRAMS+= tests/memdump
noinst_PROGRAMS+= tests/memdump
-test-memerror: clients/memerror
+test-memstat: tests/memstat
+ tests/memstat
+
+test-memerror: tests/memerror
tests/memerror
-valgrind-memerror: clients/memerror
- @$(VALGRIND_COMMAND) tests/memerror
+test-memtouch: tests/memtouch
+ tests/memtouch
-test-memcp: clients/memcp
- @echo "Testing memcp"
- @@MEMC_BINARY@ -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @clients/memcp --servers="localhost:12555" clients/memcp clients/memcat clients/memstat
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-valgrind-memcp: clients/memcat clients/memcp
- @echo "Testing memcp"
- @@MEMC_BINARY@ -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @$(VALGRIND_COMMAND) clients/memcp --servers="localhost:12555" clients/memcp clients/memcat clients/memstat
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-test-memflush: clients/memflush
- @echo "Testing memflush"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @clients/memflush --servers="localhost:12555"
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-valgrind-memflush: clients/memflush
- @echo "Testing memflush"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @$(VALGRIND_COMMAND) clients/memflush --servers="localhost:12555"
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-test-memdump: clients/memdump clients/memcp
- @echo "Testing memdump"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @clients/memcp --servers="localhost:12555" clients/memcat
- @clients/memdump --servers="localhost:12555" > /dev/null
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-valgrind-memdump: clients/memcat clients/memcp
- @echo "Testing memdump"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @clients/memcp --servers="localhost:12555" clients/memcat
- @$(VALGRIND_COMMAND) clients/memdump --servers="localhost:12555" > /dev/null
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-test-memstat: clients/memstat
- @echo "Testing memstat"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @clients/memstat --servers="localhost:12555" > /dev/null
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
-
-valgrind-memstat: clients/memstat
- @echo "Testing memstat"
- @$(MEMC_BINARY) -d -u root -P `pwd`/tests/Xumemc.pid -p 12555
- @$(VALGRIND_COMMAND) clients/memstat --servers="localhost:12555" > /dev/null
- @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
- @rm tests/Xumemc.pid
+valgrind-memerror: tests/memerror
+ @$(VALGRIND_COMMAND) tests/memerror
+valgrind-memtouch: tests/memtouch
+ @$(VALGRIND_COMMAND) tests/memtouch
using namespace libtest;
-#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
check-local: $(TEST_DOCS)
@echo "Tests completed"
-test-x: test-plus test-memcp test-memdump test-memflush test-memstat
- @echo "Tests completed"
-
test-mem: tests/var tests/libmemcached-1.0/testapp
@tests/libmemcached-1.0/testapp
if (getenv("LIBMEMCACHED_SERVER_NUMBER"))
{
int set_count= atoi(getenv("LIBMEMCACHED_SERVER_NUMBER"));
- assert(set_count >= 0);
+ fatal_assert(set_count >= 0);
world->servers().set_count(set_count);
}
else
const char *key,
size_t key_length)
{
- assert(key);
- assert(key_length);
+ fatal_assert(key);
+ fatal_assert(key_length);
return MEMCACHED_SUCCESS;
}
#include <config.h>
#include <libtest/test.hpp>
-#include <cassert>
-
#include <libmemcached/memcached.h>
#include <tests/deprecated.h>
test_return_t regression_bug_728286(memcached_st *)
{
memcached_server_st *servers= memcached_servers_parse("1.2.3.4:99");
- assert(servers);
+ fatal_assert(servers);
memcached_server_free(servers);
return TEST_SUCCESS;
#include <libhashkit-1.0/hashkit.h>
-#include <cassert>
#include <cerrno>
#include <memory>
#include <pthread.h>
/* Do Nothing */
size_t bigger= *((size_t *)(context));
(void)ptr;
- assert(bigger <= memcached_server_port(server));
+ fatal_assert(bigger <= memcached_server_port(server));
*((size_t *)(context))= memcached_server_port(server);
return MEMCACHED_SUCCESS;
/* sighandler_t function that always asserts false */
static void fail(int)
{
- assert(0);
+ fatal_assert(0);
}
#include <vector>
#include <string>
#include <cerrno>
-#include <cassert>
#include <libmemcached/memcached.h>
#include <libmemcached/util.h>
{
if (strcmp(memcached_server_name(instance), "localhost"))
{
- assert(not memcached_server_name(instance));
+ fatal_assert(not memcached_server_name(instance));
return MEMCACHED_FAILURE;
}
if (memcached_server_port(instance) < 8888 or memcached_server_port(instance) > 8892)
{
- assert(not memcached_server_port(instance));
+ fatal_assert(not memcached_server_port(instance));
return MEMCACHED_FAILURE;
}
if (instance->weight > 5 or instance->weight < 2)
{
- assert(not instance->weight);
+ fatal_assert(not instance->weight);
return MEMCACHED_FAILURE;
}
static void* connection_release(void *arg)
{
test_pool_context_st *resource= static_cast<test_pool_context_st *>(arg);
- assert(resource);
if (resource == NULL)
{
- abort();
+ fatal_message("resource == NULL");
}
// Release all of the memc we are holding
#pragma once
-#include <cassert>
-
/* The structure we use for the test system */
struct libmemcached_test_container_st
{
for (uint32_t x= 0; x < servers.count(); x++)
{
- char variable_buffer[1024];
- snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
+ in_port_t port= libtest::get_free_port();
- in_port_t port;
- char *var;
- if ((var= getenv(variable_buffer)))
- {
- port= in_port_t(atoi(var));
- }
- else
- {
- port= in_port_t(libtest::get_free_port());
- }
-
- const char *argv[1]= { "memcached" };
if (servers.sasl())
{
- if (not server_startup(servers, "memcached-sasl", port, 1, argv))
+ if (server_startup(servers, "memcached-sasl", port, 0, NULL) == false)
{
- error= TEST_FATAL;
- return NULL;
+ fatal_message("Could not start memcached-sasl");
}
}
else
{
- if (not server_startup(servers, "memcached", port, 1, argv))
+ if (server_startup(servers, "memcached", port, 0, NULL) == false)
{
- error= TEST_FATAL;
- return NULL;
+ fatal_message("Could not start memcached");
}
}
}
libmemcached_test_container_st *global_container= new libmemcached_test_container_st(servers);
- if (global_container == NULL)
- {
- error= TEST_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- error= TEST_SUCCESS;
return global_container;
}
const char *argv[1]= { "memcached" };
if (not servers.start_socket_server("memcached", libtest::get_free_port(), 1, argv))
{
- error= TEST_FATAL;
- return NULL;
+ fatal_message("Could not launch memcached");
}
}
libmemcached_test_container_st *global_container= new libmemcached_test_container_st(servers);
- if (global_container == NULL)
- {
- error= TEST_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
error= TEST_SUCCESS;
#include <libmemcached/udp.hpp>
#include <libmemcachedutil-1.0/util.h>
-#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
return NULL;
}
- const char *argv[1]= { "memcapable" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
-
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true));
-
- return TEST_SUCCESS;
-}
+static std::string executable("clients/memcat");
static test_return_t help_test(void *)
{
}
test_st memcat_tests[] ={
- {"--quiet", true, quiet_test },
{"--help", true, help_test },
{"cat(FOUND)", true, cat_test },
{"cat(NOT_FOUND)", true, NOT_FOUND_test },
return NULL;
}
- const char *argv[1]= { "memcat" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (not server_startup(servers, "memcached", libtest::default_port(), 0, NULL))
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "clients/memcat";
world->collections= collection;
world->_create= world_create;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
-
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true));
-
- return TEST_SUCCESS;
-}
+static std::string executable("./clients/memcp");
static test_return_t help_test(void *)
{
}
test_st memcp_tests[] ={
- {"--quiet", true, quiet_test },
{"--help", true, help_test },
{"--server_test", true, server_test },
{0, 0, 0}
return NULL;
}
- const char *argv[1]= { "memcp" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "./clients/memcp";
world->collections= collection;
world->_create= world_create;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
-
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true));
-
- return TEST_SUCCESS;
-}
+static std::string executable("./clients/memdump");
static test_return_t help_test(void *)
{
}
test_st memdump_tests[] ={
- {"--quiet", true, quiet_test },
{"--help", true, help_test },
{"--server", true, server_test },
{"FOUND", true, FOUND_test },
return NULL;
}
- const char *argv[1]= { "memdump" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "./clients/memdump";
world->collections= collection;
world->_create= world_create;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
+static std::string executable("./clients/memerror");
static test_return_t help_TEST(void *)
{
void get_world(Framework *world)
{
- executable= "./clients/memerror";
world->collections= collection;
world->_create= world_create;
}
#include <libtest/test.hpp>
#include <libmemcached/memcached.h>
+#include <libmemcached/util.h>
using namespace libtest;
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
-
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_true(exec_cmdline(executable, args));
- return TEST_SUCCESS;
-}
+static std::string executable("./clients/memexist");
static test_return_t help_test(void *)
{
- const char *args[]= { "--quiet", "--help", 0 };
+ const char *args[]= { "--help", 0 };
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
return TEST_SUCCESS;
}
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
- const char *args[]= { "--quiet", buffer, "foo", 0 };
+ const char *args[]= { buffer, "foo", 0 };
memcached_st *memc= memcached(buffer, strlen(buffer));
test_true(memc);
test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc));
test_compare(MEMCACHED_SUCCESS, rc);
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc));
test_compare(MEMCACHED_SUCCESS, rc);
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
- const char *args[]= { "--quiet", buffer, "foo", 0 };
+ const char *args[]= { buffer, "foo", 0 };
memcached_st *memc= memcached(buffer, strlen(buffer));
test_true(memc);
test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc));
test_compare(MEMCACHED_NOTFOUND, rc);
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true));
test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc));
test_compare(MEMCACHED_NOTFOUND, rc);
return TEST_SUCCESS;
}
+static test_return_t check_version(void*)
+{
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
+ memcached_st *memc= memcached(buffer, strlen(buffer));
+ test_true(memc);
+
+ test_return_t result= TEST_SUCCESS;
+ if (libmemcached_util_version_check(memc, 1, 4, 8) == false)
+ {
+ result= TEST_SKIPPED;
+ }
+ memcached_free(memc);
+
+ return result;
+}
+
test_st memexist_tests[] ={
- {"--quiet", true, quiet_test },
{"--help", true, help_test },
{"exist(FOUND)", true, exist_test },
{"exist(NOT_FOUND)", true, NOT_FOUND_test },
};
collection_st collection[] ={
- {"memexist", 0, 0, memexist_tests },
+ {"memexist", check_version, 0, memexist_tests },
{0, 0, 0, 0}
};
return NULL;
}
- const char *argv[1]= { "memexist" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "./clients/memexist";
world->collections= collection;
world->_create= world_create;
}
return NULL;
}
- const char *argv[1]= { "memflush" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == 0)
{
error= TEST_FAILURE;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
+static std::string executable("./clients/memrm");
static test_return_t quiet_test(void *)
{
return TEST_SUCCESS;
}
-static test_return_t NOT_FOUND_test(void *)
+static test_return_t NOT_FOUND_TEST(void *)
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
return TEST_SUCCESS;
}
+static test_return_t multiple_NOT_FOUND_TEST(void *)
+{
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
+ const char *args[]= { buffer, "protocols", "foo", "mine", "bar", "dog", "cat", "foo", "mine",
+ "eye", "for", "the", "to", "not", "know", "what", "I", "should", "be", "doing", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
+
+ return TEST_SUCCESS;
+}
+
test_st memrm_tests[] ={
{"--quiet", true, quiet_test },
{"--help", true, help_test },
{"rm(FOUND)", true, rm_test },
- {"rm(NOT_FOUND)", true, NOT_FOUND_test },
+ {"rm(NOT_FOUND)", true, NOT_FOUND_TEST },
+ {"multiple rm(NOT_FOUND)", true, multiple_NOT_FOUND_TEST },
{0, 0, 0}
};
return NULL;
}
- const char *argv[1]= { "memrm" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "./clients/memrm";
world->collections= collection;
world->_create= world_create;
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable;
-
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_true(exec_cmdline(executable, args));
- return TEST_SUCCESS;
-}
-
+static std::string executable("./clients/memstat");
static test_return_t help_test(void *)
{
- const char *args[]= { "--help", "--quiet", 0 };
+ const char *args[]= { "--help", 0 };
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
return TEST_SUCCESS;
}
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(libtest::default_port()));
- const char *args[]= { "--quiet", buffer, " --binary ", 0 };
+ const char *args[]= { buffer, " --binary ", 0 };
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
return TEST_SUCCESS;
}
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(libtest::default_port()));
- const char *args[]= { "--quiet", buffer, " --server-version", 0 };
+ const char *args[]= { buffer, " --server-version", 0 };
- test_true(exec_cmdline(executable, args));
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
return TEST_SUCCESS;
}
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(libtest::default_port()));
- const char *args[]= { "--quiet", buffer, " --binary --server-version", 0 };
+ const char *args[]= { buffer, " --binary --server-version", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
- test_true(exec_cmdline(executable, args));
return TEST_SUCCESS;
}
test_st memstat_tests[] ={
- {"--quiet", 0, quiet_test},
{"--help", 0, help_test},
{"--binary", 0, binary_TEST},
{"--server-version", 0, server_version_TEST},
return NULL;
}
- const char *argv[1]= { "memstat" };
- if (server_startup(servers, "memcached", libtest::default_port(), 1, argv) == false)
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
void get_world(Framework *world)
{
- executable= "./clients/memstat";
world->collections= collection;
world->_create= world_create;
}
#include <libtest/test.hpp>
#include <libmemcached/memcached.h>
+#include <libmemcached/util.h>
using namespace libtest;
static std::string executable;
-static test_return_t quiet_test(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- test_true(exec_cmdline(executable, args));
- return TEST_SUCCESS;
-}
-
static test_return_t help_test(void *)
{
- const char *args[]= { "--quiet", "--help", 0 };
+ const char *args[]= { "--help", 0 };
+
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
- test_true(exec_cmdline(executable, args));
return TEST_SUCCESS;
}
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
- const char *args[]= { "--quiet", "--expire=30", buffer, "foo", 0 };
memcached_st *memc= memcached(buffer, strlen(buffer));
test_true(memc);
test_compare(MEMCACHED_SUCCESS, memcached_exist(memc, test_literal_param("foo")));
- test_true(exec_cmdline(executable, args));
+ snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port()));
+ const char *args[]= { "--expire=30", buffer, "foo", 0 };
+ test_compare(EXIT_SUCCESS, exec_cmdline(executable, args, true));
test_compare(MEMCACHED_SUCCESS, memcached_exist(memc, test_literal_param("foo")));
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
- const char *args[]= { "--quiet", "--expire=30", buffer, "foo", 0 };
-
memcached_st *memc= memcached(buffer, strlen(buffer));
test_true(memc);
test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("foo")));
- test_true(exec_cmdline(executable, args));
+ snprintf(buffer, sizeof(buffer), "--servers=localhost:%d", int(default_port()));
+ const char *args[]= { "--expire=30", buffer, "foo", 0 };
+ test_compare(EXIT_FAILURE, exec_cmdline(executable, args, true));
test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("foo")));
return TEST_SUCCESS;
}
+static test_return_t check_version(void*)
+{
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port()));
+ memcached_st *memc= memcached(buffer, strlen(buffer));
+ test_true(memc);
+
+ test_return_t result= TEST_SUCCESS;
+ if (libmemcached_util_version_check(memc, 1, 4, 8) == false)
+ {
+ result= TEST_SKIPPED;
+ }
+ memcached_free(memc);
+
+ return result;
+}
+
test_st memtouch_tests[] ={
- {"--quiet", true, quiet_test },
{"--help", true, help_test },
{"touch(FOUND)", true, touch_test },
{"touch(NOT_FOUND)", true, NOT_FOUND_test },
};
collection_st collection[] ={
- {"memtouch", 0, 0, memtouch_tests },
+ {"memtouch", check_version, 0, memtouch_tests },
{0, 0, 0, 0}
};
return NULL;
}
- const char *argv[1]= { "memtouch" };
- if (not server_startup(servers, "memcached", libtest::default_port(), 1, argv))
+ if (server_startup(servers, "memcached", libtest::default_port(), 0, NULL) == false)
{
error= TEST_FAILURE;
}
util/daemon.hpp \
util/instance.hpp \
util/logfile.hpp \
+ util/log.hpp \
util/operation.hpp \
util/signal.hpp \
util/string.hpp \
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * libtest
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <cerrno>
+#include <cstdio>
+#include <fcntl.h>
+#include <iostream>
+#include <string>
+#include <syslog.h>
+
+#define UTIL_MAX_ERROR_SIZE 2048
+
+namespace datadifferential {
+namespace util {
+
+/** Verbosity levels.
+ */
+enum verbose_t
+{
+ // Logging this will cause shutdown
+ VERBOSE_FATAL= LOG_EMERG, // syslog:LOG_EMERG
+
+ VERBOSE_ALERT= LOG_ALERT, // syslog:LOG_ALERT
+ VERBOSE_CRITICAL= LOG_CRIT, // syslog:LOG_CRIT
+
+ VERBOSE_ERROR= LOG_ERR, // syslog:LOG_ERR
+
+ VERBOSE_WARN= LOG_WARNING, // syslog:LOG_WARNING
+
+ VERBOSE_NOTICE= LOG_NOTICE, // syslog:LOG_NOTICE
+
+ VERBOSE_INFO= LOG_INFO, // syslog:LOG_INFO
+
+ VERBOSE_DEBUG= LOG_DEBUG // syslog:LOG_DEBUG
+};
+
+
+struct log_info_st
+{
+ std::string name;
+ std::string filename;
+ int fd;
+ bool opt_syslog;
+ bool opt_file;
+ bool init_success;
+
+ log_info_st(const std::string& name_arg, const std::string &filename_arg, bool syslog_arg) :
+ name(name_arg),
+ filename(filename_arg),
+ fd(-1),
+ opt_syslog(syslog_arg),
+ opt_file(false),
+ init_success(false)
+ {
+ if (opt_syslog)
+ {
+ openlog(name.c_str(), LOG_PID | LOG_NDELAY, LOG_USER);
+ }
+
+ init();
+ }
+
+ void init()
+ {
+ if (filename.size())
+ {
+ if (filename.compare("stderr") == 0)
+ {
+ fd= STDERR_FILENO;
+ }
+ else
+ {
+ fd= open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ if (opt_syslog)
+ {
+ char buffer[1024];
+ char *getcwd_ret= getcwd(buffer, sizeof(buffer));
+ syslog(LOG_ERR, "Could not open log file \"%.*s\", from \"%s\", open failed with (%s)",
+ int(filename.size()), filename.c_str(),
+ getcwd_ret,
+ strerror(errno));
+ }
+ std::cerr << "Could not open log file for writing, switching to stderr." << std::endl;
+
+ fd= STDERR_FILENO;
+ }
+ }
+
+ opt_file= true;
+ }
+
+ init_success= true;
+ }
+
+ bool initialized() const
+ {
+ return init_success;
+ }
+
+ int file() const
+ {
+ return fd;
+ }
+
+ void write(verbose_t verbose, const char *mesg)
+ {
+ if (opt_file)
+ {
+ char buffer[UTIL_MAX_ERROR_SIZE];
+ int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %s\n", verbose_name(verbose), mesg);
+ if (::write(file(), buffer, buffer_length) == -1)
+ {
+ std::cerr << "Could not write to log file." << std::endl;
+ syslog(LOG_EMERG, "gearmand could not open log file %s, got error %s", filename.c_str(), strerror(errno));
+ }
+
+ }
+
+ if (opt_syslog)
+ {
+ syslog(int(verbose), "%7s %s", verbose_name(verbose), mesg);
+ }
+ }
+
+ ~log_info_st()
+ {
+ if (fd != -1 and fd != STDERR_FILENO)
+ {
+ close(fd);
+ }
+
+ if (opt_syslog)
+ {
+ closelog();
+ }
+ }
+
+private:
+ const char *verbose_name(verbose_t verbose)
+ {
+ switch (verbose)
+ {
+ case VERBOSE_FATAL:
+ return "FATAL";
+
+ case VERBOSE_ALERT:
+ return "ALERT";
+
+ case VERBOSE_CRITICAL:
+ return "CRITICAL";
+
+ case VERBOSE_ERROR:
+ return "ERROR";
+
+ case VERBOSE_WARN:
+ return "WARNING";
+
+ case VERBOSE_NOTICE:
+ return "NOTICE";
+
+ case VERBOSE_INFO:
+ return "INFO";
+
+ case VERBOSE_DEBUG:
+ return "DEBUG";
+
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+ }
+};
+
+} // namespace util
+} // namespace datadifferential