Skip to content

Commit 4ff0f01

Browse files
mhaggergitster
authored andcommitted
refs: retry acquiring reference locks for 100ms
The philosophy of reference locking has been, "if another process is changing a reference, then whatever I'm trying to do to it will probably fail anyway because my old-SHA-1 value is probably no longer current". But this argument falls down if the other process has locked the reference to do something that doesn't actually change the value of the reference, such as `pack-refs` or `reflog expire`. There actually *is* a decent chance that a planned reference update will still be able to go through after the other process has released the lock. So when trying to lock an individual reference (e.g., when creating "refs/heads/master.lock"), if it is already locked, then retry the lock acquisition for approximately 100 ms before giving up. This should eliminate some unnecessary lock conflicts without wasting a lot of time. Add a configuration setting, `core.filesRefLockTimeout`, to allow this setting to be tweaked. Note: the function `get_files_ref_lock_timeout_ms()` cannot be private to the files backend because it is also used by `write_pseudoref()` and `delete_pseudoref()`, which are defined in `refs.c` so that they can be used by other reference backends. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 4d7268b commit 4ff0f01

File tree

4 files changed

+39
-5
lines changed

4 files changed

+39
-5
lines changed

Documentation/config.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,12 @@ core.commentChar::
776776
If set to "auto", `git-commit` would select a character that is not
777777
the beginning character of any line in existing commit messages.
778778

779+
core.filesRefLockTimeout::
780+
The length of time, in milliseconds, to retry when trying to
781+
lock an individual reference. Value 0 means not to retry at
782+
all; -1 means to try indefinitely. Default is 100 (i.e.,
783+
retry for 100ms).
784+
779785
core.packedRefsTimeout::
780786
The length of time, in milliseconds, to retry when trying to
781787
lock the `packed-refs` file. Value 0 means not to retry at

refs.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,21 @@ enum ref_type ref_type(const char *refname)
561561
return REF_TYPE_NORMAL;
562562
}
563563

564+
long get_files_ref_lock_timeout_ms(void)
565+
{
566+
static int configured = 0;
567+
568+
/* The default timeout is 100 ms: */
569+
static int timeout_ms = 100;
570+
571+
if (!configured) {
572+
git_config_get_int("core.filesreflocktimeout", &timeout_ms);
573+
configured = 1;
574+
}
575+
576+
return timeout_ms;
577+
}
578+
564579
static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
565580
const unsigned char *old_sha1, struct strbuf *err)
566581
{
@@ -573,7 +588,9 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
573588
strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
574589

575590
filename = git_path("%s", pseudoref);
576-
fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
591+
fd = hold_lock_file_for_update_timeout(&lock, filename,
592+
LOCK_DIE_ON_ERROR,
593+
get_files_ref_lock_timeout_ms());
577594
if (fd < 0) {
578595
strbuf_addf(err, "could not open '%s' for writing: %s",
579596
filename, strerror(errno));
@@ -616,8 +633,9 @@ static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1
616633
int fd;
617634
unsigned char actual_old_sha1[20];
618635

619-
fd = hold_lock_file_for_update(&lock, filename,
620-
LOCK_DIE_ON_ERROR);
636+
fd = hold_lock_file_for_update_timeout(
637+
&lock, filename, LOCK_DIE_ON_ERROR,
638+
get_files_ref_lock_timeout_ms());
621639
if (fd < 0)
622640
die_errno(_("Could not open '%s' for writing"), filename);
623641
if (read_ref(pseudoref, actual_old_sha1))

refs/files-backend.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,9 @@ static int lock_raw_ref(struct files_ref_store *refs,
855855
if (!lock->lk)
856856
lock->lk = xcalloc(1, sizeof(struct lock_file));
857857

858-
if (hold_lock_file_for_update(lock->lk, ref_file.buf, LOCK_NO_DEREF) < 0) {
858+
if (hold_lock_file_for_update_timeout(
859+
lock->lk, ref_file.buf, LOCK_NO_DEREF,
860+
get_files_ref_lock_timeout_ms()) < 0) {
859861
if (errno == ENOENT && --attempts_remaining > 0) {
860862
/*
861863
* Maybe somebody just deleted one of the
@@ -1181,7 +1183,9 @@ static int create_reflock(const char *path, void *cb)
11811183
{
11821184
struct lock_file *lk = cb;
11831185

1184-
return hold_lock_file_for_update(lk, path, LOCK_NO_DEREF) < 0 ? -1 : 0;
1186+
return hold_lock_file_for_update_timeout(
1187+
lk, path, LOCK_NO_DEREF,
1188+
get_files_ref_lock_timeout_ms()) < 0 ? -1 : 0;
11851189
}
11861190

11871191
/*

refs/refs-internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
*/
6262
#define REF_DELETED_LOOSE 0x200
6363

64+
/*
65+
* Return the length of time to retry acquiring a loose reference lock
66+
* before giving up, in milliseconds:
67+
*/
68+
long get_files_ref_lock_timeout_ms(void);
69+
6470
/*
6571
* Return true iff refname is minimally safe. "Safe" here means that
6672
* deleting a loose reference by this name will not do any damage, for

0 commit comments

Comments
 (0)