summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_base.h4
-rw-r--r--include/my_global.h3
-rw-r--r--include/my_sys.h55
-rw-r--r--include/myisam.h2
-rw-r--r--isam/_locking.c4
-rw-r--r--isam/_page.c8
-rw-r--r--isam/close.c2
-rw-r--r--isam/isamchk.c12
-rw-r--r--isam/isamlog.c8
-rw-r--r--isam/panic.c2
-rw-r--r--isam/test2.c2
-rw-r--r--isam/test3.c2
-rw-r--r--myisam/mi_check.c22
-rw-r--r--myisam/mi_close.c2
-rw-r--r--myisam/mi_delete_all.c2
-rw-r--r--myisam/mi_extra.c7
-rw-r--r--myisam/mi_keycache.c24
-rw-r--r--myisam/mi_locking.c20
-rw-r--r--myisam/mi_page.c8
-rw-r--r--myisam/mi_panic.c2
-rw-r--r--myisam/mi_preload.c6
-rw-r--r--myisam/mi_test1.c2
-rw-r--r--myisam/mi_test2.c7
-rw-r--r--myisam/mi_test3.c2
-rw-r--r--myisam/myisamchk.c16
-rw-r--r--myisam/myisamdef.h2
-rw-r--r--myisam/myisamlog.c7
-rw-r--r--mysql-test/r/key_cache.result193
-rw-r--r--mysql-test/t/key_cache.test82
-rw-r--r--mysys/mf_keycache.c234
-rw-r--r--sql/ha_myisam.cc97
-rw-r--r--sql/ha_myisammrg.cc6
-rw-r--r--sql/handler.cc36
-rw-r--r--sql/handler.h5
-rw-r--r--sql/mysql_priv.h8
-rw-r--r--sql/mysqld.cc73
-rw-r--r--sql/set_var.cc156
-rw-r--r--sql/set_var.h41
-rw-r--r--sql/sql_base.cc131
-rw-r--r--sql/sql_table.cc71
-rw-r--r--sql/sql_test.cc5
-rw-r--r--sql/sql_yacc.yy17
-rw-r--r--sql/table.h34
43 files changed, 1130 insertions, 292 deletions
diff --git a/include/my_base.h b/include/my_base.h
index 8c5496cc2e0..d35b4ad7193 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -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() */
diff --git a/include/my_global.h b/include/my_global.h
index 9de8e310d79..c30d5efa0e6 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -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 */
diff --git a/include/my_sys.h b/include/my_sys.h
index dae7f3d4a11..c390171d890 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -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,
diff --git a/include/myisam.h b/include/myisam.h
index 11a59263b07..b0c9e198dae 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -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
diff --git a/isam/_locking.c b/isam/_locking.c
index 3964f7e8ddf..0ffb46a81f8 100644
--- a/isam/_locking.c
+++ b/isam/_locking.c
@@ -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;
diff --git a/isam/_page.c b/isam/_page.c
index fc150cf14bd..1a9719b53cc 100644
--- a/isam/_page.c
+++ b/isam/_page.c
@@ -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),
diff --git a/isam/close.c b/isam/close.c
index 075d67d60f5..37b35e450ae 100644
--- a/isam/close.c
+++ b/isam/close.c
@@ -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;
diff --git a/isam/isamchk.c b/isam/isamchk.c
index d3db440bf87..653d932c79d 100644
--- a/isam/isamchk.c
+++ b/isam/isamchk.c
@@ -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)))
diff --git a/isam/isamlog.c b/isam/isamlog.c
index ff3bca39e40..d8ea9d4ed80 100644
--- a/isam/isamlog.c
+++ b/isam/isamlog.c
@@ -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)));
diff --git a/isam/panic.c b/isam/panic.c
index 53e8762afd3..de765f50e62 100644
--- a/isam/panic.c
+++ b/isam/panic.c
@@ -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))
diff --git a/isam/test2.c b/isam/test2.c
index 68d2ee7a82a..541f4a39a29 100644
--- a/isam/test2.c
+++ b/isam/test2.c
@@ -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)
diff --git a/isam/test3.c b/isam/test3.c
index b753b6d4dac..1b867ba0348 100644
--- a/isam/test3.c
+++ b/isam/test3.c
@@ -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++)
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 61eba7d44bf..1b29fd01272 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -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 */
}
diff --git a/myisam/mi_close.c b/myisam/mi_close.c
index 6f13af41fbd..8e7fb497dfc 100644
--- a/myisam/mi_close.c
+++ b/myisam/mi_close.c
@@ -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;
diff --git a/myisam/mi_delete_all.c b/myisam/mi_delete_all.c
index 46d887a90d8..99873661feb 100644
--- a/myisam/mi_delete_all.c
+++ b/myisam/mi_delete_all.c
@@ -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;
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
index f0d8966c9e3..40bfd0edd30 100644
--- a/myisam/mi_extra.c
+++ b/myisam/mi_extra.c
@@ -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:
diff --git a/myisam/mi_keycache.c b/myisam/mi_keycache.c
index 75a6819f598..1010aef9e1d 100644
--- a/myisam/mi_keycache.c
+++ b/myisam/mi_keycache.c
@@ -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);
}
diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c
index 7ede4852ccd..fa415269d61 100644
--- a/myisam/mi_locking.c
+++ b/myisam/mi_locking.c
@@ -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;
diff --git a/myisam/mi_page.c b/myisam/mi_page.c
index eef65f03493..61a0c98233c 100644
--- a/myisam/mi_page.c
+++ b/myisam/mi_page.c
@@ -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),
diff --git a/myisam/mi_panic.c b/myisam/mi_panic.c
index 3a436969b06..f1d1d839fcd 100644
--- a/myisam/mi_panic.c
+++ b/myisam/mi_panic.c
@@ -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))
diff --git a/myisam/mi_preload.c b/myisam/mi_preload.c
index 39237886b57..02d5229bd4d 100644
--- a/myisam/mi_preload.c
+++ b/myisam/mi_preload.c
@@ -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;
diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c
index d08066f6028..ec68e23c0c2 100644
--- a/myisam/mi_test1.c
+++ b/myisam/mi_test1.c
@@ -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"));
diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c
index d69673c319d..11a8e12a7e5 100644
--- a/myisam/mi_test2.c
+++ b/myisam/mi_test2.c
@@ -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);
diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c
index dde8758f9bf..866c6299fac 100644
--- a/myisam/mi_test3.c
+++ b/myisam/mi_test3.c
@@ -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++)
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index 94fbea87de3..9bec92f40a8 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -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)))
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 83e28a42797..e02858453d2 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -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*);
diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c
index ff1a9d30206..5bca25dd439 100644
--- a/myisam/myisamlog.c
+++ b/myisam/myisamlog.c
@@ -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)));
diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result
index 8ec507b2a3f..acf2aa9641c 100644
--- a/mysql-test/r/key_cache.result
+++ b/mysql-test/r/key_cache.result
@@ -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
diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test
index 2da18b68624..e76183f1f5b 100644
--- a/mysql-test/t/key_cache.test
+++ b/mysql-test/t/key_cache.test
@@ -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;
+
+
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 70050e70acd..52ebff91259 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -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)))
{
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 4ca11fe0da5..85d5236a18f 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -228,6 +228,12 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
{
if (!(file=mi_open(name, mode, test_if_locked)))
return (my_errno ? my_errno : -1);
+
+ /* Synchronize key cache assignment of the handler */
+ KEY_CACHE_VAR *key_cache= table->key_cache ? table->key_cache :
+ &dflt_key_cache_var;
+ VOID(mi_extra(file, HA_EXTRA_SET_KEY_CACHE,
+ (void*) &key_cache->cache));
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
@@ -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);
}
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index a0449e83222..d6d4f58b31c 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -45,6 +45,12 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno));
return (my_errno ? my_errno : -1);
}
+ /* Synchronize key cache assignment for the file */
+ KEY_CACHE_VAR *key_cache= table->key_cache ? table->key_cache :
+ &dflt_key_cache_var;
+ VOID(myrg_extra(file, HA_EXTRA_SET_KEY_CACHE,
+ (void*) &key_cache->cache));
+
DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc..."))
myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
diff --git a/sql/handler.cc b/sql/handler.cc
index 049194a18db..1063066f588 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -984,17 +984,41 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
/* Use key cacheing on all databases */
-void ha_key_cache(void)
+int ha_key_cache(KEY_CACHE_VAR *key_cache)
{
- if (keybuff_size)
- (void) init_key_cache(&dflt_keycache,dflt_key_block_size,
- (ulong) keybuff_size);
+ if (!key_cache->cache)
+ {
+ if (!key_cache->block_size)
+ key_cache->block_size= dflt_key_cache_block_size;
+ if (!key_cache->buff_size)
+ key_cache->buff_size= dflt_key_buff_size;
+ return !init_key_cache( &key_cache->cache,
+ key_cache->block_size,
+ key_cache->buff_size,
+ key_cache);
+ }
+ return 0;
}
-void ha_resize_key_cache(void)
+int ha_resize_key_cache(KEY_CACHE_VAR *key_cache)
+{
+ if (key_cache->cache)
+ {
+ return !resize_key_cache(&key_cache->cache,
+ key_cache->buff_size);
+ }
+ return 0;
+}
+
+int ha_end_key_cache(KEY_CACHE_VAR *key_cache)
{
- (void) resize_key_cache(&dflt_keycache,(ulong) keybuff_size);
+ if (key_cache->cache)
+ {
+ end_key_cache(&key_cache->cache, 1);
+ return key_cache->cache ? 1 : 0;
+ }
+ return 0;
}
diff --git a/sql/handler.h b/sql/handler.h
index 1c6e158180e..bbd5873b396 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -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);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c9ec7e06f5b..cdffa8c7f50 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 52b1b26d7a9..09203d127c7 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -289,8 +289,6 @@ ulong rpl_recovery_rank=0;
ulong my_bind_addr; /* the address we bind to */
volatile ulong cached_thread_count= 0;
-ulonglong keybuff_size;
-
double log_10[32]; /* 10 potences */
time_t start_time;
@@ -343,6 +341,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
+ LOCK_assign,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
rw_lock_t LOCK_grant;
pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped,
@@ -866,6 +865,7 @@ void clean_up(bool print_message)
grant_free();
query_cache_destroy();
table_cache_free();
+ assign_cache_free();
hostname_cache_free();
item_user_lock_free();
lex_free(); /* Free some memory */
@@ -875,7 +875,8 @@ void clean_up(bool print_message)
udf_free();
#endif
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
- end_key_cache(&dflt_keycache,1);
+ process_key_caches(&ha_end_key_cache);
+ ha_end_key_cache(&dflt_key_cache_var);
delete_elements(&key_caches, free_key_cache);
end_thr_alarm(1); /* Free allocated memory */
#ifdef USE_RAID
@@ -950,6 +951,7 @@ static void clean_up_mutexes()
#endif
(void) pthread_mutex_destroy(&LOCK_active_mi);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
+ (void) pthread_mutex_destroy(&LOCK_assign);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
(void) pthread_cond_destroy(&COND_thread_cache);
@@ -1508,14 +1510,15 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n",
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
- fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size);
+ fprintf(stderr, "key_buffer_size=%lu\n",
+ (ulong) dflt_key_cache_var.buff_size);
fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
fprintf(stderr, "max_connections=%ld\n", max_connections);
fprintf(stderr, "threads_connected=%d\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
-bytes of memory\n", ((ulong) keybuff_size +
+bytes of memory\n", ((ulong) dflt_key_cache_var.buff_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
max_connections)/ 1024);
@@ -2081,6 +2084,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_assign, MY_MUTEX_INIT_FAST);
(void) my_rwlock_init(&LOCK_grant, NULL);
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
@@ -2131,6 +2135,7 @@ static void init_ssl()
static int init_server_components()
{
table_cache_init();
+ assign_cache_init();
hostname_cache_init();
query_cache_result_size_limit(query_cache_limit);
query_cache_set_min_res_unit(query_cache_min_res_unit);
@@ -2193,7 +2198,10 @@ static int init_server_components()
}
if (opt_myisam_log)
(void) mi_log(1);
- ha_key_cache();
+
+ ha_key_cache(&dflt_key_cache_var);
+ process_key_caches(&ha_key_cache);
+
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
if (locked_in_memory && !geteuid())
@@ -3426,7 +3434,7 @@ enum options
OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT, OPT_FT_STOPWORD_FILE,
OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE,
- OPT_KEY_BUFFER_SIZE, OPT_LONG_QUERY_TIME,
+ OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE, OPT_LONG_QUERY_TIME,
OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
@@ -4106,10 +4114,16 @@ replicating a LOAD DATA INFILE command.",
IO_SIZE, 0},
{"key_buffer_size", OPT_KEY_BUFFER_SIZE,
"The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.",
- (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0,
+ (gptr*) &dflt_key_cache_var.buff_size,
+ (gptr*) &dflt_key_cache_var.buff_size, 0,
(enum get_opt_var_type) (GET_ULL | GET_ASK_ADDR),
REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD,
IO_SIZE, 0},
+ {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,
+ "The default size of key cache blocks",
+ (gptr*) &dflt_key_cache_var.block_size,
+ (gptr*) &dflt_key_cache_var.block_size, 0, GET_ULONG,
+ REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE , 512, 1024*16, MALLOC_OVERHEAD, 512, 0},
{"long_query_time", OPT_LONG_QUERY_TIME,
"Log all queries that have taken more than long_query_time seconds to execute to file.",
(gptr*) &global_system_variables.long_query_time,
@@ -4470,13 +4484,19 @@ struct show_var_st status_vars[]= {
{"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG},
{"Handler_update", (char*) &ha_update_count, SHOW_LONG},
{"Handler_write", (char*) &ha_write_count, SHOW_LONG},
- {"Key_blocks_used", (char*) &my_blocks_used, SHOW_LONG_CONST},
- {"Key_read_requests", (char*) &my_cache_r_requests, SHOW_LONG},
- {"Key_reads", (char*) &my_cache_read, SHOW_LONG},
- {"Key_write_requests", (char*) &my_cache_w_requests, SHOW_LONG},
- {"Key_writes", (char*) &my_cache_write, SHOW_LONG},
+ {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used,
+ SHOW_LONG_CONST},
+ {"Key_read_requests", (char*) &dflt_key_cache_var.cache_r_requests,
+ SHOW_LONG},
+ {"Key_reads", (char*) &dflt_key_cache_var.cache_read,
+ SHOW_LONG},
+ {"Key_write_requests", (char*) &dflt_key_cache_var.cache_w_requests,
+ SHOW_LONG},
+ {"Key_writes", (char*) &dflt_key_cache_var.cache_write,
+ SHOW_LONG},
{"Max_used_connections", (char*) &max_used_connections, SHOW_LONG},
- {"Not_flushed_key_blocks", (char*) &my_blocks_changed, SHOW_LONG_CONST},
+ {"Not_flushed_key_blocks", (char*) &dflt_key_cache_var.blocks_changed,
+ SHOW_LONG_CONST},
{"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST},
{"Open_tables", (char*) 0, SHOW_OPENTABLES},
{"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST},
@@ -4682,7 +4702,8 @@ static void mysql_init_variables(void)
threads.empty();
thread_cache.empty();
key_caches.empty();
- if (!get_or_create_key_cache("default", 7))
+ if (!get_or_create_key_cache(DEFAULT_KEY_CACHE_NAME,
+ strlen(DEFAULT_KEY_CACHE_NAME)))
exit(1);
/* Initialize structures that is used when processing options */
@@ -5320,18 +5341,20 @@ extern "C" gptr *
mysql_getopt_value(const char *keyname, uint key_length,
const struct my_option *option)
{
- if (!key_length)
- {
- keyname= "default";
- key_length= 7;
- }
switch (option->id) {
case OPT_KEY_BUFFER_SIZE:
{
- KEY_CACHE *key_cache;
+ KEY_CACHE_VAR *key_cache;
+ if (!(key_cache= get_or_create_key_cache(keyname, key_length)))
+ exit(1);
+ return (gptr*) &key_cache->buff_size;
+ }
+ case OPT_KEY_CACHE_BLOCK_SIZE:
+ {
+ KEY_CACHE_VAR *key_cache;
if (!(key_cache= get_or_create_key_cache(keyname, key_length)))
exit(1);
- return (gptr*) &key_cache->size;
+ return (gptr*) &key_cache->block_size;
}
}
return option->value;
@@ -5385,8 +5408,10 @@ static void get_options(int argc,char **argv)
table_alias_charset= (lower_case_table_names ?
files_charset_info :
&my_charset_bin);
- /* QQ To be deleted when we have key cache variables in a struct */
- keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7))->size);
+ /* Set up default values for a key cache */
+ KEY_CACHE_VAR *key_cache= &dflt_key_cache_var;
+ dflt_key_cache_block_size= key_cache->block_size;
+ dflt_key_buff_size= key_cache->buff_size;
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index cb6c875d513..33dcd4b7e29 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -59,6 +59,9 @@
#include "ha_innodb.h"
#endif
+ulong dflt_key_buff_size;
+uint dflt_key_cache_block_size;
+
static HASH system_variable_hash;
const char *bool_type_names[]= { "OFF", "ON", NullS };
TYPELIB bool_typelib=
@@ -88,7 +91,7 @@ static void fix_query_cache_size(THD *thd, enum_var_type type);
static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type);
static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type);
-static KEY_CACHE *create_key_cache(const char *name, uint length);
+static KEY_CACHE_VAR *create_key_cache(const char *name, uint length);
void fix_sql_mode_var(THD *thd, enum_var_type type);
static byte *get_error_count(THD *thd);
static byte *get_warning_count(THD *thd);
@@ -137,6 +140,7 @@ sys_var_thd_ulong sys_interactive_timeout("interactive_timeout",
sys_var_thd_ulong sys_join_buffer_size("join_buffer_size",
&SV::join_buff_size);
sys_var_key_buffer_size sys_key_buffer_size("key_buffer_size");
+sys_var_key_cache_block_size sys_key_cache_block_size("key_cache_block_size");
sys_var_bool_ptr sys_local_infile("local_infile",
&opt_local_infile);
sys_var_thd_bool sys_log_warnings("log_warnings", &SV::log_warnings);
@@ -390,6 +394,7 @@ sys_var *sys_variables[]=
&sys_interactive_timeout,
&sys_join_buffer_size,
&sys_key_buffer_size,
+ &sys_key_cache_block_size,
&sys_last_insert_id,
&sys_local_infile,
&sys_log_binlog,
@@ -547,6 +552,8 @@ struct show_var_st init_vars[]= {
{sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS},
{sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS},
{sys_key_buffer_size.name, (char*) &sys_key_buffer_size, SHOW_SYS},
+ {sys_key_cache_block_size.name, (char*) &sys_key_cache_block_size,
+ SHOW_SYS},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
{sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS},
@@ -1412,70 +1419,93 @@ void sys_var_collation_connection::set_default(THD *thd, enum_var_type type)
}
+static LEX_STRING default_key_cache_base= {(char *) DEFAULT_KEY_CACHE_NAME, 7};
+
+static KEY_CACHE_VAR zero_key_cache= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static KEY_CACHE_VAR *get_key_cache(LEX_STRING *cache_name)
+{
+ if (!cache_name || !cache_name->str || !cache_name->length ||
+ cache_name->str == default_key_cache_base.str ||
+ (cache_name->length == default_key_cache_base.length &&
+ !memcmp(cache_name->str, default_key_cache_base.str,
+ default_key_cache_base.length)))
+ cache_name= &default_key_cache_base;
+ return ((KEY_CACHE_VAR*) find_named(&key_caches,
+ cache_name->str, cache_name->length));
+}
+
+byte *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ KEY_CACHE_VAR *key_cache= get_key_cache(base);
+ if (!key_cache)
+ key_cache= &zero_key_cache;
+ return (byte*) key_cache + offset ;
+}
+
bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
{
+ int rc;
ulonglong tmp= var->value->val_int();
+
if (!base_name.length)
- {
- base_name.str= (char*) "default";
- base_name.length= 7;
- }
- KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, base_name.str,
- base_name.length);
+ base_name= default_key_cache_base;
+ KEY_CACHE_VAR *key_cache= get_key_cache(&base_name);
+
if (!key_cache)
{
if (!tmp) // Tried to delete cache
return 0; // Ok, nothing to do
+
if (!(key_cache= create_key_cache(base_name.str,
base_name.length)))
return 1;
}
if (!tmp)
{
+ if (!key_cache->cache)
+ return 0;
/* Delete not default key caches */
- if (base_name.length != 7 || memcpy(base_name.str, "default", 7))
+ if (key_cache != &dflt_key_cache_var)
{
/*
- QQ: Here we should move tables using this key cache to default
- key cache
+ Move tables using this key cache to the default key cache
+ and remove this key cache if no tables are assigned to it
*/
- delete key_cache;
- return 0;
+ return (reassign_keycache_tables(thd, key_cache,
+ default_key_cache_base.str, 1));
}
+ return 0;
}
- key_cache->size= (ulonglong) getopt_ull_limit_value(tmp, option_limits);
+ key_cache->buff_size= (ulonglong) getopt_ull_limit_value(tmp, option_limits);
- /* QQ: Needs to be updated when we have multiple key caches */
- keybuff_size= key_cache->size;
- ha_resize_key_cache();
- return 0;
+ if (!key_cache->cache)
+ return (bool)(ha_key_cache(key_cache));
+ else
+ return (bool)(ha_resize_key_cache(key_cache));
}
-static ulonglong zero=0;
-
-byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+bool sys_var_key_cache_block_size::update(THD *thd, set_var *var)
{
- const char *name;
- uint length;
+ ulong tmp= var->value->val_int();
- if (!base->str)
- {
- name= "default";
- length= 7;
- }
- else
- {
- name= base->str;
- length= base->length;
- }
- KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, length);
- if (!key_cache)
- return (byte*) &zero;
- return (byte*) &key_cache->size;
+ if (!base_name.length)
+ base_name= default_key_cache_base;
+ KEY_CACHE_VAR *key_cache= get_key_cache(&base_name);
+
+ if (!key_cache && !(key_cache= create_key_cache(base_name.str,
+ base_name.length)))
+ return 1;
+
+ key_cache->block_size= (ulong) getopt_ull_limit_value(tmp, option_limits);
+
+ if (key_cache->cache)
+ /* Do not build a new key cache here */
+ return (bool) (ha_resize_key_cache(key_cache));
+ return 0;
}
-
/*****************************************************************************
@@ -2062,27 +2092,40 @@ void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr))
/* Key cache functions */
-static KEY_CACHE *create_key_cache(const char *name, uint length)
+static KEY_CACHE_VAR *create_key_cache(const char *name, uint length)
{
- KEY_CACHE *key_cache;
+ KEY_CACHE_VAR *key_cache;
DBUG_PRINT("info",("Creating key cache: %s", name));
- if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
- MYF(MY_ZEROFILL | MY_WME))))
+ if (length != default_key_cache_base.length ||
+ memcmp(name, default_key_cache_base.str, length))
{
- if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache))
+ if ((key_cache= (KEY_CACHE_VAR*) my_malloc(sizeof(KEY_CACHE_VAR),
+ MYF(MY_ZEROFILL | MY_WME))))
{
- my_free((char*) key_cache, MYF(0));
- key_cache= 0;
+ if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache))
+ {
+ my_free((char*) key_cache, MYF(0));
+ key_cache= 0;
+ }
}
}
+ else
+ {
+ key_cache= &dflt_key_cache_var;
+ if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache))
+ key_cache= 0;
+ }
+
return key_cache;
}
-KEY_CACHE *get_or_create_key_cache(const char *name, uint length)
+KEY_CACHE_VAR *get_or_create_key_cache(const char *name, uint length)
{
- KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name,
- length);
+ LEX_STRING key_cache_name;
+ key_cache_name.str= (char *) name;
+ key_cache_name.length= length;
+ KEY_CACHE_VAR *key_cache= get_key_cache(&key_cache_name);
if (!key_cache)
key_cache= create_key_cache(name, length);
return key_cache;
@@ -2091,7 +2134,22 @@ KEY_CACHE *get_or_create_key_cache(const char *name, uint length)
void free_key_cache(gptr key_cache)
{
- my_free(key_cache, MYF(0));
+ if (key_cache != (gptr) &dflt_key_cache_var)
+ my_free(key_cache, MYF(0));
+}
+
+bool process_key_caches(int (* func) (KEY_CACHE_VAR *))
+{
+
+ I_List_iterator<NAMED_LIST> it(key_caches);
+ NAMED_LIST *element;
+ while ((element= it++))
+ {
+ KEY_CACHE_VAR *key_cache= (KEY_CACHE_VAR *) element->data;
+ if (key_cache != &dflt_key_cache_var)
+ func(key_cache);
+ }
+ return 0;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index 978aba3384a..f057041f30d 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -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_buffer_size(const char *name_arg)
+ sys_var_key_cache_param(const char *name_arg)
:sys_var(name_arg)
- {}
+ {
+ offset= 0;
+ }
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
+
+class sys_var_key_buffer_size :public sys_var_key_cache_param
+{
+public:
+ sys_var_key_buffer_size(const char *name_arg)
+ :sys_var_key_cache_param(name_arg)
+ {
+ offset= offsetof(KEY_CACHE_VAR, buff_size);
+ }
bool update(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_LONGLONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ bool check_default(enum_var_type type) { return 1; }
+ bool is_struct() { return 1; }
+};
+
+class sys_var_key_cache_block_size :public sys_var_key_cache_param
+{
+public:
+ sys_var_key_cache_block_size(const char *name_arg)
+ :sys_var_key_cache_param(name_arg)
+ {
+ offset= offsetof(KEY_CACHE_VAR, block_size);
+ }
+ bool update(THD *thd, set_var *var);
+ SHOW_TYPE type() { return SHOW_LONG; }
bool check_default(enum_var_type type) { return 1; }
bool is_struct() { return 1; }
};
@@ -709,5 +739,6 @@ gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length);
void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr));
/* key_cache functions */
-KEY_CACHE *get_or_create_key_cache(const char *name, uint length);
+KEY_CACHE_VAR *get_or_create_key_cache(const char *name, uint length);
void free_key_cache(gptr key_cache);
+bool process_key_caches(int (* func) (KEY_CACHE_VAR *));
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 641ab46e5e0..c51dc65ac11 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -30,6 +30,7 @@
TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
+HASH assign_cache;
static int open_unireg_entry(THD *thd,TABLE *entry,const char *db,
const char *name, const char *alias);
@@ -53,7 +54,6 @@ void table_cache_init(void)
mysql_rm_tmp_tables();
}
-
void table_cache_free(void)
{
DBUG_ENTER("table_cache_free");
@@ -63,7 +63,6 @@ void table_cache_free(void)
DBUG_VOID_RETURN;
}
-
uint cached_tables(void)
{
return open_cache.records;
@@ -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,
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 28208e4220f..0a873375471 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -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
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index d2f97640010..baf11290489 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -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)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3997ed1bd82..e475fa1d052 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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;
}
;
diff --git a/sql/table.h b/sql/table.h
index 3132e72fb2f..ad5908ae5c2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -55,6 +55,31 @@ typedef struct st_filesort_info
ha_rows found_records; /* How many records in sort */
} FILESORT_INFO;
+
+/* Table key cache assignment descriptor */
+/*
+ In future the similar structure is to be used for
+ an assignment of an index to a key cache: the index name will be added.
+ The name of the database catalog will be added as well.
+ The descriptors for the current assignments are put in the
+ assignment cache: assign_cache. If a table is not found in the cache
+ it is considered assigned to the default key cache.
+*/
+typedef struct st_key_cache_asmt
+{
+ char *db_name; /* db the table belongs to */
+ char *table_name; /* the name of the table */
+ char *table_key; /* key for the assignment cache */
+ uint key_length; /* the length of this key */
+ struct st_key_cache_var *key_cache; /* reference to the key cache */
+ struct st_key_cache_asmt **prev; /* links in the chain all assignments */
+ struct st_key_cache_asmt *next; /* to this cache */
+ struct st_my_thread_var *queue; /* queue of requests for assignment */
+ uint requests; /* number of current requests */
+ bool to_reassign; /* marked when reassigning all cache */
+ bool triggered; /* marked when assignment is triggered*/
+} KEY_CACHE_ASMT;
+
/* Table cache entry struct */
class Field_timestamp;
@@ -62,11 +87,13 @@ class Field_blob;
struct st_table {
handler *file;
- Field **field; /* Pointer to fields */
+ KEY_CACHE_VAR *key_cache; /* Ref to the key cache the table assigned to*/
+ KEY_CACHE_ASMT *key_cache_asmt;/* Only when opened for key cache assignment */
+ Field **field; /* Pointer to fields */
Field_blob **blob_field; /* Pointer to blob fields */
HASH name_hash; /* hash of field names */
byte *record[2]; /* Pointer to records */
- byte *default_values; /* record with default values for INSERT */
+ byte *default_values; /* Record with default values for INSERT */
byte *insert_values; /* used by INSERT ... UPDATE */
uint fields; /* field count */
uint reclength; /* Recordlength */
@@ -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;
+
+