dbusers.c: Added function for setting read, write and connection timeout values. Set default timeouts for getUsers. Defaults are listed in service.c
gateway.c:shutdown_server is called whenever MaxScale is to be shut down. Added call for service_shutdown to shutdown_server.
service.c:service_alloc: replaced malloc with calloc and removed unnecessary zero/NULL initialization statements as a consequence.
	serviceStart: Exit serviceStartPort loop if shutdown flag is set for the service.
	serviceStartAll: Exit serviceStart loop if shutdown flag is set for the service.
service.c: Added service_shutdown which sets shutdown flag for each service found in allServices list.
service.h: Added prototype for service_shutdown
This commit is contained in:
VilhoRaatikka 2014-12-29 13:45:24 +02:00
parent 5e3d90b8b0
commit beacd524da
4 changed files with 153 additions and 51 deletions

View File

@ -52,6 +52,10 @@
#include <mysqld_error.h>
#define DEFAULT_CONNECT_TIMEOUT 3
#define DEFAULT_READ_TIMEOUT 1
#define DEFAULT_WRITE_TIMEOUT 2
#define USERS_QUERY_NO_ROOT " AND user NOT IN ('root')"
#if 0
@ -105,6 +109,11 @@ void *resource_fetch(HASHTABLE *, char *);
int resource_add(HASHTABLE *, char *, char *);
int resource_hash(char *);
static int normalize_hostname(char *input_host, char *output_host);
static int gw_mysql_set_timeouts(
MYSQL* handle,
int read_timeout,
int write_timeout,
int connect_timeout);
/**
* Load the user/passwd form mysql.user table into the service users' hashtable
@ -429,7 +438,8 @@ getDatabases(SERVICE *service, MYSQL *con)
*
* @param service The current service
* @param users The users table into which to load the users
* @return -1 on any error or the number of users inserted (0 means no users at all)
* @return -1 on any error or the number of users inserted
* (0 means no users at all)
*/
static int
getUsers(SERVICE *service, USERS *users)
@ -446,15 +456,19 @@ getUsers(SERVICE *service, USERS *users)
unsigned char hash[SHA_DIGEST_LENGTH]="";
char *users_data = NULL;
int nusers = 0;
int users_data_row_len = MYSQL_USER_MAXLEN + MYSQL_HOST_MAXLEN + MYSQL_PASSWORD_LEN + sizeof(char) + MYSQL_DATABASE_MAXLEN;
int users_data_row_len = MYSQL_USER_MAXLEN +
MYSQL_HOST_MAXLEN +
MYSQL_PASSWORD_LEN +
sizeof(char) +
MYSQL_DATABASE_MAXLEN;
int dbnames = 0;
int db_grants = 0;
serviceGetUser(service, &service_user, &service_passwd);
if (service_user == NULL || service_passwd == NULL)
return -1;
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
{
ss_dassert(service_passwd == NULL || service_user == NULL);
return -1;
}
con = mysql_init(NULL);
if (con == NULL) {
@ -464,13 +478,26 @@ getUsers(SERVICE *service, USERS *users)
mysql_error(con))));
return -1;
}
/** Set read, write and connect timeout values */
if (gw_mysql_set_timeouts(con,
DEFAULT_READ_TIMEOUT,
DEFAULT_WRITE_TIMEOUT,
DEFAULT_CONNECT_TIMEOUT))
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : failed to set timeout values for backend "
"connection.")));
mysql_close(con);
return -1;
}
if (mysql_options(con, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL)) {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : failed to set external connection. "
"It is needed for backend server connections. "
"Exiting.")));
"It is needed for backend server connections.")));
mysql_close(con);
return -1;
}
/**
@ -486,12 +513,26 @@ getUsers(SERVICE *service, USERS *users)
server = server->nextdb;
}
if (service->svc_do_shutdown)
{
free(dpwd);
mysql_close(con);
return -1;
}
/* Try loading data from master server */
if (server != NULL && (mysql_real_connect(con, server->name, service_user, dpwd, NULL, server->port, NULL, 0) != NULL)) {
if (server != NULL &&
(mysql_real_connect(con,
server->name, service_user,
dpwd,
NULL,
server->port,
NULL, 0) != NULL))
{
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"Dbusers : Loading data from backend database with Master role [%s:%i] "
"for service [%s]",
"Dbusers : Loading data from backend database with "
"Master role [%s:%i] for service [%s]",
server->name,
server->port,
service->name)));
@ -499,23 +540,32 @@ getUsers(SERVICE *service, USERS *users)
/* load data from other servers via loop */
server = service->databases;
while (server != NULL && (mysql_real_connect(con,
server->name,
service_user,
dpwd,
NULL,
server->port,
NULL,
0) == NULL))
while (!service->svc_do_shutdown &&
server != NULL &&
(mysql_real_connect(con,
server->name,
service_user,
dpwd,
NULL,
server->port,
NULL,
0) == NULL))
{
server = server->nextdb;
}
if (service->svc_do_shutdown)
{
free(dpwd);
mysql_close(con);
return -1;
}
if (server != NULL) {
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"Dbusers : Loading data from backend database [%s:%i] "
"for service [%s]",
"Dbusers : Loading data from backend database "
"[%s:%i] for service [%s]",
server->name,
server->port,
service->name)));
@ -535,9 +585,7 @@ getUsers(SERVICE *service, USERS *users)
return -1;
}
/* count users */
/* start with users and db grants for users */
/** Count users. Start with users and db grants for users */
if (mysql_query(con, MYSQL_USERS_WITH_DB_COUNT)) {
if (mysql_errno(con) != ER_TABLEACCESS_DENIED_ERROR) {
/* This is an error we cannot handle, return */
@ -1213,3 +1261,58 @@ int useorig = 0;
return netmask;
}
/**
* Set read, write and connect timeout values for MySQL database connection.
*
* @param handle MySQL handle
* @param read_timeout Read timeout value in seconds
* @param write_timeout Write timeout value in seconds
* @param connect_timeout Connect timeout value in seconds
*
* @return 0 if succeed, 1 if failed
*/
static int gw_mysql_set_timeouts(
MYSQL* handle,
int read_timeout,
int write_timeout,
int connect_timeout)
{
int rc;
if ((rc = mysql_options(handle,
MYSQL_OPT_READ_TIMEOUT,
(void *)&read_timeout)))
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : failed to set read timeout for backend "
"connection.")));
goto retblock;
}
if ((rc = mysql_options(handle,
MYSQL_OPT_CONNECT_TIMEOUT,
(void *)&connect_timeout)))
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : failed to set connect timeout for backend "
"connection.")));
goto retblock;
}
if ((rc = mysql_options(handle,
MYSQL_OPT_WRITE_TIMEOUT,
(void *)&write_timeout)))
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : failed to set write timeout for backend "
"connection.")));
goto retblock;
}
retblock:
return rc;
}

