#At file:///Users/kgeorge/mysql/work/wl5259-trunk/ based on revid:georgi.kodinov@stripped
3446 Georgi Kodinov 2010-12-22
WL#5259 : Show contents of host cache
=== INFORMATION_SCHEMA.HOST_CACHE ===
CREATE TABLE `HOST_CACHE` (
`IP_ADDRESS` varchar(64) NOT NULL DEFAULT '',
`HOSTNAME` varchar(64) DEFAULT NULL,
`ERRORS` int(10) NOT NULL DEFAULT '0'
);
This table will contain 1 row for every entry in the host cache hash.
The contents of the table can be efficiently filtered by a wildcard on IP_ADDRESS.
The HOSTNAME column can be NULL, meaning that the IP_ADDRESS cannot be resolved.
No SHOW command will be created.
After FLUSH HOSTS there will be no rows in INFORMATION_SCHEMA.HOST_CACHE.
=== Global status variables ===
The following global readonly variables will be added :
Host_cache_free : free entries in the host cache.
Host_cache_hits : number of records found in the cache
Host_cache_inserts : number of record inserted in the cache
Host_cache_misses : number of records not found in the cache
Host_cache_prunes : number of times a record is deleted from the cache to free up
place for new records
Host_cache_used : number of active records in the cache
These variable will be reset by FLUSH STATUS. Note that FLUSH HOSTS will have no
effect on them. Only Host_cache_free will probably be non-zero after FLUSH STATUS.
=== host-cache-size global variable/command line option ===
Valid values : 0-2048. Default : 128
If set at run time will have the join effect of FLUSH STATUS and FLUSH HOSTS and
will re-allocate the host cache to a new size.
added:
mysql-test/suite/sys_vars/r/host_cache_size_basic.result
mysql-test/suite/sys_vars/t/host_cache_size_basic.test
modified:
mysql-test/r/information_schema.result
mysql-test/r/information_schema_db.result
mysql-test/r/mysqld--help-notwin.result
mysql-test/r/mysqlshow.result
sql/CMakeLists.txt
sql/handler.h
sql/hash_filo.cc
sql/hash_filo.h
sql/hostname.cc
sql/hostname.h
sql/mysqld.cc
sql/sql_acl.cc
sql/sql_show.cc
sql/sys_vars.cc
=== modified file 'mysql-test/r/information_schema.result'
--- a/mysql-test/r/information_schema.result 2010-12-17 11:28:59 +0000
+++ b/mysql-test/r/information_schema.result 2010-12-22 17:31:51 +0000
@@ -55,6 +55,7 @@ EVENTS
FILES
GLOBAL_STATUS
GLOBAL_VARIABLES
+HOST_CACHE
KEY_COLUMN_USAGE
PARAMETERS
PARTITIONS
@@ -875,7 +876,7 @@ table_schema IN ('mysql', 'INFORMATION_S
AND table_name not like 'ndb%' AND table_name not like 'innodb_%'
GROUP BY TABLE_SCHEMA;
table_schema count(*)
-information_schema 30
+information_schema 31
mysql 25
create table t1 (i int, j int);
create trigger trg1 before insert on t1 for each row
@@ -1324,6 +1325,7 @@ EVENTS information_schema.EVENTS 1
FILES information_schema.FILES 1
GLOBAL_STATUS information_schema.GLOBAL_STATUS 1
GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1
+HOST_CACHE information_schema.HOST_CACHE 1
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
PARAMETERS information_schema.PARAMETERS 1
PARTITIONS information_schema.PARTITIONS 1
=== modified file 'mysql-test/r/information_schema_db.result'
--- a/mysql-test/r/information_schema_db.result 2010-11-30 17:53:11 +0000
+++ b/mysql-test/r/information_schema_db.result 2010-12-22 17:31:51 +0000
@@ -15,6 +15,7 @@ EVENTS
FILES
GLOBAL_STATUS
GLOBAL_VARIABLES
+HOST_CACHE
KEY_COLUMN_USAGE
PARAMETERS
PARTITIONS
=== modified file 'mysql-test/r/mysqld--help-notwin.result'
--- a/mysql-test/r/mysqld--help-notwin.result 2010-12-07 07:53:39 +0000
+++ b/mysql-test/r/mysqld--help-notwin.result 2010-12-22 17:31:51 +0000
@@ -186,6 +186,7 @@ The following options may be given as th
The maximum length of the result of function
GROUP_CONCAT()
-?, --help Display this help and exit.
+ --host-cache-size=# How many hostnames should be cached to avoid resolving.
--ignore-builtin-innodb
Disable initialization of builtin InnoDB plugin
--init-connect=name Command(s) that are executed for each new connection
@@ -797,6 +798,7 @@ gdb FALSE
general-log FALSE
group-concat-max-len 1024
help TRUE
+host-cache-size 128
ignore-builtin-innodb FALSE
init-connect
init-file (No default value)
=== modified file 'mysql-test/r/mysqlshow.result'
--- a/mysql-test/r/mysqlshow.result 2010-10-27 14:46:44 +0000
+++ b/mysql-test/r/mysqlshow.result 2010-12-22 17:31:51 +0000
@@ -89,6 +89,7 @@ Database: information_schema
| FILES |
| GLOBAL_STATUS |
| GLOBAL_VARIABLES |
+| HOST_CACHE |
| KEY_COLUMN_USAGE |
| PARAMETERS |
| PARTITIONS |
@@ -132,6 +133,7 @@ Database: INFORMATION_SCHEMA
| FILES |
| GLOBAL_STATUS |
| GLOBAL_VARIABLES |
+| HOST_CACHE |
| KEY_COLUMN_USAGE |
| PARAMETERS |
| PARTITIONS |
=== added file 'mysql-test/suite/sys_vars/r/host_cache_size_basic.result'
--- a/mysql-test/suite/sys_vars/r/host_cache_size_basic.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/r/host_cache_size_basic.result 2010-12-22 17:31:51 +0000
@@ -0,0 +1,30 @@
+SELECT @@global.host_cache_size;
+@@global.host_cache_size
+128
+select @@session.host_cache_size;
+ERROR HY000: Variable 'host_cache_size' is a GLOBAL variable
+show global variables like 'host_cache_size';
+Variable_name Value
+host_cache_size 128
+show session variables like 'host_cache_size';
+Variable_name Value
+host_cache_size 128
+select * from INFORMATION_SCHEMA.global_variables where variable_name='host_cache_size';
+VARIABLE_NAME VARIABLE_VALUE
+HOST_CACHE_SIZE 128
+select * from INFORMATION_SCHEMA.session_variables where variable_name='host_cache_size';
+VARIABLE_NAME VARIABLE_VALUE
+HOST_CACHE_SIZE 128
+set global host_cache_size = 1024;
+SELECT @@global.host_cache_size;
+@@global.host_cache_size
+1024
+set session host_cache_size = 1024;
+ERROR HY000: Variable 'host_cache_size' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@global.host_cache_size;
+@@global.host_cache_size
+1024
+set global host_cache_size = default;
+SELECT @@global.host_cache_size;
+@@global.host_cache_size
+128
=== added file 'mysql-test/suite/sys_vars/t/host_cache_size_basic.test'
--- a/mysql-test/suite/sys_vars/t/host_cache_size_basic.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/t/host_cache_size_basic.test 2010-12-22 17:31:51 +0000
@@ -0,0 +1,18 @@
+SELECT @@global.host_cache_size;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@session.host_cache_size;
+
+show global variables like 'host_cache_size';
+show session variables like 'host_cache_size';
+select * from INFORMATION_SCHEMA.global_variables where variable_name='host_cache_size';
+select * from INFORMATION_SCHEMA.session_variables where variable_name='host_cache_size';
+
+set global host_cache_size = 1024;
+SELECT @@global.host_cache_size;
+
+--error ER_GLOBAL_VARIABLE
+set session host_cache_size = 1024;
+SELECT @@global.host_cache_size;
+
+set global host_cache_size = default;
+SELECT @@global.host_cache_size;
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2010-12-17 09:41:21 +0000
+++ b/sql/CMakeLists.txt 2010-12-22 17:31:51 +0000
@@ -80,6 +80,7 @@ SET (SQL_SOURCE
datadict.cc sql_reload.cc
sql_partition_admin.cc
sql_admin.cc sql_alter.cc
+ hash_filo.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE})
=== modified file 'sql/handler.h'
--- a/sql/handler.h 2010-11-18 16:34:56 +0000
+++ b/sql/handler.h 2010-12-22 17:31:51 +0000
@@ -560,6 +560,7 @@ enum enum_schema_tables
SCH_FILES,
SCH_GLOBAL_STATUS,
SCH_GLOBAL_VARIABLES,
+ SCH_HOST_CACHE,
SCH_KEY_COLUMN_USAGE,
SCH_OPEN_TABLES,
SCH_PARAMETERS,
=== modified file 'sql/hash_filo.cc'
--- a/sql/hash_filo.cc 2010-07-02 18:15:21 +0000
+++ b/sql/hash_filo.cc 2010-12-22 17:31:51 +0000
@@ -25,3 +25,152 @@
#include "sql_priv.h"
#include "hash_filo.h"
+
+
+hash_filo_metrics::hash_filo_metrics()
+{
+ reset();
+}
+
+
+void hash_filo_metrics::reset()
+{
+ hits= misses= inserts= prunes= 0;
+}
+
+
+hash_filo::hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
+ my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
+ CHARSET_INFO *hash_charset_arg)
+ :key_offset(key_offset_arg), key_length(key_length_arg),
+ get_key(get_key_arg), size(size_arg), free_element(free_element_arg),init(0),
+ hash_charset(hash_charset_arg), metrics(NULL)
+{
+ bzero((char*) &cache,sizeof(cache));
+}
+
+
+hash_filo::~hash_filo()
+{
+ if (init)
+ {
+ if (cache.array.buffer) /* Avoid problems with thread library */
+ (void) my_hash_free(&cache);
+ mysql_mutex_destroy(&lock);
+ }
+}
+
+
+void hash_filo::set_metrics(hash_filo_metrics *in_metrics)
+{
+ metrics= in_metrics;
+}
+
+
+void hash_filo::clear(bool locked)
+{
+ if (!init)
+ {
+ init= 1;
+ mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST);
+ }
+ if (!locked)
+ mysql_mutex_lock(&lock);
+ (void) my_hash_free(&cache);
+ (void) my_hash_init(&cache, hash_charset, size,key_offset,
+ key_length, get_key, free_element, 0);
+ if (!locked)
+ mysql_mutex_unlock(&lock);
+ newest_element_p=oldest_element_p= 0;
+ if (metrics)
+ {
+ metrics->used= 0;
+ metrics->free= size;
+ }
+}
+
+
+void hash_filo::resize(uint new_size)
+{
+ (void) mysql_mutex_lock(&lock);
+ size= new_size;
+ if (metrics)
+ metrics->reset();
+ clear(1);
+ (void) mysql_mutex_unlock(&lock);
+}
+
+
+hash_filo_element *hash_filo::search(const uchar* key, size_t length)
+{
+ hash_filo_element *entry= (hash_filo_element*)
+ my_hash_search(&cache, key, length);
+ if (entry)
+ { // Found; link it first
+ if (metrics)
+ statistic_increment(metrics->hits, &metrics->lock);
+ if (entry != newest_element_p)
+ { // Relink used-chain
+ if (entry == oldest_element_p)
+ oldest_element_p= entry->newer_element_p;
+ else
+ {
+ entry->older_element_p->newer_element_p= entry->newer_element_p;
+ entry->newer_element_p->older_element_p= entry->older_element_p;
+ }
+ if ((entry->older_element_p= newest_element_p))
+ newest_element_p->newer_element_p= entry;
+ newest_element_p= entry;
+ }
+ else
+ {
+ if (metrics)
+ statistic_increment(metrics->misses, &metrics_lock);
+ }
+ }
+ return entry;
+}
+
+
+my_bool hash_filo::add(hash_filo_element *entry)
+{
+
+ if(unlikely(size == 0))
+ {
+ /* Our HASH size is 0, so throw away any entries attempted. */
+ if(free_element)
+ (*free_element)(entry);
+ return 0;
+ }
+
+ if (cache.records == size)
+ {
+ hash_filo_element *tmp= oldest_element_p;
+ oldest_element_p= oldest_element_p->newer_element_p;
+ my_hash_delete(&cache,(uchar*) tmp);
+ if (metrics)
+ statistic_increment(metrics->prunes, &metrics->lock);
+ }
+ if (my_hash_insert(&cache,(uchar*) entry))
+ {
+ if (free_element)
+ (*free_element)(entry); // This should never happen
+ return 1;
+ }
+
+ if (metrics)
+ statistic_increment(metrics->inserts, &metrics->lock);
+ if ((entry->older_element_p= newest_element_p))
+ newest_element_p->newer_element_p= entry;
+ else
+ oldest_element_p= entry;
+ newest_element_p= entry;
+
+ if (metrics)
+ {
+ metrics->used= cache.records;
+ metrics->free= size - cache.records;
+ }
+
+ return 0;
+}
=== modified file 'sql/hash_filo.h'
--- a/sql/hash_filo.h 2010-07-02 02:58:51 +0000
+++ b/sql/hash_filo.h 2010-12-22 17:31:51 +0000
@@ -32,106 +32,59 @@
class hash_filo_element
{
- hash_filo_element *next_used,*prev_used;
+ hash_filo_element *newer_element_p, *older_element_p;
public:
hash_filo_element() {}
+ hash_filo_element *newer_element() { return newer_element_p; }
+ hash_filo_element *older_element() { return older_element_p; }
+ friend class hash_filo;
+};
+
+
+class hash_filo_metrics
+{
+ pthread_mutex_t lock;
+ public:
+ hash_filo_metrics();
+ void reset();
+
+ ulong hits;
+ ulong misses;
+ ulong inserts;
+ ulong prunes;
+
+ ulong used, free;
+
friend class hash_filo;
};
class hash_filo
{
- const uint size, key_offset, key_length;
+ const uint key_offset, key_length;
const my_hash_get_key get_key;
+ uint size;
my_hash_free_key free_element;
bool init;
CHARSET_INFO *hash_charset;
- hash_filo_element *first_link,*last_link;
+ hash_filo_element *newest_element_p, *oldest_element_p;
+ hash_filo_metrics *metrics;
public:
mysql_mutex_t lock;
HASH cache;
hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
my_hash_get_key get_key_arg, my_hash_free_key free_element_arg,
- CHARSET_INFO *hash_charset_arg)
- :size(size_arg), key_offset(key_offset_arg), key_length(key_length_arg),
- get_key(get_key_arg), free_element(free_element_arg),init(0),
- hash_charset(hash_charset_arg)
- {
- bzero((char*) &cache,sizeof(cache));
- }
-
- ~hash_filo()
- {
- if (init)
- {
- if (cache.array.buffer) /* Avoid problems with thread library */
- (void) my_hash_free(&cache);
- mysql_mutex_destroy(&lock);
- }
- }
- void clear(bool locked=0)
- {
- if (!init)
- {
- init=1;
- mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST);
- }
- if (!locked)
- mysql_mutex_lock(&lock);
- (void) my_hash_free(&cache);
- (void) my_hash_init(&cache,hash_charset,size,key_offset,
- key_length, get_key, free_element,0);
- if (!locked)
- mysql_mutex_unlock(&lock);
- first_link=last_link=0;
- }
-
- hash_filo_element *search(uchar* key, size_t length)
- {
- hash_filo_element *entry=(hash_filo_element*)
- my_hash_search(&cache,(uchar*) key,length);
- if (entry)
- { // Found; link it first
- if (entry != first_link)
- { // Relink used-chain
- if (entry == last_link)
- last_link=entry->prev_used;
- else
- {
- entry->next_used->prev_used = entry->prev_used;
- entry->prev_used->next_used = entry->next_used;
- }
- if ((entry->next_used= first_link))
- first_link->prev_used=entry;
- first_link=entry;
- }
- }
- return entry;
- }
-
- my_bool add(hash_filo_element *entry)
- {
- if (cache.records == size)
- {
- hash_filo_element *tmp=last_link;
- last_link=last_link->prev_used;
- my_hash_delete(&cache,(uchar*) tmp);
- }
- if (my_hash_insert(&cache,(uchar*) entry))
- {
- if (free_element)
- (*free_element)(entry); // This should never happen
- return 1;
- }
- if ((entry->next_used=first_link))
- first_link->prev_used=entry;
- else
- last_link=entry;
- first_link=entry;
- return 0;
- }
+ CHARSET_INFO *hash_charset_arg);
+ ~hash_filo();
+ void set_metrics(hash_filo_metrics *in_metrics);
+ hash_filo_element *newest_element() { return newest_element_p; }
+ hash_filo_element *oldest_element() { return oldest_element_p; }
+ void clear(bool locked= 0);
+ void resize(uint new_size);
+ hash_filo_element *search(const uchar * key, size_t length= 0);
+ my_bool add(hash_filo_element *entry);
};
#endif
=== modified file 'sql/hostname.cc'
--- a/sql/hostname.cc 2010-07-23 20:59:42 +0000
+++ b/sql/hostname.cc 2010-12-22 17:31:51 +0000
@@ -26,11 +26,6 @@
#include "sql_priv.h"
#include "hostname.h"
-#include "my_global.h"
-#ifndef __WIN__
-#include <netdb.h> // getservbyname, servent
-#endif
-#include "hash_filo.h"
#include <m_ctype.h>
#include "log.h" // sql_print_warning,
// sql_print_information
@@ -48,77 +43,101 @@ extern "C" { // Because of SCO 3.2V4
#ifdef __cplusplus
}
#endif
+#include "sql_class.h"
+#include "sql_show.h" // schema_table_store_record
+#include "sql_acl.h" // wild_case_compare
-/*
- HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
-*/
-
-#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
+static hash_filo *hostname_cache;
+hash_filo_metrics hostname_cache_metrics;
+ulong host_cache_size;
-/**
- An entry in the hostname hash table cache.
+static inline Host_entry *hostname_cache_search(const char *ip_key)
+{
+ return (Host_entry *)hostname_cache->search((const uchar *) ip_key, 0);
+}
- Host name cache does two things:
- - caches host names to save DNS look ups;
- - counts connect errors from IP.
- Host name can be NULL (that means DNS look up failed), but connect errors
- still are counted.
+/*
+ A simple inline function to return the hash key for a given entry.
*/
-
-class Host_entry :public hash_filo_element
+static inline uchar *host_entry_get_key(Host_entry *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
-public:
- /**
- Client IP address. This is the key used with the hash table.
-
- The client IP address is always expressed in IPv6, even when the
- network IPv6 stack is not present.
-
- This IP address is never used to connect to a socket.
- */
- char ip_key[HOST_ENTRY_KEY_SIZE];
-
- /**
- Number of errors during handshake phase from the IP address.
- */
- uint connect_errors;
-
- /**
- One of the host names for the IP address. May be NULL.
- */
- const char *hostname;
-};
+ *length= HOST_ENTRY_KEY_SIZE;
+ return (uchar *) &entry->ip_key;
+}
-static hash_filo *hostname_cache;
-void hostname_cache_refresh()
+/*
+ A simple inline function to free a hash entry.
+*/
+static inline void host_entry_free_key(Host_entry *entry)
{
- hostname_cache->clear();
+ my_free(entry->hostname);
+ my_free((uchar *) entry);
}
+
bool hostname_cache_init()
{
Host_entry tmp;
uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp);
- if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE,
+ if (!(hostname_cache= new hash_filo(host_cache_size,
key_offset, HOST_ENTRY_KEY_SIZE,
- NULL, (my_hash_free_key) free,
- &my_charset_bin)))
+ (my_hash_get_key) host_entry_get_key,
+ (my_hash_free_key) host_entry_free_key,
+ &my_charset_latin1)))
return 1;
hostname_cache->clear();
-
+ hostname_cache->set_metrics(&hostname_cache_metrics);
return 0;
}
+
void hostname_cache_free()
{
delete hostname_cache;
hostname_cache= NULL;
}
+
+/**
+ Empty the contents of the hostname cache.
+*/
+void hostname_cache_refresh()
+{
+ DBUG_ENTER("hostname_cache_refresh");
+ hostname_cache->clear();
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Empty the contents of the hostname aggregate stats.
+*/
+void hostname_cache_metrics_reset()
+{
+ DBUG_ENTER("hostname_cache_metrics_reset");
+ mysql_mutex_lock(&hostname_cache->lock);
+ hostname_cache_metrics.reset();
+ mysql_mutex_unlock(&hostname_cache->lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Resize the hostname cache by resizing the hash table underlying it.
+
+ @param size new size of the hostname cache
+*/
+void hostname_cache_resize(uint size)
+{
+ hostname_cache->resize(size);
+}
+
+
static void prepare_hostname_cache_key(const char *ip_string,
char *ip_key)
{
@@ -129,65 +148,60 @@ static void prepare_hostname_cache_key(c
memcpy(ip_key, ip_string, ip_string_length);
}
-static inline Host_entry *hostname_cache_search(const char *ip_key)
-{
- return (Host_entry *) hostname_cache->search((uchar *) ip_key, 0);
-}
-static bool add_hostname_impl(const char *ip_key, const char *hostname)
+static bool hostname_cache_add(const char *ip_key, const char *hostname)
{
- if (hostname_cache_search(ip_key))
- return FALSE;
-
- size_t hostname_size= hostname ? strlen(hostname) + 1 : 0;
+ bool err_status= TRUE;
+ Host_entry *entry;
- Host_entry *entry= (Host_entry *) malloc(sizeof (Host_entry) + hostname_size);
-
- if (!entry)
- return TRUE;
-
- char *hostname_copy;
+ if (specialflag & SPECIAL_NO_HOST_CACHE)
+ return FALSE;
- memcpy(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
+ mysql_mutex_lock(&hostname_cache->lock);
- if (hostname_size)
+ if (!hostname_cache->search((const uchar *) ip_key, 0))
{
- hostname_copy= (char *) (entry + 1);
- memcpy(hostname_copy, hostname, hostname_size);
+ if ((entry= (Host_entry *) my_malloc(sizeof(Host_entry),
+ MYF(MY_WME|MY_ZEROFILL))))
+ {
+ memcpy(&entry->ip_key, ip_key, HOST_ENTRY_KEY_SIZE);
+ entry->hostname= hostname ? my_strdup(hostname, MYF(0)) : NULL;
- DBUG_PRINT("info", ("Adding '%s' -> '%s' to the hostname cache...'",
- (const char *) ip_key,
- (const char *) hostname_copy));
+ DBUG_PRINT("info", ("Adding '%s' -> '%s' to the hostname cache...'",
+ ip_key,
+ hostname ? hostname : "NULL"));
+ err_status= hostname_cache->add(entry);
+ }
}
else
- {
- hostname_copy= NULL;
-
- DBUG_PRINT("info", ("Adding '%s' -> NULL to the hostname cache...'",
- (const char *) ip_key));
- }
+ err_status= FALSE;
- entry->hostname= hostname_copy;
- entry->connect_errors= 0;
-
- return hostname_cache->add(entry);
+ mysql_mutex_unlock(&hostname_cache->lock);
+ return err_status;
}
-static bool add_hostname(const char *ip_key, const char *hostname)
-{
- if (specialflag & SPECIAL_NO_HOST_CACHE)
- return FALSE;
- mysql_mutex_lock(&hostname_cache->lock);
-
- bool err_status= add_hostname_impl(ip_key, hostname);
+/**
+ Add a denied IP address to the hostname cache, so it can be quickly
+ denied in the future.
- mysql_mutex_unlock(&hostname_cache->lock);
+ @param ip_key pointer to struct in_addr with IP address
+*/
- return err_status;
+static inline bool hostname_cache_add_deny(const char *ip_key)
+{
+ DBUG_ENTER("hostname_cache_add_deny");
+ DBUG_RETURN (hostname_cache_add(ip_key, NullS));
}
-void inc_host_errors(const char *ip_string)
+
+/**
+ Increment the error count for an IP address.
+
+ @param in pointer to struct in_addr with IP address
+*/
+
+void hostname_cache_inc_host_errors(const char *ip_string)
{
if (!ip_string)
return;
@@ -206,7 +220,13 @@ void inc_host_errors(const char *ip_stri
}
-void reset_host_errors(const char *ip_string)
+/**
+ Reset the error count for an IP address.
+
+ @param in pointer to struct in_addr with IP address
+*/
+
+void hostname_cache_reset_host_errors(const char *ip_string)
{
if (!ip_string)
return;
@@ -343,7 +363,7 @@ bool ip_to_hostname(struct sockaddr_stor
DBUG_PRINT("info",("IP (%s) has been found in the cache. "
"Hostname: '%s'; connect_errors: %d",
(const char *) ip_key,
- (const char *) (*hostname? *hostname : "null"),
+ (const char *) (*hostname ? *hostname : "null"),
(int) *connect_errors));
mysql_mutex_unlock(&hostname_cache->lock);
@@ -381,7 +401,7 @@ bool ip_to_hostname(struct sockaddr_stor
"no reverse address mapping.",
(const char *) ip_key);
- err_status= add_hostname(ip_key, NULL);
+ err_status= hostname_cache_add_deny(ip_key);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -436,7 +456,7 @@ bool ip_to_hostname(struct sockaddr_stor
(const char *) ip_key,
(const char *) hostname_buffer);
- err_status= add_hostname(ip_key, NULL);
+ err_status= hostname_cache_add_deny(ip_key);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -468,7 +488,7 @@ bool ip_to_hostname(struct sockaddr_stor
indefinitely.
*/
- err_status= add_hostname(ip_key, NULL);
+ err_status= hostname_cache_add_deny(ip_key);
*hostname= NULL;
*connect_errors= 0; /* New IP added to the cache. */
@@ -550,17 +570,72 @@ bool ip_to_hostname(struct sockaddr_stor
if (*hostname)
{
- err_status= add_hostname(ip_key, *hostname);
+ err_status= hostname_cache_add(ip_key, *hostname);
+ /* hostname_cache_add calls ::search(), which will increment misses */
+ statistic_decrement(hostname_cache_metrics.misses, &hostname_cache_metrics.lock);
*connect_errors= 0;
}
else
{
DBUG_PRINT("error",("Couldn't verify hostname with getaddrinfo()."));
- err_status= add_hostname(ip_key, NULL);
+ err_status= hostname_cache_add_deny(ip_key);
*hostname= NULL;
*connect_errors= 0;
}
DBUG_RETURN(err_status);
}
+
+
+/**
+ Fill the passed information_schema table with host cache information.
+
+ @param thd Ubiquitous thread object.
+ @param tables The destination of the host-cache info.
+ @param cond (Unused.)
+*/
+int hostname_cache_fill_i_s(THD *thd, TABLE_LIST *tables, Item *cond)
+{
+ DBUG_ENTER("fill_host_cache_i_s");
+ int ret= 0;
+
+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+
+ mysql_mutex_lock(&hostname_cache->lock);
+
+ Host_entry *cur;
+
+ for (cur= (Host_entry *) hostname_cache->newest_element();
+ cur != NULL; cur= (Host_entry *) cur->older_element())
+ {
+ if (wild && wild[0] && wild_case_compare(cs, cur->ip_key, wild))
+ continue;
+
+ table->field[0]->store(cur->ip_key, strlen(cur->ip_key), system_charset_info);
+ if(cur->hostname)
+ {
+ table->field[1]->store(cur->hostname, strlen(cur->hostname), system_charset_info);
+ table->field[1]->set_notnull();
+ }
+ else
+ {
+ table->field[1]->store(NULL, 0, system_charset_info);
+ table->field[1]->set_null();
+ }
+ table->field[2]->store((longlong)cur->connect_errors, TRUE);
+
+ if (schema_table_store_record(thd, table))
+ {
+ ret= 1;
+ goto clean_up;
+ }
+ }
+
+clean_up:
+ mysql_mutex_unlock(&hostname_cache->lock);
+
+ DBUG_RETURN(ret);
+}
=== modified file 'sql/hostname.h'
--- a/sql/hostname.h 2010-07-02 02:58:51 +0000
+++ b/sql/hostname.h 2010-12-22 17:31:51 +0000
@@ -17,14 +17,68 @@
#define HOSTNAME_INCLUDED
#include "my_global.h" /* uint */
+#include "hash_filo.h"
+#include "table.h"
+#ifndef __WIN__
+#include <netdb.h> // getservbyname, servent
+#endif
+
+/*
+ HOST_ENTRY_KEY_SIZE -- size of IP address string in the hash cache.
+*/
+
+#define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN
+
+
+/**
+ An entry in the hostname hash table cache.
+
+ Host name cache does two things:
+ - caches host names to save DNS look ups;
+ - counts connect errors from IP.
+
+ Host name can be NULL (that means DNS look up failed), but connect errors
+ still are counted.
+*/
+
+class Host_entry :public hash_filo_element
+{
+public:
+ /**
+ Client IP address. This is the key used with the hash table.
+
+ The client IP address is always expressed in IPv6, even when the
+ network IPv6 stack is not present.
+
+ This IP address is never used to connect to a socket.
+ */
+ char ip_key[HOST_ENTRY_KEY_SIZE];
+
+ /**
+ Number of errors during handshake phase from the IP address.
+ */
+ uint connect_errors;
+
+ /**
+ One of the host names for the IP address. May be NULL.
+ */
+ char *hostname;
+};
+
+
+extern hash_filo_metrics hostname_cache_metrics;
+extern ulong host_cache_size;
bool ip_to_hostname(struct sockaddr_storage *ip_storage,
const char *ip_string,
char **hostname, uint *connect_errors);
-void inc_host_errors(const char *ip_string);
-void reset_host_errors(const char *ip_string);
+void hostname_cache_inc_host_errors(const char *ip_string);
+void hostname_cache_reset_host_errors(const char *ip_string);
bool hostname_cache_init();
void hostname_cache_free();
void hostname_cache_refresh(void);
+void hostname_cache_metrics_reset(void);
+void hostname_cache_resize(uint size);
+int hostname_cache_fill_i_s(THD *thd, TABLE_LIST *tables, Item *cond);
#endif /* HOSTNAME_INCLUDED */
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2010-12-17 11:28:59 +0000
+++ b/sql/mysqld.cc 2010-12-22 17:31:51 +0000
@@ -6674,6 +6674,12 @@ SHOW_VAR status_vars[]= {
{"Handler_savepoint_rollback",(char*) offsetof(STATUS_VAR, ha_savepoint_rollback_count), SHOW_LONG_STATUS},
{"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS},
{"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS},
+ {"Host_cache_free", (char*) &hostname_cache_metrics.free, SHOW_LONG_NOFLUSH},
+ {"Host_cache_hits", (char*) &hostname_cache_metrics.hits, SHOW_LONG_NOFLUSH},
+ {"Host_cache_inserts", (char*) &hostname_cache_metrics.inserts, SHOW_LONG_NOFLUSH},
+ {"Host_cache_misses", (char*) &hostname_cache_metrics.misses, SHOW_LONG_NOFLUSH},
+ {"Host_cache_prunes", (char*) &hostname_cache_metrics.prunes, SHOW_LONG_NOFLUSH},
+ {"Host_cache_used", (char*) &hostname_cache_metrics.used, SHOW_LONG_NOFLUSH},
{"Key_blocks_not_flushed", (char*) offsetof(KEY_CACHE, global_blocks_changed), SHOW_KEY_CACHE_LONG},
{"Key_blocks_unused", (char*) offsetof(KEY_CACHE, blocks_unused), SHOW_KEY_CACHE_LONG},
{"Key_blocks_used", (char*) offsetof(KEY_CACHE, blocks_used), SHOW_KEY_CACHE_LONG},
@@ -7858,6 +7864,8 @@ void refresh_status(THD *thd)
mysql_mutex_lock(&LOCK_thread_count);
max_used_connections= thread_count-delayed_insert_threads;
mysql_mutex_unlock(&LOCK_thread_count);
+
+ hostname_cache_metrics_reset();
}
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2010-12-17 11:28:59 +0000
+++ b/sql/sql_acl.cc 2010-12-22 17:31:51 +0000
@@ -8422,7 +8422,7 @@ static ulong parse_client_handshake_pack
return packet_error;
if (mpvio->connect_errors)
- reset_host_errors(mpvio->ip);
+ hostname_cache_reset_host_errors(mpvio->ip);
ulong client_capabilities= uint2korr(net->read_pos);
if (client_capabilities & CLIENT_PROTOCOL_41)
@@ -8794,7 +8794,7 @@ static int server_mpvio_read_packet(MYSQ
err:
if (mpvio->status == MPVIO_EXT::FAILURE)
{
- inc_host_errors(mpvio->ip);
+ hostname_cache_inc_host_errors(mpvio->ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
}
DBUG_RETURN(-1);
@@ -9391,7 +9391,7 @@ static int native_password_authenticate(
CR_ERROR : CR_OK);
}
- inc_host_errors(mpvio->ip);
+ hostname_cache_inc_host_errors(mpvio->ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
DBUG_RETURN(CR_ERROR);
}
@@ -9445,7 +9445,7 @@ static int old_password_authenticate(MYS
CR_ERROR : CR_OK;
}
- inc_host_errors(mpvio->ip);
+ hostname_cache_inc_host_errors(mpvio->ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0), mpvio->auth_info.host_or_ip);
return CR_ERROR;
}
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2010-12-17 11:28:59 +0000
+++ b/sql/sql_show.cc 2010-12-22 17:31:51 +0000
@@ -53,6 +53,7 @@
#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH
#include "debug_sync.h"
#include "datadict.h" // dd_frm_type()
+#include "hostname.h"
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
@@ -7418,6 +7419,15 @@ ST_FIELD_INFO tablespaces_fields_info[]=
};
+ST_FIELD_INFO host_cache_info[]=
+{
+ {"IP_ADDRESS", 64, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE},
+ {"HOSTNAME", 64, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, NULL, SKIP_OPEN_TABLE},
+ {"ERRORS", 10, MYSQL_TYPE_LONG, 0, 0, NULL, SKIP_OPEN_TABLE},
+ {NULL, 0, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE}
+};
+
+
/*
Description of ST_FIELD_INFO in table.h
@@ -7453,6 +7463,8 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_status, make_old_format, 0, 0, -1, 0, 0},
{"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
+ {"HOST_CACHE", host_cache_info, create_schema_table,
+ hostname_cache_fill_i_s, make_old_format, 0, -1, -1, 0, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc 2010-12-17 11:28:59 +0000
+++ b/sql/sys_vars.cc 2010-12-22 17:31:51 +0000
@@ -45,6 +45,7 @@
// mysql_user_table_is_in_short_password_format
#include "derror.h" // read_texts
#include "sql_base.h" // close_cached_tables
+#include "hostname.h" // host_cache_size, hostname_cache_resize
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
#include "../storage/perfschema/pfs_server.h"
@@ -3224,3 +3225,19 @@ static Sys_var_tz Sys_time_zone(
SESSION_VAR(time_zone), NO_CMD_LINE,
DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
+
+static bool fix_host_cache_size(sys_var *self, THD *thd, enum_var_type type)
+{
+ hostname_cache_resize((uint) host_cache_size);
+ return false;
+}
+
+
+static Sys_var_ulong Sys_host_cache_size(
+ "host_cache_size",
+ "How many hostnames should be cached to avoid resolving.",
+ GLOBAL_VAR(host_cache_size),
+ CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 2048),
+ DEFAULT(HOST_CACHE_SIZE),
+ BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL), ON_UPDATE(fix_host_cache_size));
Attachment: [text/bzr-bundle] bzr/georgi.kodinov@oracle.com-20101222173151-ezl6g8r1wrx4fivr.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-wl5259 branch (Georgi.Kodinov:3446) WL#5259 | Georgi Kodinov | 22 Dec |