|
4 | 4 | #include <stdio.h>
|
5 | 5 | #include <unistd.h>
|
6 | 6 | #include <stdlib.h>
|
| 7 | +#include <assert.h> |
7 | 8 |
|
8 | 9 | #include "libdtm.h"
|
9 | 10 |
|
10 |
| -#if 0 |
| 11 | +#ifdef TEST |
| 12 | +// standalone test without postgres functions |
11 | 13 | #define palloc malloc
|
12 | 14 | #define pfree free
|
13 | 15 | #endif
|
@@ -119,159 +121,109 @@ void DtmDisconnect(DTMConn dtm) {
|
119 | 121 | free(dtm);
|
120 | 122 | }
|
121 | 123 |
|
122 |
| -// Asks DTM for a fresh snapshot. Returns a snapshot on success, or NULL |
123 |
| -// otherwise. Please free the snapshot memory yourself after use. |
124 |
| -Snapshot DtmGlobalGetSnapshot(DTMConn dtm, NodeId nodeid, TransactionId xid, Snapshot s) { |
| 124 | +static bool dtm_query(DTMConn dtm, char cmd, int argc, ...) { |
| 125 | + va_list argv; |
| 126 | + int i; |
| 127 | + |
| 128 | + if (!dtm_write_char(dtm, cmd)) return false; |
| 129 | + if (!dtm_write_hex16(dtm, argc)) return false; |
| 130 | + |
| 131 | + va_start(argv, argc); |
| 132 | + for (i = 0; i < argc; i++) { |
| 133 | + xid_t arg = va_arg(argv, xid_t); |
| 134 | + if (!dtm_write_hex16(dtm, arg)) { |
| 135 | + va_end(argv); |
| 136 | + return false; |
| 137 | + } |
| 138 | + } |
| 139 | + va_end(argv); |
| 140 | + |
| 141 | + return true; |
| 142 | +} |
| 143 | + |
| 144 | +// Asks DTM for a fresh snapshot. Returns 'true' on success, or 'false' |
| 145 | +// otherwise. |
| 146 | +bool DtmGlobalGetSnapshot(DTMConn dtm, NodeId nodeid, TransactionId xid, Snapshot s) { |
125 | 147 | bool ok;
|
126 | 148 | int i;
|
127 | 149 | xid_t number;
|
128 | 150 |
|
129 |
| - if (!dtm_write_char(dtm, 'h')) { |
130 |
| - return NULL; |
131 |
| - } |
| 151 | + assert(s != NULL); |
132 | 152 |
|
133 |
| - if (!dtm_read_bool(dtm, &ok)) { |
134 |
| - return NULL; |
135 |
| - } |
136 |
| - if (!ok) { |
137 |
| - return NULL; |
138 |
| - } |
| 153 | + // query |
| 154 | + if (!dtm_query(dtm, 'h', 2, nodeid, xid)) return false; |
139 | 155 |
|
140 |
| - if (!dtm_read_hex16(dtm, &number)) { |
141 |
| - goto cleanup_snapshot; |
142 |
| - } |
| 156 | + // response |
| 157 | + if (!dtm_read_bool(dtm, &ok)) return false; |
| 158 | + if (!ok) return false; |
| 159 | + |
| 160 | + if (!dtm_read_hex16(dtm, &number)) return false; |
143 | 161 | s->xmin = number;
|
144 | 162 | Assert(s->xmin == number); // the number should fits into xmin field size
|
145 | 163 |
|
146 |
| - if (!dtm_read_hex16(dtm, &number)) { |
147 |
| - goto cleanup_snapshot; |
148 |
| - } |
| 164 | + if (!dtm_read_hex16(dtm, &number)) return false; |
149 | 165 | s->xmax = number;
|
150 | 166 | Assert(s->xmax == number); // the number should fit into xmax field size
|
151 | 167 |
|
152 |
| - if (!dtm_read_hex16(dtm, &number)) { |
153 |
| - goto cleanup_snapshot; |
154 |
| - } |
| 168 | + if (!dtm_read_hex16(dtm, &number)) return false; |
155 | 169 | s->xcnt = number;
|
156 | 170 | Assert(s->xcnt == number); // the number should definitely fit into xcnt field size
|
157 | 171 |
|
| 172 | + if (s->xip) pfree(s->xip); |
158 | 173 | s->xip = palloc(s->xcnt * sizeof(TransactionId));
|
159 | 174 | for (i = 0; i < s->xcnt; i++) {
|
160 |
| - if (!dtm_read_hex16(dtm, &number)) { |
161 |
| - goto cleanup_active_list; |
162 |
| - } |
| 175 | + if (!dtm_read_hex16(dtm, &number)) return false; |
163 | 176 | s->xip[i] = number;
|
164 | 177 | Assert(s->xip[i] == number); // the number should fit into xip[i] size
|
165 | 178 | }
|
166 | 179 |
|
167 |
| - return s; |
168 |
| - |
169 |
| -cleanup_active_list: |
170 |
| - pfree(s->xip); |
171 |
| -cleanup_snapshot: |
172 |
| - pfree(s); |
173 |
| - return NULL; |
174 |
| -} |
175 |
| - |
176 |
| -#if 0 |
177 |
| -// Starts a transaction. Returns the 'gxid' on success, or INVALID_GXID otherwise. |
178 |
| -xid_t DtmGlobalBegin(DTMConn dtm) { |
179 |
| - bool ok; |
180 |
| - xid_t gxid; |
181 |
| - |
182 |
| - if (!dtm_write_char(dtm, 'b')) { |
183 |
| - return INVALID_GXID; |
184 |
| - } |
185 |
| - |
186 |
| - if (!dtm_read_bool(dtm, &ok)) { |
187 |
| - return INVALID_GXID; |
188 |
| - } |
189 |
| - if (!ok) { |
190 |
| - return INVALID_GXID; |
191 |
| - } |
192 |
| - |
193 |
| - if (!dtm_read_hex16(dtm, &gxid)) { |
194 |
| - return INVALID_GXID; |
195 |
| - } |
196 |
| - |
197 |
| - return gxid; |
| 180 | + return true; |
198 | 181 | }
|
199 |
| -#endif |
200 | 182 |
|
201 |
| -void DtmGlobalSetTransStatus(DTMConn dtm, NodeId nodeid, TransactionId xid, XidStatus status) |
| 183 | +// Commits transaction only once all participants have called this function, |
| 184 | +// does not change CLOG otherwise. Returns 'true' on success, 'false' if |
| 185 | +// something failed on the daemon side. |
| 186 | +bool DtmGlobalSetTransStatus(DTMConn dtm, NodeId nodeid, TransactionId xid, XidStatus status) |
202 | 187 | {
|
203 |
| -} |
204 |
| -#if 0 |
205 |
| -// Marks a given transaction as 'committed'. Returns 'true' on success, |
206 |
| -// 'false' otherwise. |
207 |
| -bool DtmGlobalCommit(DTMConn dtm, xid_t gxid) { |
208 |
| - bool result; |
209 |
| - |
210 |
| - if (!dtm_write_char(dtm, 'c')) { |
211 |
| - return false; |
212 |
| - } |
213 |
| - |
214 |
| - if (!dtm_write_hex16(dtm, gxid)) { |
215 |
| - return false; |
216 |
| - } |
217 |
| - |
218 |
| - if (!dtm_read_bool(dtm, &result)) { |
219 |
| - return false; |
220 |
| - } |
221 |
| - |
222 |
| - return result; |
223 |
| -} |
224 |
| - |
225 |
| -// Marks a given transaction as 'aborted'. |
226 |
| -void DtmGlobalRollback(DTMConn dtm, xid_t gxid) { |
227 |
| - bool result; |
228 |
| - |
229 |
| - if (!dtm_write_char(dtm, 'a')) { |
230 |
| - return; |
| 188 | + bool ok; |
| 189 | + switch (status) { |
| 190 | + case TRANSACTION_STATUS_COMMITTED: |
| 191 | + // query |
| 192 | + if (!dtm_query(dtm, 'c', 2, nodeid, xid)) return false; |
| 193 | + break; |
| 194 | + case TRANSACTION_STATUS_ABORTED: |
| 195 | + // query |
| 196 | + if (!dtm_query(dtm, 'a', 2, nodeid, xid)) return false; |
| 197 | + break; |
| 198 | + default: |
| 199 | + assert(false); // should not happen |
| 200 | + return false; |
231 | 201 | }
|
232 | 202 |
|
233 |
| - if (!dtm_write_hex16(dtm, gxid)) { |
234 |
| - return; |
235 |
| - } |
| 203 | + if (!dtm_read_bool(dtm, &ok)) return false; |
236 | 204 |
|
237 |
| - if (!dtm_read_bool(dtm, &result)) { |
238 |
| - return; |
239 |
| - } |
| 205 | + return ok; |
240 | 206 | }
|
241 |
| -#endif |
242 | 207 |
|
243 |
| -// Gets the status of the transaction identified by 'gxid'. Returns the status |
| 208 | +// Gets the status of the transaction identified by 'xid'. Returns the status |
244 | 209 | // on success, or -1 otherwise.
|
245 |
| -XidStatus DtmGlobalGetTransStatus(DTMConn dtm, NodeId nodeid, TransactionId gxid) { |
| 210 | +XidStatus DtmGlobalGetTransStatus(DTMConn dtm, NodeId nodeid, TransactionId xid) { |
246 | 211 | bool result;
|
247 | 212 | char statuschar;
|
248 | 213 |
|
249 |
| - if (!dtm_write_char(dtm, 's')) { |
250 |
| - return -1; |
251 |
| - } |
252 |
| - |
253 |
| - if (!dtm_write_hex16(dtm, gxid)) { |
254 |
| - return -1; |
255 |
| - } |
| 214 | + if (!dtm_query(dtm, 's', 2, nodeid, xid)) return -1; |
256 | 215 |
|
257 |
| - if (!dtm_read_bool(dtm, &result)) { |
258 |
| - return -1; |
259 |
| - } |
260 |
| - if (!result) { |
261 |
| - return -1; |
262 |
| - } |
263 |
| - |
264 |
| - if (!dtm_read_char(dtm, &statuschar)) { |
265 |
| - return -1; |
266 |
| - } |
| 216 | + if (!dtm_read_bool(dtm, &result)) return -1; |
| 217 | + if (!result) return -1; |
| 218 | + if (!dtm_read_char(dtm, &statuschar)) return -1; |
267 | 219 |
|
268 | 220 | switch (statuschar) {
|
269 | 221 | case 'c':
|
270 |
| - return COMMIT_YES; |
| 222 | + return TRANSACTION_STATUS_COMMITTED; |
271 | 223 | case 'a':
|
272 |
| - return COMMIT_NO; |
| 224 | + return TRANSACTION_STATUS_ABORTED; |
273 | 225 | case '?':
|
274 |
| - return COMMIT_UNKNOWN; |
| 226 | + return TRANSACTION_STATUS_IN_PROGRESS; |
275 | 227 | default:
|
276 | 228 | return -1;
|
277 | 229 | }
|
|
0 commit comments