* 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 <sys/socket.h>
-#include <netdb.h>
-#include <netinet/tcp.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <libmemcached/protocol_handler.h>
#include <libmemcached/byteorder.h>
#include "storage.h"
+#include "memcached_light.h"
static protocol_binary_response_status noop_command_handler(const void *cookie,
protocol_binary_request_header *header,
response_handler(cookie, header, (void*)&response);
/* I need a better way to signal to close the connection */
- return PROTOCOL_BINARY_RESPONSE_EIO;
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
}
static protocol_binary_response_status get_command_handler(const void *cookie,
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)
uint64_t initial= ntohll(req->message.body.initial);
uint64_t delta= 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)
- {
- item= create_item(key, keylen, NULL, sizeof(initial), 0, (time_t)expiration);
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- else
- {
- memcpy(item->data, &initial, sizeof(initial));
- put_item(item);
- }
- }
- else
+ if (item != NULL)
{
if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT ||
header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ)
{
- (*(uint64_t*)item->data) += delta;
+ value= (*(uint64_t*)item->data) + delta;
}
else
{
if (delta > *(uint64_t*)item->data)
{
- *(uint64_t*)item->data= 0;
+ value= 0;
}
else
{
- *(uint64_t*)item->data -= delta;
+ value= *(uint64_t*)item->data - delta;
}
}
+ expiration= (uint32_t)item->exp;
+ flags= item->flags;
- struct item *nitem= create_item(key, keylen, NULL, sizeof(initial), 0, item->exp);
- if (item == NULL)
- {
- rval= PROTOCOL_BINARY_RESPONSE_ENOMEM;
- delete_item(key, keylen);
- }
- else
- {
- memcpy(nitem->data, item->data, item->size);
- delete_item(key, keylen);
- put_item(nitem);
- item = nitem;
- }
+ 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);
response.message.body.value= ntohll((*(uint64_t*)item->data));
response.message.header.response.cas= ntohll(item->cas);
+ release_item(item);
if (header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENTQ ||
header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENTQ)
{
void *val= (char*)key + keylen;
struct item *item= get_item(key, keylen);
- struct item *nitem;
+ struct item *nitem= NULL;
+
if (item == NULL)
{
rval= PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
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, 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)
{
.opcode= header->request.opcode,
.status= htons(rval),
.opaque= header->request.opaque,
- .cas= htonll(nitem->cas),
+ .cas= htonll(cas),
}
}
};
{
/* validate cas */
struct item* item= get_item(key, keylen);
- if (item != NULL && item->cas != ntohll(header->request.cas))
+ if (item != NULL)
{
- response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
- return response_handler(cookie, header, (void*)&response);
+ if (item->cas != 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 == 0)
+ if (item == NULL)
{
response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
}
if (header->request.opcode == PROTOCOL_BINARY_CMD_SET)
{
response.message.header.response.cas= htonll(item->cas);
+ release_item(item);
return response_handler(cookie, header, (void*)&response);
}
+ release_item(item);
+
return PROTOCOL_BINARY_RESPONSE_SUCCESS;
}
if (item == NULL)
{
item= create_item(key, keylen, data, datalen, flags, timeout);
- if (item == 0)
+ if (item == NULL)
response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
else
{
if (header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
{
response.message.header.response.cas= 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);
}
response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
else if (header->request.cas == 0 || ntohll(header->request.cas) == item->cas)
{
+ release_item(item);
delete_item(key, keylen);
item= create_item(key, keylen, data, datalen, flags, timeout);
- if (item == 0)
+ if (item == NULL)
response.message.header.response.status= htons(PROTOCOL_BINARY_RESPONSE_ENOMEM);
else
{
if (header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
{
response.message.header.response.cas= 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);
}
return response_handler(cookie, header, (void*)&response);
}
-struct memcached_binary_protocol_callback_st interface_v0_impl= {
- .interface_version= 0,
+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_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;
+}