src/dbfs/op_base.c
changeset 56 9dfc861273e5
parent 42 40a3b13ffc9d
child 57 527d23bf6441
--- a/src/dbfs/op_base.c	Tue Nov 18 02:06:52 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-#include <stdlib.h>
-#include <assert.h>
-
-#include "op_base.h"
-#include "../lib/log.h"
-
-/*
- * Free the op.
- *
- * The op must any oustanding request responded to first, must not be open, and must not have a transaction.
- *
- * The op will be free'd.
- */
-static void dbfs_op_free (struct dbfs_op *op) {
-    assert(op);
-    assert(!op->open);
-    assert(!op->req);
-    assert(!op->trans);
-
-    // free_fn
-    if (op->free_fn)
-        op->free_fn(op);
-    
-    // and then free the op
-    free(op);
-}
-
-void dbfs_op_fail (struct dbfs_op *op, int err) {
-    assert(op->req);
-    
-    if (op->trans) {
-        // abort the trans
-        evsql_trans_abort(op->trans);
-        
-        op->trans = NULL;
-    }
-
-    // send an error reply
-    if ((err = fuse_reply_err(op->req, err)))
-        // XXX: handle these failures /somehow/, or requests will hang and interrupts might handle invalid ops
-        EFATAL(err, "\tdbfs_op.fail %p:%p -> reply with fuse_reply_err", op, op->req);
-   
-    // drop the req
-    op->req = NULL;
-
-    // is it open?
-    if (!op->open) {
-        // no, we can free it now and then forget about the whole thing
-        dbfs_op_free(op);
-
-    } else {
-        // we need to wait for release
-
-    }
-}
-
-/*
- * The op_open transaction is ready for use.
- */
-static void dbfs_op_ready (struct evsql_trans *trans, void *arg) {
-    struct dbfs_op *op = arg;
-    
-    assert(trans == op->trans);
-    assert(op->req);
-    assert(!op->open);
-
-    INFO("\tdbfs_op.ready %p:%p -> trans=%p", op, op->req, trans);
-
-    // remember the transaction
-    op->trans = trans;
-
-    // ready
-    op->open_fn(op);
-    
-    // good
-    return;
-}
-
-/*
- * The op trans was committed, i.e. release has completed
- */
-static void dbfs_op_done (struct evsql_trans *trans, void *arg) {
-    struct dbfs_op *op = arg;
-    int err;
-    
-    assert(trans == op->trans);
-    assert(op->req);
-    assert(!op->open);   // should not be considered as open anymore at this point, as errors should release
-
-    INFO("\tdbfs_op.done %p:%p -> OK", op, op->req);
-
-    // forget trans
-    op->trans = NULL;
-    
-    // just reply
-    if ((err = fuse_reply_err(op->req, 0)))
-        // XXX: handle these failures /somehow/, or requests will hang and interrupts might handle invalid ops
-        EFATAL(err, "dbfs_op.done %p:%p -> reply with fuse_reply_err", op, op->req);
-    
-    // req is done
-    op->req = NULL;
-
-    // then we can just free op
-    dbfs_op_free(op);
-}
-
-/*
- * The op trans has failed, somehow, at some point, some where.
- *
- * This might happend during the open evsql_trans, during a read evsql_query, during the release
- * evsql_trans_commit, or at any point in between.
- *
- * 1) loose the transaction
- * 2) if op has a req, we handle failing it
- */
-static void dbfs_op_error (struct evsql_trans *trans, void *arg) {
-    struct dbfs_op *op = arg;
-    
-    // unless we fail 
-    assert(trans == op->trans);
-
-    INFO("\tdbfs_op.error %p:%p -> evsql transaction error: %s", op, op->req, evsql_trans_error(trans));
-    
-    // deassociate the trans
-    op->trans = NULL;
-    
-    // if we were answering a req, error it out, and if the op isn't open, free
-    // if we didn't have a req outstanding, the op must be open, so we wouldn't free it in any case, and must wait
-    // for the next read/release to detect this and return an error reply
-    if (op->req)
-        dbfs_op_fail(op, EIO);
-    else
-        assert(op->open);
-}
-
-int dbfs_op_open (struct dbfs *ctx, struct dbfs_op *op, struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi, dbfs_op_free_cb free_fn, dbfs_op_open_cb open_fn) {
-    int err;
-
-    assert(op && req && ino && fi);
-    assert(!(op->req || op->ino));
-
-    // initialize the op
-    op->req = req;
-    op->ino = ino;
-    // copy *fi since it's on the stack
-    op->fi = *fi;
-    op->fi.fh = (uint64_t) op;
-    op->free_fn = free_fn;
-    op->open_fn = open_fn;
-
-    // start a new transaction
-    if ((op->trans = evsql_trans(ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_op_error, dbfs_op_ready, dbfs_op_done, op)) == NULL)
-        SERROR(err = EIO);
-    
-    // XXX: handle interrupts
-    
-    // good
-    return 0;
-
-error:
-    // nothing of ours to cleanup
-    return err;
-}
-
-int dbfs_op_open_reply (struct dbfs_op *op) {
-    int err;
-    
-    // detect earlier failures
-    if (!op->trans && (err = EIO))
-        ERROR("op trans has failed");
-
-    // send the openddir reply
-    if ((err = fuse_reply_open(op->req, &op->fi)))
-        EERROR(err, "fuse_reply_open");
-    
-    // req is done
-    op->req = NULL;
-
-    // op is now open
-    op->open = 1;
- 
-    // good
-    return 0;
-
-error:
-    return err;
-}
-
-struct dbfs_op *dbfs_op_req (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
-    struct dbfs_op *op = (struct dbfs_op *) fi->fh;
-    int err;
-    
-    // validate
-    assert(op);
-    assert(op->open);
-    assert(op->ino == ino);
-    
-    // detect concurrent requests
-    if (op->req) {
-        // must handle req ourself, shouldn't fail the other req
-        WARNING("op.%p: concurrent req: %p -> %p", op, op->req, req);
-        
-        // XXX: ignore error errors...
-        fuse_reply_err(req, EBUSY);
-
-        return NULL;
-
-    } else
-        // store the new req
-        op->req = req;
-    
-    // inodes change?
-    if (op->ino != ino)
-        XERROR(err = EBADF, "op.%p: wrong ino: %u -> %lu", op, op->ino, ino);
-    
-    // detect earlier failures
-    if (!op->trans && (err = EIO))
-        ERROR("op trans has failed");
-
-    // good
-    return op;
-
-error:
-    dbfs_op_fail(op, err);
-    
-    return NULL;
-}
-
-int dbfs_op_req_done (struct dbfs_op *op) {
-    // validate
-    assert(op);
-    assert(op->req);
-    assert(op->open);
-
-    // unassign the req
-    op->req = NULL;
-
-    // k
-    return 0;
-}
-
-void dbfs_op_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
-    struct dbfs_op *op = (struct dbfs_op *) fi->fh;
-    int err;
-    
-    assert(op);
-    assert(!op->req);
-    assert(op->ino == ino);
-    
-    // update to this req
-    op->req = req;
-
-    // fi is irrelevant, we don't touch the flags anyways
-    (void) fi;
-
-    // handle failed trans
-    if (!op->trans && (err = EIO))
-        ERROR("trans has failed");
-    
-    // log
-    INFO("\tdbfs_op.release %p:%p : ino=%lu, fi=%p : trans=%p", op, req, ino, fi, op->trans);
-    
-    // we must commit the transaction.
-    // Note that this might cause dbfs_op_error to be called, we can tell if that happaned by looking at op->req
-    // or op->trans - this means that we need to keep the op open when calling trans_commit, so that op_error
-    // doesn't free it out from underneath us.
-    if (evsql_trans_commit(op->trans))
-        SERROR(err = EIO);
-
-    // fall-through to cleanup
-    err = 0;
-
-error:
-    // the op is not open anymore and can be free'd next, because we either:
-    // a) already caught an error
-    // b) we get+send an error later on
-    // c) we get+send the done/no-error later on
-    op->open = 0;
-
-    // did the commit/pre-commit-checks fail?
-    if (err) {
-        // a) the trans failed earlier (read), so we have a req but no trans
-        // b) the trans commit failed, op_error got called -> no req and no trans
-        // c) the trans commit failed, op_error did not get called -> have req and trans
-        // we either have a req (may or may not have trans), or we don't have a trans either
-        // i.e. there is no situation where we don't have a req but do have a trans
-
-        if (op->req)
-            dbfs_op_fail(op, err);
-        else
-            assert(!op->trans);
-
-    } else {
-        // shouldn't slip by, op_done should not get called directly. Once it does, it will handle both.
-        assert(op->req);
-        assert(op->trans);
-    }
-}
-