1 |
|
2 #include <stdlib.h> |
|
3 #include <assert.h> |
|
4 |
|
5 #include "trans.h" |
|
6 #include "../lib/log.h" |
|
7 |
|
8 void dbfs_trans_free (struct dbfs_trans *ctx) { |
|
9 assert(!ctx->req); |
|
10 assert(!ctx->trans); |
|
11 |
|
12 if (ctx->free_fn) |
|
13 ctx->free_fn(ctx); |
|
14 |
|
15 free(ctx); |
|
16 } |
|
17 |
|
18 void dbfs_trans_fail (struct dbfs_trans *ctx, int err) { |
|
19 if (ctx->req) { |
|
20 if ((err = fuse_reply_err(ctx->req, err))) |
|
21 EWARNING(err, "fuse_reply_err: request hangs"); |
|
22 |
|
23 ctx->req = NULL; |
|
24 } |
|
25 |
|
26 if (ctx->trans) { |
|
27 evsql_trans_abort(ctx->trans); |
|
28 |
|
29 ctx->trans = NULL; |
|
30 } |
|
31 |
|
32 dbfs_trans_free(ctx); |
|
33 } |
|
34 |
|
35 static void dbfs_trans_error (struct evsql_trans *trans, void *arg) { |
|
36 struct dbfs_trans *ctx = arg; |
|
37 |
|
38 // deassociate trans |
|
39 ctx->trans = NULL; |
|
40 |
|
41 // log error |
|
42 INFO("\t[dbfs_trans.err %p:%p] %s", ctx, ctx->req, evsql_trans_error(trans)); |
|
43 |
|
44 // mark |
|
45 if (ctx->err_ptr) |
|
46 *ctx->err_ptr = EIO; |
|
47 |
|
48 // fail |
|
49 dbfs_trans_fail(ctx, EIO); |
|
50 } |
|
51 |
|
52 static void dbfs_trans_ready (struct evsql_trans *trans, void *arg) { |
|
53 struct dbfs_trans *ctx = arg; |
|
54 |
|
55 // associate trans |
|
56 ctx->trans = trans; |
|
57 |
|
58 // log |
|
59 INFO("\t[dbfs_trans.ready %p:%p] -> trans=%p", ctx, ctx->req, trans); |
|
60 |
|
61 // trigger the callback |
|
62 ctx->begin_fn(ctx); |
|
63 } |
|
64 |
|
65 static void dbfs_trans_done (struct evsql_trans *trans, void *arg) { |
|
66 struct dbfs_trans *ctx = arg; |
|
67 |
|
68 // deassociate trans |
|
69 ctx->trans = NULL; |
|
70 |
|
71 // log |
|
72 INFO("\t[dbfs_trans.done %p:%p]", ctx, ctx->req); |
|
73 |
|
74 // trigger the callback |
|
75 ctx->commit_fn(ctx); |
|
76 } |
|
77 |
|
78 int dbfs_trans_init (struct dbfs_trans *ctx, struct fuse_req *req) { |
|
79 struct dbfs *dbfs_ctx = fuse_req_userdata(req); |
|
80 int err; |
|
81 |
|
82 // store |
|
83 ctx->req = req; |
|
84 |
|
85 // trans |
|
86 if ((ctx->trans = evsql_trans(dbfs_ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_trans_error, dbfs_trans_ready, dbfs_trans_done, ctx)) == NULL) |
|
87 EERROR(err = EIO, "evsql_trans"); |
|
88 |
|
89 // good |
|
90 return 0; |
|
91 |
|
92 error: |
|
93 return -1; |
|
94 } |
|
95 |
|
96 struct dbfs_trans *dbfs_trans_new (struct fuse_req *req) { |
|
97 struct dbfs_trans *ctx = NULL; |
|
98 |
|
99 // alloc |
|
100 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) |
|
101 ERROR("calloc"); |
|
102 |
|
103 // init |
|
104 if (dbfs_trans_init(ctx, req)) |
|
105 goto error; |
|
106 |
|
107 // good |
|
108 return ctx; |
|
109 |
|
110 error: |
|
111 free(ctx); |
|
112 |
|
113 return NULL; |
|
114 } |
|
115 |
|
116 void dbfs_trans_commit (struct dbfs_trans *ctx) { |
|
117 int err, trans_err = 0; |
|
118 |
|
119 // detect errors |
|
120 ctx->err_ptr = &trans_err; |
|
121 |
|
122 // attempt commit |
|
123 if (evsql_trans_commit(ctx->trans)) |
|
124 SERROR(err = EIO); |
|
125 |
|
126 // drop err_ptr |
|
127 ctx->err_ptr = NULL; |
|
128 |
|
129 // ok, wait for done or error |
|
130 return; |
|
131 |
|
132 error: |
|
133 // fail if not already failed |
|
134 if (!trans_err) |
|
135 dbfs_trans_fail(ctx, err); |
|
136 } |
|
137 |
|
138 |
|