From: Johannes Sixt <j.sixt@viscovery.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: Steffen Prohaska <prohaska@zib.de>,
Johannes Schindelin <Johannes.Schindelin@gmx.de>,
Git Mailing List <git@vger.kernel.org>
Subject: [PATCH 1/2] Windows: Work around intermittent failures in mingw_rename
Date: Mon, 20 Apr 2009 10:01:37 +0200 [thread overview]
Message-ID: <49EC2BE1.9080200@viscovery.net> (raw)
From: Johannes Sixt <j6t@kdbg.org>
Date: Fri, 3 Apr 2009 08:49:59 +0200
We have replaced rename() with a version that can rename a file to a
destination that already exists. Nevertheless, many users, the author
included, observe failures in the code that are not reproducible.
The theory is that the failures are due to some other process that happens
to have opened the destination file briefly at the wrong moment. (And there
is no way on Windows to delete or replace a file that is currently open.)
The most likely candidate for such a process is a virus scanner. The
failure is more often observed while there is heavy git activity (for
example while the test suite is running or during a rebase operation).
We work around the failure by retrying the rename operation if it failed
due to ERROR_ACCESS_DENIED. The retries are delayed a bit: The first only
by giving up the time slice, the next after the minimal scheduling
granularity, and if more retries are needed, then we wait some non-trivial
amount of time with exponential back-off.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
Steffen, Dscho,
this is slightly different from the version that is currently 4msysgit:
I removed the warning that was printed when a retry was attempted.
-- Hannes
compat/mingw.c | 21 +++++++++++++++++++--
1 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index 4b37d93..74eae20 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -978,7 +978,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
#undef rename
int mingw_rename(const char *pold, const char *pnew)
{
- DWORD attrs;
+ DWORD attrs, gle;
+ int tries = 0;
+ static const int delay[] = { 0, 1, 10, 20, 40 };
/*
* Try native rename() first to get errno right.
@@ -988,10 +990,12 @@ int mingw_rename(const char *pold, const char *pnew)
return 0;
if (errno != EEXIST)
return -1;
+repeat:
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0;
/* TODO: translate more errors */
- if (GetLastError() == ERROR_ACCESS_DENIED &&
+ gle = GetLastError();
+ if (gle == ERROR_ACCESS_DENIED &&
(attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
errno = EISDIR;
@@ -1001,10 +1005,23 @@ int mingw_rename(const char *pold, const char *pnew)
SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0;
+ gle = GetLastError();
/* revert file attributes on failure */
SetFileAttributes(pnew, attrs);
}
}
+ if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
+ /*
+ * We assume that some other process had the source or
+ * destination file open at the wrong moment and retry.
+ * In order to give the other process a higher chance to
+ * complete its operation, we give up our time slice now.
+ * If we have to retry again, we do sleep a bit.
+ */
+ Sleep(delay[tries]);
+ tries++;
+ goto repeat;
+ }
errno = EACCES;
return -1;
}
--
1.6.3.rc1.989.ga175e.dirty
next reply other threads:[~2009-04-20 8:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-20 8:01 Johannes Sixt [this message]
2009-04-20 10:01 ` [PATCH 1/2] Windows: Work around intermittent failures in mingw_rename Johannes Schindelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49EC2BE1.9080200@viscovery.net \
--to=j.sixt@viscovery.net \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=prohaska@zib.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).