MXS-1929: Move user reloading to Service
The Service class now handles the reloading of users. This removes the need to expose the rate limits.
This commit is contained in:
@ -25,7 +25,7 @@
|
|||||||
* @file service.h - MaxScale internal service functions
|
* @file service.h - MaxScale internal service functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct UserLoadLimit
|
struct LastUserLoad
|
||||||
{
|
{
|
||||||
time_t last = 0; // The last time the users were loaded
|
time_t last = 0; // The last time the users were loaded
|
||||||
bool warned = false; // Has a warning been logged
|
bool warned = false; // Has a warning been logged
|
||||||
@ -36,6 +36,7 @@ class Service: public SERVICE
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FilterList = std::vector<SFilterDef>;
|
using FilterList = std::vector<SFilterDef>;
|
||||||
|
using RateLimits = std::vector<LastUserLoad>;
|
||||||
|
|
||||||
Service(const std::string& name, const std::string& router, MXS_CONFIG_PARAMETER* params);
|
Service(const std::string& name, const std::string& router, MXS_CONFIG_PARAMETER* params);
|
||||||
|
|
||||||
@ -91,12 +92,18 @@ public:
|
|||||||
return !m_filters.empty();
|
return !m_filters.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload users for all listeners
|
||||||
|
*
|
||||||
|
* @return True if loading of users was successful
|
||||||
|
*/
|
||||||
|
bool refresh_users();
|
||||||
|
|
||||||
// TODO: Make JSON output internal (could iterate over get_filters() but that takes the service lock)
|
// TODO: Make JSON output internal (could iterate over get_filters() but that takes the service lock)
|
||||||
json_t* json_relationships(const char* host) const;
|
json_t* json_relationships(const char* host) const;
|
||||||
|
|
||||||
// TODO: Make these private
|
// TODO: Make these private
|
||||||
mutable std::mutex lock;
|
mutable std::mutex lock;
|
||||||
std::vector<UserLoadLimit> rate_limits; /**< The refresh rate limits for users of each thread */
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FilterList m_filters; /**< Ordered list of filters */
|
FilterList m_filters; /**< Ordered list of filters */
|
||||||
@ -106,6 +113,7 @@ private:
|
|||||||
std::string m_password; /**< Password */
|
std::string m_password; /**< Password */
|
||||||
std::string m_weightby; /**< Weighting parameter name */
|
std::string m_weightby; /**< Weighting parameter name */
|
||||||
std::string m_version_string; /**< Version string sent to clients */
|
std::string m_version_string; /**< Version string sent to clients */
|
||||||
|
RateLimits m_rate_limits; /**< The refresh rate limits for users of each thread */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -151,14 +151,13 @@ static std::string get_version_string(MXS_CONFIG_PARAMETER* params)
|
|||||||
|
|
||||||
Service::Service(const std::string& service_name, const std::string& router_name,
|
Service::Service(const std::string& service_name, const std::string& router_name,
|
||||||
MXS_CONFIG_PARAMETER* params):
|
MXS_CONFIG_PARAMETER* params):
|
||||||
rate_limits(config_threadcount()),
|
|
||||||
m_name(service_name),
|
m_name(service_name),
|
||||||
m_router_name(router_name),
|
m_router_name(router_name),
|
||||||
m_user(config_get_string(params, CN_USER)),
|
m_user(config_get_string(params, CN_USER)),
|
||||||
m_password(config_get_string(params, CN_PASSWORD)),
|
m_password(config_get_string(params, CN_PASSWORD)),
|
||||||
m_weightby(config_get_string(params, CN_WEIGHTBY)),
|
m_weightby(config_get_string(params, CN_WEIGHTBY)),
|
||||||
m_version_string(get_version_string(params))
|
m_version_string(get_version_string(params)),
|
||||||
|
m_rate_limits(config_threadcount())
|
||||||
{
|
{
|
||||||
const MXS_MODULE* module = get_module(router_name.c_str(), MODULE_ROUTER);
|
const MXS_MODULE* module = get_module(router_name.c_str(), MODULE_ROUTER);
|
||||||
ss_dassert(module);
|
ss_dassert(module);
|
||||||
@ -196,6 +195,29 @@ Service::Service(const std::string& service_name, const std::string& router_name
|
|||||||
log_auth_warnings = config_get_bool(params, CN_LOG_AUTH_WARNINGS);
|
log_auth_warnings = config_get_bool(params, CN_LOG_AUTH_WARNINGS);
|
||||||
strip_db_esc = config_get_bool(params, CN_STRIP_DB_ESC);
|
strip_db_esc = config_get_bool(params, CN_STRIP_DB_ESC);
|
||||||
session_track_trx_state = config_get_bool(params, CN_SESSION_TRACK_TRX_STATE);
|
session_track_trx_state = config_get_bool(params, CN_SESSION_TRACK_TRX_STATE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* At service start last update is set to config->users_refresh_time seconds earlier.
|
||||||
|
* This way MaxScale could try reloading users just after startup. But only if user
|
||||||
|
* refreshing has not been turned off.
|
||||||
|
*/
|
||||||
|
MXS_CONFIG* cnf = config_get_global_options();
|
||||||
|
|
||||||
|
// Defaults for disabled reloading of users
|
||||||
|
bool warned = true;
|
||||||
|
bool last = time(NULL);
|
||||||
|
|
||||||
|
if (cnf->users_refresh_time != INT32_MAX)
|
||||||
|
{
|
||||||
|
last -= cnf->users_refresh_time;
|
||||||
|
warned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& a : m_rate_limits)
|
||||||
|
{
|
||||||
|
a.last = last;
|
||||||
|
a.warned = warned;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::~Service()
|
Service::~Service()
|
||||||
@ -404,34 +426,6 @@ serviceStartPort(Service *service, SERV_LISTENER *port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MXS_CONFIG* config = config_get_global_options();
|
|
||||||
time_t last;
|
|
||||||
bool warned;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* At service start last update is set to config->users_refresh_time seconds earlier.
|
|
||||||
* This way MaxScale could try reloading users just after startup. But only if user
|
|
||||||
* refreshing has not been turned off.
|
|
||||||
*/
|
|
||||||
if (config->users_refresh_time == INT32_MAX)
|
|
||||||
{
|
|
||||||
last = time(NULL);
|
|
||||||
warned = true; // So that there will not be a refresh rate warning.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
last = time(NULL) - config->users_refresh_time;
|
|
||||||
warned = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nthreads = config_threadcount();
|
|
||||||
|
|
||||||
for (int i = 0; i < nthreads; ++i)
|
|
||||||
{
|
|
||||||
service->rate_limits[i].last = last;
|
|
||||||
service->rate_limits[i].warned = warned;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port->listener->func.listen(port->listener, config_bind))
|
if (port->listener->func.listen(port->listener, config_bind))
|
||||||
{
|
{
|
||||||
port->listener->session = session_alloc(service, port->listener);
|
port->listener->session = session_alloc(service, port->listener);
|
||||||
@ -1327,6 +1321,75 @@ void dListListeners(DCB *dcb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Service::refresh_users()
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
int self = mxs_rworker_get_current_id();
|
||||||
|
ss_dassert(self >= 0);
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
// Use unique_lock instead of lock_guard to make the locking conditional
|
||||||
|
std::unique_lock<std::mutex> guard(lock, std::defer_lock);
|
||||||
|
|
||||||
|
if ((capabilities & ACAP_TYPE_ASYNC) == 0)
|
||||||
|
{
|
||||||
|
// Use only one rate limitation for synchronous authenticators to keep
|
||||||
|
// rate limitations synchronous as well
|
||||||
|
self = 0;
|
||||||
|
guard.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
MXS_CONFIG* config = config_get_global_options();
|
||||||
|
|
||||||
|
/* Check if refresh rate limit has been exceeded */
|
||||||
|
if (now < m_rate_limits[self].last + config->users_refresh_time)
|
||||||
|
{
|
||||||
|
if (!m_rate_limits[self].warned)
|
||||||
|
{
|
||||||
|
MXS_WARNING("[%s] Refresh rate limit (once every %ld seconds) exceeded for "
|
||||||
|
"load of users' table.",
|
||||||
|
m_name.c_str(), config->users_refresh_time);
|
||||||
|
m_rate_limits[self].warned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_rate_limits[self].last = now;
|
||||||
|
m_rate_limits[self].warned = false;
|
||||||
|
|
||||||
|
LISTENER_ITERATOR iter;
|
||||||
|
|
||||||
|
for (SERV_LISTENER *listener = listener_iterator_init(this, &iter);
|
||||||
|
listener; listener = listener_iterator_next(&iter))
|
||||||
|
{
|
||||||
|
/** Load the authentication users before before starting the listener */
|
||||||
|
if (listener_is_active(listener) && listener->listener &&
|
||||||
|
listener->listener->authfunc.loadusers)
|
||||||
|
{
|
||||||
|
switch (listener->listener->authfunc.loadusers(listener))
|
||||||
|
{
|
||||||
|
case MXS_AUTH_LOADUSERS_FATAL:
|
||||||
|
MXS_ERROR("[%s] Fatal error when loading users for listener '%s',"
|
||||||
|
" authentication will not work.", m_name.c_str(), listener->name);
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MXS_AUTH_LOADUSERS_ERROR:
|
||||||
|
MXS_WARNING("[%s] Failed to load users for listener '%s', authentication"
|
||||||
|
" might not work.", m_name.c_str(), listener->name);
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the database users for the service
|
* Refresh the database users for the service
|
||||||
* This function replaces the MySQL users used by the service with the latest
|
* This function replaces the MySQL users used by the service with the latest
|
||||||
@ -1339,73 +1402,7 @@ int service_refresh_users(SERVICE *svc)
|
|||||||
{
|
{
|
||||||
Service* service = static_cast<Service*>(svc);
|
Service* service = static_cast<Service*>(svc);
|
||||||
ss_dassert(service);
|
ss_dassert(service);
|
||||||
int ret = 1;
|
return service->refresh_users() ? 0 : 1;
|
||||||
int self = mxs_rworker_get_current_id();
|
|
||||||
ss_dassert(self >= 0);
|
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
// Use unique_lock instead of lock_guard to make the locking conditional
|
|
||||||
std::unique_lock<std::mutex> guard(service->lock, std::defer_lock);
|
|
||||||
|
|
||||||
if ((service->capabilities & ACAP_TYPE_ASYNC) == 0)
|
|
||||||
{
|
|
||||||
// Use only one rate limitation for synchronous authenticators to keep
|
|
||||||
// rate limitations synchronous as well
|
|
||||||
self = 0;
|
|
||||||
guard.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
MXS_CONFIG* config = config_get_global_options();
|
|
||||||
|
|
||||||
/* Check if refresh rate limit has been exceeded */
|
|
||||||
if (now < service->rate_limits[self].last + config->users_refresh_time)
|
|
||||||
{
|
|
||||||
if (!service->rate_limits[self].warned)
|
|
||||||
{
|
|
||||||
MXS_WARNING("[%s] Refresh rate limit (once every %ld seconds) exceeded for "
|
|
||||||
"load of users' table.",
|
|
||||||
service->name, config->users_refresh_time);
|
|
||||||
service->rate_limits[self].warned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
service->rate_limits[self].last = now;
|
|
||||||
service->rate_limits[self].warned = false;
|
|
||||||
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
LISTENER_ITERATOR iter;
|
|
||||||
|
|
||||||
for (SERV_LISTENER *listener = listener_iterator_init(service, &iter);
|
|
||||||
listener; listener = listener_iterator_next(&iter))
|
|
||||||
{
|
|
||||||
/** Load the authentication users before before starting the listener */
|
|
||||||
if (listener_is_active(listener) && listener->listener &&
|
|
||||||
listener->listener->authfunc.loadusers)
|
|
||||||
{
|
|
||||||
switch (listener->listener->authfunc.loadusers(listener))
|
|
||||||
{
|
|
||||||
case MXS_AUTH_LOADUSERS_FATAL:
|
|
||||||
MXS_ERROR("[%s] Fatal error when loading users for listener '%s',"
|
|
||||||
" authentication will not work.", service->name, listener->name);
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MXS_AUTH_LOADUSERS_ERROR:
|
|
||||||
MXS_WARNING("[%s] Failed to load users for listener '%s', authentication"
|
|
||||||
" might not work.", service->name, listener->name);
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_add_parameters(Service *service, const MXS_CONFIG_PARAMETER *param)
|
void service_add_parameters(Service *service, const MXS_CONFIG_PARAMETER *param)
|
||||||
|
|||||||
Reference in New Issue
Block a user