summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2020-09-17 22:27:45 +0200
committerVladislav Vaintroub <wlad@mariadb.com>2020-09-17 22:27:45 +0200
commitade782c001affa69df80ed51e807e16198a9fe04 (patch)
treeced220c91c4494e946fdb6046b9b550c567c5198 /mysys
parent7e07e38cf687ccd7fa3bd3a35c1eb7e4b307ca5f (diff)
downloadmariadb-git-ade782c001affa69df80ed51e807e16198a9fe04.tar.gz
MDEV-23741 Windows : error when renaming file in ALTER TABLE
The presumed reason for the error is that the file was opened by 3rd party antivirus or backup program, causing ERROR_SHARING_VIOLATION on rename. The fix, actually a workaround, is to retry MoveFileEx couple of times before finally giving up. We expect 3rd party programs not to hold file for extended time.
Diffstat (limited to 'mysys')
-rw-r--r--mysys/my_rename.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
index 81b43064ea8..5702af94272 100644
--- a/mysys/my_rename.c
+++ b/mysys/my_rename.c
@@ -19,8 +19,62 @@
#include "m_string.h"
#undef my_rename
- /* On unix rename deletes to file if it exists */
+#ifdef _WIN32
+
+#define RENAME_MAX_RETRIES 50
+
+/*
+ On Windows, bad 3rd party programs (backup or anitivirus, or something else)
+ can have file open with a sharing mode incompatible with renaming, i.e they
+ won't use FILE_SHARE_DELETE when opening file.
+
+ The following function will do a couple of retries, in case MoveFileEx returns
+ ERROR_SHARING_VIOLATION.
+*/
+static BOOL win_rename_with_retries(const char *from, const char *to)
+{
+#ifndef DBUG_OFF
+ FILE *fp = NULL;
+ DBUG_EXECUTE_IF("rename_sharing_violation",
+ {
+ fp= fopen(from, "r");
+ DBUG_ASSERT(fp);
+ }
+ );
+#endif
+
+ for (int retry= RENAME_MAX_RETRIES; retry--;)
+ {
+ DWORD ret = MoveFileEx(from, to,
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
+
+ DBUG_ASSERT(fp == NULL || (ret == FALSE && GetLastError() == ERROR_SHARING_VIOLATION));
+
+ if (!ret && (GetLastError() == ERROR_SHARING_VIOLATION))
+ {
+#ifndef DBUG_OFF
+ /*
+ If error was injected in via DBUG_EXECUTE_IF, close the file
+ that is causing ERROR_SHARING_VIOLATION, so that retry succeeds.
+ */
+ if (fp)
+ {
+ fclose(fp);
+ fp= NULL;
+ }
+#endif
+
+ Sleep(10);
+ }
+ else
+ return ret;
+ }
+ return FALSE;
+}
+#endif
+
+ /* On unix rename deletes to file if it exists */
int my_rename(const char *from, const char *to, myf MyFlags)
{
int error = 0;
@@ -28,8 +82,7 @@ int my_rename(const char *from, const char *to, myf MyFlags)
DBUG_PRINT("my",("from %s to %s MyFlags %lu", from, to, MyFlags));
#if defined(__WIN__)
- if (!MoveFileEx(from, to, MOVEFILE_COPY_ALLOWED |
- MOVEFILE_REPLACE_EXISTING))
+ if (!win_rename_with_retries(from, to))
{
my_osmaperr(GetLastError());
#elif defined(HAVE_RENAME)