summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorunknown <monty@mashka.mysql.fi>2003-11-18 13:47:27 +0200
committerunknown <monty@mashka.mysql.fi>2003-11-18 13:47:27 +0200
commite72124c4ccad5b390b84562389175dcd7355769c (patch)
tree0a23d90c946c5f05a8c160fc7c6ef3f05505fc79 /mysys
parent61e682b8adafdfae736327fee4ea0263e1a0bd37 (diff)
downloadmariadb-git-e72124c4ccad5b390b84562389175dcd7355769c.tar.gz
CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS
New multi-key-cache handling. This was needed becasue the old one didn't work reliable with MERGE tables. ALTER TABLE table_name ... CHARACTER SET ... now changes all char/varchar/text columns to the given character set (One must use ALTER TABLE ... DEFAULT CHARACTER SET ... to change the default character set) Fixed that have_compress is detected properly (fixes problems with func_compress.test on platforms without zlib) New syntax for CACHE INDEX ('keys' is optional if no index name is given and one mentions the key cache name only ones) Removed compiler warnings Added mysql_set_server_option() to allow clients like PHP to easaily set/reset the multi-statement flag. BUILD/compile-pentium-valgrind-max: Add test of isam client/mysql.cc: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS include/my_base.h: Remove HA_EXTRA_SET_KEY_CACHE include/my_no_pthread.h: Add defines to ignore rw-locks when running without threads include/my_sys.h: Added function for multi-key-caches include/myisam.h: Added function to handle multi-key-caches include/mysql.h: Added mysql_set_server_option include/mysql_com.h: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS Added enum_mysql_set_option include/mysqld_error.h: Added error message for unknown key cache innobase/srv/srv0start.c: Removed warning that is confused for MySQL users libmysql/libmysql.c: Added mysql_set_server_option() libmysql/libmysql.def: Added mysql_set_server_option() myisam/ft_nlq_search.c: Removed compiler warning myisam/ft_static.c: Removed compiler warning and fixed wrong return value myisam/mi_check.c: Clean up multi-key-cache usage myisam/mi_checksum.c: Removed not used variable myisam/mi_close.c: keycache -> key_cache myisam/mi_delete_all.c: keycache -> key_cache myisam/mi_extra.c: keycache -> key_cache Removed HA_EXTRA_SET_KEY_CACHE myisam/mi_keycache.c: Changed logic so that it's MyISAM that is responsible for assign tables to different key caches instead of the upper level myisam/mi_locking.c: Don't change key cache on unlock (must be done before) myisam/mi_open.c: Fetch key cache to use from multi_key_cache_search() myisam/mi_page.c: keycache -> key_cache myisam/mi_panic.c: keycache -> key_cache myisam/mi_preload.c: keycache -> key_cache myisam/mi_test1.c: Use KEY_CACHE_BLOCK_SIZE myisam/mi_test2.c: Always test resize_key_cache() myisam/mi_test3.c: Use KEY_CACHE_BLOCK_SIZE instead of 512 myisam/myisamchk.c: update for multiple key caches myisam/myisamdef.h: Remove reg_keycache Add unique_name_length for storing length of unique_file_name myisam/myisamlog.c: Change how end_key_cache() is called mysql-test/mysql-test-run.sh: Fixed web link Added name of failed test to abort row. mysql-test/r/alter_table.result: Testing of ALTER TABLE ... [DEFAULT] CHARACTER SET mysql-test/r/case.result: Update result for DEFAULT CHARSET... mysql-test/r/cast.result: Update result for DEFAULT CHARSET... mysql-test/r/create.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_collate.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_latin1_de.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_many.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_mb.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_recoding.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_ucs.result: Update result for DEFAULT CHARSET... mysql-test/r/derived.result: Use STRAIGHT_JOIN to make join order predictable mysql-test/r/fulltext.result: Update result for DEFAULT CHARSET... mysql-test/r/func_str.result: Update result for DEFAULT CHARSET... mysql-test/r/func_system.result: Update result for DEFAULT CHARSET... mysql-test/r/gis-rtree.result: Update result for DEFAULT CHARSET... mysql-test/r/innodb.result: Update result for DEFAULT CHARSET... mysql-test/r/key_cache.result: Update test for new key cache syntax. Added more tests mysql-test/r/merge.result: Update result for DEFAULT CHARSET... mysql-test/r/preload.result: New syntax mysql-test/r/show_check.result: Update result for DEFAULT CHARSET... mysql-test/r/sql_mode.result: Update result for DEFAULT CHARSET... mysql-test/r/subselect.result: Update result for DEFAULT CHARSET... mysql-test/r/type_blob.result: Update result for DEFAULT CHARSET... mysql-test/r/type_enum.result: Update result for DEFAULT CHARSET... mysql-test/r/type_nchar.result: Update result for DEFAULT CHARSET... mysql-test/r/type_set.result: Update result for DEFAULT CHARSET... mysql-test/r/union.result: Use STRAIGHT_JOIN to make join order predictable mysql-test/t/alter_table.test: Testing of ALTER TABLE ... [DEFAULT] CHARACTER SET mysql-test/t/ctype_many.test: Update result for DEFAULT CHARSET... mysql-test/t/derived.test: Use STRAIGHT_JOIN to make join order predictable mysql-test/t/isam.test: Use disable warnings for test loop mysql-test/t/join.test: Update test now when we only support 61 tables in join mysql-test/t/key_cache.test: Update test for new key cache syntax. Added more tests mysql-test/t/preload.test: Update for new syntax mysql-test/t/union.test: Use STRAIGHT_JOIN to make join order predictable mysys/Makefile.am: Added mf_keycaches.c mysys/hash.c: TRUE -> 1 mysys/mf_keycache.c: Removed compiler warnings Striped end space Fixed indentation and improved function comments TRUE -> 1 Changed parameters to end_key_cache() to make it easer to use Fixed bug when using key blocks size > 1024 bytes (First part of index file could be overwritten with wrong data) Split function flush_key_blocks into two functions to not get mutex used twice when called from flush_all_key_blocks() mysys/my_bitmap.c: More debugging Safe bitmap_free() Fixed indentation mysys/my_getopt.c: Ensure that we initialize option->value, option->max_value and value from GET_ASK_ADDR mysys/my_thr_init.c: Remove not used mutex THR_LOCK_keycache mysys/typelib.c: Fixed function comments sql-common/client.c: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS Fixed the multi_result flag is set also on SELECT;s sql/ha_myisam.cc: Fixed multiple key_cache handling (Now done on MyISAM level) sql/ha_myisammrg.cc: Fixed multiple key_cache handling (Now done on MyISAM level) sql/handler.cc: New multi key cache handling sql/handler.h: New multi key cache handling Added support for default character set sql/item.h: Added function cleanup() (Needed for prepared statements / cursors) sql/item_cmpfunc.h: Added cleanup function sql/item_func.cc: Indentation cleanup sql/mysql_priv.h: New multi-key-cache functions Removed LOCK_assign sql/mysqld.cc: New multi-key-cache handling Fixed that variable have_compress is set correctly sql/protocol.cc: SELECT didn't work reliable in multi-statements sql/set_var.cc: Support for new key cache variables sql/set_var.h: Support for new key cache variables sql/share/czech/errmsg.txt: New error messages sql/share/danish/errmsg.txt: New error messages sql/share/dutch/errmsg.txt: New error messages sql/share/english/errmsg.txt: New error messages sql/share/estonian/errmsg.txt: New error messages sql/share/french/errmsg.txt: New error messages sql/share/german/errmsg.txt: New error messages sql/share/greek/errmsg.txt: New error messages sql/share/hungarian/errmsg.txt: New error messages sql/share/italian/errmsg.txt: New error messages sql/share/japanese/errmsg.txt: New error messages sql/share/korean/errmsg.txt: New error messages sql/share/norwegian-ny/errmsg.txt: New error messages sql/share/norwegian/errmsg.txt: New error messages sql/share/polish/errmsg.txt: New error messages sql/share/portuguese/errmsg.txt: New error messages sql/share/romanian/errmsg.txt: New error messages sql/share/russian/errmsg.txt: New error messages sql/share/serbian/errmsg.txt: New error messages sql/share/slovak/errmsg.txt: New error messages sql/share/spanish/errmsg.txt: New error messages sql/share/swedish/errmsg.txt: New error messages sql/share/ukrainian/errmsg.txt: New error messages sql/sql_base.cc: Removed all key_cache handling (this is now done on MyISAM level) Change table_charset -> default_table_charset sql/sql_db.cc: table_charset -> default_table_charset sql/sql_delete.cc: table_charset -> default_table_charset sql/sql_lex.cc: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS sql/sql_lex.h: New option to store a name and length sql/sql_parse.cc: Support for mysql_set_server_option() Reset "default" keycache status variables in 'FLUSH STATUS' (Need to be improved later) sql/sql_show.cc: Add DEFAULT before CHARSET (for table character sets) Fetch key cache variables from 'sql_key_cache' sql/sql_table.cc: table_charset -> default_table_charset New multi-key-cache handling sql/sql_test.cc: Write information from all key caches sql/sql_yacc.yy: Changed syntax for CACHE INDEX ... Force user to use DEFAULT before database/table level character sets sql/structs.h: Added SHOW_KEY_CACHE_LONG (to get values from sql_key_cache) sql/table.cc: table_charset -> default_table_charset sql/table.h: New key cache handling (this is now done in mysys/mf_keycaches.c) sql/unireg.h: A
Diffstat (limited to 'mysys')
-rw-r--r--mysys/Makefile.am2
-rw-r--r--mysys/hash.c2
-rw-r--r--mysys/mf_keycache.c349
-rw-r--r--mysys/mf_keycaches.c359
-rw-r--r--mysys/my_bitmap.c48
-rw-r--r--mysys/my_getopt.c109
-rw-r--r--mysys/my_thr_init.c4
-rw-r--r--mysys/typelib.c31
8 files changed, 679 insertions, 225 deletions
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 37c79e28395..bd508b8de12 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -29,7 +29,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
mf_path.c mf_loadpath.c\
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c \
- mf_keycache.c my_crc32.c \
+ mf_keycache.c mf_keycaches.c my_crc32.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
diff --git a/mysys/hash.c b/mysys/hash.c
index b0ddbd90794..516fa171d7c 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -53,7 +53,7 @@ _hash_init(HASH *hash,CHARSET_INFO *charset,
if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0))
{
hash->free=0; /* Allow call to hash_free */
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
hash->key_offset=key_offset;
hash->key_length=key_length;
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 2f5a704234d..280b69b18bf 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -142,7 +142,7 @@ typedef struct st_block_link
KEY_CACHE_VAR dflt_key_cache_var=
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
KEY_CACHE_HANDLE *dflt_keycache= &dflt_key_cache_var.cache;
@@ -168,7 +168,7 @@ typedef struct st_key_cache
ulong warm_blocks; /* number of blocks in warm sub-chain */
#if defined(KEYCACHE_DEBUG)
long blocks_available; /* number of blocks available in the LRU chain */
-#endif
+#endif
HASH_LINK **hash_root; /* arr. of entries into hash table buckets */
HASH_LINK *hash_link_root; /* memory for hash table links */
HASH_LINK *free_hash_list; /* list of free hash links */
@@ -184,7 +184,7 @@ typedef struct st_key_cache
} KEY_CACHE;
static int flush_all_key_blocks(KEY_CACHE_HANDLE keycache);
-static void test_key_cache(KEY_CACHE *keycache,
+static void test_key_cache(KEY_CACHE *keycache,
const char *where, my_bool lock);
#define KEYCACHE_HASH(f, pos) \
@@ -284,7 +284,7 @@ static uint next_power(uint value)
SYNOPSIS
init_ky_cache()
pkeycache in/out pointer to the key cache handle
- key_cache_block_size size of blocks to keep cached data
+ key_cache_block_size size of blocks to keep cached data
use_mem total memory to use for the key cache
env ref to other parameters of the key cache, if any
@@ -299,7 +299,7 @@ static uint next_power(uint value)
handle for a key cache with new blocks.
It's assumed that no two threads call this function simultaneously
referring to the same key cache handle.
-
+
*/
int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
@@ -308,14 +308,14 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
uint blocks, hash_links, length;
int error;
KEY_CACHE *keycache;
-
DBUG_ENTER("init_key_cache");
+ DBUG_ASSERT(key_cache_block_size >= 512);
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;
@@ -332,30 +332,30 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
if (! keycache->key_cache_inited)
{
- keycache->key_cache_inited= TRUE;
+ keycache->key_cache_inited= 1;
keycache->disk_blocks= -1;
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));
+ key_cache_block_size));
}
-
- /*
- These are safety deallocations: actually we always call the
- function after having called end_key_cache that deallocates
- these memory itself.
- */
+
+ /*
+ These are safety deallocations: actually we always call the
+ function after having called end_key_cache that deallocates
+ these memory itself.
+ */
if (keycache->block_mem)
- my_free_lock((gptr) keycache->block_mem, MYF(0));
+ my_free_lock((gptr) keycache->block_mem, MYF(0));
keycache->block_mem= NULL;
if (keycache->block_root)
- my_free((gptr) keycache->block_root, MYF(0));
+ my_free((gptr) keycache->block_root, MYF(0));
keycache->block_root= NULL;
blocks= (uint) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
- sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
+ sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
/* It doesn't make sense to have too few blocks (less than 8) */
if (blocks >= 8 && keycache->disk_blocks < 0)
{
@@ -371,18 +371,18 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
#endif
while ((length= (ALIGN_SIZE(blocks * sizeof(BLOCK_LINK)) +
ALIGN_SIZE(hash_links * sizeof(HASH_LINK)) +
- ALIGN_SIZE(sizeof(HASH_LINK*) *
+ ALIGN_SIZE(sizeof(HASH_LINK*) *
keycache->hash_entries))) +
((ulong) blocks << keycache->key_cache_shift) > use_mem)
blocks--;
/* Allocate memory for cache page buffers */
- if ((keycache->block_mem=
- my_malloc_lock((ulong) blocks * keycache->key_cache_block_size,
- MYF(0))))
+ if ((keycache->block_mem=
+ my_malloc_lock((ulong) blocks * keycache->key_cache_block_size,
+ MYF(0))))
{
/*
- Allocate memory for blocks, hash_links and hash entries;
- For each block 2 hash links are allocated
+ Allocate memory for blocks, hash_links and hash entries;
+ For each block 2 hash links are allocated
*/
if ((keycache->block_root= (BLOCK_LINK*) my_malloc((uint) length,
MYF(0))))
@@ -402,13 +402,13 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
ALIGN_SIZE(blocks*sizeof(BLOCK_LINK)));
keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
ALIGN_SIZE((sizeof(HASH_LINK*) *
- keycache->hash_entries)));
+ keycache->hash_entries)));
bzero((byte*) keycache->block_root,
- keycache->disk_blocks * sizeof(BLOCK_LINK));
+ keycache->disk_blocks * sizeof(BLOCK_LINK));
bzero((byte*) keycache->hash_root,
keycache->hash_entries * sizeof(HASH_LINK*));
bzero((byte*) keycache->hash_link_root,
- keycache->hash_links * sizeof(HASH_LINK));
+ keycache->hash_links * sizeof(HASH_LINK));
keycache->hash_links_used= 0;
keycache->free_hash_list= NULL;
keycache->blocks_used= keycache->blocks_changed= 0;
@@ -422,21 +422,21 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
keycache->used_ins= NULL;
keycache->keycache_time= 0;
keycache->warm_blocks= 0;
- keycache->min_warm_blocks= env && env->division_limit ?
- blocks * env->division_limit / 100 + 1 :
- blocks;
- keycache->age_threshold= env && env->age_threshold ?
- blocks * env->age_threshold / 100 :
- blocks;
+ keycache->min_warm_blocks= (env && env->division_limit ?
+ blocks * env->division_limit / 100 + 1 :
+ blocks);
+ keycache->age_threshold= (env && env->age_threshold ?
+ blocks * env->age_threshold / 100 :
+ blocks);
keycache->waiting_for_hash_link.last_thread= NULL;
keycache->waiting_for_block.last_thread= NULL;
DBUG_PRINT("exit",
- ("disk_blocks: %d block_root: %lx hash_entries: %d hash_root: %lx \
+ ("disk_blocks: %d block_root: %lx hash_entries: %d hash_root: %lx \
hash_links: %d hash_link_root %lx",
- keycache->disk_blocks, keycache->block_root,
- keycache->hash_entries, keycache->hash_root,
- keycache->hash_links, keycache->hash_link_root));
+ keycache->disk_blocks, keycache->block_root,
+ keycache->hash_entries, keycache->hash_root,
+ keycache->hash_links, keycache->hash_link_root));
}
bzero((gptr) keycache->changed_blocks,
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
@@ -445,7 +445,8 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
if (env)
env->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
- *pkeycache= keycache;
+ *pkeycache= keycache;
+ DBUG_PRINT("exit", ("key_cache: %lx", keycache));
DBUG_RETURN((int) blocks);
err:
@@ -473,8 +474,8 @@ err:
SYNOPSIS
resize_key_cache()
- pkeycache in/out pointer to the key cache handle
- key_cache_block_size size of blocks to keep cached data
+ pkeycache in/out pointer to the key cache handle
+ key_cache_block_size size of blocks to keep cached data
use_mem total memory to use for the new key cache
RETURN VALUE
@@ -485,8 +486,8 @@ err:
The function first compares the memory size and the block size parameters
with the corresponding parameters of the key cache referred by
*pkeycache. If they differ the function free the the memory allocated
- for the old key cache blocks by calling the end_key_cache function
- and then rebuilds the key cache with new blocks by calling init_key_cache.
+ for the old key cache blocks by calling the end_key_cache function
+ and then rebuilds the key cache with new blocks by calling init_key_cache.
*/
int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
@@ -494,6 +495,7 @@ int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
{
int blocks;
KEY_CACHE *keycache= *pkeycache;
+ DBUG_ENTER("resize_key_cache");
if (key_cache_block_size == keycache->key_cache_block_size &&
use_mem == keycache->key_cache_mem_size)
@@ -507,20 +509,20 @@ int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
return 0;
}
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- end_key_cache(pkeycache, 0);
+ end_key_cache(keycache, 0);
/* the following will work even if memory is 0 */
- blocks=init_key_cache(pkeycache, key_cache_block_size, use_mem,
- keycache->env);
+ blocks= init_key_cache(pkeycache, key_cache_block_size, use_mem,
+ keycache->env);
return blocks;
}
/*
- Change the key cache parameters
+ Change the key cache parameters
SYNOPSIS
change_key_cache_param()
- keycache the key cache handle
+ keycache the key cache handle
RETURN VALUE
none
@@ -537,14 +539,15 @@ void change_key_cache_param(KEY_CACHE_HANDLE keycache)
KEY_CACHE_VAR *env= keycache->env;
DBUG_ENTER("change_key_cache_param");
- if (!env)
- return;
- if (env->division_limit)
- keycache->min_warm_blocks= keycache->disk_blocks *
- env->division_limit / 100 + 1;
- if (env->age_threshold)
- keycache->age_threshold= keycache->disk_blocks *
- env->age_threshold / 100;
+ if (env)
+ {
+ if (env->division_limit)
+ keycache->min_warm_blocks= (keycache->disk_blocks *
+ env->division_limit / 100 + 1);
+ if (env->age_threshold)
+ keycache->age_threshold= (keycache->disk_blocks *
+ env->age_threshold / 100);
+ }
DBUG_VOID_RETURN;
}
@@ -554,7 +557,7 @@ void change_key_cache_param(KEY_CACHE_HANDLE keycache)
SYNOPSIS
end_key_cache()
- pkeycache in/out pointer to the key cache handle
+ pkeycache in/out pointer to the key cache handle
cleanup <-> the key cache data structure is freed as well
RETURN VALUE
@@ -562,15 +565,18 @@ void change_key_cache_param(KEY_CACHE_HANDLE keycache)
NOTES.
If the cleanup parameter is TRUE the data structure with all associated
- elements are freed completely and NULL is assigned to *pkeycache.
- Otherwise only memory used by the key cache blocks is freed.
+ elements are freed completely
+ Otherwise only memory used by the key cache blocks is freed.
*/
-void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
+void end_key_cache(KEY_CACHE_HANDLE keycache, my_bool cleanup)
{
- KEY_CACHE *keycache= *pkeycache;
- KEY_CACHE_VAR *env= keycache->env;
+ KEY_CACHE_VAR *env;;
DBUG_ENTER("end_key_cache");
+ DBUG_PRINT("enter", ("key_cache: %lx", keycache));
+
+ if (!keycache)
+ DBUG_VOID_RETURN;
if (keycache->disk_blocks > 0)
{
if (keycache->block_mem)
@@ -584,18 +590,19 @@ void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
}
KEYCACHE_DEBUG_CLOSE;
keycache->key_cache_inited= 0;
- if (env)
+ if ((env= keycache->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->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->cache_lock);
- my_free((gptr) *pkeycache, MYF(0));
- *pkeycache= NULL;
+ my_free((gptr) keycache, MYF(0));
}
DBUG_VOID_RETURN;
} /* end_key_cache */
@@ -606,8 +613,8 @@ void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
SYNOPSIS
link_into_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be added to the queue
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
RETURN VALUE
none
@@ -643,8 +650,8 @@ static inline void link_into_queue(KEYCACHE_WQUEUE *wqueue,
SYNOPSIS
unlink_from_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be removed from the queue
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be removed from the queue
RETURN VALUE
none
@@ -677,8 +684,8 @@ static inline void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
SYNOPSIS
add_to_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be added to the queue
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
RETURN VALUE
none
@@ -709,8 +716,8 @@ static inline void add_to_queue(KEYCACHE_WQUEUE *wqueue,
SYNOPSIS
realease_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be added to the queue
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
RETURN VALUE
none
@@ -718,7 +725,7 @@ static inline void add_to_queue(KEYCACHE_WQUEUE *wqueue,
NOTES.
See notes for add_to_queue
When removed from the queue each thread is signaled via condition
- variable thread->suspend.
+ variable thread->suspend.
*/
static void release_queue(KEYCACHE_WQUEUE *wqueue)
@@ -809,7 +816,7 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
SYNOPSIS
link_block()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
block pointer to the block to link to the LRU chain
hot <-> to link the block into the hot subchain
at_end <-> to link the block at the end of the subchain
@@ -818,11 +825,11 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
none
NOTES.
- The LRU chain is represented by a curcular list of block structures.
- The list is double-linked of the type (**prev,*next) type.
- The LRU chain is divided into two parts - hot and warm.
+ The LRU chain is represented by a curcular list of block structures.
+ The list is double-linked of the type (**prev,*next) type.
+ The LRU chain is divided into two parts - hot and warm.
There are two pointers to access the last blocks of these two
- parts. The beginning of the warm part follows right after the
+ parts. The beginning of the warm part follows right after the
end of the hot part.
Only blocks of the warm part can be used for replacement.
The first block from the beginning of this subchain is always
@@ -836,12 +843,12 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
| +------+ W A R M +------+ |
+----| beg |---->...----| end |----+
+------+ +------+ins
- first for eviction
+ first for eviction
*/
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
my_bool at_end)
-{
+{
BLOCK_LINK *ins;
BLOCK_LINK **pins;
@@ -881,7 +888,7 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
return;
}
pins= hot ? &keycache->used_ins : &keycache->used_last;
- ins= *pins;
+ ins= *pins;
if (ins)
{
ins->next_used->prev_used= &block->next_used;
@@ -915,7 +922,7 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
SYNOPSIS
unlink_block()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
block pointer to the block to unlink from the LRU chain
RETURN VALUE
@@ -938,7 +945,7 @@ static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
keycache->used_last= STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
if (keycache->used_ins == block)
keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
- }
+ }
block->next_used= NULL;
KEYCACHE_THREAD_TRACE("unlink_block");
@@ -972,27 +979,27 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
SYNOPSIS
unreg_block()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
block pointer to the block to link to the LRU chain
at_end <-> to link the block at the end of the LRU chain
RETURN VALUE
none
- NOTES.
+ NOTES.
Every linking to the LRU chain decrements by one a special block
counter (if it's positive). If the at_end parameter is TRUE the block is
added either at the end of warm sub-chain or at the end of hot sub-chain.
- It is added to the hot subchain if its counter is zero and number of
- blocks in warm sub-chain is not less than some low limit (determined by
+ It is added to the hot subchain if its counter is zero and number of
+ blocks in warm sub-chain is not less than some low limit (determined by
the division_limit parameter). Otherwise the block is added to the warm
sub-chain. If the at_end parameter is FALSE the block is always added
- at beginning of the warm sub-chain.
+ at beginning of the warm sub-chain.
Thus a warm block can be promoted to the hot sub-chain when its counter
becomes zero for the first time.
At the same time the block at the very beginning of the hot subchain
might be moved to the beginning of the warm subchain if it stays untouched
- for a too long time (this time is determined by parameter age_threshold).
+ for a too long time (this time is determined by parameter age_threshold).
*/
static inline void unreg_request(KEY_CACHE *keycache,
@@ -1123,7 +1130,7 @@ static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
Get the hash link for a page
*/
-static HASH_LINK *get_hash_link(KEY_CACHE *keycache,
+static HASH_LINK *get_hash_link(KEY_CACHE *keycache,
int file, my_off_t filepos)
{
reg1 HASH_LINK *hash_link, **start;
@@ -1206,16 +1213,16 @@ restart:
Get a block for the file page requested by a keycache read/write operation;
If the page is not in the cache return a free block, if there is none
return the lru block after saving its buffer if the page is dirty.
-
+
SYNOPSIS
find_key_block()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
file handler for the file to read page from
filepos position of the page in the file
init_hits_left how initialize the block counter for the page
wrmode <-> get for writing
- page_st out {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ}
+ page_st out {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ}
RETURN VALUE
Pointer to the found block if successful, 0 - otherwise
@@ -1227,15 +1234,15 @@ restart:
If not, the function first chooses a block for this page. If there is
no not used blocks in the key cache yet, the function takes the block
at the very beginning of the warm sub-chain. It saves the page in that
- block if it's dirty before returning the pointer to it.
+ block if it's dirty before returning the pointer to it.
The function returns in the page_st parameter the following values:
PAGE_READ - if page already in the block,
PAGE_TO_BE_READ - if it is to be read yet by the current thread
- WAIT_TO_BE_READ - if it is to be read by another thread
+ WAIT_TO_BE_READ - if it is to be read by another thread
If an error occurs THE BLOCK_ERROR bit is set in the block status.
It might happen that there are no blocks in LRU chain (in warm part) -
all blocks are unlinked for some read/write operations. Then the function
- waits until first of this operations links any block back.
+ waits until first of this operations links any block back.
*/
static BLOCK_LINK *find_key_block(KEY_CACHE *keycache,
@@ -1388,9 +1395,11 @@ restart:
The call is thread safe because only the current
thread might change the block->hash_link value
*/
- error=my_pwrite(block->hash_link->file, block->buffer,
- block->length, block->hash_link->diskpos,
- MYF(MY_NABP | MY_WAIT_IF_FULL));
+ error= my_pwrite(block->hash_link->file,
+ block->buffer+block->offset,
+ block->length - block->offset,
+ block->hash_link->diskpos+ block->offset,
+ MYF(MY_NABP | MY_WAIT_IF_FULL));
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
keycache->env->cache_write++;
@@ -1465,12 +1474,12 @@ restart:
SYNOPSIS
read_block()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
block block to which buffer the data is to be read
- read_length size of data to be read
- min_length at least so much data must be read
- primary <-> the current thread will read the data
-
+ read_length size of data to be read
+ min_length at least so much data must be read
+ primary <-> the current thread will read the data
+
RETURN VALUE
None
@@ -1551,15 +1560,15 @@ static void read_block(KEY_CACHE *keycache,
SYNOPSIS
key_cache_read()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
file handler for the file for the block of data to be read
filepos position of the block of data in the file
level determines the weight of the data
- buff buffer to where the data must be placed
+ buff buffer to where the data must be placed
length length of the buffer
- block_length length of the block in the key cache buffer
- return_buffer return pointer to the key cache buffer with the data
-
+ block_length length of the block in the key cache buffer
+ return_buffer return pointer to the key cache buffer with the data
+
RETURN VALUE
Returns address from where the data is placed if sucessful, 0 - otherwise.
@@ -1584,7 +1593,7 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
(uint) file, (ulong) filepos, length));
- if (keycache->disk_blocks > 0)
+ if (keycache && keycache->disk_blocks > 0)
{
/* Key cache is used */
reg1 BLOCK_LINK *block;
@@ -1613,7 +1622,7 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
{
/* The requested page is to be read into the block buffer */
- read_block(keycache, block,
+ read_block(keycache, block,
keycache->key_cache_block_size, read_length+offset,
(my_bool)(page_st == PAGE_TO_BE_READ));
}
@@ -1677,7 +1686,7 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
}
/* Key cache is not used */
- if (keycache->env)
+ if (keycache && keycache->env)
{
statistic_increment(keycache->env->cache_r_requests,
&keycache->cache_lock);
@@ -1696,13 +1705,13 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
SYNOPSIS
key_cache_insert()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
file handler for the file to insert data from
filepos position of the block of data in the file to insert
level determines the weight of the data
buff buffer to read data from
length length of the data in the buffer
-
+
RETURN VALUE
0 if a success, 1 - otherwise.
*/
@@ -1777,20 +1786,20 @@ int key_cache_insert(KEY_CACHE_HANDLE keycache,
/*
- Write a buffer into a cached file.
-
+ Write a buffer into a cached file.
+
SYNOPSIS
key_cache_write()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
file handler for the file to write data to
filepos position in the file to write data to
level determines the weight of the data
- buff buffer with the data
+ buff buffer with the data
length length of the buffer
dont_write if is 0 then all dirty pages involved in writing
- should have been flushed from key cache
-
+ should have been flushed from key cache
+
RETURN VALUE
0 if a success, 1 - otherwise.
@@ -1798,7 +1807,7 @@ int key_cache_insert(KEY_CACHE_HANDLE keycache,
The function copies the data of size length from buff into buffers
for key cache blocks that are assigned to contain the portion of
the file starting with position filepos.
- It ensures that this data is flushed to the file if dont_write is FALSE.
+ It ensures that this data is flushed to the file if dont_write is FALSE.
Filepos must be a multiple of 'block_length', but it doesn't
have to be a multiple of key_cache_block_size;
*/
@@ -1811,15 +1820,16 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
{
reg1 BLOCK_LINK *block;
int error=0;
-
DBUG_ENTER("key_cache_write");
- DBUG_PRINT("enter", ("file %u, filepos %lu, length %u block_length %u",
- (uint) file, (ulong) filepos, length, block_length));
+ DBUG_PRINT("enter",
+ ("file %u filepos %lu length %u block_length %u key_block_length: %u",
+ (uint) file, (ulong) filepos, length, block_length,
+ keycache ? keycache->key_cache_block_size : 0));
if (!dont_write)
{
/* Force writing from buff into disk */
- if (keycache->env)
+ if (keycache && 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)))
@@ -1831,7 +1841,7 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
test_key_cache(keycache, "start of key_cache_write", 1););
#endif
- if (keycache->disk_blocks > 0)
+ if (keycache && keycache->disk_blocks > 0)
{
/* Key cache is used */
uint read_length;
@@ -1872,7 +1882,7 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
if (! (block->status & BLOCK_ERROR))
{
if (!(read_length & 511))
- bmove512(block->buffer+offset, buff, read_length);
+ bmove512(block->buffer+offset, buff, read_length);
else
memcpy(block->buffer+offset, buff, (size_t) read_length);
}
@@ -1903,14 +1913,14 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
/* Key cache is not used */
if (dont_write)
{
- if (keycache->env)
+ if (keycache && keycache->env)
{
statistic_increment(keycache->env->cache_w_requests,
- &keycache->cache_lock);
- statistic_increment(keycache->env->cache_write,
+ &keycache->cache_lock);
+ statistic_increment(keycache->env->cache_write,
&keycache->cache_lock);
}
- if (my_pwrite(file, (byte*) buff, length, filepos,
+ if (my_pwrite(file, (byte*) buff, length, filepos,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
error=1;
}
@@ -1991,8 +2001,10 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
KEYCACHE_DBUG_PRINT("flush_cached_blocks",
("block %u to be flushed", BLOCK_NUMBER(block)));
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- error= my_pwrite(file, block->buffer+block->offset, block->length,
- block->hash_link->diskpos,
+ error= my_pwrite(file,
+ block->buffer+block->offset,
+ block->length - block->offset,
+ block->hash_link->diskpos+ block->offset,
MYF(MY_NABP | MY_WAIT_IF_FULL));
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (keycache->env)
@@ -2024,27 +2036,30 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
/*
- Flush all blocks for a file to disk
-
- SYNOPSIS
+ flush all key blocks for a file to disk, but don't do any mutex locks
flush_key_blocks()
- keycache pointer to a key cache data structure
+ keycache pointer to a key cache data structure
file handler for the file to flush to
flush_type type of the flush
-
- RETURN VALUE
- 0 if a success, 1 - otherwise.
- */
-int flush_key_blocks(KEY_CACHE_HANDLE keycache,
- File file, enum flush_type type)
+ NOTES
+ This function doesn't do any mutex locks because it needs to be called both
+ from flush_key_blocks and flush_all_key_blocks (the later one does the
+ mutex lock in the resize_key_cache() function).
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static int flush_key_blocks_int(KEY_CACHE_HANDLE keycache,
+ File file, enum flush_type type)
{
KEY_CACHE_VAR *env;
BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
int last_errno= 0;
-
- DBUG_ENTER("flush_key_blocks");
+ DBUG_ENTER("flush_key_blocks_int");
DBUG_PRINT("enter",("file: %d blocks_used: %d blocks_changed: %d",
file, keycache->blocks_used, keycache->blocks_changed));
@@ -2053,8 +2068,6 @@ int flush_key_blocks(KEY_CACHE_HANDLE keycache,
test_key_cache(keycache, "start of flush_key_blocks", 0););
#endif
- keycache_pthread_mutex_lock(&keycache->cache_lock);
-
cache= cache_buff;
if (keycache->disk_blocks > 0 &&
(!my_disable_flush_key_blocks || type != FLUSH_KEEP))
@@ -2132,7 +2145,7 @@ restart:
This happens only if there is not enough
memory for the big block
*/
- if ((error= flush_cached_blocks(keycache, file, cache,
+ if ((error= flush_cached_blocks(keycache, file, cache,
end,type)))
last_errno=error;
/*
@@ -2214,12 +2227,8 @@ restart:
}
}
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
-
if (type == FLUSH_REMOVE && (env= keycache->env) && (env->action))
- {
(*env->action)((void *) env);
- }
#ifndef DBUG_OFF
DBUG_EXECUTE("check_keycache",
@@ -2234,6 +2243,37 @@ restart:
/*
+ Flush all blocks for a file to disk
+
+ SYNOPSIS
+
+ flush_key_blocks()
+ keycache pointer to a key cache data structure
+ file handler for the file to flush to
+ flush_type type of the flush
+
+ RETURN
+ 0 ok
+ 1 error
+ */
+
+int flush_key_blocks(KEY_CACHE_HANDLE key_cache,
+ File file, enum flush_type type)
+{
+ int res;
+ DBUG_ENTER("flush_key_blocks");
+ DBUG_PRINT("enter", ("key_cache: %lx", key_cache));
+
+ if (!key_cache || !key_cache->disk_blocks)
+ DBUG_RETURN(0);
+ keycache_pthread_mutex_lock(&key_cache->cache_lock);
+ res= flush_key_blocks_int(key_cache, file, type);
+ keycache_pthread_mutex_unlock(&key_cache->cache_lock);
+ DBUG_RETURN(res);
+}
+
+
+/*
Flush all blocks in the key cache to disk
*/
@@ -2253,7 +2293,8 @@ static int flush_all_key_blocks(KEY_CACHE *keycache)
cnt++;
KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
#endif
- if (flush_key_blocks(keycache, block->hash_link->file, FLUSH_RELEASE))
+ if (flush_key_blocks_int(keycache, block->hash_link->file,
+ FLUSH_RELEASE))
return 1;
break;
}
diff --git a/mysys/mf_keycaches.c b/mysys/mf_keycaches.c
new file mode 100644
index 00000000000..1d770e17719
--- /dev/null
+++ b/mysys/mf_keycaches.c
@@ -0,0 +1,359 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Handling of multiple key caches
+
+ The idea is to have a thread safe hash on the table name,
+ with a default key cache value that is returned if the table name is not in
+ the cache.
+*/
+
+#include "mysys_priv.h"
+#include <hash.h>
+#include <m_string.h>
+
+/*****************************************************************************
+ General functions to handle SAFE_HASH objects.
+
+ A SAFE_HASH object is used to store the hash, the mutex and default value
+ needed by the rest of the key cache code.
+ This is a separate struct to make it easy to later reuse the code for other
+ purposes
+
+ All entries are linked in a list to allow us to traverse all elements
+ and delete selected ones. (HASH doesn't allow any easy ways to do this).
+*****************************************************************************/
+
+/*
+ Struct to store a key and pointer to object
+*/
+
+typedef struct st_safe_hash_entry
+{
+ byte *key;
+ uint length;
+ byte *data;
+ struct st_safe_hash_entry *next, **prev;
+} SAFE_HASH_ENTRY;
+
+
+typedef struct st_safe_hash_with_default
+{
+#ifdef THREAD
+ rw_lock_t mutex;
+#endif
+ HASH hash;
+ byte *default_value;
+ SAFE_HASH_ENTRY *root;
+} SAFE_HASH;
+
+
+/*
+ Free a SAFE_HASH_ENTRY
+
+ This function is called by the hash object on delete
+*/
+
+static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
+{
+ DBUG_ENTER("free_assign_entry");
+ my_free((gptr) entry, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+/* Get key and length for a SAFE_HASH_ENTRY */
+
+static byte *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=entry->length;
+ return (byte*) entry->key;
+}
+
+
+/*
+ Init a SAFE_HASH object
+
+ SYNOPSIS
+ safe_hash_init()
+ hash safe_hash handler
+ elements Expected max number of elements
+ default_value default value
+
+ NOTES
+ In case of error we set hash->default_value to 0 to allow one to call
+ safe_hash_free on an object that couldn't be initialized.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
+ byte *default_value)
+{
+ DBUG_ENTER("safe_hash");
+ if (hash_init(&hash->hash, &my_charset_bin, elements,
+ 0, 0, (hash_get_key) safe_hash_entry_get,
+ (void (*)(void*)) safe_hash_entry_free, 0))
+ {
+ hash->default_value= 0;
+ DBUG_RETURN(1);
+ }
+ my_rwlock_init(&hash->mutex, 0);
+ hash->default_value= default_value;
+ hash->root= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Free a SAFE_HASH object
+
+ NOTES
+ This is safe to call on any object that has been sent to safe_hash_init()
+*/
+
+static void safe_hash_free(SAFE_HASH *hash)
+{
+ /*
+ Test if safe_hash_init succeeded. This will also guard us against multiple
+ free calls.
+ */
+ if (hash->default_value)
+ {
+ hash_free(&hash->hash);
+ rwlock_destroy(&hash->mutex);
+ hash->default_value=0;
+ }
+}
+
+/*
+ Return the value stored for a key or default value if no key
+*/
+
+static byte *safe_hash_search(SAFE_HASH *hash, const byte *key, uint length)
+{
+ byte *result;
+ DBUG_ENTER("safe_hash_search");
+ rw_rdlock(&hash->mutex);
+ result= hash_search(&hash->hash, key, length);
+ rw_unlock(&hash->mutex);
+ if (!result)
+ result= hash->default_value;
+ else
+ result= ((SAFE_HASH_ENTRY*) result)->data;
+ DBUG_PRINT("exit",("data: %lx", result));
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Associate a key with some data
+
+ SYONOPSIS
+ safe_hash_set()
+ hash Hash handle
+ key key (path to table etc..)
+ length Length of key
+ data data to to associate with the data
+
+ NOTES
+ This can be used both to insert a new entry and change an existing
+ entry.
+ If one associates a key with the default key cache, the key is deleted
+
+ RETURN
+ 0 ok
+ 1 error (Can only be EOM). In this case my_message() is called.
+*/
+
+static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
+ byte *data)
+{
+ SAFE_HASH_ENTRY *entry;
+ my_bool error= 0;
+ DBUG_ENTER("safe_hash_set");
+ DBUG_PRINT("enter",("key: %.*s data: %lx", length, key, data));
+
+ rw_wrlock(&hash->mutex);
+ entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
+
+ if (data == hash->default_value)
+ {
+ /*
+ The key is to be associated with the default entry. In this case
+ we can just delete the entry (if it existed) from the hash as a
+ search will return the default entry
+ */
+ if (!entry) /* nothing to do */
+ goto end;
+ /* unlink entry from list */
+ if ((*entry->prev= entry->next))
+ entry->next->prev= entry->prev;
+ hash_delete(&hash->hash, (byte*) entry);
+ goto end;
+ }
+ if (entry)
+ {
+ /* Entry existed; Just change the pointer to point at the new data */
+ entry->data= data;
+ }
+ else
+ {
+ if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
+ MYF(MY_WME))))
+ {
+ error= 1;
+ goto end;
+ }
+ entry->key= (byte*) (entry +1);
+ memcpy((char*) entry->key, (char*) key, length);
+ entry->length= length;
+ entry->data= data;
+ /* Link entry to list */
+ if ((entry->next= hash->root))
+ entry->next->prev= &entry->next;
+ entry->prev= &hash->root;
+ hash->root= entry;
+ if (my_hash_insert(&hash->hash, (byte*) entry))
+ {
+ /* This can only happen if hash got out of memory */
+ my_delete((char*) entry, MYF(0));
+ error= 1;
+ goto end;
+ }
+ }
+
+end:
+ rw_unlock(&hash->mutex);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Change all entres with one data value to another data value
+
+ SYONOPSIS
+ safe_hash_change()
+ hash Hash handle
+ old_data Old data
+ new_data Change all 'old_data' to this
+
+ NOTES
+ We use the linked list to traverse all elements in the hash as
+ this allows us to delete elements in the case where 'new_data' is the
+ default value.
+*/
+
+static void safe_hash_change(SAFE_HASH *hash, byte *old_data, byte *new_data)
+{
+ SAFE_HASH_ENTRY *entry, *next;
+ DBUG_ENTER("safe_hash_set");
+
+ rw_wrlock(&hash->mutex);
+
+ for (entry= hash->root ; entry ; entry= next)
+ {
+ next= entry->next;
+ if (entry->data == old_data)
+ {
+ if (new_data == hash->default_value)
+ hash_delete(&hash->hash, (byte*) entry);
+ else
+ entry->data= new_data;
+ }
+ }
+
+ rw_unlock(&hash->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/*****************************************************************************
+ Functions to handle the key cache objects
+*****************************************************************************/
+
+/* Variable to store all key cache objects */
+static SAFE_HASH key_cache_hash;
+
+
+my_bool multi_keycache_init(void)
+{
+ return safe_hash_init(&key_cache_hash, 16, (byte*) dflt_keycache);
+}
+
+
+void multi_keycache_free(void)
+{
+ safe_hash_free(&key_cache_hash);
+}
+
+/*
+ Get a key cache to be used for a specific table.
+
+ SYNOPSIS
+ multi_key_cache_get()
+ key key to find (usually table path)
+ uint length Length of key.
+
+ NOTES
+ This function is coded in such a way that we will return the
+ default key cache even if one never called multi_keycache_init.
+ This will ensure that it works with old MyISAM clients.
+
+ RETURN
+ key cache to use
+*/
+
+KEY_CACHE_HANDLE *multi_key_cache_search(byte *key, uint length)
+{
+ if (!key_cache_hash.hash.records)
+ return dflt_keycache;
+ return (KEY_CACHE_HANDLE*) safe_hash_search(&key_cache_hash, key, length);
+}
+
+
+/*
+ Assosiate a key cache with a key
+
+
+ SYONOPSIS
+ multi_key_cache_set()
+ key key (path to table etc..)
+ length Length of key
+ key_cache cache to assococite with the table
+
+ NOTES
+ This can be used both to insert a new entry and change an existing
+ entry
+*/
+
+
+my_bool multi_key_cache_set(const byte *key, uint length,
+ KEY_CACHE_HANDLE *key_cache)
+{
+ return safe_hash_set(&key_cache_hash, key, length, (byte*) key_cache);
+}
+
+
+void multi_key_cache_change(KEY_CACHE_HANDLE *old_data,
+ KEY_CACHE_HANDLE *new_data)
+{
+ safe_hash_change(&key_cache_hash, (byte*) old_data, (byte*) new_data);
+}
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index aea21fb3d3c..da16457c299 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -38,6 +38,7 @@
#include <assert.h>
#include <m_string.h>
+
inline void bitmap_lock(MY_BITMAP *map)
{
#ifdef THREAD
@@ -46,6 +47,7 @@ inline void bitmap_lock(MY_BITMAP *map)
#endif
}
+
inline void bitmap_unlock(MY_BITMAP *map)
{
#ifdef THREAD
@@ -54,14 +56,19 @@ inline void bitmap_unlock(MY_BITMAP *map)
#endif
}
-my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe)
+
+my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
+ my_bool thread_safe)
{
+ DBUG_ENTER("bitmap_init");
+
DBUG_ASSERT((bitmap_size & 7) == 0);
bitmap_size/=8;
if (!(map->bitmap=buf) &&
- !(map->bitmap=(uchar*)my_malloc(bitmap_size +
- (thread_safe ? sizeof(pthread_mutex_t) : 0),
- MYF(MY_WME | MY_ZEROFILL))))
+ !(map->bitmap= (uchar*) my_malloc(bitmap_size +
+ (thread_safe ?
+ sizeof(pthread_mutex_t) : 0),
+ MYF(MY_WME | MY_ZEROFILL))))
return 1;
map->bitmap_size=bitmap_size;
#ifdef THREAD
@@ -73,22 +80,26 @@ my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread
else
map->mutex=0;
#endif
- return 0;
+ DBUG_RETURN(0);
}
+
void bitmap_free(MY_BITMAP *map)
{
-#ifdef THREAD
- if (map->mutex)
- pthread_mutex_destroy(map->mutex);
-#endif
+ DBUG_ENTER("bitmap_free");
if (map->bitmap)
{
+#ifdef THREAD
+ if (map->mutex)
+ pthread_mutex_destroy(map->mutex);
+#endif
my_free((char*) map->bitmap, MYF(0));
map->bitmap=0;
}
+ DBUG_VOID_RETURN;
}
+
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
@@ -97,6 +108,7 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
bitmap_unlock(map);
}
+
uint bitmap_set_next(MY_BITMAP *map)
{
uchar *bitmap=map->bitmap;
@@ -127,6 +139,7 @@ uint bitmap_set_next(MY_BITMAP *map)
return bit_found;
}
+
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
@@ -135,12 +148,13 @@ void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
bitmap_unlock(map);
}
+
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
uint prefix_bytes, prefix_bits;
DBUG_ASSERT(map->bitmap &&
- (prefix_size <= map->bitmap_size*8 || prefix_size == ~0));
+ (prefix_size <= map->bitmap_size*8 || prefix_size == (uint) ~0));
bitmap_lock(map);
set_if_smaller(prefix_size, map->bitmap_size*8);
if ((prefix_bytes= prefix_size / 8))
@@ -152,16 +166,19 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
bitmap_unlock(map);
}
+
void bitmap_clear_all(MY_BITMAP *map)
{
bitmap_set_prefix(map, 0);
}
+
void bitmap_set_all(MY_BITMAP *map)
{
bitmap_set_prefix(map, ~0);
}
+
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
{
uint prefix_bits= prefix_size & 7, res= 0;
@@ -188,6 +205,7 @@ ret:
return res;
}
+
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
return bitmap_is_prefix(map, 0);
@@ -198,15 +216,17 @@ my_bool bitmap_is_set_all(const MY_BITMAP *map)
return bitmap_is_prefix(map, map->bitmap_size*8);
}
+
my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
return map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7));
}
+
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
- uint length, res=0;
+ uint res=0;
uchar *m1=map1->bitmap, *m2=map2->bitmap, *end;
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
@@ -217,8 +237,10 @@ my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
end= m1+map1->bitmap_size;
while (m1 < end)
+ {
if ((*m1++) & ~(*m2++))
goto ret;
+ }
res=1;
ret:
@@ -227,6 +249,7 @@ ret:
return res;
}
+
my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
uint res;
@@ -243,6 +266,7 @@ my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
return res;
}
+
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
{
uchar *to=map->bitmap, *from=map2->bitmap, *end;
@@ -268,6 +292,7 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
bitmap_unlock(map);
}
+
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
{
uchar *to=map->bitmap, *from=map2->bitmap, *end;
@@ -286,6 +311,7 @@ void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
bitmap_unlock(map);
}
+
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
{
uchar *to=map->bitmap, *from=map2->bitmap, *end;
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index edd35749633..7fa8c9d4fa1 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -682,60 +682,77 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp)
return num;
}
-/*
- function: init_variables
+/*
+ Init one value to it's default values
+
+ SYNOPSIS
+ init_one_value()
+ option Option to initialize
+ value Pointer to variable
+*/
+
+static void init_one_value(const struct my_option *option, gptr *variable,
+ longlong value)
+{
+ switch ((option->var_type & GET_TYPE_MASK)) {
+ case GET_BOOL:
+ *((my_bool*) variable)= (my_bool) value;
+ break;
+ case GET_INT:
+ *((int*) variable)= (int) value;
+ break;
+ case GET_UINT:
+ *((uint*) variable)= (uint) value;
+ break;
+ case GET_LONG:
+ *((long*) variable)= (long) value;
+ break;
+ case GET_ULONG:
+ *((ulong*) variable)= (ulong) value;
+ break;
+ case GET_LL:
+ *((longlong*) variable)= (longlong) value;
+ break;
+ case GET_ULL:
+ *((ulonglong*) variable)= (ulonglong) value;
+ break;
+ default: /* dummy default to avoid compiler warnings */
+ break;
+ }
+}
+
+
+/*
initialize all variables to their default values
+
+ SYNOPSIS
+ init_variables()
+ options Array of options
+
+ NOTES
+ We will initialize the value that is pointed to by options->value.
+ If the value is of type GET_ASK_ADDR, we will also ask for the address
+ for a value and initialize.
*/
static void init_variables(const struct my_option *options)
{
for (; options->name; options++)
{
- gptr *value= (options->var_type & GET_ASK_ADDR ?
- (*getopt_get_addr)("", 0, options) : options->value);
- if (value)
- {
- switch ((options->var_type & GET_TYPE_MASK)) {
- case GET_BOOL:
- if (options->u_max_value)
- *((my_bool*) options->u_max_value)= (my_bool) options->max_value;
- *((my_bool*) value)= (my_bool) options->def_value;
- break;
- case GET_INT:
- if (options->u_max_value)
- *((int*) options->u_max_value)= (int) options->max_value;
- *((int*) value)= (int) options->def_value;
- break;
- case GET_UINT:
- if (options->u_max_value)
- *((uint*) options->u_max_value)= (uint) options->max_value;
- *((uint*) value)= (uint) options->def_value;
- break;
- case GET_LONG:
- if (options->u_max_value)
- *((long*) options->u_max_value)= (long) options->max_value;
- *((long*) value)= (long) options->def_value;
- break;
- case GET_ULONG:
- if (options->u_max_value)
- *((ulong*) options->u_max_value)= (ulong) options->max_value;
- *((ulong*) value)= (ulong) options->def_value;
- break;
- case GET_LL:
- if (options->u_max_value)
- *((longlong*) options->u_max_value)= (longlong) options->max_value;
- *((longlong*) value)= (longlong) options->def_value;
- break;
- case GET_ULL:
- if (options->u_max_value)
- *((ulonglong*) options->u_max_value)= (ulonglong) options->max_value;
- *((ulonglong*) value)= (ulonglong) options->def_value;
- break;
- default: /* dummy default to avoid compiler warnings */
- break;
- }
- }
+ gptr *variable;
+ /*
+ We must set u_max_value first as for some variables
+ options->u_max_value == options->value and in this case we want to
+ set the value to default value.
+ */
+ if (options->u_max_value)
+ init_one_value(options, options->u_max_value, options->max_value);
+ if (options->value)
+ init_one_value(options, options->value, options->def_value);
+ if (options->var_type & GET_ASK_ADDR &&
+ (variable= (*getopt_get_addr)("", 0, options)))
+ init_one_value(options, variable, options->def_value);
}
}
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index 9ee7371b639..1d4219e7bfb 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -28,7 +28,7 @@ pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
#else
pthread_key(struct st_my_thread_var, THR_KEY_mysys);
#endif /* USE_TLS */
-pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
THR_LOCK_net, THR_LOCK_charset;
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
@@ -63,7 +63,6 @@ my_bool my_thread_global_init(void)
pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&THR_LOCK_keycache,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
@@ -96,7 +95,6 @@ void my_thread_global_end(void)
#endif
pthread_mutex_destroy(&THR_LOCK_malloc);
pthread_mutex_destroy(&THR_LOCK_open);
- pthread_mutex_destroy(&THR_LOCK_keycache);
pthread_mutex_destroy(&THR_LOCK_lock);
pthread_mutex_destroy(&THR_LOCK_isam);
pthread_mutex_destroy(&THR_LOCK_myisam);
diff --git a/mysys/typelib.c b/mysys/typelib.c
index e32fad8742f..e4eda5bd675 100644
--- a/mysys/typelib.c
+++ b/mysys/typelib.c
@@ -20,15 +20,28 @@
#include <m_string.h>
#include <m_ctype.h>
-/***************************************************************************
-** Search after a fieldtype. Endspace in x is not compared.
-** If part, uniq field is found and full_name == 0 then x is expanded
-** to full field.
-** full_name has the following bit values:
-** If & 1 accept only whole names
-** If & 2 don't expand if half field
-** If & 4 allow #number# as type
-****************************************************************************/
+
+/*
+ Search after a string in a list of strings. Endspace in x is not compared.
+
+ SYNOPSIS
+ find_type()
+ x String to find
+ lib TYPELIB (struct of pointer to values + count)
+ full_name bitmap of what to do
+ If & 1 accept only whole names
+ If & 2 don't expand if half field
+ If & 4 allow #number# as type
+
+ NOTES
+ If part, uniq field is found and full_name == 0 then x is expanded
+ to full field.
+
+ RETURN
+ -1 Too many matching values
+ 0 No matching value
+ >0 Offset+1 in typelib for matched string
+*/
int find_type(my_string x, TYPELIB *typelib, uint full_name)
{