summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/sql_acl.cc19
-rw-r--r--sql/sql_class.cc86
-rw-r--r--sql/sql_class.h21
-rw-r--r--sql/sql_connect.cc134
-rw-r--r--sql/sql_connect.h3
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sys_vars.h5
7 files changed, 201 insertions, 74 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 3438e60683f..d3715fd2312 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -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);
}
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index bdcb85218c3..7e93157c69e 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -852,7 +852,7 @@ THD::THD()
#if defined(ENABLED_PROFILING)
profiling.set_thd(this);
#endif
- user_connect=(USER_CONN *)0;
+ m_user_connect= NULL;
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, 0);
@@ -5009,3 +5009,87 @@ bool Discrete_intervals_list::append(Discrete_interval *new_interval)
}
#endif /* !defined(MYSQL_CLIENT) */
+
+void THD::set_user_connect(USER_CONN *uc)
+{
+ DBUG_ENTER("THD::set_user_connect");
+
+ m_user_connect= uc;
+
+ DBUG_VOID_RETURN;
+}
+
+void THD::increment_user_connections_counter()
+{
+ DBUG_ENTER("THD::increment_user_connections_counter");
+
+ m_user_connect->connections++;
+
+ DBUG_VOID_RETURN;
+}
+
+void THD::decrement_user_connections_counter()
+{
+ DBUG_ENTER("THD::decrement_user_connections_counter");
+
+ DBUG_ASSERT(m_user_connect->connections > 0);
+ m_user_connect->connections--;
+
+ DBUG_VOID_RETURN;
+}
+
+void THD::increment_con_per_hour_counter()
+{
+ DBUG_ENTER("THD::decrement_conn_per_hour_counter");
+
+ m_user_connect->conn_per_hour++;
+
+ DBUG_VOID_RETURN;
+}
+
+void THD::increment_updates_counter()
+{
+ DBUG_ENTER("THD::increment_updates_counter");
+
+ m_user_connect->updates++;
+
+ DBUG_VOID_RETURN;
+}
+
+void THD::increment_questions_counter()
+{
+ DBUG_ENTER("THD::increment_updates_counter");
+
+ m_user_connect->questions++;
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Reset per-hour user resource limits when it has been more than
+ an hour since they were last checked
+
+ SYNOPSIS:
+ time_out_user_resource_limits()
+
+ 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.
+*/
+void THD::time_out_user_resource_limits()
+{
+ mysql_mutex_assert_owner(&LOCK_user_conn);
+ ulonglong check_time= start_utime;
+ DBUG_ENTER("time_out_user_resource_limits");
+
+ /* If more than a hour since last check, reset resource checking */
+ if (check_time - m_user_connect->reset_utime >= LL(3600000000))
+ {
+ m_user_connect->questions=1;
+ m_user_connect->updates=0;
+ m_user_connect->conn_per_hour=0;
+ m_user_connect->reset_utime= check_time;
+ }
+
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index bffa490ebe3..d799980f8e1 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1960,7 +1960,26 @@ public:
*/
ha_rows examined_row_count;
- USER_CONN *user_connect;
+private:
+ USER_CONN *m_user_connect;
+
+public:
+ void set_user_connect(USER_CONN *uc);
+ const USER_CONN* get_user_connect()
+ { return m_user_connect; }
+
+ void increment_user_connections_counter();
+ void decrement_user_connections_counter();
+
+ void increment_con_per_hour_counter();
+
+ void increment_updates_counter();
+
+ void increment_questions_counter();
+
+ void time_out_user_resource_limits();
+
+public:
CHARSET_INFO *db_charset;
Warning_info *warning_info;
Diagnostics_area *stmt_da;
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 366dec733c4..cdb0f5de049 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -105,8 +105,8 @@ int get_or_create_user_conn(THD *thd, const char *user,
goto end;
}
}
- thd->user_connect=uc;
- uc->connections++;
+ thd->set_user_connect(uc);
+ thd->increment_user_connections_counter();
end:
mysql_mutex_unlock(&LOCK_user_conn);
return return_val;
@@ -131,7 +131,7 @@ end:
1 error
*/
-int check_for_max_user_connections(THD *thd, USER_CONN *uc)
+int check_for_max_user_connections(THD *thd, const USER_CONN *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
@@ -145,7 +145,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
error=1;
goto end;
}
- time_out_user_resource_limits(thd, uc);
+ thd->time_out_user_resource_limits();
if (uc->user_resources.user_conn &&
uc->user_resources.user_conn < uc->connections)
{
@@ -164,18 +164,18 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
error=1;
goto end;
}
- uc->conn_per_hour++;
+ thd->increment_con_per_hour_counter();
end:
if (error)
{
- uc->connections--; // no need for decrease_user_connections() here
+ thd->decrement_user_connections_counter();
/*
The thread may returned back to the pool and assigned to a user
that doesn't have a limit. Ensure the user is not using resources
of someone else.
*/
- thd->user_connect= NULL;
+ thd->set_user_connect(NULL);
}
mysql_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
@@ -214,38 +214,37 @@ void decrease_user_connections(USER_CONN *uc)
DBUG_VOID_RETURN;
}
-
/*
- Reset per-hour user resource limits when it has been more than
- an hour since they were last checked
-
- SYNOPSIS:
- time_out_user_resource_limits()
- 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.
-*/
-
-void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
+ Decrements user connections count from the USER_CONN held by THD
+ And removes USER_CONN from the hash if no body else is using it.
+
+ SYNOPSIS
+ release_user_connection()
+ THD Thread context object.
+ */
+void release_user_connection(THD *thd)
{
- ulonglong check_time= thd->start_utime;
- DBUG_ENTER("time_out_user_resource_limits");
+ const USER_CONN *uc= thd->get_user_connect();
+ DBUG_ENTER("release_user_connection");
- /* If more than a hour since last check, reset resource checking */
- if (check_time - uc->reset_utime >= LL(3600000000))
+ if (uc)
{
- uc->questions=1;
- uc->updates=0;
- uc->conn_per_hour=0;
- uc->reset_utime= check_time;
+ mysql_mutex_lock(&LOCK_user_conn);
+ DBUG_ASSERT(uc->connections > 0);
+ thd->decrement_user_connections_counter();
+ if (!uc->connections && !mqh_used)
+ {
+ /* Last connection for user; Delete it */
+ (void) my_hash_delete(&hash_user_connections,(uchar*) uc);
+ }
+ mysql_mutex_unlock(&LOCK_user_conn);
+ thd->set_user_connect(NULL);
}
DBUG_VOID_RETURN;
}
+
/*
Check if maximum queries per hour limit has been reached
returns 0 if OK.
@@ -254,40 +253,70 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
bool check_mqh(THD *thd, uint check_command)
{
bool error= 0;
- USER_CONN *uc=thd->user_connect;
+ const USER_CONN *uc=thd->get_user_connect();
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
mysql_mutex_lock(&LOCK_user_conn);
- time_out_user_resource_limits(thd, uc);
+ thd->time_out_user_resource_limits();
/* Check that we have not done too many questions / hour */
- if (uc->user_resources.questions &&
- uc->questions++ >= uc->user_resources.questions)
+ if (uc->user_resources.questions)
{
- my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
- (long) uc->user_resources.questions);
- error=1;
- goto end;
+ thd->increment_questions_counter();
+ if ((uc->questions - 1) >= uc->user_resources.questions)
+ {
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
+ (long) uc->user_resources.questions);
+ error=1;
+ goto end;
+ }
}
if (check_command < (uint) SQLCOM_END)
{
/* Check that we have not done too many updates / hour */
if (uc->user_resources.updates &&
- (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
- uc->updates++ >= uc->user_resources.updates)
+ (sql_command_flags[check_command] & CF_CHANGES_DATA))
{
- my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
- (long) uc->user_resources.updates);
- error=1;
- goto end;
+ thd->increment_updates_counter();
+ if ((uc->updates - 1) >= uc->user_resources.updates)
+ {
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
+ (long) uc->user_resources.updates);
+ error=1;
+ goto end;
+ }
}
}
end:
mysql_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
}
+#else
+
+int check_for_max_user_connections(THD *thd, const USER_CONN *uc)
+{
+ return 0;
+}
+
+void decrease_user_connections(USER_CONN *uc)
+{
+ return;
+}
+
+void release_user_connection(THD *thd)
+{
+ const USER_CONN *uc= thd->get_user_connect();
+ DBUG_ENTER("release_user_connection");
+
+ if (uc)
+ {
+ thd->set_user_connect(NULL);
+ }
+
+ DBUG_VOID_RETURN;
+}
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
@@ -609,16 +638,13 @@ void end_connection(THD *thd)
{
NET *net= &thd->net;
plugin_thdvar_cleanup(thd);
- if (thd->user_connect)
- {
- decrease_user_connections(thd->user_connect);
- /*
- The thread may returned back to the pool and assigned to a user
- that doesn't have a limit. Ensure the user is not using resources
- of someone else.
- */
- thd->user_connect= NULL;
- }
+
+ /*
+ The thread may returned back to the pool and assigned to a user
+ that doesn't have a limit. Ensure the user is not using resources
+ of someone else.
+ */
+ release_user_connection(thd);
if (thd->killed || (net->error && net->vio != 0))
{
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index df6ac789709..2257a970ffa 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -33,6 +33,7 @@ void reset_mqh(LEX_USER *lu, bool get_them);
bool check_mqh(THD *thd, uint check_command);
void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
void decrease_user_connections(USER_CONN *uc);
+void release_user_connection(THD *thd);
bool thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd);
bool thd_prepare_connection(THD *thd);
@@ -47,6 +48,6 @@ void prepare_new_connection_state(THD* thd);
void end_connection(THD *thd);
int get_or_create_user_conn(THD *thd, const char *user,
const char *host, const USER_RESOURCES *mqh);
-int check_for_max_user_connections(THD *thd, USER_CONN *uc);
+int check_for_max_user_connections(THD *thd, const USER_CONN *uc);
#endif /* SQL_CONNECT_INCLUDED */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3e5dfa43d41..ea07bfce0cb 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -949,7 +949,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint save_db_length= thd->db_length;
char *save_db= thd->db;
- USER_CONN *save_user_connect= thd->user_connect;
+ USER_CONN *save_user_connect=
+ const_cast<USER_CONN*>(thd->get_user_connect());
Security_context save_security_ctx= *thd->security_ctx;
CHARSET_INFO *save_character_set_client=
thd->variables.character_set_client;
@@ -964,7 +965,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
my_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
- thd->user_connect= save_user_connect;
+ thd->set_user_connect(save_user_connect);
thd->reset_db (save_db, save_db_length);
thd->variables.character_set_client= save_character_set_client;
thd->variables.collation_connection= save_collation_connection;
@@ -5583,7 +5584,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
if (!err)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (mqh_used && thd->user_connect &&
+ if (mqh_used && thd->get_user_connect() &&
check_mqh(thd, lex->sql_command))
{
thd->net.error = 0;
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index d9d83ed5615..a69a91f7eb7 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -799,8 +799,9 @@ public:
{ }
uchar *session_value_ptr(THD *thd, LEX_STRING *base)
{
- if (thd->user_connect && thd->user_connect->user_resources.user_conn)
- return (uchar*) &(thd->user_connect->user_resources.user_conn);
+ const USER_CONN *uc= thd->get_user_connect();
+ if (uc && uc->user_resources.user_conn)
+ return (uchar*) &(uc->user_resources.user_conn);
return global_value_ptr(thd, base);
}
};