terom@33: terom@33: #include terom@33: #include terom@33: terom@33: #include "trans.h" terom@33: #include "../lib/log.h" terom@33: terom@33: void dbfs_trans_free (struct dbfs_trans *ctx) { terom@33: assert(!ctx->req); terom@33: assert(!ctx->trans); terom@33: terom@33: if (ctx->free_fn) terom@33: ctx->free_fn(ctx); terom@33: terom@33: free(ctx); terom@33: } terom@33: terom@33: void dbfs_trans_fail (struct dbfs_trans *ctx, int err) { terom@33: if (ctx->req) { terom@33: if ((err = fuse_reply_err(ctx->req, err))) terom@33: EWARNING(err, "fuse_reply_err: request hangs"); terom@33: terom@33: ctx->req = NULL; terom@33: } terom@33: terom@33: if (ctx->trans) { terom@33: evsql_trans_abort(ctx->trans); terom@33: terom@33: ctx->trans = NULL; terom@33: } terom@33: terom@33: dbfs_trans_free(ctx); terom@33: } terom@33: terom@33: static void dbfs_trans_error (struct evsql_trans *trans, void *arg) { terom@33: struct dbfs_trans *ctx = arg; terom@33: terom@33: // deassociate trans terom@33: ctx->trans = NULL; terom@33: terom@33: // log error terom@33: INFO("\t[dbfs_trans.err %p:%p] %s", ctx, ctx->req, evsql_trans_error(trans)); terom@33: terom@33: // mark terom@33: if (ctx->err_ptr) terom@33: *ctx->err_ptr = EIO; terom@33: terom@33: // fail terom@33: dbfs_trans_fail(ctx, EIO); terom@33: } terom@33: terom@33: static void dbfs_trans_ready (struct evsql_trans *trans, void *arg) { terom@33: struct dbfs_trans *ctx = arg; terom@33: terom@33: // associate trans terom@33: ctx->trans = trans; terom@33: terom@33: // log terom@33: INFO("\t[dbfs_trans.ready %p:%p] -> trans=%p", ctx, ctx->req, trans); terom@33: terom@33: // trigger the callback terom@33: ctx->begin_fn(ctx); terom@33: } terom@33: terom@33: static void dbfs_trans_done (struct evsql_trans *trans, void *arg) { terom@33: struct dbfs_trans *ctx = arg; terom@33: terom@33: // deassociate trans terom@33: ctx->trans = NULL; terom@33: terom@33: // log terom@33: INFO("\t[dbfs_trans.done %p:%p]", ctx, ctx->req); terom@33: terom@33: // trigger the callback terom@33: ctx->commit_fn(ctx); terom@33: } terom@33: terom@33: int dbfs_trans_init (struct dbfs_trans *ctx, struct fuse_req *req) { terom@33: struct dbfs *dbfs_ctx = fuse_req_userdata(req); terom@33: int err; terom@33: terom@33: // store terom@33: ctx->req = req; terom@33: terom@33: // trans terom@33: if ((ctx->trans = evsql_trans(dbfs_ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_trans_error, dbfs_trans_ready, dbfs_trans_done, ctx)) == NULL) terom@33: EERROR(err = EIO, "evsql_trans"); terom@33: terom@33: // good terom@33: return 0; terom@33: terom@33: error: terom@33: return -1; terom@33: } terom@33: terom@33: struct dbfs_trans *dbfs_trans_new (struct fuse_req *req) { terom@33: struct dbfs_trans *ctx = NULL; terom@33: terom@33: // alloc terom@33: if ((ctx = calloc(1, sizeof(*ctx))) == NULL) terom@33: ERROR("calloc"); terom@33: terom@33: // init terom@33: if (dbfs_trans_init(ctx, req)) terom@33: goto error; terom@33: terom@33: // good terom@33: return ctx; terom@33: terom@33: error: terom@33: free(ctx); terom@33: terom@33: return NULL; terom@33: } terom@33: terom@33: void dbfs_trans_commit (struct dbfs_trans *ctx) { terom@33: int err, trans_err = 0; terom@33: terom@33: // detect errors terom@33: ctx->err_ptr = &trans_err; terom@33: terom@33: // attempt commit terom@33: if (evsql_trans_commit(ctx->trans)) terom@33: SERROR(err = EIO); terom@33: terom@33: // drop err_ptr terom@33: ctx->err_ptr = NULL; terom@33: terom@33: // ok, wait for done or error terom@33: return; terom@33: terom@33: error: terom@33: // fail if not already failed terom@33: if (!trans_err) terom@33: dbfs_trans_fail(ctx, err); terom@33: } terom@33: terom@33: