cache/op.c
author Tero Marttila <terom@fixme.fi>
Wed, 27 Aug 2008 21:30:32 +0300
changeset 41 540737bf6bac
parent 37 f0188b445c84
permissions -rw-r--r--
sending requests, and partial support for receiving -- incomplete, not tested
#include <stdlib.h>
#include <sys/queue.h>
#include <string.h>
#include <assert.h>

#include "../cache.h"
#include "cache.h"
#include "op.h"
#include "req.h"
#include "engine.h"
#include "../common.h"

void _cache_op_free (struct cache_op *op) {
    // check we have no reqs listed
    assert(op->req_list.lh_first == NULL);

    // remove it from the engine op_list
    LIST_REMOVE(op, node);

    // tell the engine to close/free the op
    if (op->cache->engine->fn_op_close(op))
        WARNING("fn_op_close failed");
}

int _cache_op_init (struct cache_op *op, struct cache *cache, struct cache_key *key) {
    op->cache = cache;
    op->key = key;
    op->state = OP_STATE_INVALID;

    LIST_INIT(&op->req_list);

    // add this to the cache's list of ops
    LIST_INSERT_HEAD(&cache->op_list, op, node);

    return 0;
}

struct cache_op *cache_op_find (struct cache *cache, struct cache_key *key) {
    struct cache_op *op;

    for (op = cache->op_list.lh_first; op != NULL; op = op->node.le_next) {
        if (op->key->length == key->length && memcmp(op->key->buf, key->buf, key->length) == 0)
            break;
    }

    return op;
}

int cache_op_register (struct cache_op *op, struct cache_req *req) {
    LIST_INSERT_HEAD(&op->req_list, req, node);

    return 0;
}

int cache_op_deregister (struct cache_op *op, struct cache_req *req) {
    // XXX: check that the req is in our list of ops?
    
    LIST_REMOVE(req, node);
    
    if (op->req_list.lh_first == NULL) {
        // the op is now unused
        _cache_op_free(op);
    }

    return 0;
}

static int _cache_op_notify (struct cache_op *op) {
    struct cache_req *req;

    for (req = op->req_list.lh_first; req != NULL; req = req->node.le_next) {
        if (cache_req_notify(req))
            goto error;
    }

    return 0;

error:
    return -1;
}

int cache_op_available (struct cache_op *op, size_t *size, size_t *offset) {
    return op->cache->engine->fn_op_available(op, size, offset);
}

int cache_op_begin_read (struct cache_op *op) {
    assert(op->state == OP_STATE_HIT);

    op->state = OP_STATE_OPEN_READ;

    return op->cache->engine->fn_op_begin_read(op);
}

int cache_op_begin_write (struct cache_op *op, size_t size_hint) {
    assert(op->state == OP_STATE_MISS);

    op->state = OP_STATE_OPEN_WRITE;

    return op->cache->engine->fn_op_begin_write(op, size_hint);
}

int cache_op_push (struct cache_op *op, int fd, size_t *size) {
    assert(op->state == OP_STATE_WRITE);

    return op->cache->engine->fn_op_push(op, fd, size);
}

int cache_op_pull (struct cache_op *op, int fd, size_t *offset, size_t *size) {
    assert(op->state == OP_STATE_READ || op->state == OP_STATE_WRITE);

    return op->cache->engine->fn_op_pull(op, fd, offset, size);
}

int cache_op_done (struct cache_op *op) {
    assert(op->state == OP_STATE_WRITE);

    return op->cache->engine->fn_op_done(op);
}

int _cache_op_lookup_done (struct cache_op *op, int found) {
    // modify state
    op->state = found ? OP_STATE_HIT : OP_STATE_MISS;

    // notify waiting reqs
    return _cache_op_notify(op);
}

int _cache_op_read_ready (struct cache_op *op) {
    // modify state
    op->state = OP_STATE_READ;

    // notify waiting reqs
    return _cache_op_notify(op);
}

int _cache_op_write_ready (struct cache_op *op) {
    // modify state
    op->state = OP_STATE_WRITE;

    // notify waiting reqs
    return _cache_op_notify(op);
}

int _cache_op_data_available (struct cache_op *op) {
    // notify waiting reqs
    return _cache_op_notify(op);
}

int _cache_op_write_done (struct cache_op *op) {
    op->state = OP_STATE_READ;

    // notify waiting reqs
    return _cache_op_notify(op);
}