Many files:

Added key cache assignment
mi_locking.c:
  Added key cache assignment: correction
my_sys.h:
  Added key cache variable structure


include/my_sys.h:
  Added key cache variable structure
include/my_base.h:
  Added key cache assignment
include/myisam.h:
  Added key cache assignment
include/my_global.h:
  Added key cache assignment
isam/_page.c:
  Added key cache assignment
isam/close.c:
  Added key cache assignment
isam/isamchk.c:
  Added key cache assignment
isam/isamlog.c:
  Added key cache assignment
isam/panic.c:
  Added key cache assignment
isam/_locking.c:
  Added key cache assignment
isam/test2.c:
  Added key cache assignment
isam/test3.c:
  Added key cache assignment
myisam/myisamdef.h:
  Added key cache assignment
myisam/mi_check.c:
  Added key cache assignment
myisam/mi_close.c:
  Added key cache assignment
myisam/mi_extra.c:
  Added key cache assignment
myisam/mi_page.c:
  Added key cache assignment
myisam/mi_panic.c:
  Added key cache assignment
myisam/mi_preload.c:
  Added key cache assignment
myisam/mi_test1.c:
  Added key cache assignment
myisam/mi_test2.c:
  Added key cache assignment
myisam/mi_test3.c:
  Added key cache assignment
myisam/myisamchk.c:
  Added key cache assignment
myisam/myisamlog.c:
  Added key cache assignment
myisam/mi_delete_all.c:
  Added key cache assignment
myisam/mi_locking.c:
  Added key cache assignment: correction
myisam/mi_keycache.c:
  Added key cache assignment
sql/handler.h:
  Added key cache assignment
sql/mysql_priv.h:
  Added key cache assignment
sql/set_var.h:
  Added key cache assignment
sql/table.h:
  Added key cache assignment
sql/ha_myisam.cc:
  Added key cache assignment
sql/ha_myisammrg.cc:
  Added key cache assignment
sql/handler.cc:
  Added key cache assignment
sql/mysqld.cc:
  Added key cache assignment
sql/set_var.cc:
  Added key cache assignment
sql/sql_base.cc:
  Added key cache assignment
sql/sql_table.cc:
  Added key cache assignment
sql/sql_test.cc:
  Added key cache assignment
sql/sql_yacc.yy:
  Added key cache assignment
mysys/mf_keycache.c:
  Added key cache assignment
mysql-test/t/key_cache.test:
  Added key cache assignment
mysql-test/r/key_cache.result:
  Added key cache assignment
This commit is contained in:
unknown 2003-08-02 02:43:18 -07:00
parent 4f6f7f7ded
commit b6d27e20e1
43 changed files with 1133 additions and 295 deletions

View File

@ -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() */

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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),

View File

@ -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;

View File

@ -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)))

View File

@ -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)));

View File

@ -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))

View File

@ -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)

View File

@ -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++)

View File

@ -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 */
}

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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;

View File

@ -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),

View File

@ -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))

View File

@ -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;

View File

@ -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"));

View File

@ -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);

View File

@ -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++)

View File

@ -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)))

View File

@ -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*);

View File

@ -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)));

View File

@ -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

View File

@ -1,5 +1,5 @@
#
# 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;

View File

