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
|
our --skip-grant-tables do not work anymore after mysql_upgrade
|
||||||
that does "flush privileges". Instead, the shutdown event is set.
|
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()
|
void initiate_mysqld_shutdown()
|
||||||
{
|
{
|
||||||
char event_name[32];
|
char event_name[32];
|
||||||
DWORD pid= GetProcessId(mysqld_process);
|
DWORD pid= GetProcessId(mysqld_process);
|
||||||
sprintf_s(event_name, "MySQLShutdown%d", pid);
|
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");
|
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -482,6 +518,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
DWORD start_duration_ms = 0;
|
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)
|
if (do_start_stop_server)
|
||||||
{
|
{
|
||||||
/* Start/stop server with --loose-innodb-fast-shutdown=1 */
|
/* 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());
|
die("Cannot start mysqld.exe process, last error =%u", GetLastError());
|
||||||
}
|
}
|
||||||
char pipe_name[64];
|
wait_for_server_startup(mysqld_process, pipe_name, startup_timeout);
|
||||||
snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\mysql_upgrade_service_%lu",
|
// Server started, shut it down.
|
||||||
GetCurrentProcessId());
|
initiate_mysqld_shutdown();
|
||||||
for (;;)
|
if (WaitForSingleObject((HANDLE)mysqld_process, shutdown_timeout * 1000) != WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT)
|
die("Could not shutdown server");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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,
|
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);
|
log("Phase %d/%d: Waiting for startup to complete",++phase,max_phases);
|
||||||
start_duration_ms= 0;
|
wait_for_server_startup(mysqld_process, pipe_name, startup_timeout);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Phase %d/%d: Running mysql_upgrade",++phase,max_phases);
|
log("Phase %d/%d: Running mysql_upgrade",++phase,max_phases);
|
||||||
int upgrade_err= (int) run_tool(P_WAIT, mysqlupgrade_path,
|
int upgrade_err= (int) run_tool(P_WAIT, mysqlupgrade_path,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user