#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);
}