diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 0da2dcfa3..eb6b5240c 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -148,7 +148,7 @@ typedef struct service bool strip_db_esc; /**< Remove the '\' characters from database names * when querying them from the server. MySQL Workbench seems * 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 */ int n_filters; /**< Number of filters */ int64_t conn_idle_timeout; /**< Session timeout in seconds */ diff --git a/server/core/service.cc b/server/core/service.cc index 2482f6290..e9cee34af 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include "internal/config.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_router = MXS_STRDUP(router); 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) { 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)) { 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 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 ((now < service->rate_limit.last + USERS_REFRESH_TIME) || - (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME)) + /** If we have reached the limit on users refreshes, reset refresh time and count */ + if (service->rate_limits[self].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++; - - /** If we have reached the limit on users refreshes, reset refresh time and count */ - if (service->rate_limit.nloads > USERS_REFRESH_MAX_PER_TIME) + /** Load the authentication users before before starting the listener */ + if (listener_is_active(listener) && listener->listener && + listener->listener->authfunc.loadusers) { - service->rate_limit.nloads = 1; - 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)) { - 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_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; + 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; - } + default: + break; } } } - - spinlock_release(&service->spin); } return ret;