memcache/request.c
author Tero Marttila <terom@fixme.fi>
Fri, 29 Aug 2008 23:31:17 +0300
changeset 48 1c67f512779b
parent 46 8a832c0e01ee
permissions -rw-r--r--
fix doc tpyos, rename some enums, fix printf format len for non-zero terminated strings (hg status), pass args to memcache_cmd_format_header via memcache_req_*, handle zero-length STORE requests, memcache_req is_buf_ours + free, other function name typos (keymemcache_req_key), fix req state behaviour re *_DATA_* for STORE requests and FETCH/END, better memcache_server connpool events/management, modular memcache_test with a working benchmark. This is a long commit message.

#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;
        req->is_buf_ours = 0;

        // 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_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 *memcache_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) {
    // set state to REPLY_DATA/REPLY based on have_buf/is_buf_ours
    req->state = (req->have_buf && req->is_buf_ours) ? MEMCACHE_STATE_REPLY_DATA : 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);
    
    // set state to DONE_DATA/DONE based on have_buf/is_buf_ours
    req->state = (req->have_buf && req->is_buf_ours) ? MEMCACHE_STATE_DONE_DATA : 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_DONE_DATA);
    
    if (req->have_buf && req->is_buf_ours)
        free(req->buf.data);

    free(req->key.buf);
    free(req);
}