lock_ref_for_update(): new function

Extract a new function, lock_ref_for_update(), from
ref_transaction_commit().

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
This commit is contained in:
Michael Haggerty 2016-04-24 08:58:41 +02:00
parent 71564516de
commit 165056b2fc

View File

@ -3051,6 +3051,88 @@ static int ref_update_reject_duplicates(struct string_list *refnames,
return 0; return 0;
} }
/*
* Acquire all locks, verify old values if provided, check
* that new values are valid, and write new values to the
* lockfiles, ready to be activated. Only keep one lockfile
* open at a time to avoid running out of file descriptors.
*/
static int lock_ref_for_update(struct ref_update *update,
struct ref_transaction *transaction,
struct string_list *affected_refnames,
struct strbuf *err)
{
int ret;
if ((update->flags & REF_HAVE_NEW) &&
is_null_sha1(update->new_sha1))
update->flags |= REF_DELETING;
update->lock = lock_ref_sha1_basic(
update->refname,
((update->flags & REF_HAVE_OLD) ?
update->old_sha1 : NULL),
affected_refnames, NULL,
update->flags,
&update->type,
err);
if (!update->lock) {
char *reason;
ret = (errno == ENOTDIR)
? TRANSACTION_NAME_CONFLICT
: TRANSACTION_GENERIC_ERROR;
reason = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot lock ref '%s': %s",
update->refname, reason);
free(reason);
return ret;
}
if ((update->flags & REF_HAVE_NEW) &&
!(update->flags & REF_DELETING) &&
!(update->flags & REF_LOG_ONLY)) {
int overwriting_symref = ((update->type & REF_ISSYMREF) &&
(update->flags & REF_NODEREF));
if (!overwriting_symref &&
!hashcmp(update->lock->old_oid.hash, update->new_sha1)) {
/*
* The reference already has the desired
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(update->lock,
update->new_sha1,
err)) {
char *write_err = strbuf_detach(err, NULL);
/*
* The lock was freed upon failure of
* write_ref_to_lockfile():
*/
update->lock = NULL;
strbuf_addf(err,
"cannot update the ref '%s': %s",
update->refname, write_err);
free(write_err);
return TRANSACTION_GENERIC_ERROR;
} else {
update->flags |= REF_NEEDS_COMMIT;
}
}
if (!(update->flags & REF_NEEDS_COMMIT)) {
/*
* We didn't call write_ref_to_lockfile(), so
* the lockfile is still open. Close it to
* free up the file descriptor:
*/
if (close_ref(update->lock)) {
strbuf_addf(err, "couldn't close '%s.lock'",
update->refname);
return TRANSACTION_GENERIC_ERROR;
}
}
return 0;
}
int ref_transaction_commit(struct ref_transaction *transaction, int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err) struct strbuf *err)
{ {
@ -3088,75 +3170,11 @@ int ref_transaction_commit(struct ref_transaction *transaction,
for (i = 0; i < transaction->nr; i++) { for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i]; struct ref_update *update = transaction->updates[i];
if ((update->flags & REF_HAVE_NEW) && ret = lock_ref_for_update(update, transaction,
is_null_sha1(update->new_sha1)) &affected_refnames, err);
update->flags |= REF_DELETING; if (ret)
update->lock = lock_ref_sha1_basic(
update->refname,
((update->flags & REF_HAVE_OLD) ?
update->old_sha1 : NULL),
&affected_refnames, NULL,
update->flags,
&update->type,
err);
if (!update->lock) {
char *reason;
ret = (errno == ENOTDIR)
? TRANSACTION_NAME_CONFLICT
: TRANSACTION_GENERIC_ERROR;
reason = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot lock ref '%s': %s",
update->refname, reason);
free(reason);
goto cleanup; goto cleanup;
} }
if ((update->flags & REF_HAVE_NEW) &&
!(update->flags & REF_DELETING) &&
!(update->flags & REF_LOG_ONLY)) {
int overwriting_symref = ((update->type & REF_ISSYMREF) &&
(update->flags & REF_NODEREF));
if (!overwriting_symref &&
!hashcmp(update->lock->old_oid.hash, update->new_sha1)) {
/*
* The reference already has the desired
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(update->lock,
update->new_sha1,
err)) {
char *write_err = strbuf_detach(err, NULL);
/*
* The lock was freed upon failure of
* write_ref_to_lockfile():
*/
update->lock = NULL;
strbuf_addf(err,
"cannot update the ref '%s': %s",
update->refname, write_err);
free(write_err);
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
} else {
update->flags |= REF_NEEDS_COMMIT;
}
}
if (!(update->flags & REF_NEEDS_COMMIT)) {
/*
* We didn't call write_ref_to_lockfile(), so
* the lockfile is still open. Close it to
* free up the file descriptor:
*/
if (close_ref(update->lock)) {
strbuf_addf(err, "couldn't close '%s.lock'",
update->refname);
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
}
}
/* Perform updates first so live commits remain referenced */ /* Perform updates first so live commits remain referenced */
for (i = 0; i < transaction->nr; i++) { for (i = 0; i < transaction->nr; i++) {