Commit a0f3dcc3 authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

Merge rurik.mysql.com:/home/igor/mysql-4.1

into rurik.mysql.com:/home/igor/dev/mysql-4.1-0
parents f928a0c4 1e5dec8c
......@@ -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() */
......@@ -256,6 +257,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 */
......
......@@ -643,6 +643,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);
......
......@@ -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
}
......
......@@ -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
......
......@@ -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:
......
/* 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);
}
......@@ -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;
......
drop table if exists t1, t2;
create table t1 (
a int not null auto_increment,
b char(16) not null,
primary key (a),
key (b)
);
create table t2(
a int not null auto_increment,
b char(16) not null,
primary key (a),
key (b)
);
insert into t1(b) values
('test0'),
('test1'),
('test2'),
('test3'),
('test4'),
('test5'),
('test6'),
('test7');
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
select count(*) from t1;
count(*)
33448
select count(*) from t2;
count(*)
20672
flush tables;
flush status;
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
select count(*) from t1 where b = 'test1';
count(*)
4181
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 217
Key_reads 45
Key_write_requests 0
Key_writes 0
select count(*) from t1 where b = 'test1';
count(*)
4181
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 434
Key_reads 45
Key_write_requests 0
Key_writes 0
flush tables;
flush status;
select @@preload_buffer_size;
@@preload_buffer_size
32768
preload t1 keys;
Table Op Msg_type Msg_text
test.t1 preload_keys status OK
show status like "preload_%";
Variable_name Value
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
select count(*) from t1 where b = 'test1';
count(*)
4181
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 217
Key_reads 45
Key_write_requests 0
Key_writes 0
flush tables;
flush status;
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
set session preload_buffer_size=256*1024;
select @@preload_buffer_size;
@@preload_buffer_size
262144
preload t1 keys ignore leaves;
Table Op Msg_type Msg_text
test.t1 preload_keys status OK
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
select count(*) from t1 where b = 'test1';
count(*)
4181
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 217
Key_reads 45
Key_write_requests 0
Key_writes 0
flush tables;
flush status;
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
set session preload_buffer_size=1*1024;
select @@preload_buffer_size;
@@preload_buffer_size
1024
preload t1 keys, t2 keys (primary,b) ignore leaves;
Table Op Msg_type Msg_text
test.t1 preload_keys status OK
test.t2 preload_keys status OK
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
select count(*) from t1 where b = 'test1';
count(*)
4181
select count(*) from t2 where b = 'test1';
count(*)
2584
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 351
Key_reads 73
Key_write_requests 0
Key_writes 0
flush tables;
flush status;
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
preload t3 keys, t2 keys (primary,b) ;
Table Op Msg_type Msg_text
test.t3 preload_keys error Table 'test.t3' doesn't exist
test.t2 preload_keys status OK
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
flush tables;
flush status;
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
preload t3 keys (b), t2 keys (c) ;
Table Op Msg_type Msg_text
test.t3 preload_keys error Table 'test.t3' doesn't exist
test.t2 preload_keys error Key column 'c' doesn't exist in table
test.t2 preload_keys status Operation failed
show status like "key_%";
Variable_name Value
Key_blocks_used 918
Key_read_requests 0
Key_reads 0
Key_write_requests 0
Key_writes 0
drop table t1, t2;
#
# Testing of PRELOAD
#
--disable_warnings
drop table if exists t1, t2;
--enable_warnings
create table t1 (
a int not null auto_increment,
b char(16) not null,
primary key (a),
key (b)
);
create table t2(
a int not null auto_increment,
b char(16) not null,
primary key (a),
key (b)
);
insert into t1(b) values
('test0'),
('test1'),
('test2'),
('test3'),
('test4'),
('test5'),
('test6'),
('test7');
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
insert into t2(b) select b from t1;
insert into t1(b) select b from t2;
select count(*) from t1;
select count(*) from t2;
flush tables; flush status;
show status like "key_%";
select count(*) from t1 where b = 'test1';
show status like "key_%";
select count(*) from t1 where b = 'test1';
show status like "key_%";
flush tables; flush status;
select @@preload_buffer_size;
preload t1 keys;
show status like "preload_%";
show status like "key_%";
select count(*) from t1 where b = 'test1';
show status like "key_%";
flush tables; flush status;
show status like "key_%";
set session preload_buffer_size=256*1024;
select @@preload_buffer_size;
preload t1 keys ignore leaves;
show status like "key_%";
select count(*) from t1 where b = 'test1';
show status like "key_%";
flush tables; flush status;
show status like "key_%";
set session preload_buffer_size=1*1024;
select @@preload_buffer_size;
preload t1 keys, t2 keys (primary,b) ignore leaves;
show status like "key_%";
select count(*) from t1 where b = 'test1';
select count(*) from t2 where b = 'test1';
show status like "key_%";
flush tables; flush status;
show status like "key_%";
preload t3 keys, t2 keys (primary,b) ;
show status like "key_%";
flush tables; flush status;
show status like "key_%";
preload t3 keys (b), t2 keys (c) ;
show status like "key_%";
drop table t1, t2;
......@@ -1258,6 +1258,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
......
......@@ -688,6 +688,72 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, 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(&param);
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(&param, errmsg);
DBUG_RETURN(error);
}
}
/*
Deactive all not unique index that can be recreated fast
......
......@@ -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);
......
......@@ -620,6 +620,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
......
......@@ -305,6 +305,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.
......
......@@ -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},
......
......@@ -250,6 +250,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 */
......@@ -402,6 +403,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);
......@@ -593,6 +596,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);
......
......@@ -3424,6 +3424,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,
......@@ -4233,6 +4234,11 @@ replicating a LOAD DATA INFILE command",
"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.",
......
......@@ -210,6 +210,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_bool_ptr sys_readonly("read_only", &opt_readonly);
......@@ -423,6 +425,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
......@@ -602,6 +605,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_readonly.name, (char*) &sys_readonly, SHOW_SYS},
......
......@@ -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,
......@@ -2066,8 +2064,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);
......
......@@ -366,6 +366,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;
......
......@@ -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,
......
......@@ -1881,6 +1881,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:
......@@ -4108,6 +4117,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,
......
......@@ -1404,6 +1404,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];
......@@ -1559,6 +1560,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
......
......@@ -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
......@@ -579,7 +581,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
......@@ -608,7 +610,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
......@@ -656,10 +658,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
......@@ -728,6 +731,7 @@ verb_clause:
| lock
| kill
| optimize
| preload
| purge
| rename
| repair
......@@ -1833,6 +1837,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
*/
......@@ -4277,6 +4330,7 @@ keyword:
| INSERT_METHOD {}
| RELAY_THREAD {}
| LAST_SYM {}
| LEAVES {}
| LEVEL_SYM {}
| LINESTRING {}
| LOCAL_SYM {}
......@@ -4320,6 +4374,7 @@ keyword:
| PASSWORD {}
| POINT_SYM {}
| POLYGON {}
| PRELOAD {}
| PREV_SYM {}
| PROCESS {}
| PROCESSLIST_SYM {}
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment