diff options
author | unknown <igor@rurik.mysql.com> | 2003-06-12 04:29:02 -0700 |
---|---|---|
committer | unknown <igor@rurik.mysql.com> | 2003-06-12 04:29:02 -0700 |
commit | f7aed0240511510dfe51083bd7ff12482d8716bc (patch) | |
tree | 0a5a6a2ab9cef24b378ef32a9096714667680cc5 | |
parent | 767f0a9f0e124667275a3a4f4a4874974444b842 (diff) | |
download | mariadb-git-f7aed0240511510dfe51083bd7ff12482d8716bc.tar.gz |
Many files:
New feature: preload indexes into key cache.
mi_preload.c:
new file
Many files:
Added preload statement.
sql/ha_myisam.h:
Added preload statement.
sql/handler.cc:
Added preload statement.
sql/lex.h:
Added preload statement.
sql/mysql_priv.h:
Added preload statement.
sql/sql_lex.h:
Added preload statement.
sql/sql_base.cc:
Added preload statement.
sql/sql_table.cc:
New feature: preload indexes into key cache.
sql/sql_parse.cc:
New feature: preload indexes into key cache.
sql/mysqld.cc:
New feature: preload indexes into key cache.
sql/set_var.cc:
New feature: preload indexes into key cache.
sql/sql_yacc.yy:
New feature: preload indexes into key cache.
sql/ha_myisam.cc:
New feature: preload indexes into key cache.
sql/table.h:
New feature: preload indexes into key cache.
mysys/mf_keycache.c:
New feature: preload indexes into key cache.
myisam/myisamdef.h:
New feature: preload indexes into key cache.
myisam/mi_extra.c:
New feature: preload indexes into key cache.
myisam/Makefile.am:
New feature: preload indexes into key cache.
include/my_base.h:
New feature: preload indexes into key cache.
include/my_sys.h:
New feature: preload indexes into key cache.
include/myisam.h:
New feature: preload indexes into key cache.
-rw-r--r-- | include/my_base.h | 4 | ||||
-rw-r--r-- | include/my_sys.h | 2 | ||||
-rw-r--r-- | include/myisam.h | 1 | ||||
-rw-r--r-- | myisam/Makefile.am | 1 | ||||
-rw-r--r-- | myisam/mi_extra.c | 3 | ||||
-rw-r--r-- | myisam/mi_preload.c | 118 | ||||
-rw-r--r-- | myisam/myisamdef.h | 1 | ||||
-rw-r--r-- | mysys/mf_keycache.c | 80 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 66 | ||||
-rw-r--r-- | sql/ha_myisam.h | 1 | ||||
-rw-r--r-- | sql/handler.cc | 5 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 5 | ||||
-rw-r--r-- | sql/mysqld.cc | 6 | ||||
-rw-r--r-- | sql/set_var.cc | 4 | ||||
-rw-r--r-- | sql/sql_base.cc | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 10 | ||||
-rw-r--r-- | sql/sql_table.cc | 23 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 61 | ||||
-rw-r--r-- | sql/table.h | 1 |
23 files changed, 395 insertions, 9 deletions
diff --git a/include/my_base.h b/include/my_base.h index b806436fe0e..167c062deb5 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -123,7 +123,8 @@ enum ha_extra_function { HA_EXTRA_NO_IGNORE_DUP_KEY, HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */ HA_EXTRA_PREPARE_FOR_DELETE, - HA_EXTRA_PREPARE_FOR_UPDATE /* Remove read cache if problems */ + HA_EXTRA_PREPARE_FOR_UPDATE, /* Remove read cache if problems */ + HA_EXTRA_PRELOAD_BUFFER_SIZE /* Set buffer size for preloading */ }; /* The following is parameter to ha_panic() */ @@ -255,6 +256,7 @@ enum ha_base_keytype { #define HA_ERR_CANNOT_ADD_FOREIGN 150 /* Cannot add a foreign key constr. */ #define HA_ERR_NO_REFERENCED_ROW 151 /* Cannot add a child row */ #define HA_ERR_ROW_IS_REFERENCED 152 /* Cannot delete a parent row */ +#define HA_ERR_NON_UNIQUE_BLOCK_SIZE 153 /* Non unique key block size */ /* Other constants */ diff --git a/include/my_sys.h b/include/my_sys.h index 86ca6ec6a1f..75a7627dc07 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -644,6 +644,8 @@ extern int init_key_cache(ulong use_mem); extern int resize_key_cache(ulong use_mem); extern byte *key_cache_read(File file,my_off_t filepos,byte* buff,uint length, uint block_length,int return_buffer); +extern int key_cache_insert(File file, my_off_t filepos, + byte *buff, uint length); extern int key_cache_write(File file,my_off_t filepos,byte* buff,uint length, uint block_length,int force_write); extern int flush_key_blocks(int file, enum flush_type type); diff --git a/include/myisam.h b/include/myisam.h index 33aa6aa3f31..e85d3057672 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -410,6 +410,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map, int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows); void mi_flush_bulk_insert(MI_INFO *info, uint inx); void mi_end_bulk_insert(MI_INFO *info); +int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves); #ifdef __cplusplus } diff --git a/myisam/Makefile.am b/myisam/Makefile.am index f8225868d96..d4cd953ac66 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -47,6 +47,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_range.c mi_dbug.c mi_checksum.c mi_log.c \ mi_changed.c mi_static.c mi_delete_all.c \ mi_delete_table.c mi_rename.c mi_check.c \ + mi_preload.c \ ft_parser.c ft_stopwords.c ft_static.c \ ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c \ rt_index.c rt_key.c rt_mbr.c rt_split.c sp_key.c diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 75057dd4e6a..4b71f3a867b 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -367,6 +367,9 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (!share->state.header.uniques) info->opt_flag|= OPT_NO_ROWS; break; + case HA_EXTRA_PRELOAD_BUFFER_SIZE: + info->preload_buff_size= *((ulong *) extra_arg); + break; case HA_EXTRA_KEY_CACHE: case HA_EXTRA_NO_KEY_CACHE: default: diff --git a/myisam/mi_preload.c b/myisam/mi_preload.c new file mode 100644 index 00000000000..be45be66ecf --- /dev/null +++ b/myisam/mi_preload.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Preload indexes into key cache +*/ + +#include "myisamdef.h" + + +/* + Preload pages of the index file for a table into the key cache + + SYNOPSIS + mi_preload() + info open table + map map of indexes to preload into key cache + ignore_leaves only non-leaves pages are to be preloaded + + RETURN VALUE + 0 if a success. error code - otherwise. + + NOTES. + At present pages for all indexes are preloaded. + In future only pages for indexes specified in the key_map parameter + of the table will be preloaded. +*/ + +int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves) +{ + uint i; + uint length; + uint block_length= 0; + uchar *buff= NULL; + MYISAM_SHARE* share= info->s; + uint keys= share->state.header.keys; + MI_KEYDEF *keyinfo= share->keyinfo; + my_off_t key_file_length= share->state.state.key_file_length; + my_off_t pos= share->base.keystart; + + if (!keys || !key_map || key_file_length == pos) + return 0; + + block_length= keyinfo[0].block_length; + + if (!key_map) + return 0; + + /* Check whether all indexes use the same block size */ + for (i= 1 ; i < keys ; i++) + { + if (keyinfo[i].block_length != block_length) + return (my_errno= HA_ERR_NON_UNIQUE_BLOCK_SIZE); + } + + length= info->preload_buff_size/block_length * block_length; + set_if_bigger(length, block_length); + + if (!(buff= (uchar *) my_malloc(length, MYF(MY_WME)))) + return (my_errno= HA_ERR_OUT_OF_MEM); + + if (flush_key_blocks(share->kfile, FLUSH_RELEASE)) + goto err; + + do + { + /* Read the next block of index file into the preload buffer */ + set_if_smaller(length, key_file_length-pos); + if (my_pread(share->kfile, (byte*) buff, length, pos, MYF(MY_FAE))) + goto err; + + if (ignore_leaves) + { + uchar *end= buff+length; + do + { + if (mi_test_if_nod(buff)) + { + if (key_cache_insert(share->kfile, pos, (byte*) buff, block_length)) + goto err; + } + pos+= block_length; + } + while ((buff+= block_length) != end); + buff= end-length; + } + else + { + if (key_cache_insert(share->kfile, pos, (byte*) buff, length)) + goto err; + pos+= length; + } + + } + while (pos != key_file_length); + + my_free(buff, MYF(0)); + + return 0; + +err: + my_free(buff, MYF(MY_ALLOW_ZERO_PTR)); + return (my_errno= errno); +} + diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 50320f1ecbd..9321a3918e2 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -262,6 +262,7 @@ struct st_myisam_info { int save_lastinx; LIST open_list; IO_CACHE rec_cache; /* When cacheing records */ + uint preload_buff_size; /* When preloading indexes */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ my_bool was_locked; /* Was locked in panic */ my_bool quick_mode; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 264037e9a70..3276044fc2f 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1259,6 +1259,86 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length, /* + Insert a block of file data from a buffer into key cache + + SYNOPSIS + key_cache_insert() + file file descriptor + filepos file offset of the data from the buffer + buff buffer with data to insert into key cache + length length of the data in the buffer + + RETURN VALUE + 0 if a success, 1 -otherwise. +*/ + +int key_cache_insert(File file, my_off_t filepos, byte *buff, uint length) +{ + DBUG_ENTER("key_cache_insert"); + DBUG_PRINT("enter", ("file %u, filepos %lu, length %u", + (uint) file,(ulong) filepos, length)); + + if (my_disk_blocks > 0) + { + /* Key cache is used */ + reg1 BLOCK_LINK *block; + uint offset= (uint) (filepos & (key_cache_block_size-1)); + uint read_length; + int page_st; + + /* Read data into key cache from buff in key_cache_block_size increments */ + filepos-= offset; + do + { + read_length= length > key_cache_block_size ? + key_cache_block_size : length; + KEYCACHE_DBUG_ASSERT(read_length > 0); + keycache_pthread_mutex_lock(&THR_LOCK_keycache); + my_cache_r_requests++; + block=find_key_block(file, filepos, 0, &page_st); + if (block->status != BLOCK_ERROR && page_st != PAGE_READ) + { + /* The requested page is to be read into the block buffer */ +#if !defined(SERIALIZED_READ_FROM_CACHE) + keycache_pthread_mutex_unlock(&THR_LOCK_keycache); +#endif + + /* Copy data from buff */ + if (!(read_length & 511)) + bmove512(block->buffer+offset, buff, read_length); + else + memcpy(block->buffer+offset, buff, (size_t) read_length); + +#if !defined(SERIALIZED_READ_FROM_CACHE) + keycache_pthread_mutex_lock(&THR_LOCK_keycache); +#endif + block->status= BLOCK_READ; + block->length= read_length+offset; + } + + remove_reader(block); + /* + Link the block into the LRU chain + if it's the last submitted request for the block + */ + unreg_request(block,1); + + keycache_pthread_mutex_unlock(&THR_LOCK_keycache); + + if (block->status & BLOCK_ERROR) + DBUG_RETURN(1); + + buff+=read_length; + filepos+=read_length; + offset=0; + + } while ((length-= read_length)); + } + DBUG_RETURN(0); +} + + +/* Write a buffer into disk; filepos must be a multiple of 'block_length', but it doesn't have to be a multiple of key cache block size; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 213f5baf388..d9b9f3130de 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -675,6 +675,72 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) /* + Preload pages of the index file for a table into the key cache. +*/ + +int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt) +{ + int error; + const char *errmsg; + ulonglong map= ~(ulonglong) 0; + TABLE_LIST *table_list= table->pos_in_table_list; + my_bool ignore_leaves= table_list->ignore_leaves; + + DBUG_ENTER("ha_myisam::preload_keys"); + + /* Check validity of the index references */ + if (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; + } + + mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE, + (void *) &thd->variables.preload_buff_size); + + if ((error= mi_preload(file, map, ignore_leaves))) + { + switch (error) { + case HA_ERR_NON_UNIQUE_BLOCK_SIZE: + errmsg= "Indexes use different block sizes"; + break; + case HA_ERR_OUT_OF_MEM: + errmsg= "Failed to allocate buffer"; + break; + default: + char buf[ERRMSGSIZE+20]; + my_snprintf(buf, ERRMSGSIZE, + "Failed to read from index file (errno: %d)", my_errno); + errmsg= buf; + } + error= HA_ADMIN_FAILED; + goto err; + } + + DBUG_RETURN(HA_ADMIN_OK); + + err: + { + MI_CHECK param; + myisamchk_init(¶m); + param.thd= thd; + param.op_name= (char*)"preload_keys"; + param.db_name= table->table_cache_key; + param.table_name= table->table_name; + param.testflag= 0; + mi_check_print_error(¶m, errmsg); + DBUG_RETURN(error); + } +} + +/* Deactive all not unique index that can be recreated fast SYNOPSIS diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 154429ecc0d..8486e25556b 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 preload_keys(THD* thd, HA_CHECK_OPT* check_opt); #ifdef HAVE_REPLICATION int dump(THD* thd, int fd); int net_read_dump(NET* net); diff --git a/sql/handler.cc b/sql/handler.cc index f2b7dbdf531..e84c9bf3569 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -588,6 +588,11 @@ int handler::analyze(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; +} + /* Read first row (only) from a table This is never called for InnoDB or BDB tables, as these table types diff --git a/sql/handler.h b/sql/handler.h index 8c23a3625e0..a2408ab0fe0 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -304,6 +304,7 @@ public: virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt); virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt); virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); + virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); /* restore assumes .frm file must exist, and that generate_table() has been called; It will just copy the data file and run repair. diff --git a/sql/lex.h b/sql/lex.h index f85431aadf7..0cbc048e00c 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -221,6 +221,7 @@ static SYMBOL symbols[] = { { "KILL", SYM(KILL_SYM),0,0}, { "LAST", SYM(LAST_SYM),0,0}, { "LEADING", SYM(LEADING),0,0}, + { "LEAVES", SYM(LEAVES),0,0}, { "LEFT", SYM(LEFT),0,0}, { "LEVEL", SYM(LEVEL_SYM),0,0}, { "LIKE", SYM(LIKE),0,0}, @@ -299,6 +300,7 @@ static SYMBOL symbols[] = { { "POLYGON", SYM(POLYGON),0,0}, { "PURGE", SYM(PURGE),0,0}, { "PRECISION", SYM(PRECISION),0,0}, + { "PRELOAD", SYM(PRELOAD),0,0}, { "PREV", SYM(PREV_SYM),0,0}, { "PRIMARY", SYM(PRIMARY_SYM),0,0}, { "PROCEDURE", SYM(PROCEDURE),0,0}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ea6e544a1fd..e0c3f5aeaec 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -246,6 +246,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); /* Options to add_table_to_list() */ #define TL_OPTION_UPDATING 1 #define TL_OPTION_FORCE_INDEX 2 +#define TL_OPTION_IGNORE_LEAVES 4 /* Some portable defines */ @@ -393,6 +394,8 @@ 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_preload_keys(THD* thd, TABLE_LIST* table_list); + bool check_simple_select(); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); @@ -584,6 +587,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, extern const Item **not_found_item; Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter, find_item_error_report_type report_error); +key_map get_key_map_from_key_list(TABLE *table, + List<String> *index_list); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f73bd6721f0..7f3c69cb7c9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3464,6 +3464,7 @@ enum options OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT, OPT_OPEN_FILES_LIMIT, + OPT_PRELOAD_BUFFER_SIZE, OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE, OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, @@ -4244,6 +4245,11 @@ Disable with --skip-isam", "If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.", (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 65535, 0, 1, 0}, + {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, + "The size of the buffer that is allocated when preloading indexes", + (gptr*) &global_system_variables.preload_buff_size, + (gptr*) &max_system_variables.preload_buff_size, 0, GET_ULONG, + REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_limit", OPT_QUERY_CACHE_LIMIT, "Don't cache results that are bigger than this.", diff --git a/sql/set_var.cc b/sql/set_var.cc index e4adbb0a318..ddaef4c4e14 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -199,6 +199,8 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", &SV::net_retry_count, fix_net_retry_count); sys_var_thd_bool sys_new_mode("new", &SV::new_mode); +sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size", + &SV::preload_buff_size); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", &SV::read_buff_size); sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", @@ -402,6 +404,7 @@ sys_var *sys_variables[]= &sys_net_wait_timeout, &sys_net_write_timeout, &sys_new_mode, + &sys_preload_buff_size, &sys_pseudo_thread_id, &sys_query_cache_size, #ifdef HAVE_QUERY_CACHE @@ -573,6 +576,7 @@ struct show_var_st init_vars[]= { {"log_error", (char*) log_error_file, SHOW_CHAR}, {"port", (char*) &mysql_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, + {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fc95f5deb40..c7db77e1d84 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -35,8 +35,6 @@ static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, const char *name, const char *alias); static void free_cache_entry(TABLE *entry); static void mysql_rm_tmp_tables(void); -static key_map get_key_map_from_key_list(TABLE *table, - List<String> *index_list); extern "C" byte *table_cache_key(const byte *record,uint *length, @@ -2058,8 +2056,8 @@ bool setup_tables(TABLE_LIST *tables) } -static key_map get_key_map_from_key_list(TABLE *table, - List<String> *index_list) +key_map get_key_map_from_key_list(TABLE *table, + List<String> *index_list) { key_map map=0; List_iterator_fast<String> it(*index_list); diff --git a/sql/sql_class.h b/sql/sql_class.h index 925afde2202..996331b071f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -365,6 +365,7 @@ struct system_variables ulong net_retry_count; ulong net_wait_timeout; ulong net_write_timeout; + ulong preload_buff_size; ulong query_cache_type; ulong read_buff_size; ulong read_rnd_buff_size; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f31b3305e07..04f784e62dc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -59,7 +59,7 @@ 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_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1d2449839d8..2596d349a1c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1819,6 +1819,15 @@ mysql_execute_command(THD *thd) res = mysql_restore_table(thd, tables); break; } + case SQLCOM_PRELOAD_KEYS: + { + if (check_db_used(thd, tables) || + check_access(thd, INDEX_ACL, tables->db, &tables->grant.privilege)) + goto error; + res = mysql_preload_keys(thd, tables); + break; + } + #ifndef EMBEDDED_LIBRARY case SQLCOM_CHANGE_MASTER: @@ -3937,6 +3946,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->lock_type= lock_type; ptr->updating= test(table_options & TL_OPTION_UPDATING); ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); + ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; if (use_index) ptr->use_index=(List<String> *) thd->memdup((gptr) use_index, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3cac88d05b2..a73f55077c9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1331,6 +1331,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, goto err; continue; } + table->table->pos_in_table_list= table; if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; @@ -1487,6 +1488,28 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) /* + Preload specified indexes for a table into key cache + + SYNOPSIS + mysql_preload_keys() + thd Thread object + tables Table list (one table only) + + RETURN VALUES + 0 ok + -1 error +*/ + +int mysql_preload_keys(THD* thd, TABLE_LIST* tables) +{ + DBUG_ENTER("mysql_preload_keys"); + DBUG_RETURN(mysql_admin_table(thd, tables, 0, + "preload_keys", TL_READ, 0, 0, 0, + &handler::preload_keys)); +} + + +/* Create a table identical to the specified table SYNOPSIS diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e3b2c738949..6c120574644 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -256,6 +256,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token KEY_SYM %token LEADING %token LEAST_SYM +%token LEAVES %token LEVEL_SYM %token LEX_HOSTNAME %token LIKE @@ -309,6 +310,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DUMPFILE %token PACK_KEYS_SYM %token PARTIAL +%token PRELOAD %token PRIMARY_SYM %token PRIVILEGES %token PROCESS @@ -584,7 +586,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); type int_type real_type order_dir opt_field_spec lock_option udf_type if_exists opt_local opt_table_options table_options table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type - delete_option opt_temporary all_or_any opt_distinct + delete_option opt_temporary all_or_any opt_distinct opt_ignore_leafs %type <ulong_num> ULONG_NUM raid_types merge_insert_types @@ -613,7 +615,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); key_alg opt_btree_or_rtree %type <string_list> - key_usage_list + key_usage_list %type <key_part> key_part @@ -661,10 +663,11 @@ 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 flush + show describe load alter optimize preload flush reset purge begin commit rollback slave master_def master_defs repair restore backup analyze check start field_list field_list_item field_spec kill column_def key_def + 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 @@ -733,6 +736,7 @@ verb_clause: | lock | kill | optimize + | preload | purge | rename | repair @@ -1824,6 +1828,55 @@ table_to_table: YYABORT; }; +preload: + PRELOAD + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_PRELOAD_KEYS; + } + preload_list + {} + ; + +preload_list: + preload_keys + | preload_list ',' preload_keys; + +preload_keys: + table_ident preload_keys_spec opt_ignore_leafs + { + LEX *lex=Lex; + SELECT_LEX *sel= &lex->select_lex; + if (!sel->add_table_to_list(lex->thd, $1, NULL, $3, + TL_READ, + sel->get_use_index(), + (List<String> *)0)) + YYABORT; + } + ; + +preload_keys_spec: + keys_or_index { Select->select_lex()->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; + } + ; + +preload_key_list_or_empty: + /* empty */ + | '(' key_usage_list2 ')' {} + ; + +opt_ignore_leafs: + /* empty */ + { $$= 0; } + | IGNORE_SYM LEAVES { $$= TL_OPTION_IGNORE_LEAVES; } + ; + /* Select : retrieve data from table */ @@ -4251,6 +4304,7 @@ keyword: | INSERT_METHOD {} | RELAY_THREAD {} | LAST_SYM {} + | LEAVES {} | LEVEL_SYM {} | LINESTRING {} | LOCAL_SYM {} @@ -4294,6 +4348,7 @@ keyword: | PASSWORD {} | POINT_SYM {} | POLYGON {} + | PRELOAD {} | PREV_SYM {} | PROCESS {} | PROCESSLIST_SYM {} diff --git a/sql/table.h b/sql/table.h index 2aefe23cb2f..3132e72fb2f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -181,6 +181,7 @@ typedef struct st_table_list bool straight; /* optimize with prev table */ bool updating; /* for replicate-do/ignore table */ bool force_index; /* Prefer index over table scan */ + bool ignore_leaves; /* Preload only non-leaf nodes */ } TABLE_LIST; typedef struct st_changed_table_list |