Skip to content
Permalink
Browse files
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.
  • Loading branch information
vaintroub committed Sep 17, 2020
1 parent 7e07e38 commit ade782c
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
@@ -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;
@@ -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,17 +19,70 @@
#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;
DBUG_ENTER("my_rename");
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)

0 comments on commit ade782c

Please sign in to comment.