Commit 71acf514 authored by unknown's avatar unknown

Fix per-hour user connection limits by making sure that the number of

connections is actually reset after an hour, and also fix (unlikely)
conditions under which the per-hour query and connection limits could be
exceeded. (Bug #8350)


sql/sql_parse.cc:
  Add time_out_user_resource_limits() function to
  reset the user resource limits before they are
  checked, and add locking to check_mqh() because
  not doing so isn't as safe as the old comment
  explaining its absence said it is.
parent 22f839cd
...@@ -52,7 +52,8 @@ extern "C" pthread_mutex_t THR_LOCK_keycache; ...@@ -52,7 +52,8 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen); extern "C" int gethostname(char *name, int namelen);
#endif #endif
static int check_for_max_user_connections(USER_CONN *uc); static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
...@@ -272,7 +273,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -272,7 +273,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
return -1; return -1;
if (thd->user_connect && (thd->user_connect->user_resources.connections || if (thd->user_connect && (thd->user_connect->user_resources.connections ||
max_user_connections) && max_user_connections) &&
check_for_max_user_connections(thd->user_connect)) check_for_max_user_connections(thd, thd->user_connect))
return -1; return -1;
if (db && db[0]) if (db && db[0])
{ {
...@@ -312,7 +313,7 @@ void init_max_user_conn(void) ...@@ -312,7 +313,7 @@ void init_max_user_conn(void)
} }
static int check_for_max_user_connections(USER_CONN *uc) static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{ {
int error=0; int error=0;
DBUG_ENTER("check_for_max_user_connections"); DBUG_ENTER("check_for_max_user_connections");
...@@ -325,6 +326,7 @@ static int check_for_max_user_connections(USER_CONN *uc) ...@@ -325,6 +326,7 @@ static int check_for_max_user_connections(USER_CONN *uc)
error=1; error=1;
goto end; goto end;
} }
time_out_user_resource_limits(thd, uc);
if (uc->user_resources.connections && if (uc->user_resources.connections &&
uc->user_resources.connections <= uc->conn_per_hour) uc->user_resources.connections <= uc->conn_per_hour)
{ {
...@@ -397,33 +399,54 @@ void init_update_queries(void) ...@@ -397,33 +399,54 @@ void init_update_queries(void)
/* /*
Check if maximum queries per hour limit has been reached Reset per-hour user resource limits when it has been more than
returns 0 if OK. an hour since they were last checked
In theory we would need a mutex in the USER_CONN structure for this to SYNOPSIS:
be 100 % safe, but as the worst scenario is that we would miss counting time_out_user_resource_limits()
a couple of queries, this isn't critical. thd Thread handler
*/ uc User connection details
NOTE:
This assumes that the LOCK_user_conn mutex has been acquired, so it is
safe to test and modify members of the USER_CONN structure.
*/
static bool check_mqh(THD *thd, uint check_command) void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
{ {
bool error=0;
time_t check_time = thd->start_time ? thd->start_time : time(NULL); time_t check_time = thd->start_time ? thd->start_time : time(NULL);
USER_CONN *uc=thd->user_connect; DBUG_ENTER("time_out_user_resource_limits");
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
/* If more than a hour since last check, reset resource checking */ /* If more than a hour since last check, reset resource checking */
if (check_time - uc->intime >= 3600) if (check_time - uc->intime >= 3600)
{ {
(void) pthread_mutex_lock(&LOCK_user_conn);
uc->questions=1; uc->questions=1;
uc->updates=0; uc->updates=0;
uc->conn_per_hour=0; uc->conn_per_hour=0;
uc->intime=check_time; uc->intime=check_time;
(void) pthread_mutex_unlock(&LOCK_user_conn);
} }
DBUG_VOID_RETURN;
}
/*
Check if maximum queries per hour limit has been reached
returns 0 if OK.
*/
static bool check_mqh(THD *thd, uint check_command)
{
bool error=0;
time_t check_time = thd->start_time ? thd->start_time : time(NULL);
USER_CONN *uc=thd->user_connect;
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
(void) pthread_mutex_lock(&LOCK_user_conn);
time_out_user_resource_limits(thd, uc);
/* Check that we have not done too many questions / hour */ /* Check that we have not done too many questions / hour */
if (uc->user_resources.questions && if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions) uc->questions++ >= uc->user_resources.questions)
...@@ -446,6 +469,7 @@ static bool check_mqh(THD *thd, uint check_command) ...@@ -446,6 +469,7 @@ static bool check_mqh(THD *thd, uint check_command)
} }
} }
end: end:
(void) pthread_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment