lock_ref_sha1_basic(): on SCLD_VANISHED, retry
authorMichael Haggerty <mhagger@alum.mit.edu>
Sat, 18 Jan 2014 22:48:54 +0000 (23:48 +0100)
committerJunio C Hamano <gitster@pobox.com>
Tue, 21 Jan 2014 21:46:07 +0000 (13:46 -0800)
If safe_create_leading_directories() fails because a file along the
path unexpectedly vanished, try again (up to 3 times).

This can occur if another process is deleting directories at the same
time as we are trying to make them. For example, "git pack-refs
--all" tries to delete the loose refs and any empty directories that
are left behind. If a pack-refs process is running, then it might
delete a directory that we need to put a new loose reference in.

If safe_create_leading_directories() thinks this might have happened,
then take its advice and try again (maximum three attempts).

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c
diff --git a/refs.c b/refs.c
index 5e5a3824b992132aaac8d86698feebcb773e13c6..2d0faf23262b79a1627238e996a1852f0e87ecd1 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -2039,6 +2039,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        int type, lflags;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
        int missing = 0;
+       int attempts_remaining = 3;
 
        lock = xcalloc(1, sizeof(struct ref_lock));
        lock->lock_fd = -1;
@@ -2093,7 +2094,15 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
                lock->force_write = 1;
 
-       if (safe_create_leading_directories(ref_file)) {
+ retry:
+       switch (safe_create_leading_directories(ref_file)) {
+       case SCLD_OK:
+               break; /* success */
+       case SCLD_VANISHED:
+               if (--attempts_remaining > 0)
+                       goto retry;
+               /* fall through */
+       default:
                last_errno = errno;
                error("unable to create directory for %s", ref_file);
                goto error_return;