Add shutdown detection

The maxscale_is_shutting_down function is used to detect when MaxScale
should stop. This fixes a race condition in the code where the workers has
not yet been initialized but a termination signal has been received. It
also replaces the misuse of the service_should_stop variable with a proper
function.
This commit is contained in:
Markus Mäkelä
2018-08-23 23:22:27 +03:00
parent 8f3eabb868
commit 8b653133a7
8 changed files with 43 additions and 19 deletions

View File

@ -43,4 +43,14 @@ time_t maxscale_started(void);
*/ */
int maxscale_uptime(void); int maxscale_uptime(void);
/**
* Is MaxScale shutting down
*
* This function can be used to detect whether the shutdown has been initiated. It does not tell
* whether the shutdown has been completed so thread-safety is still important.
*
* @return True if MaxScale is shutting down
*/
bool maxscale_is_shutting_down();
MXS_END_DECLS MXS_END_DECLS

View File

@ -146,9 +146,6 @@ typedef enum count_spec_t
#define SERVICE_STATE_FAILED 3 /**< The service failed to start */ #define SERVICE_STATE_FAILED 3 /**< The service failed to start */
#define SERVICE_STATE_STOPPED 4 /**< The service has been stopped */ #define SERVICE_STATE_STOPPED 4 /**< The service has been stopped */
// Set to 1 when services should stop
extern volatile sig_atomic_t service_should_stop;
/** /**
* Find a service * Find a service
* *

View File

@ -2037,6 +2037,13 @@ int main(int argc, char **argv)
goto return_main; goto return_main;
} }
// Before we start the workers we need to check if a shutdown signal has been received
if (maxscale_is_shutting_down())
{
rc = MAXSCALE_SHUTDOWN;
goto return_main;
}
if (!RoutingWorker::init()) if (!RoutingWorker::init())
{ {
MXS_ERROR("Failed to initialize routing workers."); MXS_ERROR("Failed to initialize routing workers.");
@ -2044,6 +2051,16 @@ int main(int argc, char **argv)
goto return_main; goto return_main;
} }
/**
* If a shutdown signal was received while we were initializing the workers, we need to exit.
* After this point, the shutdown will be driven by the workers.
*/
if (maxscale_is_shutting_down())
{
rc = MAXSCALE_SHUTDOWN;
goto return_main;
}
if (!config_load(cnf_file_path)) if (!config_load(cnf_file_path))
{ {
const char* fprerr = const char* fprerr =

View File

@ -36,15 +36,19 @@ int maxscale_uptime()
return time(0) - started; return time(0) - started;
} }
static sig_atomic_t n_shutdowns = 0;
bool maxscale_is_shutting_down()
{
return n_shutdowns != 0;
}
int maxscale_shutdown() int maxscale_shutdown()
{ {
static int n_shutdowns = 0; int n = n_shutdowns++;
int n = atomic_add(&n_shutdowns, 1);
if (n == 0) if (n == 0)
{ {
service_shutdown();
mxs::RoutingWorker::shutdown_all(); mxs::RoutingWorker::shutdown_all();
} }

View File

@ -481,7 +481,7 @@ int serviceStartAllPorts(Service* service)
if (port) if (port)
{ {
while (!service_should_stop && port) while (!maxscale_is_shutting_down() && port)
{ {
listeners += serviceStartPort(service, port); listeners += serviceStartPort(service, port);
port = port->next; port = port->next;
@ -635,7 +635,7 @@ int service_launch_all()
error = true; error = true;
} }
if (service_should_stop) if (maxscale_is_shutting_down())
{ {
break; break;
} }
@ -1520,13 +1520,6 @@ const char* serviceGetWeightingParameter(SERVICE *svc)
return service->weightby; return service->weightby;
} }
volatile sig_atomic_t service_should_stop = 0;
void service_shutdown()
{
service_should_stop = 1;
}
void service_destroy_instances(void) void service_destroy_instances(void)
{ {
// The global list is modified by service_free so we need a copy of it // The global list is modified by service_free so we need a copy of it

View File

@ -24,6 +24,7 @@
#include <maxscale/alloc.h> #include <maxscale/alloc.h>
#include <maxscale/dcb.h> #include <maxscale/dcb.h>
#include <maxscale/log.h> #include <maxscale/log.h>
#include <maxscale/maxscale.h>
#include <maxscale/mysql_utils.h> #include <maxscale/mysql_utils.h>
#include <maxscale/paths.h> #include <maxscale/paths.h>
#include <maxscale/protocol/mysql.h> #include <maxscale/protocol/mysql.h>
@ -923,7 +924,7 @@ static int get_users(SERV_LISTENER *listener, bool skip_local)
int total_users = -1; int total_users = -1;
bool no_active_servers = true; bool no_active_servers = true;
for (server = service->dbref; !service_should_stop && server; server = server->next) for (server = service->dbref; !maxscale_is_shutting_down() && server; server = server->next)
{ {
if (!SERVER_REF_IS_ACTIVE(server) || !server_is_active(server->server) || if (!SERVER_REF_IS_ACTIVE(server) || !server_is_active(server->server) ||
(skip_local && server_is_mxs_service(server->server))) (skip_local && server_is_mxs_service(server->server)))

View File

@ -34,6 +34,7 @@
#include <maxscale/alloc.h> #include <maxscale/alloc.h>
#include <maxscale/log.h> #include <maxscale/log.h>
#include <maxscale/maxscale.h>
#include <maxscale/pcre2.h> #include <maxscale/pcre2.h>
#include <maxscale/utils.h> #include <maxscale/utils.h>
@ -493,7 +494,7 @@ avro_binlog_end_t avro_read_all_events(Avro *router)
std::string next_binlog; std::string next_binlog;
bool rotate_seen = false; bool rotate_seen = false;
while (!service_should_stop) while (!maxscale_is_shutting_down())
{ {
avro_binlog_end_t rc; avro_binlog_end_t rc;
REP_HEADER hdr; REP_HEADER hdr;

View File

@ -24,6 +24,7 @@
#include <ini.h> #include <ini.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <maxbase/atomic.h> #include <maxbase/atomic.h>
#include <maxscale/maxscale.h>
#include <maxbase/worker.hh> #include <maxbase/worker.hh>
#include <maxscale/alloc.h> #include <maxscale/alloc.h>
#include <maxscale/dcb.h> #include <maxscale/dcb.h>
@ -328,7 +329,7 @@ static bool conversion_task_ctl(Avro *inst, bool start)
{ {
bool rval = false; bool rval = false;
if (!service_should_stop) if (!maxscale_is_shutting_down())
{ {
Worker* worker = static_cast<Worker*>(mxs_rworker_get(MXS_RWORKER_MAIN)); Worker* worker = static_cast<Worker*>(mxs_rworker_get(MXS_RWORKER_MAIN));
std::unique_ptr<ConversionCtlTask> task(new (std::nothrow) ConversionCtlTask(inst, start)); std::unique_ptr<ConversionCtlTask> task(new (std::nothrow) ConversionCtlTask(inst, start));