MDEV-36283 "OpenEvent() failed" fatal error in mariadb-upgrade-service
The issue occurs when mariadb-upgrade-service shuts down the server it started. There is a race condition where the server is online and responsive to pings but has not yet created the named Windows shutdown event. This fix refactors the startup/shutdown logic to ensure startup waits for the shutdown event. Additionally, mariadb-admin is unnecessary, as waiting for the named pipe is already sufficient.
This commit is contained in:
parent
730dcf7e6d
commit
fc60b89d0c
@ -302,13 +302,29 @@ void stop_mysqld_service()
|
||||
our --skip-grant-tables do not work anymore after mysql_upgrade
|
||||
that does "flush privileges". Instead, the shutdown event is set.
|
||||
*/
|
||||
#define OPEN_EVENT_RETRY_SLEEP_MS 100
|
||||
#define OPEN_EVENT_MAX_RETRIES 50
|
||||
|
||||
void initiate_mysqld_shutdown()
|
||||
{
|
||||
char event_name[32];
|
||||
DWORD pid= GetProcessId(mysqld_process);
|
||||
sprintf_s(event_name, "MySQLShutdown%d", pid);
|
||||
HANDLE shutdown_handle= OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
|
||||
if(!shutdown_handle)
|
||||
|
||||
HANDLE shutdown_handle;
|
||||
for (int i= 0;; i++)
|
||||
{
|
||||
shutdown_handle= OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
|
||||
if(shutdown_handle != nullptr || i == OPEN_EVENT_MAX_RETRIES)
|
||||
break;
|
||||
if (WaitForSingleObject(mysqld_process, OPEN_EVENT_RETRY_SLEEP_MS) !=
|
||||
WAIT_TIMEOUT)
|
||||
{
|
||||
die("server process exited before shutdown event was created");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!shutdown_handle)
|
||||
{
|
||||
die("OpenEvent() failed for shutdown event");
|
||||
}
|
||||
@ -403,6 +419,26 @@ static void change_service_config()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Waits until starting server can be connected to, via given named pipe, with timeout
|
||||
Dies if either server process exited meanwhile, or when timeout was exceeded.
|
||||
*/
|
||||
static void wait_for_server_startup(HANDLE process, const char *named_pipe, DWORD timeout_sec)
|
||||
{
|
||||
unsigned long long end_time= GetTickCount64() + 1000ULL*timeout_sec;
|
||||
for (;;)
|
||||
{
|
||||
if (WaitNamedPipe(named_pipe, 0))
|
||||
return;
|
||||
|
||||
if (GetTickCount64() >= end_time)
|
||||
die("Server did not startup after %lu seconds", timeout_sec);
|
||||
|
||||
if (WaitForSingleObject(process, 100) != WAIT_TIMEOUT)
|
||||
die("Server did not start");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -482,6 +518,10 @@ int main(int argc, char **argv)
|
||||
|
||||
DWORD start_duration_ms = 0;
|
||||
|
||||
char pipe_name[64];
|
||||
snprintf(pipe_name, sizeof(pipe_name),
|
||||
"\\\\.\\pipe\\mysql_upgrade_service_%lu", GetCurrentProcessId());
|
||||
|
||||
if (do_start_stop_server)
|
||||
{
|
||||
/* Start/stop server with --loose-innodb-fast-shutdown=1 */
|
||||
@ -493,37 +533,23 @@ int main(int argc, char **argv)
|
||||
{
|
||||
die("Cannot start mysqld.exe process, last error =%u", GetLastError());
|
||||
}
|
||||
char pipe_name[64];
|
||||
snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\mysql_upgrade_service_%lu",
|
||||
GetCurrentProcessId());
|
||||
for (;;)
|
||||
wait_for_server_startup(mysqld_process, pipe_name, startup_timeout);
|
||||
// Server started, shut it down.
|
||||
initiate_mysqld_shutdown();
|
||||
if (WaitForSingleObject((HANDLE)mysqld_process, shutdown_timeout * 1000) != WAIT_OBJECT_0)
|
||||
{
|
||||
if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT)
|
||||
die("mysqld.exe did not start");
|
||||
|
||||
if (WaitNamedPipe(pipe_name, 0))
|
||||
{
|
||||
// Server started, shut it down.
|
||||
initiate_mysqld_shutdown();
|
||||
if (WaitForSingleObject((HANDLE)mysqld_process, shutdown_timeout * 1000) != WAIT_OBJECT_0)
|
||||
{
|
||||
die("Could not shutdown server started with '--innodb-fast-shutdown=0'");
|
||||
}
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess((HANDLE)mysqld_process, &exit_code))
|
||||
{
|
||||
die("Could not get mysqld's exit code");
|
||||
}
|
||||
if (exit_code)
|
||||
{
|
||||
die("Could not get successfully shutdown mysqld");
|
||||
}
|
||||
CloseHandle(mysqld_process);
|
||||
break;
|
||||
}
|
||||
Sleep(500);
|
||||
start_duration_ms += 500;
|
||||
die("Could not shutdown server");
|
||||
}
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess((HANDLE)mysqld_process, &exit_code))
|
||||
{
|
||||
die("Could not get server's exit code");
|
||||
}
|
||||
if (exit_code)
|
||||
{
|
||||
die("Could not get successfully shutdown server (exit code %u)",exit_code);
|
||||
}
|
||||
CloseHandle(mysqld_process);
|
||||
}
|
||||
|
||||
log("Phase %d/%d: Fixing server config file%s", ++phase, max_phases,
|
||||
@ -550,22 +576,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
log("Phase %d/%d: Waiting for startup to complete",++phase,max_phases);
|
||||
start_duration_ms= 0;
|
||||
for(;;)
|
||||
{
|
||||
if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT)
|
||||
die("mysqld.exe did not start");
|
||||
|
||||
if (run_tool(P_WAIT, mysqladmin_path, "--protocol=pipe", socket_param,
|
||||
"ping", "--no-beep", NULL) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (start_duration_ms > startup_timeout*1000)
|
||||
die("Server did not come up in %d seconds",startup_timeout);
|
||||
Sleep(500);
|
||||
start_duration_ms+= 500;
|
||||
}
|
||||
wait_for_server_startup(mysqld_process, pipe_name, startup_timeout);
|
||||
|
||||
log("Phase %d/%d: Running mysql_upgrade",++phase,max_phases);
|
||||
int upgrade_err= (int) run_tool(P_WAIT, mysqlupgrade_path,
|
||||
|
Loading…
x
Reference in New Issue
Block a user