1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

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.
This commit is contained in:
Vladislav Vaintroub
2020-09-17 22:27:45 +02:00
parent 7e07e38cf6
commit ade782c001
3 changed files with 71 additions and 3 deletions

View File

@ -0,0 +1,4 @@
# 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;

View File

@ -0,0 +1,11 @@
# 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

View File

@ -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)