View File

@ -56,6 +56,7 @@
#include <config.h>
#include <poll.h>
#include <housekeeper.h>
#include <service.h>
#include <memlog.h>
#include <stdlib.h>
@ -1837,7 +1838,8 @@ return_main:
void
shutdown_server()
{
poll_shutdown();
service_shutdown();
poll_shutdown();
hkshutdown();
memlog_flush_all();
log_flush_shutdown();

View File

@ -87,7 +87,6 @@ static void service_add_qualified_param(
SERVICE* svc,
CONFIG_PARAMETER* param);
/**
* Allocate a new service for the gateway to support
*
@ -102,7 +101,7 @@ service_alloc(const char *servname, const char *router)
{
SERVICE *service;
if ((service = (SERVICE *)malloc(sizeof(SERVICE))) == NULL)
if ((service = (SERVICE *)calloc(1, sizeof(SERVICE))) == NULL)
return NULL;
if ((service->router = load_module(router, MODULE_ROUTER)) == NULL)
{
@ -132,27 +131,10 @@ SERVICE *service;
free(service);
return NULL;
}
service->version_string = NULL;
memset(&service->stats, 0, sizeof(SERVICE_STATS));
service->ports = NULL;
service->stats.started = time(0);
service->state = SERVICE_STATE_ALLOC;
service->credentials.name = NULL;
service->credentials.authdata = NULL;
service->enable_root = 0;
service->localhost_match_wildcard_host = 0;
service->routerOptions = NULL;
service->databases = NULL;
service->svc_config_param = NULL;
service->svc_config_version = 0;
service->filters = NULL;
service->n_filters = 0;
service->weightby = 0;
service->users = NULL;
service->resources = NULL;
spinlock_init(&service->spin);
spinlock_init(&service->users_table_spin);
memset(&service->rate_limit, 0, sizeof(SERVICE_REFRESH_RATE));
spinlock_acquire(&service_spin);
service->next = allServices;
@ -360,7 +342,7 @@ int listeners = 0;
}
port = service->ports;
while (port)
while (!service->svc_do_shutdown && port)
{
listeners += serviceStartPort(service, port);
port = port->next;
@ -408,16 +390,16 @@ SERVICE *ptr;
int n = 0,i;
ptr = allServices;
while (ptr)
while (ptr && !ptr->svc_do_shutdown)
{
n += (i = serviceStart(ptr));
if(i == 0)
{
LOGIF(LE, (skygw_log_write(
LOGFILE_ERROR,
"Error : Failed to start service '%s'.",
ptr->name)));
LOGFILE_ERROR,
"Error : Failed to start service '%s'.",
ptr->name)));
}
ptr = ptr->next;
@ -1422,3 +1404,16 @@ serviceEnableLocalhostMatchWildcardHost(SERVICE *service, int action)
return 1;
}
void service_shutdown()
{
SERVICE* svc;
spinlock_acquire(&service_spin);
svc = allServices;
while (svc != NULL)
{
svc->svc_do_shutdown = true;
svc = svc->next;
}
spinlock_release(&service_spin);
}

View File

@ -130,6 +130,7 @@ typedef struct service {
CONFIG_PARAMETER*
svc_config_param; /*< list of config params and values */
int svc_config_version; /*< Version number of configuration */
bool svc_do_shutdown; /*< tells the service to exit loops etc. */
SPINLOCK
users_table_spin; /**< The spinlock for users data refresh */
SERVICE_REFRESH_RATE
@ -186,4 +187,5 @@ extern void dprintService(DCB *, SERVICE *);
extern void dListServices(DCB *);
extern void dListListeners(DCB *);
char* service_get_name(SERVICE* svc);
void service_shutdown();
#endif