Skip to content

Commit f2dd90f

Browse files
committed
Merge branch 'mh/ref-lock-entry'
The code to acquire a lock on a reference (e.g. while accepting a push from a client) used to immediately fail when the reference is already locked---now it waits for a very short while and retries, which can make it succeed if the lock holder was holding it during a read-only operation. * mh/ref-lock-entry: refs: retry acquiring reference locks for 100ms
2 parents 138e52e + 4ff0f01 commit f2dd90f

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
@@ -579,6 +579,21 @@ enum ref_type ref_type(const char *refname)
579579
return REF_TYPE_NORMAL;
580580
}
581581

582+
long get_files_ref_lock_timeout_ms(void)
583+
{
584+
static int configured = 0;
585+
586+
/* The default timeout is 100 ms: */
587+
static int timeout_ms = 100;
588+
589+
if (!configured) {
590+
git_config_get_int("core.filesreflocktimeout", &timeout_ms);
591+
configured = 1;
592+
}
593+
594+
return timeout_ms;
595+
}
596+
582597
static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
583598
const unsigned char *old_sha1, struct strbuf *err)
584599
{
@@ -591,7 +606,9 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
591606
strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
592607

593608
filename = git_path("%s", pseudoref);
594-
fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
609+
fd = hold_lock_file_for_update_timeout(&lock, filename,
610+
LOCK_DIE_ON_ERROR,
611+
get_files_ref_lock_timeout_ms());
595612
if (fd < 0) {
596613
strbuf_addf(err, "could not open '%s' for writing: %s",
597614
filename, strerror(errno));
@@ -634,8 +651,9 @@ static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1
634651
int fd;
635652
unsigned char actual_old_sha1[20];
636653

637-
fd = hold_lock_file_for_update(&lock, filename,
638-
LOCK_DIE_ON_ERROR);
654+
fd = hold_lock_file_for_update_timeout(
655+
&lock, filename, LOCK_DIE_ON_ERROR,
656+
get_files_ref_lock_timeout_ms());
639657
if (fd < 0)
640658
die_errno(_("Could not open '%s' for writing"), filename);
641659
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
@@ -537,7 +537,9 @@ static int lock_raw_ref(struct files_ref_store *refs,
537537
if (!lock->lk)
538538
lock->lk = xcalloc(1, sizeof(struct lock_file));
539539

540-
if (hold_lock_file_for_update(lock->lk, ref_file.buf, LOCK_NO_DEREF) < 0) {
540+
if (hold_lock_file_for_update_timeout(
541+
lock->lk, ref_file.buf, LOCK_NO_DEREF,
542+
get_files_ref_lock_timeout_ms()) < 0) {
541543
if (errno == ENOENT && --attempts_remaining > 0) {
542544
/*
543545
* Maybe somebody just deleted one of the
@@ -865,7 +867,9 @@ static int create_reflock(const char *path, void *cb)
865867
{
866868
struct lock_file *lk = cb;
867869

868-
return hold_lock_file_for_update(lk, path, LOCK_NO_DEREF) < 0 ? -1 : 0;
870+
return hold_lock_file_for_update_timeout(
871+
lk, path, LOCK_NO_DEREF,
872+
get_files_ref_lock_timeout_ms()) < 0 ? -1 : 0;
869873
}
870874

871875
/*

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)