Track the status of a transaction in a new status field. Check the field for
sanity, i.e. that status must be OPEN when _commit/_create/_delete or
_update is called or else die(BUG:...)
Signed-off-by: Ronnie Sahlberg <redacted>
---
refs.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/refs.c b/refs.c
index b5186cd..00d8fc9 100644
--- a/refs.c
+++ b/refs.c
@@ -3331,6 +3331,30 @@ struct ref_update {
};
/*
+ * Transaction states.
+ * OPEN: The transaction is in a valid state and can accept new updates.
+ * An OPEN transaction can be committed.
+ * CLOSED: If an open transaction is successfully committed the state will
+ * change to CLOSED. No further changes can be made to a CLOSED
+ * transaction.
+ * CLOSED means that all updates have been successfully committed and
+ * the only thing that remains is to free the completed transaction.
+ * ERROR: The transaction has failed and is no longer committable.
+ * Eventhough the transaction can no longer be committed it is still
+ * possible to add additional updates to the transaction. The reason
+ * for this is to allow a caller to continue trying more updates
+ * so that a caller can report a list of ALL updates that would fail
+ * instead of just the first update that fails.
+ * An ERRORed transaction can not be committed and must be rolled
+ * back using transaction_free.
+ */
+enum ref_transaction_state {
+ REF_TRANSACTION_OPEN = 0,
+ REF_TRANSACTION_CLOSED = 1,
+ REF_TRANSACTION_ERROR = 2,
+};
+
+/*
* Data structure for holding a reference transaction, which can
* consist of checks and updates to multiple references, carried out
* as atomically as possible. This structure is opaque to callers.@@ -3339,6 +3363,8 @@ struct ref_transaction {
struct ref_update **updates;
size_t alloc;
size_t nr;
+ enum ref_transaction_state state;
+ int status;
};
struct ref_transaction *ref_transaction_begin(struct strbuf *err)@@ -3476,8 +3502,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
- if (!n)
+ if (transaction->state != REF_TRANSACTION_OPEN)
+ return transaction->status;
+
+ if (!n) {
+ transaction->state = REF_TRANSACTION_CLOSED;
return 0;
+ }
/* Allocate work space */
delnames = xmalloc(sizeof(*delnames) * n);@@ -3540,6 +3571,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
clear_loose_ref_cache(&ref_cache);
cleanup:
+ transaction->state = ret ? REF_TRANSACTION_ERROR
+ : REF_TRANSACTION_CLOSED;
+
for (i = 0; i < n; i++)
if (updates[i]->lock)
unlock_ref(updates[i]->lock);
--
2.0.0.rc3.474.g3833130