If a directory vanishes while renaming the temporary reflog file,
retry (up to 3 times). This could happen if another process deletes
the directory created by safe_create_leading_directories() just before
we rename the file into the directory.
As far as I can tell, this race could not occur internal to git. The
only time that a directory under $GIT_DIR/logs is deleted is if room
has to be made for a log file for a reference with the same name;
for example, in the following sequence:
git branch foo/bar # Creates file .git/logs/refs/heads/foo/bar
git branch -d foo/bar # Deletes file but leaves .git/logs/refs/heads/foo/
git branch foo # Deletes .git/logs/refs/heads/foo/
But the only reason the last command deletes the directory is because
it wants to create a file with the same name. So if another process
(e.g.,
git branch foo/baz
) wants to create that directory, one of the two is doomed to failure
anyway because of a D/F conflict.
Signed-off-by: Michael Haggerty <[email protected]>
---
refs.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/refs.c b/refs.c
index 5bc01a7..8de636e 100644
--- a/refs.c
+++ b/refs.c
@@ -2530,12 +2530,14 @@ int delete_ref(const char *refname, const unsigned char
*sha1, int delopt)
static int rename_tmp_log(const char *newrefname)
{
+ int attempts = 3;
+
+ retry:
if (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
error("unable to create directory for %s", newrefname);
return -1;
}
- retry:
if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname)))
{
if (errno==EISDIR || errno==ENOTDIR) {
/*
@@ -2548,6 +2550,13 @@ static int rename_tmp_log(const char *newrefname)
return -1;
}
goto retry;
+ } else if (errno == ENOENT && --attempts > 0) {
+ /*
+ * Maybe another process just deleted one of
+ * the directories in the path to newrefname.
+ * Try again from the beginning.
+ */
+ goto retry;
} else {
error("unable to move logfile "TMP_RENAMED_LOG" to
logs/%s: %s",
newrefname, strerror(errno));
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html