refs: add a concept of a reference transaction
Build out the API for dealing with a bunch of reference checks and changes within a transaction. Define an opaque ref_transaction type that is managed entirely within refs.c. Introduce functions for beginning a transaction, adding updates to a transaction, and committing/rolling back a transaction. This API will soon replace update_refs(). Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Haggerty committed
Apr 7, 2014 at 15:48 UTC
caa4046c4f480ceae5afb20e3172a437865cc51f
2 files changed
+164
refs.c
+99
@@ -3267,6 +3267,96 @@ static int update_ref_write(const char *action, const char *refname,
3267
return 0;
3268
}
3269
3270
+/*
3271
+ * Data structure for holding a reference transaction, which can
3272
+ * consist of checks and updates to multiple references, carried out
3273
+ * as atomically as possible. This structure is opaque to callers.
3274
+ */
3275
+struct ref_transaction {
3276
+ struct ref_update **updates;
3277
+ size_t alloc;
3278
+ size_t nr;
3279
+};
3280
+
3281
+struct ref_transaction *ref_transaction_begin(void)
3282
+{
3283
+ return xcalloc(1, sizeof(struct ref_transaction));
3284
+}
3285
+
3286
+static void ref_transaction_free(struct ref_transaction *transaction)
3287
+{
3288
+ int i;
3289
+
3290
+ for (i = 0; i < transaction->nr; i++) {
3291
+ struct ref_update *update = transaction->updates[i];
3292
+
3293
+ free((char *)update->ref_name);
3294
+ free(update);
3295
+ }
3296
+
3297
+ free(transaction->updates);
3298
+ free(transaction);
3299
+}
3300
+
3301
+void ref_transaction_rollback(struct ref_transaction *transaction)
3302
+{
3303
+ ref_transaction_free(transaction);
3304
+}
3305
+
3306
+static struct ref_update *add_update(struct ref_transaction *transaction,
3307
+ const char *refname)
3308
+{
3309
+ struct ref_update *update = xcalloc(1, sizeof(*update));
3310
+
3311
+ update->ref_name = xstrdup(refname);
3312
+ ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
3313
+ transaction->updates[transaction->nr++] = update;
3314
+ return update;
3315
+}
3316
+
3317
+void ref_transaction_update(struct ref_transaction *transaction,
3318
+ const char *refname,
3319
+ unsigned char *new_sha1, unsigned char *old_sha1,
3320
+ int flags, int have_old)
3321
+{
3322
+ struct ref_update *update = add_update(transaction, refname);
3323
+
3324
+ hashcpy(update->new_sha1, new_sha1);
3325
+ update->flags = flags;
3326
+ update->have_old = have_old;
3327
+ if (have_old)
3328
+ hashcpy(update->old_sha1, old_sha1);
3329
+}
3330
+
3331
+void ref_transaction_create(struct ref_transaction *transaction,
3332
+ const char *refname,
3333
+ unsigned char *new_sha1,
3334
+ int flags)
3335
+{
3336
+ struct ref_update *update = add_update(transaction, refname);
3337
+
3338
+ assert(!is_null_sha1(new_sha1));
3339
+ hashcpy(update->new_sha1, new_sha1);
3340
+ hashclr(update->old_sha1);
3341
+ update->flags = flags;
3342
+ update->have_old = 1;
3343
+}
3344
+
3345
+void ref_transaction_delete(struct ref_transaction *transaction,
3346
+ const char *refname,
3347
+ unsigned char *old_sha1,
3348
+ int flags, int have_old)
3349
+{
3350
+ struct ref_update *update = add_update(transaction, refname);
3351
+
3352
+ update->flags = flags;
3353
+ update->have_old = have_old;
3354
+ if (have_old) {
3355
+ assert(!is_null_sha1(old_sha1));
3356
+ hashcpy(update->old_sha1, old_sha1);
3357
+ }
3358
+}
3359
+
3360
int update_ref(const char *action, const char *refname,
3361
const unsigned char *sha1, const unsigned char *oldval,
3362
int flags, enum action_on_err onerr)
@@ -3378,6 +3468,15 @@ cleanup:
3468
return ret;
3469
}
3470
3471
+int ref_transaction_commit(struct ref_transaction *transaction,
3472
+ const char *msg, enum action_on_err onerr)
3473
+{
3474
+ int ret = update_refs(msg, transaction->updates, transaction->nr,
3475
+ onerr);
3476
+ ref_transaction_free(transaction);
3477
+ return ret;
3478
+}
3479
+
3480
char *shorten_unambiguous_ref(const char *refname, int strict)
3481
{
3482
int i;
refs.h
+65
@@ -24,6 +24,8 @@ struct ref_update {
24
int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
25
};
26
27
+struct ref_transaction;
28
+
29
/*
30
* Bit values set in the flags argument passed to each_ref_fn():
31
*/
@@ -220,6 +222,69 @@ enum action_on_err {
222
UPDATE_REFS_QUIET_ON_ERR
223
};
224
225
+/*
226
+ * Begin a reference transaction. The reference transaction must
227
+ * eventually be commited using ref_transaction_commit() or rolled
228
+ * back using ref_transaction_rollback().
229
+ */
230
+struct ref_transaction *ref_transaction_begin(void);
231
+
232
+/*
233
+ * Roll back a ref_transaction and free all associated data.
234
+ */
235
+void ref_transaction_rollback(struct ref_transaction *transaction);
236
+
237
+
238
+/*
239
+ * The following functions add a reference check or update to a
240
+ * ref_transaction. In all of them, refname is the name of the
241
+ * reference to be affected. The functions make internal copies of
242
+ * refname, so the caller retains ownership of the parameter. flags
243
+ * can be REF_NODEREF; it is passed to update_ref_lock().
244
+ */
245
+
246
+
247
+/*
248
+ * Add a reference update to transaction. new_sha1 is the value that
249
+ * the reference should have after the update, or zeros if it should
250
+ * be deleted. If have_old is true, then old_sha1 holds the value
251
+ * that the reference should have had before the update, or zeros if
252
+ * it must not have existed beforehand.
253
+ */
254
+void ref_transaction_update(struct ref_transaction *transaction,
255
+ const char *refname,
256
+ unsigned char *new_sha1, unsigned char *old_sha1,
257
+ int flags, int have_old);
258
+
259
+/*
260
+ * Add a reference creation to transaction. new_sha1 is the value
261
+ * that the reference should have after the update; it must not be the
262
+ * null SHA-1. It is verified that the reference does not exist
263
+ * already.
264
+ */
265
+void ref_transaction_create(struct ref_transaction *transaction,
266
+ const char *refname,
267
+ unsigned char *new_sha1,
268
+ int flags);
269
+
270
+/*
271
+ * Add a reference deletion to transaction. If have_old is true, then
272
+ * old_sha1 holds the value that the reference should have had before
273
+ * the update (which must not be the null SHA-1).
274
+ */
275
+void ref_transaction_delete(struct ref_transaction *transaction,
276
+ const char *refname,
277
+ unsigned char *old_sha1,
278
+ int flags, int have_old);
279
+
280
+/*
281
+ * Commit all of the changes that have been queued in transaction, as
282
+ * atomically as possible. Return a nonzero value if there is a
283
+ * problem. The ref_transaction is freed by this function.
284
+ */
285
+int ref_transaction_commit(struct ref_transaction *transaction,
286
+ const char *msg, enum action_on_err onerr);
287
+
288
/** Lock a ref and then write its file */
289
int update_ref(const char *action, const char *refname,
290
const unsigned char *sha1, const unsigned char *oldval,