1
0
mirror of https://github.com/MariaDB/server.git synced 2025-12-24 11:21:21 +03:00

Bug#14003080:65104: MAX_USER_CONNECTIONS WITH PROCESSLIST EMPTY

Analysis:
-------------
If server is started with limit of MAX_CONNECTIONS and 
MAX_USER_CONNECTIONS then only MAX_USER_CONNECTIONS of any particular
users can be connected to server and total MAX_CONNECTIONS of client can
be connected to server.

Server maintains a counter for total CONNECTIONS and total CONNECTIONS 
from particular user.

Here, MAX_CONNECTIONS of connections are created to server. Out of this
MAX_CONNECTIONS, connections from particular user (say USER1) are
also created. The connections from USER1 is lesser than 
MAX_USER_CONNECTIONS. After that there was one more connection request from
USER1. Since USER1 can still create connections as he havent reached
MAX_USER_CONNECTIONS, server increments counter of CONNECTIONS per user.
As server already has MAX_CONNECTIONS of connections, next check to total
CONNECTION count fails. In this case control is returned WITHOUT 
decrementing the CONNECTIONS per user. So the counter per user CONNECTIONS goes
on incrementing for each attempt until current connections are closed. 
And because of this counter per CONNECTIONS reached MAX_USER_CONNECTIONS. 
So, next connections form USER1 user always returns with MAX_USER_CONNECTION 
limit error, even when total connection to sever are less than MAX_CONNECTIONS.

Fix:
-------------
This issue is occurred because of not handling counters properly in the
server. Changed the code to handle per user connection counters properly.
This commit is contained in:
Praveenkumar Hulakund
2012-05-28 11:14:43 +05:30
parent b2888adb70
commit b2c3acc987
7 changed files with 200 additions and 73 deletions

View File

@@ -7810,8 +7810,6 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
#undef HAVE_OPENSSL
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define initialized 0
#define decrease_user_connections(X) /* nothing */
#define check_for_max_user_connections(X, Y) 0
#endif
#endif
#ifndef HAVE_OPENSSL
@@ -9297,7 +9295,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
mpvio.packets_read++; // take COM_CHANGE_USER packet into account
/* Clear variables that are allocated */
thd->user_connect= 0;
thd->set_user_connect(NULL);
if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
{
@@ -9460,11 +9458,11 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
else
sctx->skip_grants();
if (thd->user_connect &&
(thd->user_connect->user_resources.conn_per_hour ||
thd->user_connect->user_resources.user_conn ||
const USER_CONN *uc;
if ((uc= thd->get_user_connect()) &&
(uc->user_resources.conn_per_hour || uc->user_resources.user_conn ||
global_system_variables.max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
check_for_max_user_connections(thd, uc))
{
DBUG_RETURN(1); // The error is set in check_for_max_user_connections()
}
@@ -9486,6 +9484,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
mysql_mutex_unlock(&LOCK_connection_count);
if (!count_ok)
{ // too many connections
release_user_connection(thd);
my_error(ER_CON_COUNT_ERROR, MYF(0));
DBUG_RETURN(1);
}
@@ -9504,11 +9503,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
if (mysql_change_db(thd, &mpvio.db, FALSE))
{
/* mysql_change_db() has pushed the error message. */
if (thd->user_connect)
{
decrease_user_connections(thd->user_connect);
thd->user_connect= 0;
}
release_user_connection(thd);
DBUG_RETURN(1);
}
}