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:
Markus Mäkelä
2017-11-23 14:07:47 +02:00
parent 4194c1c558
commit a2d275aca3
2 changed files with 41 additions and 50 deletions

View File

@ -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 */

View File

@ -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;