diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_myisam.cc | 131 | ||||
-rw-r--r-- | sql/ha_myisam.h | 1 | ||||
-rw-r--r-- | sql/ha_myisammrg.cc | 6 | ||||
-rw-r--r-- | sql/handler.cc | 72 | ||||
-rw-r--r-- | sql/handler.h | 7 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 98 | ||||
-rw-r--r-- | sql/opt_range.cc | 15 | ||||
-rw-r--r-- | sql/set_var.cc | 221 | ||||
-rw-r--r-- | sql/set_var.h | 72 | ||||
-rw-r--r-- | sql/sql_base.cc | 131 | ||||
-rw-r--r-- | sql/sql_lex.cc | 33 | ||||
-rw-r--r-- | sql/sql_lex.h | 14 | ||||
-rw-r--r-- | sql/sql_parse.cc | 17 | ||||
-rw-r--r-- | sql/sql_table.cc | 106 | ||||
-rw-r--r-- | sql/sql_test.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 68 | ||||
-rw-r--r-- | sql/table.h | 34 |
19 files changed, 906 insertions, 136 deletions
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index a23e4c55618..6c46fc141f3 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -228,6 +228,12 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) { if (!(file=mi_open(name, mode, test_if_locked))) return (my_errno ? my_errno : -1); + + /* Synchronize key cache assignment of the handler */ + KEY_CACHE_VAR *key_cache= table->key_cache ? table->key_cache : + &dflt_key_cache_var; + VOID(mi_extra(file, HA_EXTRA_SET_KEY_CACHE, + (void*) &key_cache->cache)); if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE)) VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0)); @@ -692,6 +698,131 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) /* + Assign table indexes to a key cache. +*/ + +int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) +{ + uint len; + KEY_CACHE_VAR *old_key_cache; + KEY_CACHE_VAR *new_key_cache; + const char *errmsg=0; + int error= HA_ADMIN_OK; + ulonglong map= ~(ulonglong) 0; + TABLE_LIST *table_list= table->pos_in_table_list; + const char *new_key_cache_name= table_list->option ? + (const char *) table_list->option : + DEFAULT_KEY_CACHE_NAME; + KEY_CACHE_ASMT *key_cache_asmt= table->key_cache_asmt; + bool triggered= key_cache_asmt->triggered; + + DBUG_ENTER("ha_myisam::assign_to_keycache"); + + VOID(pthread_mutex_lock(&LOCK_assign)); + + old_key_cache= key_cache_asmt->key_cache; + + /* Check validity of the index references */ + if (!triggered && table_list->use_index) + { + key_map kmap= get_key_map_from_key_list(table, table_list->use_index); + if (kmap == ~(key_map) 0) + { + errmsg= thd->net.last_error; + error= HA_ADMIN_FAILED; + goto err; + } + if (kmap) + map= kmap; + } + + len= strlen(new_key_cache_name); + new_key_cache= get_or_create_key_cache(new_key_cache_name, len); + if (old_key_cache == new_key_cache) + { + /* Nothing to do: table is assigned to the same key cache */ + goto ok; + } + + if (!new_key_cache || + (!new_key_cache->cache && ha_key_cache(new_key_cache))) + { + if (key_cache_asmt->triggered) + error= HA_ERR_OUT_OF_MEM; + else + { + char buf[ERRMSGSIZE]; + my_snprintf(buf, ERRMSGSIZE, + "Failed to create key cache %s", new_key_cache_name); + errmsg= buf; + error= HA_ADMIN_FAILED; + } + goto err; + } + + reassign_key_cache(key_cache_asmt, new_key_cache); + + VOID(pthread_mutex_unlock(&LOCK_assign)); + error= mi_assign_to_keycache(file, map, new_key_cache, &LOCK_assign); + VOID(pthread_mutex_lock(&LOCK_assign)); + + if (error && !key_cache_asmt->triggered) + { + switch (error) { + default: + char buf[ERRMSGSIZE+20]; + my_snprintf(buf, ERRMSGSIZE, + "Failed to flush to index file (errno: %d)", my_errno); + errmsg= buf; + } + error= HA_ADMIN_CORRUPT; + goto err; + } + + goto ok; + + err: + if (!triggered) + { + MI_CHECK param; + myisamchk_init(¶m); + param.thd= thd; + param.op_name= (char*)"assign_to_keycache"; + param.db_name= table->table_cache_key; + param.table_name= table->table_name; + param.testflag= 0; + mi_check_print_error(¶m, errmsg); + } + + ok: + if (--key_cache_asmt->requests) + { + /* There is a queue of assignments for the table */ + + /* Remove the first member from the queue */ + struct st_my_thread_var *last= key_cache_asmt->queue; + struct st_my_thread_var *thread= last->next; + if (thread->next == thread) + key_cache_asmt->queue= 0; + else + { + last->next= thread->next; + last->next->prev= &last->next; + thread->next= 0; + } + /* Signal the first waiting thread to proceed */ + VOID(pthread_cond_signal(&thread->suspend)); + } + + key_cache_asmt->triggered= 0; + + VOID(pthread_mutex_unlock(&LOCK_assign)); + + DBUG_RETURN(error); +} + + +/* Preload pages of the index file for a table into the key cache. */ diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 38dce25d1fb..e6297373fea 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -127,6 +127,7 @@ class ha_myisam: public handler int optimize(THD* thd, HA_CHECK_OPT* check_opt); int restore(THD* thd, HA_CHECK_OPT* check_opt); int backup(THD* thd, HA_CHECK_OPT* check_opt); + int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt); int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); #ifdef HAVE_REPLICATION int dump(THD* thd, int fd); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 42c2ba10808..05da214c1d4 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -45,6 +45,12 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno)); return (my_errno ? my_errno : -1); } + /* Synchronize key cache assignment for the file */ + KEY_CACHE_VAR *key_cache= table->key_cache ? table->key_cache : + &dflt_key_cache_var; + VOID(myrg_extra(file, HA_EXTRA_SET_KEY_CACHE, + (void*) &key_cache->cache)); + DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")) myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || diff --git a/sql/handler.cc b/sql/handler.cc index a8e9f9cf50a..28f399818c4 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -736,6 +736,11 @@ int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt) return HA_ADMIN_NOT_IMPLEMENTED; } +int handler::assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt) +{ + return HA_ADMIN_NOT_IMPLEMENTED; +} + int handler::preload_keys(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; @@ -1102,27 +1107,62 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, /* Use key cacheing on all databases */ -void ha_key_cache(void) +int ha_key_cache(KEY_CACHE_VAR *key_cache) { - /* - The following mutex is not really needed as long as keybuff_size is - treated as a long value, but we use the mutex here to guard for future - changes. - */ - pthread_mutex_lock(&LOCK_global_system_variables); - long tmp= (long) keybuff_size; - pthread_mutex_unlock(&LOCK_global_system_variables); - if (tmp) - (void) init_key_cache(tmp); + if (!key_cache->cache) + { + /* + The following mutex is not really needed as long as keybuff_size is + treated as a long value, but we use the mutex here to guard for future + changes. + */ + pthread_mutex_lock(&LOCK_global_system_variables); + if (!key_cache->block_size) + key_cache->block_size= dflt_key_cache_block_size; + if (!key_cache->buff_size) + key_cache->buff_size= dflt_key_buff_size; + long tmp_buff_size= (long) key_cache->buff_size; + long tmp_block_size= (long) key_cache->block_size; + pthread_mutex_unlock(&LOCK_global_system_variables); + return !init_key_cache(&key_cache->cache, + tmp_block_size, + tmp_buff_size, + key_cache); + } + return 0; } +int ha_resize_key_cache(KEY_CACHE_VAR *key_cache) +{ + if (key_cache->cache) + { + pthread_mutex_lock(&LOCK_global_system_variables); + long tmp_buff_size= (long) key_cache->buff_size; + long tmp_block_size= (long) key_cache->block_size; + pthread_mutex_unlock(&LOCK_global_system_variables); + return !resize_key_cache(&key_cache->cache, tmp_block_size, + tmp_buff_size); + } + return 0; +} + +int ha_change_key_cache_param(KEY_CACHE_VAR *key_cache) +{ + if (key_cache->cache) + { + change_key_cache_param(key_cache->cache); + } + return 0; +} -void ha_resize_key_cache(void) +int ha_end_key_cache(KEY_CACHE_VAR *key_cache) { - pthread_mutex_lock(&LOCK_global_system_variables); - long tmp= (long) keybuff_size; - pthread_mutex_unlock(&LOCK_global_system_variables); - (void) resize_key_cache(tmp); + if (key_cache->cache) + { + end_key_cache(&key_cache->cache, 1); + return key_cache->cache ? 1 : 0; + } + return 0; } diff --git a/sql/handler.h b/sql/handler.h index 29dea7f213b..c24bf777f01 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -306,6 +306,7 @@ public: virtual bool check_and_repair(THD *thd) {return 1;} virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt); virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt); + virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt); virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); /* @@ -389,8 +390,10 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, bool update_create_info); int ha_delete_table(enum db_type db_type, const char *path); void ha_drop_database(char* path); -void ha_key_cache(void); -void ha_resize_key_cache(void); +int ha_key_cache(KEY_CACHE_VAR *key_cache); +int ha_resize_key_cache(KEY_CACHE_VAR *key_cache); +int ha_change_key_cache_param(KEY_CACHE_VAR *key_cache); +int ha_end_key_cache(KEY_CACHE_VAR *key_cache); int ha_start_stmt(THD *thd); int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, my_off_t end_offset); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 41e7060335c..28ba6199bee 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -245,7 +245,7 @@ public: longlong val_int(); enum Functype functype() const { return NE_FUNC; } cond_result eq_cmp_result() const { return COND_FALSE; } - optimize_type select_optimize() const { return OPTIMIZE_NONE; } + optimize_type select_optimize() const { return OPTIMIZE_KEY; } const char *func_name() const { return "<>"; } }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 980d85b4b80..f7b12bd959c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -424,6 +424,10 @@ bool check_stack_overrun(THD *thd,char *dummy); void table_cache_init(void); void table_cache_free(void); uint cached_tables(void); +void assign_cache_init(void); +void assign_cache_free(void); +void reassign_key_cache(KEY_CACHE_ASMT *key_cache_asmt, + KEY_CACHE_VAR *new_key_cache); void kill_mysql(void); void close_connection(THD *thd, uint errcode, bool lock); bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, @@ -453,7 +457,10 @@ int mysql_analyze_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); +int mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list); int mysql_preload_keys(THD* thd, TABLE_LIST* table_list); +int reassign_keycache_tables(THD* thd, KEY_CACHE_VAR* src_cache, + char *dest_name, bool remove_fl); bool check_simple_select(); @@ -826,7 +833,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, - LOCK_global_system_variables, LOCK_user_conn; + LOCK_global_system_variables, LOCK_user_conn, LOCK_assign; extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 15e51d34138..fafc67e059d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -307,8 +307,6 @@ ulong rpl_recovery_rank=0; ulong my_bind_addr; /* the address we bind to */ volatile ulong cached_thread_count= 0; -ulonglong keybuff_size; - double log_10[32]; /* 10 potences */ time_t start_time; @@ -371,6 +369,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, + LOCK_assign, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; rw_lock_t LOCK_grant; pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped, @@ -897,6 +896,7 @@ void clean_up(bool print_message) #endif query_cache_destroy(); table_cache_free(); + assign_cache_free(); hostname_cache_free(); item_user_lock_free(); lex_free(); /* Free some memory */ @@ -906,7 +906,8 @@ void clean_up(bool print_message) udf_free(); #endif (void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */ - end_key_cache(); + process_key_caches(&ha_end_key_cache); + ha_end_key_cache(&dflt_key_cache_var); delete_elements(&key_caches, free_key_cache); end_thr_alarm(1); /* Free allocated memory */ #ifdef USE_RAID @@ -989,6 +990,7 @@ static void clean_up_mutexes() #endif (void) pthread_mutex_destroy(&LOCK_active_mi); (void) pthread_mutex_destroy(&LOCK_global_system_variables); + (void) pthread_mutex_destroy(&LOCK_assign); (void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_thread_cache); @@ -1558,14 +1560,15 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n", We will try our best to scrape up some info that will hopefully help diagnose\n\ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size); + fprintf(stderr, "key_buffer_size=%lu\n", + (ulong) dflt_key_cache_var.buff_size); fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size); fprintf(stderr, "max_used_connections=%ld\n", max_used_connections); fprintf(stderr, "max_connections=%ld\n", max_connections); fprintf(stderr, "threads_connected=%d\n", thread_count); fprintf(stderr, "It is possible that mysqld could use up to \n\ key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\ -bytes of memory\n", ((ulong) keybuff_size + +bytes of memory\n", ((ulong) dflt_key_cache_var.buff_size + (global_system_variables.read_buff_size + global_system_variables.sortbuff_size) * max_connections)/ 1024); @@ -2186,6 +2189,7 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_assign, MY_MUTEX_INIT_FAST); (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); @@ -2237,6 +2241,7 @@ static int init_server_components() { DBUG_ENTER("init_server_components"); table_cache_init(); + assign_cache_init(); hostname_cache_init(); query_cache_result_size_limit(query_cache_limit); query_cache_set_min_res_unit(query_cache_min_res_unit); @@ -2307,7 +2312,10 @@ Now disabling --log-slave-updates."); } if (opt_myisam_log) (void) mi_log(1); - ha_key_cache(); + + ha_key_cache(&dflt_key_cache_var); + process_key_caches(&ha_key_cache); + #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) if (locked_in_memory && !geteuid()) @@ -3573,7 +3581,9 @@ enum options_mysqld OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN, OPT_FT_MAX_WORD_LEN, OPT_FT_QUERY_EXPANSION_LIMIT, OPT_FT_STOPWORD_FILE, OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE, - OPT_KEY_BUFFER_SIZE, OPT_LONG_QUERY_TIME, + OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE, + OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD, + OPT_LONG_QUERY_TIME, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, @@ -4286,10 +4296,26 @@ replicating a LOAD DATA INFILE command.", IO_SIZE, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", - (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, + (gptr*) &dflt_key_cache_var.buff_size, + (gptr*) &dflt_key_cache_var.buff_size, 0, (enum get_opt_var_type) (GET_ULL | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE, 0}, + {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, + "The default size of key cache blocks", + (gptr*) &dflt_key_cache_var.block_size, + (gptr*) &dflt_key_cache_var.block_size, 0, GET_ULONG, + REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE , 512, 1024*16, MALLOC_OVERHEAD, 512, 0}, + {"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT, + "The minimum percentage of warm blocks in key cache", + (gptr*) &dflt_key_cache_var.division_limit, + (gptr*) &dflt_key_cache_var.division_limit, 0, GET_ULONG, + REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, + {"key_cache_division_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, + "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", + (gptr*) &dflt_key_cache_var.age_threshold, + (gptr*) &dflt_key_cache_var.age_threshold, 0, GET_ULONG, + REQUIRED_ARG, 300, 100, ~0L, 0, 100, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", (gptr*) &global_system_variables.long_query_time, @@ -4707,13 +4733,19 @@ struct show_var_st status_vars[]= { {"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG}, {"Handler_update", (char*) &ha_update_count, SHOW_LONG}, {"Handler_write", (char*) &ha_write_count, SHOW_LONG}, - {"Key_blocks_used", (char*) &my_blocks_used, SHOW_LONG_CONST}, - {"Key_read_requests", (char*) &my_cache_r_requests, SHOW_LONG}, - {"Key_reads", (char*) &my_cache_read, SHOW_LONG}, - {"Key_write_requests", (char*) &my_cache_w_requests, SHOW_LONG}, - {"Key_writes", (char*) &my_cache_write, SHOW_LONG}, + {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used, + SHOW_LONG_CONST}, + {"Key_read_requests", (char*) &dflt_key_cache_var.cache_r_requests, + SHOW_LONG}, + {"Key_reads", (char*) &dflt_key_cache_var.cache_read, + SHOW_LONG}, + {"Key_write_requests", (char*) &dflt_key_cache_var.cache_w_requests, + SHOW_LONG}, + {"Key_writes", (char*) &dflt_key_cache_var.cache_write, + SHOW_LONG}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, - {"Not_flushed_key_blocks", (char*) &my_blocks_changed, SHOW_LONG_CONST}, + {"Not_flushed_key_blocks", (char*) &dflt_key_cache_var.blocks_changed, + SHOW_LONG_CONST}, {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST}, {"Open_tables", (char*) 0, SHOW_OPENTABLES}, {"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST}, @@ -4925,7 +4957,8 @@ static void mysql_init_variables(void) threads.empty(); thread_cache.empty(); key_caches.empty(); - if (!get_or_create_key_cache("default", 7)) + if (!get_or_create_key_cache(DEFAULT_KEY_CACHE_NAME, + strlen(DEFAULT_KEY_CACHE_NAME))) exit(1); /* Initialize structures that is used when processing options */ @@ -5551,21 +5584,28 @@ extern "C" gptr * mysql_getopt_value(const char *keyname, uint key_length, const struct my_option *option) { - if (!key_length) - { - keyname= "default"; - key_length= 7; - } switch (option->id) { case OPT_KEY_BUFFER_SIZE: + case OPT_KEY_CACHE_BLOCK_SIZE: + case OPT_KEY_CACHE_DIVISION_LIMIT: + case OPT_KEY_CACHE_AGE_THRESHOLD: { - KEY_CACHE *key_cache; + KEY_CACHE_VAR *key_cache; if (!(key_cache= get_or_create_key_cache(keyname, key_length))) exit(1); - return (gptr*) &key_cache->size; + switch (option->id) { + case OPT_KEY_BUFFER_SIZE: + return (gptr*) &key_cache->buff_size; + case OPT_KEY_CACHE_BLOCK_SIZE: + return (gptr*) &key_cache->block_size; + case OPT_KEY_CACHE_DIVISION_LIMIT: + return (gptr*) &key_cache->division_limit; + case OPT_KEY_CACHE_AGE_THRESHOLD: + return (gptr*) &key_cache->age_threshold; + } } } - return option->value; + return option->value; } @@ -5629,16 +5669,16 @@ static void get_options(int argc,char **argv) table_alias_charset= (lower_case_table_names ? files_charset_info : &my_charset_bin); - /* QQ To be deleted when we have key cache variables in a struct */ - { - NAMED_LIST *not_used; - keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7, - ¬_used))->size); - } if (opt_short_log_format) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; if (opt_log_queries_not_using_indexes) opt_specialflag|= SPECIAL_LOG_QUERIES_NOT_USING_INDEXES; + /* Set up default values for a key cache */ + KEY_CACHE_VAR *key_cache= &dflt_key_cache_var; + dflt_key_cache_block_size= key_cache->block_size; + dflt_key_buff_size= key_cache->buff_size; + dflt_key_cache_division_limit= key_cache->division_limit; + dflt_key_cache_age_threshold= key_cache->age_threshold; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index aa216849d76..e2761832e65 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -905,10 +905,17 @@ static SEL_TREE * get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, Item *value, Item_result cmp_type) { + bool ne_func= FALSE; DBUG_ENTER("get_mm_parts"); if (field->table != param->table) DBUG_RETURN(0); + if (type == Item_func::NE_FUNC) + { + ne_func= TRUE; + type= Item_func::LT_FUNC; + } + KEY_PART *key_part = param->key_parts; KEY_PART *end = param->key_parts_end; SEL_TREE *tree=0; @@ -943,6 +950,14 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); } } + + if (ne_func) + { + SEL_TREE *tree2= get_mm_parts(param, field, Item_func::GT_FUNC, + value, cmp_type); + if (tree2) + tree= tree_or(param,tree,tree2); + } DBUG_RETURN(tree); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 327bcb1a223..57076bec603 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -60,6 +60,11 @@ #include "ha_innodb.h" #endif +ulonglong dflt_key_buff_size; +uint dflt_key_cache_block_size; +uint dflt_key_cache_division_limit; +uint dflt_key_cache_age_threshold; + static HASH system_variable_hash; const char *bool_type_names[]= { "OFF", "ON", NullS }; TYPELIB bool_typelib= @@ -92,7 +97,7 @@ static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); static void fix_max_connections(THD *thd, enum_var_type type); -static KEY_CACHE *create_key_cache(const char *name, uint length); +static KEY_CACHE_VAR *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); @@ -143,6 +148,11 @@ sys_var_thd_ulong sys_interactive_timeout("interactive_timeout", sys_var_thd_ulong sys_join_buffer_size("join_buffer_size", &SV::join_buff_size); sys_var_key_buffer_size sys_key_buffer_size("key_buffer_size"); +sys_var_key_cache_block_size sys_key_cache_block_size("key_cache_block_size"); +sys_var_key_cache_division_limit + sys_key_cache_division_limit("key_cache_division_limit"); +sys_var_key_cache_age_threshold + sys_key_cache_age_threshold("key_cache_age_threshold"); sys_var_bool_ptr sys_local_infile("local_infile", &opt_local_infile); sys_var_thd_bool sys_log_warnings("log_warnings", &SV::log_warnings); @@ -422,6 +432,9 @@ sys_var *sys_variables[]= &sys_interactive_timeout, &sys_join_buffer_size, &sys_key_buffer_size, + &sys_key_cache_block_size, + &sys_key_cache_division_limit, + &sys_key_cache_age_threshold, &sys_last_insert_id, &sys_local_infile, &sys_log_binlog, @@ -595,6 +608,12 @@ struct show_var_st init_vars[]= { {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, {sys_key_buffer_size.name, (char*) &sys_key_buffer_size, SHOW_SYS}, + {sys_key_cache_block_size.name, (char*) &sys_key_cache_block_size, + SHOW_SYS}, + {sys_key_cache_division_limit.name, (char*) &sys_key_cache_division_limit, + SHOW_SYS}, + {sys_key_cache_age_threshold.name, (char*) &sys_key_cache_age_threshold, + SHOW_SYS}, {"language", language, SHOW_CHAR}, {"large_files_support", (char*) &opt_large_files, SHOW_BOOL}, {sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS}, @@ -1697,79 +1716,143 @@ void sys_var_collation_server::set_default(THD *thd, enum_var_type type) } +static LEX_STRING default_key_cache_base= {(char *) DEFAULT_KEY_CACHE_NAME, 7}; + +static KEY_CACHE_VAR zero_key_cache= + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static KEY_CACHE_VAR *get_key_cache(LEX_STRING *cache_name) +{ + if (!cache_name || !cache_name->str || !cache_name->length || + cache_name->str == default_key_cache_base.str || + (cache_name->length == default_key_cache_base.length && + !memcmp(cache_name->str, default_key_cache_base.str, + default_key_cache_base.length))) + cache_name= &default_key_cache_base; + return ((KEY_CACHE_VAR*) find_named(&key_caches, + cache_name->str, cache_name->length, + 0)); +} + +byte *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + KEY_CACHE_VAR *key_cache= get_key_cache(base); + if (!key_cache) + key_cache= &zero_key_cache; + return (byte*) key_cache + offset ; +} + bool sys_var_key_buffer_size::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; - NAMED_LIST *list; LEX_STRING *base_name= &var->base; - if (!base_name->length) - { - /* We are using SET KEY_BUFFER_SIZE=# */ - base_name->str= (char*) "default"; - base_name->length= 7; - } - KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, base_name->str, - base_name->length, &list); + base_name= &default_key_cache_base; + KEY_CACHE_VAR *key_cache= get_key_cache(base_name); + if (!key_cache) { if (!tmp) // Tried to delete cache return 0; // Ok, nothing to do if (!(key_cache= create_key_cache(base_name->str, - base_name->length))) + base_name->length))) return 1; } if (!tmp) // Zero size means delete { - /* Don't delete the default key cache */ - if (base_name->length != 7 || memcmp(base_name->str, "default", 7)) + if (!key_cache->cache) + return 0; + /* Delete not default key caches */ + if (key_cache != &dflt_key_cache_var) { /* - QQ: Here we should move tables that is using the found key cache - to the default key cache + Move tables using this key cache to the default key cache + and remove this key cache if no tables are assigned to it */ + NAMED_LIST *list; + key_cache= (KEY_CACHE_VAR *) find_named(&key_caches, base_name->str, + base_name->length, &list); delete list; + int rc= reassign_keycache_tables(thd, key_cache, + default_key_cache_base.str, 1); my_free((char*) key_cache, MYF(0)); - return 0; + return rc; + } + return 0; } - key_cache->size= (ulonglong) getopt_ull_limit_value(tmp, option_limits); + key_cache->buff_size= (ulonglong) getopt_ull_limit_value(tmp, option_limits); + + if (!key_cache->cache) + return (bool)(ha_key_cache(key_cache)); + else + return (bool)(ha_resize_key_cache(key_cache)); +} - /* QQ: Needs to be updated when we have multiple key caches */ - keybuff_size= key_cache->size; - ha_resize_key_cache(); +bool sys_var_key_cache_block_size::update(THD *thd, set_var *var) +{ + ulong tmp= var->value->val_int(); + LEX_STRING *base_name= &var->base; + if (!base_name->length) + base_name= &default_key_cache_base; + KEY_CACHE_VAR *key_cache= get_key_cache(base_name); + + if (!key_cache && !(key_cache= create_key_cache(base_name->str, + base_name->length))) + return 1; + + key_cache->block_size= (ulong) getopt_ull_limit_value(tmp, option_limits); + + if (key_cache->cache) + /* Do not build a new key cache here */ + return (bool) (ha_resize_key_cache(key_cache)); return 0; } +bool sys_var_key_cache_division_limit::update(THD *thd, set_var *var) +{ + ulong tmp= var->value->val_int(); + LEX_STRING *base_name= &var->base; + if (!base_name->length) + base_name= &default_key_cache_base; + KEY_CACHE_VAR *key_cache= get_key_cache(base_name); + + if (!key_cache && !(key_cache= create_key_cache(base_name->str, + base_name->length))) + return 1; + + key_cache->division_limit= + (ulong) getopt_ull_limit_value(tmp, option_limits); -static ulonglong zero=0; + if (key_cache->cache) + /* Do not build a new key cache here */ + return (bool) (ha_change_key_cache_param(key_cache)); + return 0; +} -byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) +bool sys_var_key_cache_age_threshold::update(THD *thd, set_var *var) { - const char *name; - uint length; - KEY_CACHE *key_cache; - NAMED_LIST *not_used; + ulong tmp= var->value->val_int(); + LEX_STRING *base_name= &var->base; + if (!base_name->length) + base_name= &default_key_cache_base; + KEY_CACHE_VAR *key_cache= get_key_cache(base_name); + + if (!key_cache && !(key_cache= create_key_cache(base_name->str, + base_name->length))) + return 1; + + key_cache->division_limit= + (ulong) getopt_ull_limit_value(tmp, option_limits); - if (!base->str) - { - name= "default"; - length= 7; - } - else - { - name= base->str; - length= base->length; - } - key_cache= (KEY_CACHE*) find_named(&key_caches, name, length, ¬_used); - if (!key_cache) - return (byte*) &zero; - return (byte*) &key_cache->size; + if (key_cache->cache) + /* Do not build a new key cache here */ + return (bool) (ha_change_key_cache_param(key_cache)); + return 0; } - /***************************************************************************** @@ -2355,7 +2438,8 @@ gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length, { if (element->cmp(name, length)) { - *found= element; + if (found) + *found= element; return element->data; } } @@ -2378,29 +2462,41 @@ void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr)) /* Key cache functions */ -static KEY_CACHE *create_key_cache(const char *name, uint length) +static KEY_CACHE_VAR *create_key_cache(const char *name, uint length) { - KEY_CACHE *key_cache; + KEY_CACHE_VAR *key_cache; DBUG_PRINT("info",("Creating key cache: %.*s length: %d", length, name, length)); - if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE), - MYF(MY_ZEROFILL | MY_WME)))) + if (length != default_key_cache_base.length || + memcmp(name, default_key_cache_base.str, length)) { - if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache)) + if ((key_cache= (KEY_CACHE_VAR*) my_malloc(sizeof(KEY_CACHE_VAR), + MYF(MY_ZEROFILL | MY_WME)))) { - my_free((char*) key_cache, MYF(0)); - key_cache= 0; + if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache)) + { + my_free((char*) key_cache, MYF(0)); + key_cache= 0; + } } } + else + { + key_cache= &dflt_key_cache_var; + if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache)) + key_cache= 0; + } + return key_cache; } -KEY_CACHE *get_or_create_key_cache(const char *name, uint length) +KEY_CACHE_VAR *get_or_create_key_cache(const char *name, uint length) { - NAMED_LIST *not_used; - KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, - length, ¬_used); + LEX_STRING key_cache_name; + key_cache_name.str= (char *) name; + key_cache_name.length= length; + KEY_CACHE_VAR *key_cache= get_key_cache(&key_cache_name); if (!key_cache) key_cache= create_key_cache(name, length); return key_cache; @@ -2409,7 +2505,22 @@ KEY_CACHE *get_or_create_key_cache(const char *name, uint length) void free_key_cache(gptr key_cache) { - my_free(key_cache, MYF(0)); + if (key_cache != (gptr) &dflt_key_cache_var) + my_free(key_cache, MYF(0)); +} + +bool process_key_caches(int (* func) (KEY_CACHE_VAR *)) +{ + + I_List_iterator<NAMED_LIST> it(key_caches); + NAMED_LIST *element; + while ((element= it++)) + { + KEY_CACHE_VAR *key_cache= (KEY_CACHE_VAR *) element->data; + if (key_cache != &dflt_key_cache_var) + func(key_cache); + } + return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index 752f275c9f2..16b2c1d5d37 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -30,6 +30,11 @@ class set_var; typedef struct system_variables SV; extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib; +extern ulonglong dflt_key_buff_size; +extern uint dflt_key_cache_block_size; +extern uint dflt_key_cache_division_limit; +extern uint dflt_key_cache_age_threshold; + enum enum_var_type { OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL @@ -546,15 +551,71 @@ public: byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; -class sys_var_key_buffer_size :public sys_var +class sys_var_key_cache_param :public sys_var { +protected: + uint offset; public: - sys_var_key_buffer_size(const char *name_arg) + sys_var_key_cache_param(const char *name_arg) :sys_var(name_arg) - {} + { + offset= 0; + } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; + +class sys_var_key_buffer_size :public sys_var_key_cache_param +{ +public: + sys_var_key_buffer_size(const char *name_arg) + :sys_var_key_cache_param(name_arg) + { + offset= offsetof(KEY_CACHE_VAR, buff_size); + } bool update(THD *thd, set_var *var); SHOW_TYPE type() { return SHOW_LONGLONG; } - byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + bool check_default(enum_var_type type) { return 1; } + bool is_struct() { return 1; } +}; + +class sys_var_key_cache_block_size :public sys_var_key_cache_param +{ +public: + sys_var_key_cache_block_size(const char *name_arg) + :sys_var_key_cache_param(name_arg) + { + offset= offsetof(KEY_CACHE_VAR, block_size); + } + bool update(THD *thd, set_var *var); + SHOW_TYPE type() { return SHOW_LONG; } + bool check_default(enum_var_type type) { return 1; } + bool is_struct() { return 1; } +}; + +class sys_var_key_cache_division_limit :public sys_var_key_cache_param +{ +public: + sys_var_key_cache_division_limit(const char *name_arg) + :sys_var_key_cache_param(name_arg) + { + offset= offsetof(KEY_CACHE_VAR, division_limit); + } + bool update(THD *thd, set_var *var); + SHOW_TYPE type() { return SHOW_LONG; } + bool check_default(enum_var_type type) { return 1; } + bool is_struct() { return 1; } +}; + +class sys_var_key_cache_age_threshold :public sys_var_key_cache_param +{ +public: + sys_var_key_cache_age_threshold(const char *name_arg) + :sys_var_key_cache_param(name_arg) + { + offset= offsetof(KEY_CACHE_VAR, age_threshold); + } + bool update(THD *thd, set_var *var); + SHOW_TYPE type() { return SHOW_LONG; } bool check_default(enum_var_type type) { return 1; } bool is_struct() { return 1; } }; @@ -785,5 +846,6 @@ gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length, void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr)); /* key_cache functions */ -KEY_CACHE *get_or_create_key_cache(const char *name, uint length); +KEY_CACHE_VAR *get_or_create_key_cache(const char *name, uint length); void free_key_cache(gptr key_cache); +bool process_key_caches(int (* func) (KEY_CACHE_VAR *)); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b151400db68..cc068451ecf 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -30,6 +30,7 @@ TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ +HASH assign_cache; static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, const char *name, const char *alias); @@ -53,7 +54,6 @@ void table_cache_init(void) mysql_rm_tmp_tables(); } - void table_cache_free(void) { DBUG_ENTER("table_cache_free"); @@ -63,7 +63,6 @@ void table_cache_free(void) DBUG_VOID_RETURN; } - uint cached_tables(void) { return open_cache.records; @@ -762,6 +761,8 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, reg1 TABLE *table; char key[MAX_DBKEY_LENGTH]; uint key_length; + KEY_CACHE_ASMT *key_cache_asmt; + KEY_CACHE_VAR *key_cache; DBUG_ENTER("open_table"); /* find a unused table in the open table cache */ @@ -802,6 +803,77 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias); DBUG_RETURN(0); } + + VOID(pthread_mutex_lock(&LOCK_assign)); + key_cache_asmt= (KEY_CACHE_ASMT*) hash_search(&assign_cache, + (byte*) key, key_length) ; + if (thd->open_options & HA_OPEN_TO_ASSIGN) + { + /* When executing a CACHE INDEX command*/ + if (key_cache_asmt) + { + if (key_cache_asmt->requests++) + { + /* Another thread are assigning this table to some key cache*/ + + /* Put the assignment request into the queue of such requests */ + struct st_my_thread_var *last; + struct st_my_thread_var *thread= thd->mysys_var; + if (! (last= key_cache_asmt->queue)) + thread->next= thread; + else + { + thread->next= last->next; + last->next= thread; + } + key_cache_asmt->queue= thread; + + /* Wait until the request can be processed */ + do + { + VOID(pthread_cond_wait(&thread->suspend, &LOCK_assign)); + } + while (thread->next); + } + } + else + { + /* + The table has not been explicitly assigned to any key cache yet; + by default it's assigned to the default key cache; + */ + + if (!(key_cache_asmt= + (KEY_CACHE_ASMT *) my_malloc(sizeof(*key_cache_asmt), + MYF(MY_WME | MY_ZEROFILL))) || + !(key_cache_asmt->db_name= my_strdup(db, MYF(MY_WME))) || + !(key_cache_asmt->table_name= my_strdup(table_name, MYF(MY_WME))) || + !(key_cache_asmt->table_key= my_memdup((const byte *) key, + key_length, MYF(MY_WME)))) + { + VOID(pthread_mutex_unlock(&LOCK_assign)); + + if (key_cache_asmt) + { + if (key_cache_asmt->db_name) + my_free((gptr) key_cache_asmt->db_name, MYF(0)); + if (key_cache_asmt->table_name) + my_free((gptr) key_cache_asmt->table_name, MYF(0)); + my_free((gptr) key_cache_asmt, MYF(0)); + } + DBUG_RETURN(NULL); + } + key_cache_asmt->key_length= key_length; + key_cache_asmt->key_cache= &dflt_key_cache_var; + VOID(my_hash_insert(&assign_cache, (byte *) key_cache_asmt)); + key_cache_asmt->requests++; + } + key_cache_asmt->to_reassign= 0; + } + + key_cache= key_cache_asmt ? key_cache_asmt->key_cache : &dflt_key_cache_var; + VOID(pthread_mutex_unlock(&LOCK_assign)); + VOID(pthread_mutex_lock(&LOCK_open)); if (!thd->open_tables) @@ -844,6 +916,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, } table->prev->next=table->next; /* Remove from unused list */ table->next->prev=table->prev; + + table->key_cache= key_cache; + table->key_cache_asmt= key_cache_asmt; } else { @@ -857,6 +932,8 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(NULL); } + table->key_cache= key_cache; + table->key_cache_asmt= key_cache_asmt; if (open_unireg_entry(thd, table,db,table_name,alias) || !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key, key_length))) @@ -875,6 +952,8 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->in_use=thd; check_unused(); + + VOID(pthread_mutex_unlock(&LOCK_open)); if (refresh) { @@ -1646,6 +1725,54 @@ bool rm_temporary_table(enum db_type base, char *path) DBUG_RETURN(error); } +static void free_assign_entry(KEY_CACHE_ASMT *key_cache_asmt) +{ + DBUG_ENTER("free_assign_entry"); + my_free((gptr) key_cache_asmt->table_key, MYF(0)); + my_free((gptr) key_cache_asmt, MYF(0)); + DBUG_VOID_RETURN; +} + +static byte *assign_cache_key(const byte *record,uint *length, + my_bool not_used __attribute__((unused))) +{ + KEY_CACHE_ASMT *entry=(KEY_CACHE_ASMT *) record; + *length=entry->key_length; + return (byte*) entry->table_key; +} + +void assign_cache_init(void) +{ + VOID(hash_init(&assign_cache, &my_charset_bin, + table_cache_size+16, 0, 0, assign_cache_key, + (hash_free_key) free_assign_entry,0)); +} + +void assign_cache_free(void) +{ + DBUG_ENTER("assign_cache_free"); + hash_free(&assign_cache); + DBUG_VOID_RETURN; +} + +void reassign_key_cache(KEY_CACHE_ASMT *key_cache_asmt, + KEY_CACHE_VAR *new_key_cache) +{ + if (key_cache_asmt->prev) + { + /* Unlink key_cache_asmt from the assignment list for the old key cache */ + if ((*key_cache_asmt->prev= key_cache_asmt->next)) + key_cache_asmt->next->prev= key_cache_asmt->prev; + } + /* Link key_cache_asmt into the assignment list for the new key cache */ + key_cache_asmt->prev= &new_key_cache->assign_list; + if ((key_cache_asmt->next= new_key_cache->assign_list)) + key_cache_asmt->next->prev= &key_cache_asmt->next; + new_key_cache->assign_list= key_cache_asmt; + + key_cache_asmt->key_cache= new_key_cache; +} + /***************************************************************************** ** find field in list or tables. if field is unqualifed and unique, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 352a79843a9..c3ff69184e6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1218,7 +1218,16 @@ TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } List<Item>* st_select_lex_node::get_item_list() { return 0; } List<String>* st_select_lex_node::get_use_index() { return 0; } List<String>* st_select_lex_node::get_ignore_index() { return 0; } - +TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, + LEX_STRING *alias, + ulong table_join_options, + thr_lock_type flags, + List<String> *use_index, + List<String> *ignore_index, + LEX_STRING *option) +{ + return 0; +} ulong st_select_lex_node::get_table_join_options() { return 0; @@ -1242,6 +1251,28 @@ bool st_select_lex::test_limit() return(0); } + + + + + + + + + + + + + + + + + + + + + + /* Interface method of table list creation for query diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7545f525082..c31420b951c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -59,7 +59,8 @@ enum enum_sql_command { SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, - SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS, + SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, + SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, @@ -257,6 +258,13 @@ public: virtual List<String>* get_use_index(); virtual List<String>* get_ignore_index(); virtual ulong get_table_join_options(); + virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, + LEX_STRING *alias, + ulong table_options, + thr_lock_type flags= TL_UNLOCK, + List<String> *use_index= 0, + List<String> *ignore_index= 0, + LEX_STRING *option= 0); virtual void set_lock_for_tables(thr_lock_type lock_type) {} friend class st_select_lex_unit; @@ -443,8 +451,8 @@ public: ulong table_options, thr_lock_type flags= TL_UNLOCK, List<String> *use_index= 0, - List<String> *ignore_index= 0); - + List<String> *ignore_index= 0, + LEX_STRING *option= 0); TABLE_LIST* get_table_list(); List<Item>* get_item_list(); List<String>* get_use_index(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b3c2b0c9274..a6c6080dd98 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1907,10 +1907,20 @@ mysql_execute_command(THD *thd) res = mysql_restore_table(thd, tables); break; } + case SQLCOM_ASSIGN_TO_KEYCACHE: + { + if (check_db_used(thd, tables) || + check_access(thd, INDEX_ACL, tables->db, + &tables->grant.privilege, 0, 0)) + goto error; + res = mysql_assign_to_keycache(thd, tables); + break; + } case SQLCOM_PRELOAD_KEYS: { if (check_db_used(thd, tables) || - check_access(thd, INDEX_ACL, tables->db, &tables->grant.privilege,0,0)) + check_access(thd, INDEX_ACL, tables->db, + &tables->grant.privilege, 0, 0)) goto error; res = mysql_preload_keys(thd, tables); break; @@ -4213,7 +4223,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ulong table_options, thr_lock_type lock_type, List<String> *use_index, - List<String> *ignore_index) + List<String> *ignore_index, + LEX_STRING *option) { register TABLE_LIST *ptr; char *alias_str; @@ -4274,7 +4285,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (ignore_index) ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index, sizeof(*ignore_index)); - + ptr->option= option ? option->str : 0; /* check that used name is unique */ if (lock_type != TL_IGNORE) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7559f2a86e2..1a2021abf90 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1613,6 +1613,112 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) /* + Assigned specified indexes for a table into key cache + + SYNOPSIS + mysql_assign_to_keycache() + thd Thread object + tables Table list (one table only) + + RETURN VALUES + 0 ok + -1 error +*/ + +int mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables) +{ + DBUG_ENTER("mysql_assign_to_keycache"); + DBUG_RETURN(mysql_admin_table(thd, tables, 0, + "assign_to_keycache", TL_READ, 0, + HA_OPEN_TO_ASSIGN, 0, + &handler::assign_to_keycache)); +} + + +/* + Reassign all tables assigned to a key cache to another key cache + + SYNOPSIS + reassign_keycache_tables() + thd Thread object + src_cache Reference to the key cache to clean up + dest_name Name of the cache to assign tables to + remove_fl Flag to destroy key cache when all tables are reassigned + + RETURN VALUES + 0 ok + -1 error +*/ + +int reassign_keycache_tables(THD* thd, KEY_CACHE_VAR* src_cache, + char *dest_name, bool remove_fl) +{ + int rc= 0; + TABLE_LIST table; + KEY_CACHE_ASMT *key_cache_asmt; + + DBUG_ENTER("reassign_keycache_tables"); + + VOID(pthread_mutex_lock(&LOCK_assign)); + for (key_cache_asmt= src_cache->assign_list ; + key_cache_asmt; + key_cache_asmt= key_cache_asmt->next) + key_cache_asmt->to_reassign = 1; + key_cache_asmt= src_cache->assign_list; + while (key_cache_asmt) + { + if (key_cache_asmt->to_reassign) + { + bool refresh; + VOID(pthread_mutex_unlock(&LOCK_assign)); + bzero((byte *) &table, sizeof(table)); + table.option= dest_name; + table.db= key_cache_asmt->db_name; + table.alias= table.real_name= key_cache_asmt->table_name; + thd->open_options|= HA_OPEN_TO_ASSIGN; + while (!(table.table=open_table(thd,table.db, + table.real_name,table.alias, + &refresh)) && refresh) ; + thd->open_options&= ~HA_OPEN_TO_ASSIGN; + if (!table.table) + DBUG_RETURN(-1); + table.table->pos_in_table_list= &table; + key_cache_asmt->triggered= 1; + rc= table.table->file->assign_to_keycache(thd, 0); + close_thread_tables(thd); + if (rc) + DBUG_RETURN(rc); + VOID(pthread_mutex_lock(&LOCK_assign)); + key_cache_asmt= src_cache->assign_list; + continue; + } + else + key_cache_asmt= key_cache_asmt->next; + } + + while (src_cache->assignments) + { + struct st_my_thread_var *waiting_thread= my_thread_var; + pthread_cond_wait(&waiting_thread->suspend, &LOCK_assign); + } + if (src_cache->extra_info) + { + my_free((char *) src_cache->extra_info, MYF(0)); + src_cache->extra_info= 0; + } + + if (remove_fl && !src_cache->assign_list && src_cache != &dflt_key_cache_var) + { + end_key_cache(&src_cache->cache, 1); + src_cache->buff_size= 0; + src_cache->block_size= 0; + } + VOID(pthread_mutex_unlock(&LOCK_assign)); + DBUG_RETURN(0); +} + + +/* Preload specified indexes for a table into key cache SYNOPSIS diff --git a/sql/sql_test.cc b/sql/sql_test.cc index d8d6d716abe..7e3513367fd 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -323,8 +323,9 @@ w_requests: %10lu\n\ writes: %10lu\n\ r_requests: %10lu\n\ reads: %10lu\n", - my_blocks_used,my_blocks_changed,my_cache_w_requests, - my_cache_write,my_cache_r_requests,my_cache_read); + dflt_key_cache_var.blocks_used,dflt_key_cache_var.blocks_changed, + dflt_key_cache_var.cache_w_requests,dflt_key_cache_var.cache_write, + dflt_key_cache_var.cache_r_requests,dflt_key_cache_var.cache_read); pthread_mutex_unlock(&THR_LOCK_keycache); if (thd) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ce8df77cde..00277759763 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -685,12 +685,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type <NONE> query verb_clause create change select do drop insert replace insert2 insert_values update delete truncate rename - show describe load alter optimize preload flush + show describe load alter optimize keycache preload flush reset purge begin commit rollback savepoint slave master_def master_defs master_file_def repair restore backup analyze check start checksum field_list field_list_item field_spec kill column_def key_def - preload_list preload_keys + keycache_list assign_to_keycache preload_list preload_keys select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item @@ -762,6 +762,7 @@ verb_clause: | load | lock | optimize + | keycache | preload | purge | rename @@ -1986,6 +1987,45 @@ table_to_table: YYABORT; }; +keycache: + CACHE_SYM INDEX + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_ASSIGN_TO_KEYCACHE; + } + keycache_list + {} + ; + +keycache_list: + assign_to_keycache + | keycache_list ',' assign_to_keycache; + +assign_to_keycache: + table_ident cache_keys_spec IN_SYM ident + { + LEX *lex=Lex; + SELECT_LEX *sel= &lex->select_lex; + if (!sel->add_table_to_list(lex->thd, $1, NULL, 0, + TL_READ, + sel->get_use_index(), + (List<String> *)0, + &($4))) + YYABORT; + } + | + table_ident cache_keys_spec IN_SYM DEFAULT + { + LEX *lex=Lex; + SELECT_LEX *sel= &lex->select_lex; + if (!sel->add_table_to_list(lex->thd, $1, NULL, 0, + TL_READ, + sel->get_use_index(), + (List<String> *)0)) + YYABORT; + } + ; + preload: LOAD INDEX INTO CACHE_SYM { @@ -2001,7 +2041,7 @@ preload_list: | preload_list ',' preload_keys; preload_keys: - table_ident preload_keys_spec opt_ignore_leaves + table_ident cache_keys_spec opt_ignore_leaves { LEX *lex=Lex; SELECT_LEX *sel= &lex->select_lex; @@ -2013,18 +2053,18 @@ preload_keys: } ; -preload_keys_spec: - keys_or_index { Select->interval_list.empty(); } - preload_key_list_or_empty - { - LEX *lex=Lex; - SELECT_LEX *sel= &lex->select_lex; - sel->use_index= sel->interval_list; - sel->use_index_ptr= &sel->use_index; - } - ; +cache_keys_spec: + keys_or_index { Select->interval_list.empty(); } + cache_key_list_or_empty + { + LEX *lex=Lex; + SELECT_LEX *sel= &lex->select_lex; + sel->use_index= sel->interval_list; + sel->use_index_ptr= &sel->use_index; + } + ; -preload_key_list_or_empty: +cache_key_list_or_empty: /* empty */ | '(' key_usage_list2 ')' {} ; diff --git a/sql/table.h b/sql/table.h index 7b4e5745732..b9c6a72bb09 100644 --- a/sql/table.h +++ b/sql/table.h @@ -55,6 +55,31 @@ typedef struct st_filesort_info ha_rows found_records; /* How many records in sort */ } FILESORT_INFO; + +/* Table key cache assignment descriptor */ +/* + In future the similar structure is to be used for + an assignment of an index to a key cache: the index name will be added. + The name of the database catalog will be added as well. + The descriptors for the current assignments are put in the + assignment cache: assign_cache. If a table is not found in the cache + it is considered assigned to the default key cache. +*/ +typedef struct st_key_cache_asmt +{ + char *db_name; /* db the table belongs to */ + char *table_name; /* the name of the table */ + char *table_key; /* key for the assignment cache */ + uint key_length; /* the length of this key */ + struct st_key_cache_var *key_cache; /* reference to the key cache */ + struct st_key_cache_asmt **prev; /* links in the chain all assignments */ + struct st_key_cache_asmt *next; /* to this cache */ + struct st_my_thread_var *queue; /* queue of requests for assignment */ + uint requests; /* number of current requests */ + bool to_reassign; /* marked when reassigning all cache */ + bool triggered; /* marked when assignment is triggered*/ +} KEY_CACHE_ASMT; + /* Table cache entry struct */ class Field_timestamp; @@ -62,11 +87,13 @@ class Field_blob; struct st_table { handler *file; - Field **field; /* Pointer to fields */ + KEY_CACHE_VAR *key_cache; /* Ref to the key cache the table assigned to*/ + KEY_CACHE_ASMT *key_cache_asmt;/* Only when opened for key cache assignment */ + Field **field; /* Pointer to fields */ Field_blob **blob_field; /* Pointer to blob fields */ HASH name_hash; /* hash of field names */ byte *record[2]; /* Pointer to records */ - byte *default_values; /* record with default values for INSERT */ + byte *default_values; /* Record with default values for INSERT */ byte *insert_values; /* used by INSERT ... UPDATE */ uint fields; /* field count */ uint reclength; /* Recordlength */ @@ -161,6 +188,7 @@ typedef struct st_table_list { struct st_table_list *next; char *db, *alias, *real_name; + char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ struct st_table_list *natural_join; /* natural join on this table*/ /* ... join ... USE INDEX ... IGNORE INDEX */ @@ -192,3 +220,5 @@ typedef struct st_open_table_list char *db,*table; uint32 in_use,locked; } OPEN_TABLE_LIST; + + |