diff options
author | monty@donna.mysql.com <> | 2001-02-21 01:11:32 +0200 |
---|---|---|
committer | monty@donna.mysql.com <> | 2001-02-21 01:11:32 +0200 |
commit | 70a627a1db87e60e461b5783ca3b1ffffc6be28c (patch) | |
tree | 38658cc2814def641b51eadf71b72e44ebd61e31 | |
parent | 96a860811e545f10b37c6e13e68380e682f19547 (diff) | |
download | mariadb-git-70a627a1db87e60e461b5783ca3b1ffffc6be28c.tar.gz |
Added max_user_connections
-rwxr-xr-x | BUILD/compile-pentium-debug | 3 | ||||
-rw-r--r-- | Docs/manual.texi | 11 | ||||
-rw-r--r-- | innobase/os/os0sync.c | 53 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 134 |
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]); |