Commit ade782c0 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

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.
parent 7e07e38c
# mdev-23741 sharing violation when renaming .frm file in ALTER
CREATE TABLE t(i int);
SET STATEMENT debug_dbug='+d, win_simulate_rename_error' FOR ALTER TABLE t ADD PRIMARY KEY (i);
DROP TABLE t;
# Windows-specific tests , debug mode
--source include/have_debug.inc
--source include/windows.inc
--echo # mdev-23741 sharing violation when renaming .frm file in ALTER
CREATE TABLE t(i int);
SET STATEMENT debug_dbug='+d,rename_sharing_violation' FOR ALTER TABLE t ADD PRIMARY KEY (i);
DROP TABLE t;
#End of 10.3 tests
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment