summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormonty@donna.mysql.com <>2001-02-21 01:11:32 +0200
committermonty@donna.mysql.com <>2001-02-21 01:11:32 +0200
commit70a627a1db87e60e461b5783ca3b1ffffc6be28c (patch)
tree38658cc2814def641b51eadf71b72e44ebd61e31
parent96a860811e545f10b37c6e13e68380e682f19547 (diff)
downloadmariadb-git-70a627a1db87e60e461b5783ca3b1ffffc6be28c.tar.gz
Added max_user_connections
-rwxr-xr-xBUILD/compile-pentium-debug3
-rw-r--r--Docs/manual.texi11
-rw-r--r--innobase/os/os0sync.c53
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_parse.cc134
5 files changed, 178 insertions, 25 deletions
diff --git a/BUILD/compile-pentium-debug b/BUILD/compile-pentium-debug
index 85d06c77886..2c5e867471b 100755
--- a/BUILD/compile-pentium-debug
+++ b/BUILD/compile-pentium-debug
@@ -11,7 +11,8 @@ extra_configs="$pentium_configs $debug_configs"
# Use the debug version if it exists
if test -d /usr/local/BerkeleyDB-dbug/
then
- extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/ --with-innobase"
+ extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/"
fi
+extra_configs="$extra_configs --with-innobase"
. "$path/FINISH.sh"
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 880c5917f40..ae93496050f 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -9579,6 +9579,7 @@ uses:
@findex command-line options
@cindex options, command-line
+@cindex mysqld options
@node Command-line options, Option files, Automatic start, Post-installation
@subsection Command-line Options
@@ -11522,6 +11523,11 @@ in the grant tables. In principle, the @code{--secure} option to
@code{mysqld} should make hostnames safe. In any case, you should be very
careful about creating grant table entries using hostname values that
contain wild cards!
+
+@item
+If you want to restrict the number of connections for a single user, you
+can do this by setting the @code{max_user_connections} variable in
+@code{mysqld}.
@end itemize
@node Privileges options, What Privileges, Security, Privilege system
@@ -21048,6 +21054,9 @@ The number of bytes to use when sorting @code{BLOB} or @code{TEXT}
values (only the first @code{max_sort_length} bytes of each value
are used; the rest are ignored).
+@item @code{max_user_connections}
+The maximum number of active connections for a single user (0 = no limit).
+
@item @code{max_tmp_tables}
(This option doesn't yet do anything.)
Maximum number of temporary tables a client can keep open at the same time.
@@ -41585,6 +41594,8 @@ not yet 100 % confident in this code.
@appendixsubsec Changes in release 3.23.34
@itemize @bullet
@item
+Added option @code{max_user_connections} to @code{mysqld}.
+@item
Limit query length for replication by max_allowed_packet, not the arbitrary
limit of 4 MB
@item
diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c
index 1647dd982f3..9f9b2605884 100644
--- a/innobase/os/os0sync.c
+++ b/innobase/os/os0sync.c
@@ -19,14 +19,14 @@ Created 9/6/1995 Heikki Tuuri
#include "ut0mem.h"
/* Type definition for an operating system mutex struct */
-struct os_mutex_struct{
+struct os_mutex_struct{
void* handle; /* OS handle to mutex */
ulint count; /* we use this counter to check
that the same thread does not
recursively lock the mutex: we
do not assume that the OS mutex
supports recursive locking, though
- NT seems to do that */
+ NT seems to do that */
};
/*************************************************************
@@ -44,7 +44,7 @@ os_event_create(
{
#ifdef __WIN__
HANDLE event;
-
+
event = CreateEvent(NULL, /* No security attributes */
TRUE, /* Manual reset */
FALSE, /* Initial state nonsignaled */
@@ -60,9 +60,9 @@ os_event_create(
event = ut_malloc(sizeof(struct os_event_struct));
os_fast_mutex_init(&(event->os_mutex));
- os_fast_mutex_init(&(event->wait_mutex));
+ pthread_cond_init(&(event->cond_var), NULL);
- event->is_set = TRUE;
+ event->is_set = FALSE;
return(event);
#endif
@@ -108,7 +108,7 @@ os_event_set(
/*=========*/
os_event_t event) /* in: event to set */
{
-#ifdef __WIN__
+#ifdef __WIN__
ut_a(event);
ut_a(SetEvent(event));
#else
@@ -119,12 +119,12 @@ os_event_set(
if (event->is_set) {
/* Do nothing */
} else {
- os_fast_mutex_unlock(&(event->wait_mutex));
event->is_set = TRUE;
+ pthread_cond_broadcast(&(event->cond_var));
}
os_fast_mutex_unlock(&(event->os_mutex));
-#endif
+#endif
}
/**************************************************************
@@ -148,7 +148,6 @@ os_event_reset(
if (!event->is_set) {
/* Do nothing */
} else {
- os_fast_mutex_lock(&(event->wait_mutex));
event->is_set = FALSE;
}
@@ -163,7 +162,7 @@ void
os_event_free(
/*==========*/
os_event_t event) /* in: event to free */
-
+
{
#ifdef __WIN__
ut_a(event);
@@ -173,7 +172,7 @@ os_event_free(
ut_a(event);
os_fast_mutex_free(&(event->os_mutex));
- os_fast_mutex_free(&(event->wait_mutex));
+ pthread_cond_destroy(&(event->cond_var));
ut_free(event);
#endif
@@ -197,8 +196,22 @@ os_event_wait(
ut_a(err == WAIT_OBJECT_0);
#else
- os_fast_mutex_lock(&(event->wait_mutex));
- os_fast_mutex_unlock(&(event->wait_mutex));
+ os_fast_mutex_lock(&(event->os_mutex));
+loop:
+ if (event->is_set == TRUE) {
+ os_fast_mutex_unlock(&(event->os_mutex));
+
+ /* Ok, we may return */
+
+ return;
+ }
+
+ pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
+
+ /* Solaris manual said that spurious wakeups may occur: we have
+ to check the 'is_set' variable again */
+
+ goto loop;
#endif
}
@@ -225,7 +238,7 @@ os_event_wait_time(
} else {
err = WaitForSingleObject(event, INFINITE);
}
-
+
if (err == WAIT_OBJECT_0) {
return(0);
@@ -237,7 +250,7 @@ os_event_wait_time(
}
#else
UT_NOT_USED(time);
-
+
/* In Posix this is just an ordinary, infinite wait */
os_event_wait(event);
@@ -277,7 +290,7 @@ os_event_wait_multiple(
return(index - WAIT_OBJECT_0);
#else
ut_a(n == 0);
-
+
/* In Posix we can only wait for a single event */
os_event_wait(*event_array);
@@ -318,7 +331,7 @@ os_mutex_create(
os_mutex_t mutex_str;
UT_NOT_USED(name);
-
+
os_mutex = ut_malloc(sizeof(os_fast_mutex_t));
os_fast_mutex_init(os_mutex);
@@ -329,7 +342,7 @@ os_mutex_create(
mutex_str->count = 0;
return(mutex_str);
-#endif
+#endif
}
/**************************************************************
@@ -385,7 +398,7 @@ os_mutex_exit(
(mutex->count)--;
os_fast_mutex_unlock(mutex->handle);
-#endif
+#endif
}
/**************************************************************
@@ -419,7 +432,7 @@ os_fast_mutex_init(
{
#ifdef __WIN__
ut_a(fast_mutex);
-
+
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else
pthread_mutex_init(fast_mutex, NULL);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b0a10830663..352cdcee6f6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -521,7 +521,7 @@ extern uint protocol_version,dropping_tables;
extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
max_join_size,join_buff_size,tmp_table_size,
max_connections,max_connect_errors,long_query_time,
- max_insert_delayed_threads,
+ max_insert_delayed_threads, max_user_connections,
long_query_count,net_wait_timeout,net_interactive_timeout,
net_read_timeout,net_write_timeout,
what_to_log,flush_time,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ebf49583e7b..5ff0bc91c5f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -22,6 +22,7 @@
#include <thr_alarm.h>
#include <myisam.h>
#include <my_dir.h>
+#include <assert.h>
#define SCRAMBLE_LENGTH 8
@@ -32,6 +33,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif
+static int check_for_max_user_connections(const char *user, int u_length,
+ const char *host);
+static void decrease_user_connections(const char *user, const char *host);
static bool check_table_access(THD *thd,uint want_access, 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);
@@ -145,13 +149,134 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
db ? db : (char*) "");
thd->db_access=0;
+ if (max_user_connections &&
+ check_for_max_user_connections(user, strlen(user), thd->host))
+ return -1;
if (db && db[0])
- return test(mysql_change_db(thd,db));
+ {
+ bool error=test(mysql_change_db(thd,db));
+ if (error)
+ decrease_user_connections(user,thd->host);
+ return error;
+ }
else
send_ok(net); // Ready to handle questions
return 0; // ok
}
+/*
+** check for maximum allowable user connections
+** if mysql server is started with corresponding
+** variable that is greater then 0
+*/
+
+static HASH hash_user_connections;
+static DYNAMIC_ARRAY user_conn_array;
+extern pthread_mutex_t LOCK_user_conn;
+
+struct user_conn {
+ char user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ int connections, len;
+};
+
+static byte* get_key_conn(user_conn *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->len;
+ return (byte*) buff->user;
+}
+
+#define DEF_USER_COUNT 50
+
+void init_max_user_conn(void)
+{
+ (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
+ (hash_get_key) get_key_conn,0, 0);
+ (void) init_dynamic_array(&user_conn_array,sizeof(user_conn),
+ DEF_USER_COUNT, DEF_USER_COUNT);
+}
+
+
+static int check_for_max_user_connections(const char *user, int u_length,
+ const char *host)
+{
+ uint temp_len;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ struct user_conn *uc;
+ if (!user)
+ user="";
+ if (!host)
+ host="";
+ temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
+ NullS) - temp_user);
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len);
+ if (uc) /* user found ; check for no. of connections */
+ {
+ if (max_user_connections == uc->connections)
+ {
+ net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
+ pthread_mutex_unlock(&LOCK_user_conn);
+ return 1;
+ }
+ uc->connections++;
+ }
+ else
+ {
+ /* the user is not found in the cache; Insert it */
+ struct user_conn uc;
+ memcpy(uc.user,temp_user,temp_len+1);
+ uc.len = temp_len;
+ uc.connections = 1;
+ if (!insert_dynamic(&user_conn_array, (char *) &uc))
+ {
+ hash_insert(&hash_user_connections,
+ (byte *) dynamic_array_ptr(&user_conn_array,
+ user_conn_array.elements - 1));
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return 0;
+}
+
+
+static void decrease_user_connections(const char *user, const char *host)
+{
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ int temp_len;
+ struct user_conn uucc, *uc;
+ if (!user)
+ user="";
+ if (!host)
+ host="";
+ temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
+ NullS) - temp_user);
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+
+ uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len);
+ dbug_assert(uc != 0); // We should always find the user
+ if (!uc)
+ goto end; // Safety; Something went wrong
+ if (! --uc->connections)
+ {
+ /* Last connection for user; Delete it */
+ (void) hash_delete(&hash_user_connections,(char *) uc);
+ uint element= ((uint) ((byte*) uc - (byte*) user_conn_array.buffer) /
+ user_conn_array.size_of_element);
+ delete_dynamic_element(&user_conn_array,element);
+ }
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+}
+
+void free_max_user_conn(void)
+{
+ delete_dynamic(&user_conn_array);
+ hash_free(&hash_user_connections);
+}
+
/*
** check connnetion and get priviliges
@@ -417,6 +542,8 @@ pthread_handler_decl(handle_one_connection,arg)
thread_safe_increment(aborted_threads,&LOCK_thread_count);
}
+ if (max_user_connections)
+ decrease_user_connections(thd->user,thd->host);
end_thread:
close_connection(net);
end_thread(thd,1);
@@ -512,7 +639,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
DBUG_ENTER("mysql_table_dump");
db = (db && db[0]) ? db : thd->db;
if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
- DBUG_RETURN(1); // out of memory
+ DBUG_RETURN(1); // out of memory
table_list->db = db;
table_list->real_name = table_list->name = tbl_name;
table_list->lock_type = TL_READ_NO_INSERT;
@@ -641,7 +768,7 @@ bool do_command(THD *thd)
send_error(net, ER_UNKNOWN_COM_ERROR);
break;
}
- if (check_user(thd, COM_CHANGE_USER, user, passwd, db,0))
+ if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
{ // Restore old user
x_free(thd->user);
x_free(thd->db);
@@ -652,6 +779,7 @@ bool do_command(THD *thd)
thd->priv_user=save_priv_user;
break;
}
+ decrease_user_connections (save_user, thd->host);
x_free((gptr) save_db);
x_free((gptr) save_user);
thd->password=test(passwd[0]);