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