@ -138,20 +138,21 @@ typedef struct st_block_link
KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
} BLOCK_LINK;
void *dflt_keycache;
uint key_cache_block_size; /* size of the page buffer of a cache block */
ulong my_cache_w_requests, my_cache_write, /* counters */
my_cache_r_requests, my_cache_read; /* for statistics */
ulong my_blocks_used, /* number of currently used blocks */
my_blocks_changed; /* number of currently dirty blocks */
KEY_CACHE_VAR dflt_key_cache_var=
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
KEY_CACHE_HANDLE *dflt_keycache= &dflt_key_cache_var.cache;
#define CHANGED_BLOCKS_HASH 128 /* must be power of 2 */
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
typedef struct st_key_cache
{
KEY_CACHE_VAR *env; /* pointer to key cache variables (if any) */
my_bool key_cache_inited;
uint key_cache_shift;
ulong key_cache_mem_size; /* specified size of the cache memory */
uint key_cache_block_size; /* size of the page buffer of a cache block */
uint hash_entries; /* max number of entries in the hash table */
int hash_links; /* max number of hash links */
@ -159,12 +160,8 @@ typedef struct st_key_cache
int disk_blocks; /* max number of blocks in the cache */
ulong blocks_used; /* number of currently used blocks */
ulong blocks_changed; /* number of currently dirty blocks */
ulong cache_w_requests;
ulong cache_write;
ulong cache_r_requests;
ulong cache_read;
#if defined(KEYCACHE_DEBUG)
ulong_blocks_available; /* number of blocks available in the LRU chain */
long blocks_available; /* number of blocks available in the LRU chain */
#endif
HASH_LINK **hash_root; /* arr. of entries into hash table buckets */
HASH_LINK *hash_link_root; /* memory for hash table links */
@ -172,14 +169,14 @@ typedef struct st_key_cache
BLOCK_LINK *block_root; /* memory for block links */
byte HUGE_PTR *block_mem; /* memory for block buffers */
BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */
pthread_mutex_t thr_lock_keycache;
pthread_mutex_t cache_lock; /* to lock access to the cache structure */
KEYCACHE_WQUEUE waiting_for_hash_link; /* waiting for a free hash link */
KEYCACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */
BLOCK_LINK *changed_blocks[CHANGED_BLOCKS_HASH]; /* hash for dirty file bl.*/
BLOCK_LINK *file_blocks[CHANGED_BLOCKS_HASH]; /* hash for other file bl.*/
} KEY_CACHE;
static int flush_all_key_blocks();
static int flush_all_key_blocks(KEY_CACHE_HANDLE keycache);
static void test_key_cache(KEY_CACHE *keycache,
const char *where, my_bool lock);
@ -279,8 +276,8 @@ static uint next_power(uint value)
return number of blocks in it
*/
int init_key_cache(void **pkeycache, uint key_cache_block_size,
ulong use_mem)
int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
ulong use_mem, KEY_CACHE_VAR *env)
{
uint blocks, hash_links, length;
int error;
@ -288,12 +285,12 @@ int init_key_cache(void **pkeycache, uint key_cache_block_size,
DBUG_ENTER("init_key_cache");
if (!*pkeycache)
{
if (!(*pkeycache= my_malloc(sizeof(KEY_CACHE), MYF(MY_ZEROFILL))))
DBUG_RETURN(0);
}
keycache= (KEY_CACHE *) *pkeycache;
if (!(keycache= (KEY_CACHE *) *pkeycache) &&
!(keycache= (KEY_CACHE *) my_malloc(sizeof(KEY_CACHE),
MYF(MY_ZEROFILL))))
DBUG_RETURN(0);
keycache->env= env;
KEYCACHE_DEBUG_OPEN;
if (keycache->key_cache_inited && keycache->disk_blocks > 0)
@ -301,20 +298,24 @@ int init_key_cache(void **pkeycache, uint key_cache_block_size,
DBUG_PRINT("warning",("key cache already in use"));
DBUG_RETURN(0);
}
if (env && ! keycache->key_cache_inited)
{
env->cache_w_requests= env->cache_r_requests= 0;
env->cache_read= env->cache_write=0;
}
if (! keycache->key_cache_inited)
{
keycache->key_cache_inited= TRUE;
keycache->disk_blocks= -1;
pthread_mutex_init(&keycache->thr_lock_keycache, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&keycache->cache_lock, MY_MUTEX_INIT_FAST);
keycache->key_cache_shift= my_bit_log2(key_cache_block_size);
keycache->key_cache_mem_size= use_mem;
keycache->key_cache_block_size= key_cache_block_size;
DBUG_PRINT("info",("key_cache_block_size: %u",
key_cache_block_size));
}
keycache->cache_w_requests= keycache->cache_r_requests= 0;
keycache->cache_read= keycache->cache_write=0;
keycache->block_mem= NULL;
keycache->block_root= NULL;
@ -375,8 +376,10 @@ int init_key_cache(void **pkeycache, uint key_cache_block_size,
keycache->hash_links_used= 0;
keycache->free_hash_list= NULL;
keycache->blocks_used= keycache->blocks_changed= 0;
if (env)
env->blocks_used= env->blocks_changed= 0;
#if defined(KEYCACHE_DEBUG)
keycache->_blocks_available=0;
keycache->blocks_available=0;
#endif
/* The LRU chain is empty after initialization */
keycache->used_last=NULL;
@ -395,6 +398,9 @@ int init_key_cache(void **pkeycache, uint key_cache_block_size,
bzero((gptr) keycache->file_blocks,
sizeof(keycache->file_blocks[0])*CHANGED_BLOCKS_HASH);
if (env)
env->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
*pkeycache= keycache;
DBUG_RETURN((int) blocks);
err:
@ -402,7 +408,9 @@ err:
if (keycache->block_mem)
my_free_lock((gptr) keycache->block_mem, MYF(0));
if (keycache->block_mem)
my_free((gptr) keycache->block_root,MYF(0));
my_free((gptr) keycache->block_root, MYF(0));
if (*pkeycache)
my_free((gptr) keycache, MYF(0));
my_errno= error;
DBUG_RETURN(0);
}
@ -411,23 +419,23 @@ err:
/*
Resize the key cache
*/
int resize_key_cache(void **pkeycache, ulong use_mem)
int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, ulong use_mem)
{
int blocks;
KEY_CACHE *keycache= (KEY_CACHE *) *pkeycache;
uint key_cache_block_size= keycache->key_cache_block_size;
KEY_CACHE *keycache= *pkeycache;
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
if (flush_all_key_blocks())
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (flush_all_key_blocks(keycache))
{
/* TODO: if this happens, we should write a warning in the log file ! */
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
return 0;
}
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
end_key_cache(pkeycache, 0);
/* the following will work even if memory is 0 */
blocks=init_key_cache(pkeycache, key_cache_block_size, use_mem);
blocks=init_key_cache(pkeycache, keycache->key_cache_block_size, use_mem,
keycache->env);
return blocks;
}
@ -436,9 +444,10 @@ int resize_key_cache(void **pkeycache, ulong use_mem)
Remove key_cache from memory
*/
void end_key_cache(void **pkeycache, my_bool cleanup)
void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
{
KEY_CACHE *keycache= (KEY_CACHE *) *pkeycache;
KEY_CACHE *keycache= *pkeycache;
KEY_CACHE_VAR *env= keycache->env;
DBUG_ENTER("end_key_cache");
if (keycache->disk_blocks > 0)
{
@ -451,15 +460,16 @@ void end_key_cache(void **pkeycache, my_bool cleanup)
}
KEYCACHE_DEBUG_CLOSE;
keycache->key_cache_inited=0;
DBUG_PRINT("status",
("used: %d changed: %d w_requests: %ld \
writes: %ld r_requests: %ld reads: %ld",
keycache->blocks_used, keycache->blocks_changed,
keycache->cache_w_requests, keycache->cache_write,
keycache->cache_r_requests, keycache->cache_read));
if (env)
DBUG_PRINT("status",
("used: %d changed: %d w_requests: %ld \
writes: %ld r_requests: %ld reads: %ld",
env->blocks_used, env->blocks_changed,
env->cache_w_requests, env->cache_write,
env->cache_r_requests, env->cache_read));
if (cleanup)
{
pthread_mutex_destroy(&keycache->thr_lock_keycache);
pthread_mutex_destroy(&keycache->cache_lock);
my_free(*pkeycache, MYF(0));
*pkeycache= NULL;
}
@ -595,6 +605,8 @@ static void link_to_file_list(KEY_CACHE *keycache,
{
block->status&=~BLOCK_CHANGED;
keycache->blocks_changed--;
if (keycache->env)
keycache->env->blocks_changed--;
}
}
@ -612,6 +624,8 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
&keycache->changed_blocks[FILE_HASH(block->hash_link->file)]);
block->status|=BLOCK_CHANGED;
keycache->blocks_changed++;
if (keycache->env)
keycache->env->blocks_changed++;
}
@ -652,7 +666,7 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool at_end)
KEYCACHE_DBUG_PRINT("link_block",
("linked,unlinked block %u status=%x #requests=%u #available=%u",
BLOCK_NUMBER(block), block->status,
block->requests, blocks_available));
block->requests, keycache->blocks_available));
#endif
return;
}
@ -678,7 +692,8 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool at_end)
("linked block %u:%1u status=%x #requests=%u #available=%u",
BLOCK_NUMBER(block),at_end,block->status,
block->requests, keycache->blocks_available));
KEYCACHE_DBUG_ASSERT(keycache->blocks_available <= keycache->blocks_used);
KEYCACHE_DBUG_ASSERT((ulong) keycache->blocks_available <=
keycache->blocks_used);
#endif
}
@ -758,7 +773,7 @@ static inline void wait_for_readers(KEY_CACHE *keycache, BLOCK_LINK *block)
while (block->hash_link->requests)
{
block->condvar=&thread->suspend;
keycache_pthread_cond_wait(&thread->suspend, &keycache->thr_lock_keycache);
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
block->condvar=NULL;
}
}
@ -862,7 +877,7 @@ restart:
hash_link= hash_link->next;
#if defined(KEYCACHE_DEBUG)
cnt++;
if (! (cnt <= my_hash_links_used))
if (! (cnt <= keycache->hash_links_used))
{
int i;
for (i=0, hash_link= *start ;
@ -896,7 +911,7 @@ restart:
thread->opt_info= (void *) &page;
link_into_queue(&keycache->waiting_for_hash_link, thread);
keycache_pthread_cond_wait(&thread->suspend,
&keycache->thr_lock_keycache);
&keycache->cache_lock);
thread->opt_info= NULL;
goto restart;
}
@ -970,7 +985,7 @@ restart:
do
{
keycache_pthread_cond_wait(&thread->suspend,
&keycache->thr_lock_keycache);
&keycache->cache_lock);
}
while(thread->next);
}
@ -999,6 +1014,8 @@ restart:
block->offset= keycache->key_cache_block_size;
block->requests= 1;
keycache->blocks_used++;
if (keycache->env)
keycache->env->blocks_used++;
link_to_file_list(keycache, block, file, 0);
block->hash_link= hash_link;
page_status= PAGE_TO_BE_READ;
@ -1022,7 +1039,7 @@ restart:
do
{
keycache_pthread_cond_wait(&thread->suspend,
&keycache->thr_lock_keycache);
&keycache->cache_lock);
}
while (thread->next);
thread->opt_info= NULL;
@ -1054,7 +1071,7 @@ restart:
KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
/*
The call is thread safe because only the current
thread might change the block->hash_link value
@ -1062,8 +1079,9 @@ restart:
error=my_pwrite(block->hash_link->file, block->buffer,
block->length, block->hash_link->diskpos,
MYF(MY_NABP | MY_WAIT_IF_FULL));
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache->cache_write++;
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_write++;
}
block->status|= BLOCK_REASSIGNED;
@ -1102,8 +1120,8 @@ restart:
PAGE_READ : PAGE_WAIT_TO_BE_READ;
}
}
keycache->cache_read++;
if (keycache->env)
keycache->env->cache_read++;
}
else
{
@ -1141,7 +1159,7 @@ static void read_block(KEY_CACHE *keycache,
{
uint got_length;
/* On entry THR_LOCK_keycache is locked */
/* On entry cache_lock is locked */
KEYCACHE_THREAD_TRACE("read_block");
if (primary)
@ -1155,10 +1173,10 @@ static void read_block(KEY_CACHE *keycache,
("page to be read by primary request"));
/* Page is not in buffer yet, is to be read from disk */
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
got_length= my_pread(block->hash_link->file, block->buffer,
read_length, block->hash_link->diskpos, MYF(0));
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (got_length < min_length)
block->status|= BLOCK_ERROR;
else
@ -1187,7 +1205,7 @@ static void read_block(KEY_CACHE *keycache,
do
{
keycache_pthread_cond_wait(&thread->suspend,
&keycache->thr_lock_keycache);
&keycache->cache_lock);
}
while (thread->next);
}
@ -1206,13 +1224,12 @@ static void read_block(KEY_CACHE *keycache,
returns adress from where data is read
*/
byte *key_cache_read(void *pkeycache,
byte *key_cache_read(KEY_CACHE_HANDLE keycache,
File file, my_off_t filepos, byte *buff, uint length,
uint block_length __attribute__((unused)),
int return_buffer __attribute__((unused)))
{
int error=0;
KEY_CACHE *keycache= (KEY_CACHE *) pkeycache;
DBUG_ENTER("key_cache_read");
DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
(uint) file,(ulong) filepos,length));
@ -1239,8 +1256,9 @@ byte *key_cache_read(void *pkeycache,
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache->cache_r_requests++;
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_r_requests++;
block=find_key_block(keycache, file, filepos, 0, &page_st);
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
{
@ -1268,7 +1286,7 @@ byte *key_cache_read(void *pkeycache,
#endif
{
#if !defined(SERIALIZED_READ_FROM_CACHE)
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
#endif
/* Copy data from the cache buffer */
@ -1278,7 +1296,7 @@ byte *key_cache_read(void *pkeycache,
memcpy(buff, block->buffer+offset, (size_t) read_length);
#if !defined(SERIALIZED_READ_FROM_CACHE)
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_lock(&keycache->cache_lock);
#endif
}
}
@ -1290,7 +1308,7 @@ byte *key_cache_read(void *pkeycache,
*/
unreg_request(keycache, block,1);
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
if (status & BLOCK_ERROR)
DBUG_RETURN((byte *) 0);
@ -1309,10 +1327,13 @@ byte *key_cache_read(void *pkeycache,
}
/* Key cache is not used */
statistic_increment(keycache->cache_r_requests,
&keycache->thr_lock_keycache);
statistic_increment(keycache->cache_read,
&keycache->thr_lock_keycache);
if (keycache->env)
{
statistic_increment(keycache->env->cache_r_requests,
&keycache->cache_lock);
statistic_increment(keycache->env->cache_read,
&keycache->cache_lock);
}
if (my_pread(file, (byte*) buff, length, filepos, MYF(MY_NABP)))
error= 1;
DBUG_RETURN(error? (byte*) 0 : buff);
@ -1333,10 +1354,9 @@ byte *key_cache_read(void *pkeycache,
0 if a success, 1 -otherwise.
*/
int key_cache_insert(void *pkeycache,
int key_cache_insert(KEY_CACHE_HANDLE keycache,
File file, my_off_t filepos, byte *buff, uint length)
{
KEY_CACHE *keycache= (KEY_CACHE *) pkeycache;
DBUG_ENTER("key_cache_insert");
DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
(uint) file,(ulong) filepos, length));
@ -1356,14 +1376,15 @@ int key_cache_insert(void *pkeycache,
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache->cache_r_requests++;
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_r_requests++;
block= find_key_block(keycache, 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(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
#endif
/* Copy data from buff */
@ -1373,7 +1394,7 @@ int key_cache_insert(void *pkeycache,
memcpy(block->buffer+offset, buff, (size_t) read_length);
#if !defined(SERIALIZED_READ_FROM_CACHE)
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_lock(&keycache->cache_lock);
#endif
block->status= BLOCK_READ;
block->length= read_length+offset;
@ -1386,7 +1407,7 @@ int key_cache_insert(void *pkeycache,
*/
unreg_request(keycache, block,1);
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
if (block->status & BLOCK_ERROR)
DBUG_RETURN(1);
@ -1409,14 +1430,13 @@ int key_cache_insert(void *pkeycache,
have been flushed from key cache before the function starts
*/
int key_cache_write(void *pkeycache,
int key_cache_write(KEY_CACHE_HANDLE keycache,
File file, my_off_t filepos, byte *buff, uint length,
uint block_length __attribute__((unused)),
int dont_write)
{
reg1 BLOCK_LINK *block;
int error=0;
KEY_CACHE *keycache= (KEY_CACHE *) pkeycache;
DBUG_ENTER("key_cache_write");
DBUG_PRINT("enter", ("file %u, filepos %lu, length %u block_length %u",
@ -1425,8 +1445,9 @@ int key_cache_write(void *pkeycache,
if (!dont_write)
{
/* Force writing from buff into disk */
statistic_increment(keycache->cache_write,
&keycache->thr_lock_keycache);
if (keycache->env)
statistic_increment(keycache->env->cache_write,
&keycache->cache_lock);
if (my_pwrite(file, buff, length, filepos, MYF(MY_NABP | MY_WAIT_IF_FULL)))
DBUG_RETURN(1);
}
@ -1450,8 +1471,9 @@ int key_cache_write(void *pkeycache,
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache->cache_w_requests++;
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_w_requests++;
block= find_key_block(keycache, file, filepos, 1, &page_st);
if (block->status != BLOCK_ERROR && page_st != PAGE_READ &&
(offset || read_length < keycache->key_cache_block_size))
@ -1489,12 +1511,12 @@ int key_cache_write(void *pkeycache,
if (block->status & BLOCK_ERROR)
{
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
error= 1;
break;
}
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
buff+= read_length;
filepos+= read_length;
@ -1507,10 +1529,13 @@ int key_cache_write(void *pkeycache,
/* Key cache is not used */
if (dont_write)
{
statistic_increment(keycache->cache_w_requests,
&keycache->thr_lock_keycache);
statistic_increment(keycache->cache_write,
&keycache->thr_lock_keycache);
if (keycache->env)
{
statistic_increment(keycache->env->cache_w_requests,
&keycache->cache_lock);
statistic_increment(keycache->env->cache_write,
&keycache->cache_lock);
}
if (my_pwrite(file, (byte*) buff, length, filepos,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
error=1;
@ -1577,26 +1602,27 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
uint count= end-cache;
/* Don't lock the cache during the flush */
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
/*
As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
we are guarunteed no thread will change them
*/
qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_lock(&keycache->cache_lock);
for ( ; cache != end ; cache++)
{
BLOCK_LINK *block= *cache;
KEYCACHE_DBUG_PRINT("flush_cached_blocks",
("block %u to be flushed", BLOCK_NUMBER(block)));
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
error= my_pwrite(file, block->buffer+block->offset, block->length,
block->hash_link->diskpos,
MYF(MY_NABP | MY_WAIT_IF_FULL));
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache->cache_write++;
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_write++;
if (error)
{
block->status|= BLOCK_ERROR;
@ -1607,6 +1633,8 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{
keycache->blocks_changed--;
if (keycache->env)
keycache->env->blocks_changed--;
free_block(keycache, block);
}
else
@ -1625,12 +1653,12 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
Flush all blocks for a file to disk
*/
int flush_key_blocks(void *pkeycache,
int flush_key_blocks(KEY_CACHE_HANDLE keycache,
File file, enum flush_type type)
{
BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
int last_errno= 0;
KEY_CACHE *keycache= (KEY_CACHE *) pkeycache;
DBUG_ENTER("flush_key_blocks");
DBUG_PRINT("enter",("file: %d blocks_used: %d blocks_changed: %d",
file, keycache->blocks_used, keycache->blocks_changed));
@ -1640,7 +1668,7 @@ int flush_key_blocks(void *pkeycache,
test_key_cache(keycache, "start of flush_key_blocks", 0););
#endif
keycache_pthread_mutex_lock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_lock(&keycache->cache_lock);
cache= cache_buff;
if (keycache->disk_blocks > 0 &&
@ -1735,6 +1763,8 @@ restart:
{
/* It's a temporary file */
keycache->blocks_changed--;
if (keycache->env)
keycache->env->blocks_changed--;
free_block(keycache, block);
}
}
@ -1764,7 +1794,7 @@ restart:
do
{
keycache_pthread_cond_wait(&thread->suspend,
&keycache->thr_lock_keycache);
&keycache->cache_lock);
}
while (thread->next);
}
@ -1799,7 +1829,7 @@ restart:
}
}
keycache_pthread_mutex_unlock(&keycache->thr_lock_keycache);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
#ifndef DBUG_OFF
DBUG_EXECUTE("check_keycache",
@ -1849,7 +1879,7 @@ static int flush_all_key_blocks(KEY_CACHE *keycache)
/*
Test if disk-cache is ok
*/
static void test_key_cache(KEY_CACHE *keycache,
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
const char *where __attribute__((unused)),
my_bool lock __attribute__((unused)))
{

View File

@ -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);
}

View File

@ -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 ||

View File

@ -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)
{
(void) resize_key_cache(&dflt_keycache,(ulong) keybuff_size);
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)
{
if (key_cache->cache)
{
end_key_cache(&key_cache->cache, 1);
return key_cache->cache ? 1 : 0;
}
return 0;
}

View File

@ -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);

View File

@ -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;

View File

@ -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->size;
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->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;
}

View File

@ -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,71 +1419,94 @@ 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();
if (!key_cache->cache)
return (bool)(ha_key_cache(key_cache));
else
return (bool)(ha_resize_key_cache(key_cache));
}
bool sys_var_key_cache_block_size::update(THD *thd, set_var *var)
{
ulong tmp= var->value->val_int();
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;
}
static ulonglong zero=0;
byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
const char *name;
uint length;
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;
}
/*****************************************************************************
Functions to handle SET NAMES and SET CHARACTER SET
@ -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;
}

View File

@ -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 @@ public:
};
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_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(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 *));

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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;
}
;

View File

@ -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;