MXS-1539: Make refresh rate limitations thread-specific
The refresh rate limitations are now also thread-specific. This is required when the authentication data is partitioned on a per thread basis.
This commit is contained in:
@ -148,7 +148,7 @@ typedef struct service
|
|||||||
bool strip_db_esc; /**< Remove the '\' characters from database names
|
bool strip_db_esc; /**< Remove the '\' characters from database names
|
||||||
* when querying them from the server. MySQL Workbench seems
|
* when querying them from the server. MySQL Workbench seems
|
||||||
* to escape at least the underscore character. */
|
* to escape at least the underscore character. */
|
||||||
SERVICE_REFRESH_RATE rate_limit; /**< The refresh rate limit for users table */
|
SERVICE_REFRESH_RATE *rate_limits; /**< The refresh rate limits for users of each thread */
|
||||||
MXS_FILTER_DEF **filters; /**< Ordered list of filters */
|
MXS_FILTER_DEF **filters; /**< Ordered list of filters */
|
||||||
int n_filters; /**< Number of filters */
|
int n_filters; /**< Number of filters */
|
||||||
int64_t conn_idle_timeout; /**< Session timeout in seconds */
|
int64_t conn_idle_timeout; /**< Session timeout in seconds */
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include <maxscale/version.h>
|
#include <maxscale/version.h>
|
||||||
#include <maxscale/jansson.h>
|
#include <maxscale/jansson.h>
|
||||||
#include <maxscale/json_api.h>
|
#include <maxscale/json_api.h>
|
||||||
|
#include <maxscale/worker.h>
|
||||||
|
|
||||||
#include "internal/config.h"
|
#include "internal/config.h"
|
||||||
#include "internal/filter.h"
|
#include "internal/filter.h"
|
||||||
@ -102,7 +103,8 @@ SERVICE* service_alloc(const char *name, const char *router)
|
|||||||
char *my_name = MXS_STRDUP(name);
|
char *my_name = MXS_STRDUP(name);
|
||||||
char *my_router = MXS_STRDUP(router);
|
char *my_router = MXS_STRDUP(router);
|
||||||
SERVICE *service = (SERVICE *)MXS_CALLOC(1, sizeof(*service));
|
SERVICE *service = (SERVICE *)MXS_CALLOC(1, sizeof(*service));
|
||||||
|
SERVICE_REFRESH_RATE* rate_limit = (SERVICE_REFRESH_RATE*)MXS_CALLOC(config_threadcount(),
|
||||||
|
sizeof(*rate_limit));
|
||||||
if (!my_name || !my_router || !service)
|
if (!my_name || !my_router || !service)
|
||||||
{
|
{
|
||||||
MXS_FREE(my_name);
|
MXS_FREE(my_name);
|
||||||
@ -324,13 +326,6 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* At service start last update is set to USERS_REFRESH_TIME seconds earlier. This way MaxScale
|
|
||||||
* could try reloading users just after startup.
|
|
||||||
*/
|
|
||||||
service->rate_limit.last = time(NULL) - USERS_REFRESH_TIME;
|
|
||||||
service->rate_limit.nloads = 1;
|
|
||||||
|
|
||||||
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);
|
||||||
@ -1612,60 +1607,56 @@ service_update(SERVICE *service, char *router, char *user, char *auth)
|
|||||||
int service_refresh_users(SERVICE *service)
|
int service_refresh_users(SERVICE *service)
|
||||||
{
|
{
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
int self = mxs_worker_get_current_id();
|
||||||
|
ss_dassert(self);
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
if (spinlock_acquire_nowait(&service->spin))
|
/* Check if refresh rate limit has been exceeded */
|
||||||
|
if ((now < service->rate_limits[self].last + USERS_REFRESH_TIME) ||
|
||||||
|
(service->rate_limits[self].nloads >= USERS_REFRESH_MAX_PER_TIME))
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
MXS_ERROR("[%s] Refresh rate limit exceeded for load of users' table.", service->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
service->rate_limits[self].nloads++;
|
||||||
|
|
||||||
/* Check if refresh rate limit has been exceeded */
|
/** If we have reached the limit on users refreshes, reset refresh time and count */
|
||||||
if ((now < service->rate_limit.last + USERS_REFRESH_TIME) ||
|
if (service->rate_limits[self].nloads >= USERS_REFRESH_MAX_PER_TIME)
|
||||||
(service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME))
|
|
||||||
{
|
{
|
||||||
MXS_ERROR("[%s] Refresh rate limit exceeded for load of users' table.", service->name);
|
service->rate_limits[self].nloads = 0;
|
||||||
|
service->rate_limits[self].last = now;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
ret = 0;
|
||||||
|
LISTENER_ITERATOR iter;
|
||||||
|
|
||||||
|
for (SERV_LISTENER *listener = listener_iterator_init(service, &iter);
|
||||||
|
listener; listener = listener_iterator_next(&iter))
|
||||||
{
|
{
|
||||||
service->rate_limit.nloads++;
|
/** Load the authentication users before before starting the listener */
|
||||||
|
if (listener_is_active(listener) && listener->listener &&
|
||||||
/** If we have reached the limit on users refreshes, reset refresh time and count */
|
listener->listener->authfunc.loadusers)
|
||||||
if (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME)
|
|
||||||
{
|
{
|
||||||
service->rate_limit.nloads = 1;
|
switch (listener->listener->authfunc.loadusers(listener))
|
||||||
service->rate_limit.last = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
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',"
|
||||||
case MXS_AUTH_LOADUSERS_FATAL:
|
" authentication will not work.", service->name, listener->name);
|
||||||
MXS_ERROR("[%s] Fatal error when loading users for listener '%s',"
|
ret = 1;
|
||||||
" authentication will not work.", service->name, listener->name);
|
break;
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MXS_AUTH_LOADUSERS_ERROR:
|
case MXS_AUTH_LOADUSERS_ERROR:
|
||||||
MXS_WARNING("[%s] Failed to load users for listener '%s', authentication"
|
MXS_WARNING("[%s] Failed to load users for listener '%s', authentication"
|
||||||
" might not work.", service->name, listener->name);
|
" might not work.", service->name, listener->name);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spinlock_release(&service->spin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user