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

Many files:

  Added key cache assignment
mi_locking.c:
  Added key cache assignment: correction
my_sys.h:
  Added key cache variable structure
parent f0ca5d54
......@@ -46,6 +46,7 @@
#define HA_OPEN_DELAY_KEY_WRITE 8 /* Don't update index */
#define HA_OPEN_ABORT_IF_CRASHED 16
#define HA_OPEN_FOR_REPAIR 32 /* open even if crashed */
#define HA_OPEN_TO_ASSIGN 64 /* Open for key cache assignment */
/* The following is parameter to ha_rkey() how to use key */
......@@ -124,7 +125,8 @@ enum ha_extra_function {
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_PRELOAD_BUFFER_SIZE /* Set buffer size for preloading */
HA_EXTRA_PRELOAD_BUFFER_SIZE, /* Set buffer size for preloading */
HA_EXTRA_SET_KEY_CACHE /* Set ref to assigned key cache */
};
/* The following is parameter to ha_panic() */
......
......@@ -552,6 +552,9 @@ typedef SOCKET_SIZE_TYPE size_socket;
#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD)
/* Typical key cash */
#define KEY_CACHE_SIZE (uint) (8*1024*1024-MALLOC_OVERHEAD)
/* Default size of a key cache block */
#define KEY_CACHE_BLOCK_SIZE (uint) 1024
/* Some things that this system doesn't have */
......
......@@ -111,8 +111,6 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */
#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */
#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */
#define DEFAULT_KEYCACHE_BLOCK_SIZE 1024
#define MAX_KEYCACHE_BLOCK_SIZE 16384
/* root_alloc flags */
#define MY_KEEP_PREALLOC 1
......@@ -248,8 +246,6 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io,
extern char wild_many,wild_one,wild_prefix;
extern const char *charsets_dir;
extern char *defaults_extra_file;
extern void *dflt_keycache;
#define dflt_key_block_size DEFAULT_KEYCACHE_BLOCK_SIZE
typedef struct wild_file_pack /* Struct to hold info when selecting files */
{
......@@ -503,11 +499,37 @@ my_off_t my_b_append_tell(IO_CACHE* info);
#define my_b_bytes_in_cache(info) (uint) (*(info)->current_end - \
*(info)->current_pos)
/* key_cache_variables */
typedef struct st_keycache
/* Pointer to a key cache data structure (see the key cache module) */
typedef struct st_key_cache* KEY_CACHE_HANDLE;
/* Key cache variable structure */
/*
The structure contains the parameters of a key cache that can
be set and undated by regular set global statements.
It also contains read-only statistics parameters.
If the corresponding key cache data structure has been already
created the variable contains the key cache handle.
The variables are put into a named list called key_caches.
At present the variables are only added to this list.
*/
typedef struct st_key_cache_var
{
ulonglong size;
} KEY_CACHE;
ulonglong buff_size; /* size the memory allocated for the cache */
ulong block_size; /* size of the blocks in the key cache */
KEY_CACHE_HANDLE cache; /* handles for the current and registered */
ulong blocks_used; /* number of currently used blocks */
ulong blocks_changed; /* number of currently dirty blocks */
ulong cache_w_requests; /* number of write requests (write hits) */
ulong cache_write; /* number of writes from the cache to files */
ulong cache_r_requests; /* number of read requests (read hits) */
ulong cache_read; /* number of reads from files to the cache */
int blocks; /* max number of blocks in the cache */
struct st_key_cache_asmt *assign_list; /* list of assignments to the cache */
} KEY_CACHE_VAR;
#define DEFAULT_KEY_CACHE_NAME "default"
extern KEY_CACHE_HANDLE *dflt_keycache;
extern KEY_CACHE_VAR dflt_key_cache_var;
#include <my_alloc.h>
......@@ -647,21 +669,22 @@ extern int flush_write_cache(RECORD_CACHE *info);
extern long my_clock(void);
extern sig_handler sigtstp_handler(int signal_number);
extern void handle_recived_signals(void);
extern int init_key_cache(void **pkeycache,uint key_cache_block_size,
ulong use_mem);
extern int resize_key_cache(void **pkeycache,ulong use_mem);
extern byte *key_cache_read(void *pkeycache,
extern int init_key_cache(KEY_CACHE_HANDLE *pkeycache,
uint key_cache_block_sie,
ulong use_mem, KEY_CACHE_VAR* env);
extern int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, ulong use_mem);
extern byte *key_cache_read(KEY_CACHE_HANDLE keycache,
File file,my_off_t filepos,byte* buff,uint length,
uint block_length,int return_buffer);
extern int key_cache_insert(void *pkeycache,
extern int key_cache_insert(KEY_CACHE_HANDLE keycache,
File file, my_off_t filepos,
byte *buff, uint length);
extern int key_cache_write(void *pkeycache,
extern int key_cache_write(KEY_CACHE_HANDLE keycache,
File file,my_off_t filepos,byte* buff,uint length,
uint block_length,int force_write);
extern int flush_key_blocks(void *pkeycache,
extern int flush_key_blocks(KEY_CACHE_HANDLE keycache,
int file, enum flush_type type);
extern void end_key_cache(void **pkeycache,my_bool cleanup);
extern void end_key_cache(KEY_CACHE_HANDLE *pkeycache,my_bool cleanup);
extern sig_handler my_set_alarm_variable(int signo);
extern void my_string_ptr_sort(void *base,uint items,size_s size);
extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
......
......@@ -411,7 +411,7 @@ 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_assign_to_keycache(MI_INFO *info, ulonglong key_map,
char *keycache_name);
KEY_CACHE_HANDLE *reg_keycache);
int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves);
#ifdef __cplusplus
......
......@@ -50,7 +50,7 @@ int nisam_lock_database(N_INFO *info, int lock_type)
else
count= --share->w_locks;
if (info->lock_type == F_WRLCK && !share->w_locks &&
flush_key_blocks(dflt_keycache,share->kfile,FLUSH_KEEP))
flush_key_blocks(*dflt_keycache,share->kfile,FLUSH_KEEP))
error=my_errno;
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
if (end_io_cache(&info->rec_cache))
......@@ -329,7 +329,7 @@ int _nisam_test_if_changed(register N_INFO *info)
share->state.uniq != info->last_uniq)
{ /* Keyfile has changed */
if (share->state.process != share->this_process)
VOID(flush_key_blocks(dflt_keycache,share->kfile,FLUSH_RELEASE));
VOID(flush_key_blocks(*dflt_keycache,share->kfile,FLUSH_RELEASE));
share->last_process=share->state.process;
info->last_loop= share->state.loop;
info->last_uniq= share->state.uniq;
......
......@@ -27,7 +27,7 @@ uchar *_nisam_fetch_keypage(register N_INFO *info, N_KEYDEF *keyinfo,
my_off_t page, uchar *buff, int return_buffer)
{
uchar *tmp;
tmp=(uchar*) key_cache_read(dflt_keycache,
tmp=(uchar*) key_cache_read(*dflt_keycache,
info->s->kfile,page,(byte*) buff,
(uint) keyinfo->base.block_length,
(uint) keyinfo->base.block_length,
......@@ -84,7 +84,7 @@ int _nisam_write_keypage(register N_INFO *info, register N_KEYDEF *keyinfo,
length=keyinfo->base.block_length;
}
#endif
return (key_cache_write(dflt_keycache,
return (key_cache_write(*dflt_keycache,
info->s->kfile,page,(byte*) buff,length,
(uint) keyinfo->base.block_length,
(int) (info->lock_type != F_UNLCK)));
......@@ -101,7 +101,7 @@ int _nisam_dispose(register N_INFO *info, N_KEYDEF *keyinfo, my_off_t pos)
old_link=info->s->state.key_del[keynr];
info->s->state.key_del[keynr]=(ulong) pos;
DBUG_RETURN(key_cache_write(dflt_keycache,
DBUG_RETURN(key_cache_write(*dflt_keycache,
info->s->kfile,pos,(byte*) &old_link,
sizeof(long),
(uint) keyinfo->base.block_length,
......@@ -129,7 +129,7 @@ ulong _nisam_new(register N_INFO *info, N_KEYDEF *keyinfo)
}
else
{
if (!key_cache_read(dflt_keycache,
if (!key_cache_read(*dflt_keycache,
info->s->kfile,pos,
(byte*) &info->s->state.key_del[keynr],
(uint) sizeof(long),
......
......@@ -57,7 +57,7 @@ int nisam_close(register N_INFO *info)
if (flag)
{
if (share->kfile >= 0 &&
flush_key_blocks(dflt_keycache,share->kfile,FLUSH_RELEASE))
flush_key_blocks(*dflt_keycache,share->kfile,FLUSH_RELEASE))
error=my_errno;
if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
error = my_errno;
......
......@@ -516,8 +516,8 @@ static int nisamchk(my_string filename)
if (!rep_quick)
{
if (testflag & T_EXTEND)
VOID(init_key_cache(&dflt_keycache,dflt_key_block_size,
use_buffers));
VOID(init_key_cache(dflt_keycache,KEY_CACHE_BLOCK_SIZE,
use_buffers,&dflt_key_cache_var));
VOID(init_io_cache(&read_cache,datafile,(uint) read_buffer_length,
READ_CACHE,share->pack.header_length,1,
MYF(MY_WME)));
......@@ -1460,7 +1460,8 @@ my_string name;
printf("Data records: %lu\n",(ulong) share->state.records);
}
VOID(init_key_cache(&dflt_keycache,dflt_key_block_size,use_buffers));
VOID(init_key_cache(dflt_keycache,KEY_CACHE_BLOCK_SIZE,use_buffers,
&dflt_key_cache_var));
if (init_io_cache(&read_cache,info->dfile,(uint) read_buffer_length,
READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
goto err;
......@@ -1893,7 +1894,7 @@ File file;
print_error("%d when trying to write bufferts",my_errno);
return(1);
}
end_key_cache(&dflt_keycache,1);
end_key_cache(dflt_keycache,1);
return 0;
} /* flush_blocks */
......@@ -1937,7 +1938,8 @@ int write_info;
if (share->state.key_root[sort_key] == NI_POS_ERROR)
DBUG_RETURN(0); /* Nothing to do */
init_key_cache(&dflt_keycache,dflt_key_block_size,use_buffers);
init_key_cache(dflt_keycache,KEY_CACHE_BLOCK_SIZE,use_buffers,
&dflt_key_cache_var);
if (init_io_cache(&info->rec_cache,-1,(uint) write_buffer_length,
WRITE_CACHE,share->pack.header_length,1,
MYF(MY_WME | MY_WAIT_IF_FULL)))
......
......@@ -329,8 +329,8 @@ static int examine_log(my_string file_name, char **table_names)
bzero((gptr) com_count,sizeof(com_count));
init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1,
(tree_element_free) file_info_free, NULL);
VOID(init_key_cache(KEY_CACHE_SIZE));
VOID(init_key_cache(dflt_keycache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE,
&dflt_key_cache_var));
files_open=0; access_time=0;
while (access_time++ != number_of_commands &&
!my_b_read(&cache,(byte*) head,9))
......@@ -622,7 +622,7 @@ static int examine_log(my_string file_name, char **table_names)
goto end;
}
}
end_key_cache();
end_key_cache(dflt_keycache,1);
delete_tree(&tree);
VOID(end_io_cache(&cache));
VOID(my_close(file,MYF(0)));
......@@ -642,7 +642,7 @@ static int examine_log(my_string file_name, char **table_names)
llstr(isamlog_filepos,llbuff)));
fflush(stderr);
end:
end_key_cache();
end_key_cache(dflt_keycache,1);
delete_tree(&tree);
VOID(end_io_cache(&cache));
VOID(my_close(file,MYF(0)));
......
......@@ -48,7 +48,7 @@ int nisam_panic(enum ha_panic_function flag)
if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
break;
#endif
if (flush_key_blocks(dflt_keycache,info->s->kfile,FLUSH_RELEASE))
if (flush_key_blocks(*dflt_keycache,info->s->kfile,FLUSH_RELEASE))
error=my_errno;
if (info->opt_flag & WRITE_CACHE_USED)
if (flush_io_cache(&info->rec_cache))
......
......@@ -156,7 +156,7 @@ int main(int argc, char *argv[])
goto err;
printf("- Writing key:s\n");
if (key_cacheing)
init_key_cache(&dflt_keycache,dflt_key_block_size,IO_SIZE*16); /* Use a small cache */
init_key_cache(dflt_keycache,512,IO_SIZE*16,0); /* Use a small cache */
if (locking)
nisam_lock_database(file,F_WRLCK);
if (write_cacheing)
......
......@@ -173,7 +173,7 @@ void start_test(int id)
exit(1);
}
if (key_cacheing && rnd(2) == 0)
init_key_cache(&dflt_keycache,dflt_key_block_size,65536L);
init_key_cache(dflt_keycache,512,65536L,0);
printf("Process %d, pid: %d\n",id,(int) getpid()); fflush(stdout);
for (error=i=0 ; i < tests && !error; i++)
......
......@@ -230,7 +230,7 @@ static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr)
if (next_link > info->state->key_file_length ||
next_link & (info->s->blocksize-1))
DBUG_RETURN(1);
if (!(buff=key_cache_read(dflt_keycache,
if (!(buff=key_cache_read(*info->s->keycache,
info->s->kfile, next_link, (byte*) info->buff,
myisam_block_size, block_size, 1)))
DBUG_RETURN(1);
......@@ -260,7 +260,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info)
if (!(param->testflag & T_SILENT)) puts("- check file-size");
flush_key_blocks(dflt_keycache,
flush_key_blocks(*info->s->keycache,
info->s->kfile, FLUSH_FORCE_WRITE); /* If called externally */
size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
......@@ -1121,8 +1121,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
param->testflag|=T_REP; /* for easy checking */
if (!param->using_global_keycache)
VOID(init_key_cache(&dflt_keycache,dflt_key_block_size,
param->use_buffers));
VOID(init_key_cache(dflt_keycache,dflt_key_cache_var.block_size,
param->use_buffers,&dflt_key_cache_var));
if (init_io_cache(&param->read_cache,info->dfile,
(uint) param->read_buffer_length,
......@@ -1480,13 +1480,13 @@ void lock_memory(MI_CHECK *param __attribute__((unused)))
int flush_blocks(MI_CHECK *param, File file)
{
if (flush_key_blocks(dflt_keycache,file,FLUSH_RELEASE))
if (flush_key_blocks(*dflt_keycache,file,FLUSH_RELEASE))
{
mi_check_print_error(param,"%d when trying to write bufferts",my_errno);
return(1);
}
if (!param->using_global_keycache)
end_key_cache(&dflt_keycache,1);
end_key_cache(dflt_keycache,1);
return 0;
} /* flush_blocks */
......@@ -1540,7 +1540,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
}
/* Flush key cache for this file if we are calling this outside myisamchk */
flush_key_blocks(dflt_keycache,share->kfile, FLUSH_IGNORE_CHANGED);
flush_key_blocks(*share->keycache,share->kfile, FLUSH_IGNORE_CHANGED);
share->state.version=(ulong) time((time_t*) 0);
old_state=share->state; /* save state if not stored */
......@@ -1846,7 +1846,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
Flush key cache for this file if we are calling this outside
myisamchk
*/
flush_key_blocks(dflt_keycache,share->kfile, FLUSH_IGNORE_CHANGED);
flush_key_blocks(*share->keycache,share->kfile, FLUSH_IGNORE_CHANGED);
/* Clear the pointers to the given rows */
for (i=0 ; i < share->base.keys ; i++)
share->state.key_root[i]= HA_OFFSET_ERROR;
......@@ -1856,7 +1856,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
}
else
{
if (flush_key_blocks(dflt_keycache,share->kfile, FLUSH_FORCE_WRITE))
if (flush_key_blocks(*share->keycache,share->kfile, FLUSH_FORCE_WRITE))
goto err;
key_map= ~key_map; /* Create the missing keys */
}
......@@ -2209,7 +2209,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
Flush key cache for this file if we are calling this outside
myisamchk
*/
flush_key_blocks(dflt_keycache,share->kfile, FLUSH_IGNORE_CHANGED);
flush_key_blocks(*share->keycache,share->kfile, FLUSH_IGNORE_CHANGED);
/* Clear the pointers to the given rows */
for (i=0 ; i < share->base.keys ; i++)
share->state.key_root[i]= HA_OFFSET_ERROR;
......@@ -2219,7 +2219,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
}
else
{
if (flush_key_blocks(dflt_keycache,share->kfile, FLUSH_FORCE_WRITE))
if (flush_key_blocks(*share->keycache,share->kfile, FLUSH_FORCE_WRITE))
goto err;
key_map= ~key_map; /* Create the missing keys */
}
......
......@@ -64,7 +64,7 @@ int mi_close(register MI_INFO *info)
if (flag)
{
if (share->kfile >= 0 &&
flush_key_blocks(dflt_keycache,share->kfile,
flush_key_blocks(*share->keycache,share->kfile,
share->temporary ? FLUSH_IGNORE_CHANGED :
FLUSH_RELEASE))
error=my_errno;
......
......@@ -53,7 +53,7 @@ int mi_delete_all_rows(MI_INFO *info)
If we are using delayed keys or if the user has done changes to the tables
since it was locked then there may be key blocks in the key cache
*/
flush_key_blocks(dflt_keycache, share->kfile, FLUSH_IGNORE_CHANGED);
flush_key_blocks(*share->keycache, share->kfile, FLUSH_IGNORE_CHANGED);
if (my_chsize(info->dfile, 0, 0, MYF(MY_WME)) ||
my_chsize(share->kfile, share->base.keystart, 0, MYF(MY_WME)) )
goto err;
......
......@@ -279,7 +279,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
#ifdef __WIN__
/* Close the isam and data files as Win32 can't drop an open table */
pthread_mutex_lock(&share->intern_lock);
if (flush_key_blocks(dflt_keycache, share->kfile,
if (flush_key_blocks(*share->keycache, share->kfile,
(function == HA_EXTRA_FORCE_REOPEN ?
FLUSH_RELEASE : FLUSH_IGNORE_CHANGED)))
{
......@@ -325,7 +325,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
break;
case HA_EXTRA_FLUSH:
if (!share->temporary)
flush_key_blocks(dflt_keycache,share->kfile,FLUSH_KEEP);
flush_key_blocks(*share->keycache,share->kfile,FLUSH_KEEP);
#ifdef HAVE_PWRITE
_mi_decrement_open_count(info);
#endif
......@@ -370,6 +370,9 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
case HA_EXTRA_PRELOAD_BUFFER_SIZE:
info->preload_buff_size= *((ulong *) extra_arg);
break;
case HA_EXTRA_SET_KEY_CACHE:
share->reg_keycache= share->keycache= (KEY_CACHE_HANDLE *) extra_arg;
break;
case HA_EXTRA_KEY_CACHE:
case HA_EXTRA_NO_KEY_CACHE:
default:
......
......@@ -28,7 +28,7 @@
mi_assign_to_keycache()
info open table
map map of indexes to assign to the key cache
keycache_name name of of the key cache to assign index to
key_cache_ptr pointer to the key cache handle
RETURN VALUE
0 if a success. error code - otherwise.
......@@ -39,9 +39,25 @@
of the table will be assigned to the specified key cache.
*/
int mi_assign_to_keycache(MI_INFO *info, ulonglong key_map,
char *keycache_name)
int mi_assign_to_keycache(MI_INFO *info, ulonglong key_map,
KEY_CACHE_HANDLE *reg_keycache)
{
return 0;
int error= 0;
MYISAM_SHARE* share= info->s;
DBUG_ENTER("mi_assign_to_keycache");
share->reg_keycache= reg_keycache;
if (!(info->lock_type == F_WRLCK && share->w_locks))
{
if (flush_key_blocks(*share->keycache, share->kfile, FLUSH_RELEASE))
{
error=my_errno;
mi_mark_crashed(info); /* Mark that table must be checked */
}
share->keycache= reg_keycache;
}
DBUG_RETURN(error);
}
......@@ -34,6 +34,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
uint count;
MYISAM_SHARE *share=info->s;
uint flag;
uint switch_fl= 0;
DBUG_ENTER("mi_lock_database");
if (share->options & HA_OPTION_READ_ONLY_DATA ||
......@@ -50,13 +51,26 @@ int mi_lock_database(MI_INFO *info, int lock_type)
else
count= --share->w_locks;
--share->tot_locks;
/*
During a key cache reassignment the current and registered
key caches for the table are different.
Although at present key cache ressignment is always
performed with a shared cache for the table acquired,
for future possible optimizations we still
handle this situation as if we could come to this point
during the ressignment (in non-reassignment thread).
*/
if (info->lock_type == F_WRLCK && !share->w_locks &&
!share->delay_key_write &&
flush_key_blocks(dflt_keycache,share->kfile,FLUSH_KEEP))
((switch_fl= share->keycache != share->reg_keycache) ||
!share->delay_key_write) &&
flush_key_blocks(*share->keycache, share->kfile,
switch_fl ? FLUSH_RELEASE : FLUSH_KEEP))
{
error=my_errno;
mi_mark_crashed(info); /* Mark that table must be checked */
}
if (switch_fl)
share->keycache= share->reg_keycache;
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{
if (end_io_cache(&info->rec_cache))
......@@ -386,7 +400,7 @@ int _mi_test_if_changed(register MI_INFO *info)
{ /* Keyfile has changed */
DBUG_PRINT("info",("index file changed"));
if (share->state.process != share->this_process)
VOID(flush_key_blocks(dflt_keycache,share->kfile,FLUSH_RELEASE));
VOID(flush_key_blocks(*share->keycache,share->kfile,FLUSH_RELEASE));
share->last_process=share->state.process;
info->last_unique= share->state.unique;
info->last_loop= share->state.update_count;
......
......@@ -31,7 +31,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo,
DBUG_ENTER("_mi_fetch_keypage");
DBUG_PRINT("enter",("page: %ld",page));
tmp=(uchar*) key_cache_read(dflt_keycache,
tmp=(uchar*) key_cache_read(*info->s->keycache,
info->s->kfile,page,(byte*) buff,
(uint) keyinfo->block_length,
(uint) keyinfo->block_length,
......@@ -93,7 +93,7 @@ int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo,
length=keyinfo->block_length;
}
#endif
DBUG_RETURN((key_cache_write(dflt_keycache,
DBUG_RETURN((key_cache_write(*info->s->keycache,
info->s->kfile,page,(byte*) buff,length,
(uint) keyinfo->block_length,
(int) ((info->lock_type != F_UNLCK) ||
......@@ -114,7 +114,7 @@ int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos)
info->s->state.key_del[keyinfo->block_size]=pos;
mi_sizestore(buff,old_link);
info->s->state.changed|= STATE_NOT_SORTED_PAGES;
DBUG_RETURN(key_cache_write(dflt_keycache,
DBUG_RETURN(key_cache_write(*info->s->keycache,
info->s->kfile,pos,buff,
sizeof(buff),
(uint) keyinfo->block_length,
......@@ -143,7 +143,7 @@ my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo)
}
else
{
if (!key_cache_read(dflt_keycache,
if (!key_cache_read(*info->s->keycache,
info->s->kfile,pos,
buff,
(uint) sizeof(buff),
......
......@@ -48,7 +48,7 @@ int mi_panic(enum ha_panic_function flag)
if (info->s->options & HA_OPTION_READ_ONLY_DATA)
break;
#endif
if (flush_key_blocks(dflt_keycache,info->s->kfile,FLUSH_RELEASE))
if (flush_key_blocks(*info->s->keycache,info->s->kfile,FLUSH_RELEASE))
error=my_errno;
if (info->opt_flag & WRITE_CACHE_USED)
if (flush_io_cache(&info->rec_cache))
......
......@@ -69,7 +69,7 @@ int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves)
if (!(buff= (uchar *) my_malloc(length, MYF(MY_WME))))
DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
if (flush_key_blocks(dflt_keycache,share->kfile, FLUSH_RELEASE))
if (flush_key_blocks(*share->keycache,share->kfile, FLUSH_RELEASE))
goto err;
do
......@@ -87,7 +87,7 @@ int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves)
{
if (mi_test_if_nod(buff))
{
if (key_cache_insert(dflt_keycache,
if (key_cache_insert(*share->keycache,
share->kfile, pos, (byte*) buff, block_length))
goto err;
}
......@@ -98,7 +98,7 @@ int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves)
}
else
{
if (key_cache_insert(dflt_keycache,
if (key_cache_insert(*share->keycache,
share->kfile, pos, (byte*) buff, length))
goto err;
pos+= length;
......
......@@ -50,7 +50,7 @@ int main(int argc,char *argv[])
MY_INIT(argv[0]);
my_init();
if (key_cacheing)
init_key_cache(&dflt_keycache,dflt_key_block_size,IO_SIZE*16);
init_key_cache(dflt_keycache,512,IO_SIZE*16,0);
get_options(argc,argv);
exit(run_test("test1"));
......
......@@ -49,6 +49,7 @@ static int verbose=0,testflag=0,
static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1,
create_flag=0;
static ulong key_cache_size=IO_SIZE*16;
static uint key_cache_block_size=IO_SIZE;
static uint keys=MYISAM_KEYS,recant=1000;
static uint use_blob=0;
......@@ -214,7 +215,7 @@ int main(int argc, char *argv[])
if (!silent)
printf("- Writing key:s\n");
if (key_cacheing)
init_key_cache(&dflt_keycache,dflt_key_block_size,key_cache_size); /* Use a small cache */
init_key_cache(dflt_keycache,key_cache_block_size,key_cache_size,0); /* Use a small cache */
if (locking)
mi_lock_database(file,F_WRLCK);
if (write_cacheing)
......@@ -274,7 +275,7 @@ int main(int argc, char *argv[])
goto end;
}
if (key_cacheing)
resize_key_cache(&dflt_keycache,key_cache_size*2);
resize_key_cache(dflt_keycache,key_cache_size*2);
}
if (!silent)
......@@ -828,7 +829,7 @@ reads: %10lu\n",
my_cache_r_requests, my_cache_read);
#endif
}
end_key_cache(&dflt_keycache,1);
end_key_cache(dflt_keycache,1);
if (blob_buffer)
my_free(blob_buffer,MYF(0));
my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
......
......@@ -177,7 +177,7 @@ void start_test(int id)
exit(1);
}
if (key_cacheing && rnd(2) == 0)
init_key_cache(&dflt_keycache,dflt_key_block_size,65536L);
init_key_cache(dflt_keycache,512,65536L,0);
printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
for (error=i=0 ; i < tests && !error; i++)
......
......@@ -44,6 +44,7 @@ static const char *load_default_groups[]= { "myisamchk", 0 };
static const char *set_charset_name, *opt_tmpdir;
static CHARSET_INFO *set_charset;
static long opt_myisam_block_size;
static long opt_key_cache_block_size;
static const char *my_progname_short;
static int stopwords_inited= 0;
static MY_TMPDIR myisamchk_tmpdir;
......@@ -148,7 +149,8 @@ int main(int argc, char **argv)
enum options {
OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS,
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE, OPT_MYISAM_BLOCK_SIZE,
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT
......@@ -283,6 +285,11 @@ static struct my_option my_long_options[] =
(gptr*) &check_param.use_buffers, (gptr*) &check_param.use_buffers, 0,
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
(gptr*) &opt_key_cache_block_size,
(gptr*) &opt_key_cache_block_size, 0,
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
(gptr*) &opt_myisam_block_size, (gptr*) &opt_myisam_block_size, 0,
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
......@@ -1020,8 +1027,8 @@ static int myisamchk(MI_CHECK *param, my_string filename)
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
{
if (param->testflag & (T_EXTEND | T_MEDIUM))
VOID(init_key_cache(&dflt_keycache,dflt_key_block_size,
param->use_buffers));
VOID(init_key_cache(dflt_keycache,opt_key_cache_block_size,
param->use_buffers,&dflt_key_cache_var));
VOID(init_io_cache(&param->read_cache,datafile,
(uint) param->read_buffer_length,
READ_CACHE,
......@@ -1438,7 +1445,8 @@ static int mi_sort_records(MI_CHECK *param,
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
DBUG_RETURN(0); /* Nothing to do */
init_key_cache(&dflt_keycache,dflt_key_block_size,param->use_buffers);
init_key_cache(dflt_keycache,opt_key_cache_block_size,param->use_buffers,
&dflt_key_cache_var);
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
WRITE_CACHE,share->pack.header_length,1,
MYF(MY_WME | MY_WAIT_IF_FULL)))
......
......@@ -166,6 +166,8 @@ typedef struct st_mi_isam_share { /* Shared between opens */
char *data_file_name, /* Resolved path names from symlinks */
*index_file_name;
byte *file_map; /* mem-map of file if possible */
KEY_CACHE_HANDLE *keycache; /* ref to the current key cache */
KEY_CACHE_HANDLE *reg_keycache; /* ref to the registered key cache */
MI_DECODE_TREE *decode_trees;
uint16 *decode_tables;
int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
......
......@@ -333,7 +333,8 @@ static int examine_log(my_string file_name, char **table_names)
bzero((gptr) com_count,sizeof(com_count));
init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1,
(tree_element_free) file_info_free, NULL);
VOID(init_key_cache(&dflt_keycache,dflt_key_block_size,KEY_CACHE_SIZE));
VOID(init_key_cache(dflt_keycache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE,
&dflt_key_cache_var));
files_open=0; access_time=0;
while (access_time++ != number_of_commands &&
......@@ -639,7 +640,7 @@ static int examine_log(my_string file_name, char **table_names)
goto end;
}
}
end_key_cache(&dflt_keycache,1);
end_key_cache(dflt_keycache,1);
delete_tree(&tree);
VOID(end_io_cache(&cache));
VOID(my_close(file,MYF(0)));
......@@ -659,7 +660,7 @@ static int examine_log(my_string file_name, char **table_names)
llstr(isamlog_filepos,llbuff)));
fflush(stderr);
end:
end_key_cache(&dflt_keycache,1);
end_key_cache(dflt_keycache,1);
delete_tree(&tree);
VOID(end_io_cache(&cache));
VOID(my_close(file,MYF(0)));
......
......@@ -35,9 +35,200 @@ SELECT @@small.key_buffer_size;
1048576
SELECT @@medium.key_buffer_size;
@@medium.key_buffer_size
4194304
0
SET @@global.key_buffer_size=@save_key_buffer;
SELECT @@default.key_buffer_size;
ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'default.key_buffer_size' at line 1
SELECT @@skr.table_type="test";
ERROR HY000: Variable 'table_type' is not a variable component (Can't be used as XXXX.variable_name)
select @@keycache1.key_cache_block_size;
@@keycache1.key_cache_block_size
0
select @@keycache1.key_buffer_size;
@@keycache1.key_buffer_size
0
set global keycache1.key_cache_block_size=2048;
select @@keycache1.key_buffer_size;
@@keycache1.key_buffer_size
0
select @@keycache1.key_cache_block_size;
@@keycache1.key_cache_block_size
2048
set global keycache1.key_buffer_size=1*1024*1024;
select @@keycache1.key_buffer_size;
@@keycache1.key_buffer_size
1048576
select @@keycache1.key_cache_block_size;
@@keycache1.key_cache_block_size
2048
set global keycache2.key_buffer_size=4*1024*1024;
select @@keycache2.key_buffer_size;
@@keycache2.key_buffer_size
4194304
select @@keycache2.key_cache_block_size;
@@keycache2.key_cache_block_size
1024
set global keycache1.key_buffer_size=0;
select @@keycache1.key_buffer_size;
@@keycache1.key_buffer_size
0
select @@keycache1.key_cache_block_size;
@@keycache1.key_cache_block_size
0
select @@key_buffer_size;
@@key_buffer_size
16777216
select @@key_cache_block_size;
@@key_cache_block_size
1024
drop table if exists t1, t2;
create table t1 (p int primary key, a char(10));
create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a));
insert into t1 values (1, 'qqqq'), (11, 'yyyy');
insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
(3, 1, 'yyyy'), (4, 3, 'zzzz');
select * from t1;
p a
1 qqqq
11 yyyy
select * from t2;
p i a
1 1 qqqq
2 1 pppp
3 1 yyyy
4 3 zzzz
update t1 set p=2 where p=1;
update t2 set i=2 where i=1;
cache index t1 keys in keycache1;
Table Op Msg_type Msg_text
test.t1 assign_to_keycache status OK
explain select p from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
select p from t1;
p
2
11
explain select i from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL k1 5 NULL 4 Using index
select i from t2;
i
2
2
2
3
explain select count(*) from t1, t2 where t1.p = t2.i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index
1 SIMPLE t2 index k1 k1 5 NULL 4 Using where; Using index
select count(*) from t1, t2 where t1.p = t2.i;
count(*)
3
cache index t2 keys in keycache1;
Table Op Msg_type Msg_text
test.t2 assign_to_keycache status OK
update t2 set p=p+1000, i=2 where a='qqqq';
cache index t2 keys in keycache2;
Table Op Msg_type Msg_text
test.t2 assign_to_keycache status OK
insert into t2 values (2000, 3, 'yyyy');
cache index t2 keys in keycache1;
Table Op Msg_type Msg_text
test.t2 assign_to_keycache status OK
update t2 set p=3000 where a='zzzz';
select * from t2;
p i a
1001 2 qqqq
2 2 pppp
3 2 yyyy
3000 3 zzzz
2000 3 yyyy
explain select p from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 Using index
select p from t2;
p
2
3
1001
2000
3000
explain select i from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL k1 5 NULL 5 Using index
select i from t2;
i
2
2
2
3
3
explain select a from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL k2 11 NULL 5 Using index
select a from t2;
a
pppp
qqqq
yyyy
yyyy
zzzz
select @@keycache2.key_buffer_size;
@@keycache2.key_buffer_size
4194304
select @@keycache2.key_cache_block_size;
@@keycache2.key_cache_block_size
1024
set global keycache2.key_buffer_size=0;
select @@keycache2.key_buffer_size;
@@keycache2.key_buffer_size
0
select @@keycache2.key_cache_block_size;
@@keycache2.key_cache_block_size
0
update t2 set p=4000 where a='zzzz';
update t1 set p=p+1;
set global keycache1.key_buffer_size=0;
select * from t2;
p i a
1001 2 qqqq
2 2 pppp
3 2 yyyy
4000 3 zzzz
2000 3 yyyy
select p from t2;
p
2
3
1001
2000
4000
explain select i from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL k1 5 NULL 5 Using index
select i from t2;
i
2
2
2
3
3
explain select a from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL k2 11 NULL 5 Using index
select a from t2;
a
pppp
qqqq
yyyy
yyyy
zzzz
select * from t1;
p a
3 qqqq
12 yyyy
select p from t1;
p
3
12
#
# Test of key cache
# Test of multiple key caches
#
SET @save_key_buffer=@@key_buffer_size;
......@@ -40,3 +40,83 @@ SET @@global.key_buffer_size=@save_key_buffer;
SELECT @@default.key_buffer_size;
--error 1270
SELECT @@skr.table_type="test";
select @@keycache1.key_cache_block_size;
select @@keycache1.key_buffer_size;
set global keycache1.key_cache_block_size=2048;
select @@keycache1.key_buffer_size;
select @@keycache1.key_cache_block_size;
set global keycache1.key_buffer_size=1*1024*1024;
select @@keycache1.key_buffer_size;
select @@keycache1.key_cache_block_size;
set global keycache2.key_buffer_size=4*1024*1024;
select @@keycache2.key_buffer_size;
select @@keycache2.key_cache_block_size;
set global keycache1.key_buffer_size=0;
select @@keycache1.key_buffer_size;
select @@keycache1.key_cache_block_size;
select @@key_buffer_size;
select @@key_cache_block_size;
--disable_warnings
drop table if exists t1, t2;
--enable_warnings
create table t1 (p int primary key, a char(10));
create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a));
insert into t1 values (1, 'qqqq'), (11, 'yyyy');
insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
(3, 1, 'yyyy'), (4, 3, 'zzzz');
select * from t1;
select * from t2;
update t1 set p=2 where p=1;
update t2 set i=2 where i=1;
cache index t1 keys in keycache1;
explain select p from t1;
select p from t1;
explain select i from t2;
select i from t2;
explain select count(*) from t1, t2 where t1.p = t2.i;
select count(*) from t1, t2 where t1.p = t2.i;
cache index t2 keys in keycache1;
update t2 set p=p+1000, i=2 where a='qqqq';
cache index t2 keys in keycache2;
insert into t2 values (2000, 3, 'yyyy');
cache index t2 keys in keycache1;
update t2 set p=3000 where a='zzzz';
select * from t2;
explain select p from t2;
select p from t2;
explain select i from t2;
select i from t2;
explain select a from t2;
select a from t2;
select @@keycache2.key_buffer_size;
select @@keycache2.key_cache_block_size;
set global keycache2.key_buffer_size=0;
select @@keycache2.key_buffer_size;
select @@keycache2.key_cache_block_size;
update t2 set p=4000 where a='zzzz';
update t1 set p=p+1;
set global keycache1.key_buffer_size=0;
select * from t2;
select p from t2;
explain select i from t2;
select i from t2;
explain select a from t2;
select a from t2;
select * from t1;
select p from t1;
This diff is collapsed.
......@@ -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));
......@@ -694,16 +700,27 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
{
int error;
const char *errmsg;
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;
char *keycache_name= table_list->option;
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 (table_list->use_index)
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)
......@@ -715,23 +732,54 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
if (kmap)
map= kmap;
}
if ((error= mi_assign_to_keycache(file, map, keycache_name)))
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->cache);
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 read from index file (errno: %d)", my_errno);
"Failed to flush to index file (errno: %d)", my_errno);
errmsg= buf;
}
error= HA_ADMIN_FAILED;
error= HA_ADMIN_CORRUPT;
goto err;
}
DBUG_RETURN(HA_ADMIN_OK);
goto ok;
err:
if (!triggered)
{
MI_CHECK param;
myisamchk_init(&param);
......@@ -741,8 +789,33 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
param.table_name= table->table_name;
param.testflag= 0;
mi_check_print_error(&param, errmsg);
DBUG_RETURN(error);
}
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);
}
......
......@@ -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 ||
......
......@@ -984,17 +984,41 @@ 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)
{
if (keybuff_size)
(void) init_key_cache(&dflt_keycache,dflt_key_block_size,
(ulong) keybuff_size);
if (!key_cache->cache)
{
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;
return !init_key_cache( &key_cache->cache,
key_cache->block_size,
key_cache->buff_size,
key_cache);
}
return 0;
}
void ha_resize_key_cache(void)
int ha_resize_key_cache(KEY_CACHE_VAR *key_cache)
{
if (key_cache->cache)
{
return !resize_key_cache(&key_cache->cache,
key_cache->buff_size);
}
return 0;
}
int ha_end_key_cache(KEY_CACHE_VAR *key_cache)
{
(void) resize_key_cache(&dflt_keycache,(ulong) keybuff_size);
if (key_cache->cache)
{
end_key_cache(&key_cache->cache, 1);
return key_cache->cache ? 1 : 0;
}
return 0;
}
......
......@@ -387,8 +387,9 @@ 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_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);
......
......@@ -386,6 +386,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
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 check_access(THD *thd, ulong access, const char *db=0, ulong *save_priv=0,
......@@ -407,6 +411,8 @@ 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();
......@@ -769,7 +775,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_global_system_variables, 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;
......
......@@ -289,8 +289,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;
......@@ -343,6 +341,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,
......@@ -866,6 +865,7 @@ void clean_up(bool print_message)
grant_free();
query_cache_destroy();
table_cache_free();
assign_cache_free();
hostname_cache_free();
item_user_lock_free();
lex_free(); /* Free some memory */
......@@ -875,7 +875,8 @@ void clean_up(bool print_message)
udf_free();
#endif
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
end_key_cache(&dflt_keycache,1);
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
......@@ -950,6 +951,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);
......@@ -1508,14 +1510,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);
......@@ -2081,6 +2084,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);
......@@ -2131,6 +2135,7 @@ static void init_ssl()
static int 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);
......@@ -2193,7 +2198,10 @@ static int init_server_components()
}
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())
......@@ -3426,7 +3434,7 @@ enum options
OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT, 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_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,
......@@ -4106,10 +4114,16 @@ 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},
{"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,
......@@ -4470,13 +4484,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},
......@@ -4682,7 +4702,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 */
......@@ -5320,18 +5341,20 @@ 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:
{
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->buff_size;
}
case OPT_KEY_CACHE_BLOCK_SIZE:
{
KEY_CACHE_VAR *key_cache;
if (!(key_cache= get_or_create_key_cache(keyname, key_length)))
exit(1);
return (gptr*) &key_cache->size;
return (gptr*) &key_cache->block_size;
}
}
return option->value;
......@@ -5385,8 +5408,10 @@ 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 */
keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7))->size);
/* 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;
}
......
......@@ -59,6 +59,9 @@
#include "ha_innodb.h"
#endif
ulong dflt_key_buff_size;
uint dflt_key_cache_block_size;
static HASH system_variable_hash;
const char *bool_type_names[]= { "OFF", "ON", NullS };
TYPELIB bool_typelib=
......@@ -88,7 +91,7 @@ static void fix_query_cache_size(THD *thd, enum_var_type type);
static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type);
static void fix_myisam_max_sort_file_size(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);
......@@ -137,6 +140,7 @@ 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_bool_ptr sys_local_infile("local_infile",
&opt_local_infile);
sys_var_thd_bool sys_log_warnings("log_warnings", &SV::log_warnings);
......@@ -390,6 +394,7 @@ sys_var *sys_variables[]=
&sys_interactive_timeout,
&sys_join_buffer_size,
&sys_key_buffer_size,
&sys_key_cache_block_size,
&sys_last_insert_id,
&sys_local_infile,
&sys_log_binlog,
......@@ -547,6 +552,8 @@ 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},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
{sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS},
......@@ -1412,70 +1419,93 @@ void sys_var_collation_connection::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 };
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));
}
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)
{
int rc;
ulonglong tmp= var->value->val_int();
if (!base_name.length)
{
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);
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)))
return 1;
}
if (!tmp)
{
if (!key_cache->cache)
return 0;
/* Delete not default key caches */
if (base_name.length != 7 || memcpy(base_name.str, "default", 7))
if (key_cache != &dflt_key_cache_var)
{
/*
QQ: Here we should move tables using this key cache to 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
*/
delete key_cache;
return 0;
return (reassign_keycache_tables(thd, key_cache,
default_key_cache_base.str, 1));
}
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);
/* QQ: Needs to be updated when we have multiple key caches */
keybuff_size= key_cache->size;
ha_resize_key_cache();
return 0;
if (!key_cache->cache)
return (bool)(ha_key_cache(key_cache));
else
return (bool)(ha_resize_key_cache(key_cache));
}
static ulonglong zero=0;
byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
bool sys_var_key_cache_block_size::update(THD *thd, set_var *var)
{
const char *name;
uint length;
ulong tmp= var->value->val_int();
if (!base->str)
{
name= "default";
length= 7;
}
else
{
name= base->str;
length= base->length;
}
KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, length);
if (!key_cache)
return (byte*) &zero;
return (byte*) &key_cache->size;
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;
}
/*****************************************************************************
......@@ -2062,27 +2092,40 @@ 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", name));
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)
{
KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name,
length);
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;
......@@ -2091,7 +2134,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;
}
......
......@@ -29,6 +29,8 @@ class sys_var;
class set_var;
typedef struct system_variables SV;
extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
extern uint dflt_key_cache_block_size;
extern ulong dflt_key_buff_size;
enum enum_var_type
{
......@@ -529,15 +531,43 @@ class sys_var_collation_connection :public sys_var_collation
};
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; }
};
......@@ -709,5 +739,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 *));
......@@ -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;
......@@ -765,6 +764,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 */
......@@ -804,6 +805,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(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)
......@@ -846,6 +918,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
{
......@@ -859,6 +934,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)))
......@@ -877,6 +954,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,
......
......@@ -1577,10 +1577,79 @@ 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_WRITE, 0, 0, 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)
{
VOID(pthread_mutex_unlock(&LOCK_assign));
bzero((byte *) &table, sizeof(table));
table.option= dest_name;
table.lock_type= TL_READ;
table.db= key_cache_asmt->db_name;
table.alias= table.real_name= key_cache_asmt->table_name;
thd->open_options|= HA_OPEN_TO_ASSIGN;
table.table = open_ltable(thd, &table, TL_READ);
thd->open_options&= ~HA_OPEN_TO_ASSIGN;
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;
}
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
......
......@@ -321,8 +321,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)
......
......@@ -1872,15 +1872,26 @@ keycache_list:
| keycache_list ',' assign_to_keycache;
assign_to_keycache:
table_ident cache_keys_spec ident
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_WRITE,
TL_READ,
sel->get_use_index(),
(List<String> *)0,
&($3)))
&($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;
}
;
......
......@@ -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 */
......@@ -159,6 +186,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 */
......@@ -197,3 +225,5 @@ typedef struct st_open_table_list
char *db,*table;
uint32 in_use,locked;
} OPEN_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