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 <sahlberg@xxxxxxxxxx> --- 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 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html