#include <stdlib.h>
#include <assert.h>
#include "request.h"
#include "memcache.h"
#include "../common.h"
struct memcache_req *memcache_req_alloc (struct memcache *mc, enum memcache_command cmd_type, const struct memcache_key *key, const struct memcache_obj *obj, const struct memcache_buf *buf, void *cb_arg) {
struct memcache_req *req = NULL;
// ensure key is provided
assert(key != NULL);
// allocate it
if ((req = calloc(1, sizeof(*req))) == NULL)
ERROR("calloc");
// state
req->state = MEMCACHE_STATE_INVALID;
// key length?
if (key->len == 0)
req->key.len = strlen(key->buf);
else
req->key.len = key->len;
if (req->key.len == 0)
ERROR("zero-length key");
// copy the key
if ((req->key.buf = malloc(req->key.len)) == NULL)
ERROR("malloc key buf");
memcpy(req->key.buf, key->buf, req->key.len);
// copy the obj if provided
if (obj) {
memcpy(&req->obj, obj, sizeof(req->obj));
req->have_obj = 1;
}
// copy the buf if provided, and reset the offset to zero
if (buf) {
// ensure that it is a valid buffer
assert(buf->data && buf->len > 0 && buf->offset == buf->len);
memcpy(&req->buf, buf, sizeof(req->buf));
req->have_buf = 1;
// set offset to zero
req->buf.offset = 0;
}
// store the other data
req->mc = mc;
req->cmd_type = cmd_type;
req->cb_arg = cb_arg;
// success
return req;
error:
if (req) {
free(req->key.buf);
free(req);
}
return NULL;
}
// accessors
enum memcache_req_state memcache_req_state (struct memcache_req *req) {
return req->state;
}
enum memcache_command memcache_req_cmd (struct memcache_req *req) {
return req->cmd_type;
}
enum memcache_reply memcache_req_reply (struct memcache_req *req) {
return req->reply_type;
}
const struct memcache_key *keymemcache_req_key (struct memcache_req *req) {
return &req->key;
}
const struct memcache_obj *memcache_req_obj (struct memcache_req *req) {
return req->have_obj ? &req->obj : NULL;
}
const struct memcache_buf *memcache_req_buf (struct memcache_req *req) {
return req->have_buf ? &req->buf : NULL;
}
// events
static void _memcache_req_notify (struct memcache_req *req) {
req->mc->cb_fn(req, req->cb_arg);
}
void memcache_req_queued (struct memcache_req *req) {
req->state = MEMCACHE_STATE_QUEUED;
// _memcache_req_notify(req);
}
void memcache_req_send (struct memcache_req *req) {
req->state = MEMCACHE_STATE_SEND;
// _memcache_req_notify(req);
}
void memcache_req_recv (struct memcache_req *req, enum memcache_reply reply_type) {
req->state = MEMCACHE_STATE_REPLY;
req->reply_type = reply_type;
// we must surely have a valid obj now
req->have_obj = 1;
_memcache_req_notify(req);
}
void memcache_req_data (struct memcache_req *req) {
assert(req->state == MEMCACHE_STATE_REPLY || req->state == MEMCACHE_STATE_REPLY_DATA);
req->state = MEMCACHE_STATE_REPLY_DATA;
// we must surely have a valid buf now
req->have_buf = 1;
_memcache_req_notify(req);
}
void memcache_req_done (struct memcache_req *req) {
// make sure we are in the REPLY/REPLY_DATA state
assert(req->state == MEMCACHE_STATE_REPLY || req->state == MEMCACHE_STATE_REPLY_DATA);
// are we supposed to have data?
if (req->buf.data) {
// make sure we really have the full data, if applicable
assert(req->buf.offset == req->buf.len);
// yes...
req->have_buf = 1;
// have data
req->state = MEMCACHE_STATE_DATA_DONE;
} else {
// no data
req->state = MEMCACHE_STATE_DONE;
}
// forget the connection
req->conn = NULL;
_memcache_req_notify(req);
}
void memcache_req_error (struct memcache_req *req) {
// forget our connection
req->conn = NULL;
req->state = MEMCACHE_STATE_ERROR;
_memcache_req_notify(req);
}
void memcache_req_free (struct memcache_req *req) {
// must be unused
assert(req->conn == NULL);
assert(req->state == MEMCACHE_STATE_INVALID || req->state == MEMCACHE_STATE_ERROR || req->state == MEMCACHE_STATE_DONE || req->state == MEMCACHE_STATE_DATA_DONE);
free(req->key.buf);
free(req);
}