diff options
author | unknown <monty@mashka.mysql.fi> | 2003-11-18 13:47:27 +0200 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-11-18 13:47:27 +0200 |
commit | e72124c4ccad5b390b84562389175dcd7355769c (patch) | |
tree | 0a23d90c946c5f05a8c160fc7c6ef3f05505fc79 /mysys | |
parent | 61e682b8adafdfae736327fee4ea0263e1a0bd37 (diff) | |
download | mariadb-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.am | 2 | ||||
-rw-r--r-- | mysys/hash.c | 2 | ||||
-rw-r--r-- | mysys/mf_keycache.c | 349 | ||||
-rw-r--r-- | mysys/mf_keycaches.c | 359 | ||||
-rw-r--r-- | mysys/my_bitmap.c | 48 | ||||
-rw-r--r-- | mysys/my_getopt.c | 109 | ||||
-rw-r--r-- | mysys/my_thr_init.c | 4 | ||||
-rw-r--r-- | mysys/typelib.c | 31 |
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) { |