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:
4
mysql-test/main/windows_debug.result
Normal file
4
mysql-test/main/windows_debug.result
Normal 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;
|
11
mysql-test/main/windows_debug.test
Normal file
11
mysql-test/main/windows_debug.test
Normal 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
|
@ -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)
|
||||
|
Reference in New Issue
Block a user