summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
Diffstat (limited to 'mysys')
-rw-r--r--mysys/Makefile.am2
-rw-r--r--mysys/default.c1
-rw-r--r--mysys/hash.c7
-rw-r--r--mysys/mf_keycache.c687
-rw-r--r--mysys/mf_keycaches.c360
-rw-r--r--mysys/my_bitmap.c48
-rw-r--r--mysys/my_getopt.c113
-rw-r--r--mysys/my_thr_init.c4
-rw-r--r--mysys/thr_alarm.c2
-rw-r--r--mysys/thr_mutex.c23
-rw-r--r--mysys/typelib.c31
11 files changed, 840 insertions, 438 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/default.c b/mysys/default.c
index b1d9e40a1c2..3a751eb4e29 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -251,6 +251,7 @@ int load_defaults(const char *conf_file, const char **groups,
err:
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
exit(1);
+ return 0; /* Keep compiler happy */
}
diff --git a/mysys/hash.c b/mysys/hash.c
index b0ddbd90794..665e3d11e8d 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -29,6 +29,11 @@
#define HIGHFIND 4
#define HIGHUSED 8
+typedef struct st_hash_info {
+ uint next; /* index to next key */
+ byte *data; /* data for current entry */
+} HASH_LINK;
+
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
@@ -53,7 +58,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..b1ef03fdcd2 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -15,14 +15,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
- These functions are to handle keyblock cacheing
- for NISAM, MISAM and PISAM databases.
+ These functions handle keyblock cacheing for ISAM and MyISAM tables.
+
One cache can handle many files.
It must contain buffers of the same blocksize.
init_key_cache() should be used to init cache handler.
*/
#include "mysys_priv.h"
+#include <keycache.h>
#include "my_static.h"
#include <m_string.h>
#include <errno.h>
@@ -85,28 +86,22 @@
typedef pthread_cond_t KEYCACHE_CONDVAR;
-/* info about requests in a waiting queue */
-typedef struct st_keycache_wqueue
-{
- struct st_my_thread_var *last_thread; /* circular list of waiting threads */
-} KEYCACHE_WQUEUE;
-
/* descriptor of the page in the key cache block buffer */
-typedef struct st_keycache_page
+struct st_keycache_page
{
int file; /* file to which the page belongs to */
my_off_t filepos; /* position of the page in the file */
-} KEYCACHE_PAGE;
+};
/* element in the chain of a hash table bucket */
-typedef struct st_hash_link
+struct st_hash_link
{
struct st_hash_link *next, **prev; /* to connect links in the same bucket */
struct st_block_link *block; /* reference to the block for the page: */
File file; /* from such a file */
my_off_t diskpos; /* with such an offset */
uint requests; /* number of requests for the page */
-} HASH_LINK; /* offset is always alighed for key_cache_block_size */
+};
/* simple states of a block */
#define BLOCK_ERROR 1 /* an error occured when performing disk i/o */
@@ -122,7 +117,7 @@ typedef struct st_hash_link
#define PAGE_WAIT_TO_BE_READ 2
/* key cache block */
-typedef struct st_block_link
+struct st_block_link
{
struct st_block_link
*next_used, **prev_used; /* to connect links in the LRU chain (ring) */
@@ -138,53 +133,15 @@ typedef struct st_block_link
uint hits_left; /* number of hits left until promotion */
ulonglong last_hit_time; /* timestamp of the last hit */
KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
-} BLOCK_LINK;
-
-KEY_CACHE_VAR dflt_key_cache_var=
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-KEY_CACHE_HANDLE *dflt_keycache= &dflt_key_cache_var.cache;
-#define CHANGED_BLOCKS_HASH 128 /* must be power of 2 */
+KEY_CACHE dflt_key_cache_var;
+KEY_CACHE *dflt_key_cache= &dflt_key_cache_var;
+
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
-typedef struct st_key_cache
-{
- KEY_CACHE_VAR *env; /* pointer to key cache variables (if any) */
- my_bool key_cache_inited;
- uint key_cache_shift;
- ulong key_cache_mem_size; /* specified size of the cache memory */
- uint key_cache_block_size; /* size of the page buffer of a cache block */
- ulong min_warm_blocks; /* min number of warm blocks; */
- ulong age_threshold; /* age threshold for hot blocks */
- ulonglong keycache_time; /* total number of block link operations */
- uint hash_entries; /* max number of entries in the hash table */
- int hash_links; /* max number of hash links */
- int hash_links_used; /* number of hash links currently used */
- int disk_blocks; /* max number of blocks in the cache */
- ulong blocks_used; /* number of currently used blocks */
- ulong blocks_changed; /* number of currently dirty blocks */
- ulong 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
- 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 */
- BLOCK_LINK *block_root; /* memory for block links */
- byte HUGE_PTR *block_mem; /* memory for block buffers */
- BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */
- BLOCK_LINK *used_ins; /* ptr to the insertion block in LRU chain */
- pthread_mutex_t cache_lock; /* to lock access to the cache structure */
- KEYCACHE_WQUEUE waiting_for_hash_link; /* waiting for a free hash link */
- KEYCACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */
- BLOCK_LINK *changed_blocks[CHANGED_BLOCKS_HASH]; /* hash for dirty file bl.*/
- BLOCK_LINK *file_blocks[CHANGED_BLOCKS_HASH]; /* hash for other file bl.*/
-} KEY_CACHE;
-
-static int flush_all_key_blocks(KEY_CACHE_HANDLE keycache);
-static void test_key_cache(KEY_CACHE *keycache,
+static int flush_all_key_blocks(KEY_CACHE *keycache);
+static void test_key_cache(KEY_CACHE *keycache,
const char *where, my_bool lock);
#define KEYCACHE_HASH(f, pos) \
@@ -202,10 +159,10 @@ static void test_key_cache(KEY_CACHE *keycache,
static FILE *keycache_debug_log=NULL;
static void keycache_debug_print _VARARGS((const char *fmt,...));
#define KEYCACHE_DEBUG_OPEN \
- keycache_debug_log=fopen(KEYCACHE_DEBUG_LOG, "w")
+ if (!keycache_debug_log) keycache_debug_log=fopen(KEYCACHE_DEBUG_LOG, "w")
#define KEYCACHE_DEBUG_CLOSE \
- if (keycache_debug_log) fclose(keycache_debug_log)
+ if (keycache_debug_log) { fclose(keycache_debug_log); keycache_debug_log=0; }
#else
#define KEYCACHE_DEBUG_OPEN
#define KEYCACHE_DEBUG_CLOSE
@@ -283,40 +240,34 @@ 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
- use_mem total memory to use for the key cache
- env ref to other parameters of the key cache, if any
+ keycache pointer to the key cache handle to initialize
+ key_cache_block_size size of blocks to keep cached data
+ use_mem total memory to use for the key cache
+ division_limit division limit (may be zero)
+ age_threshold age threshold (may be zero)
RETURN VALUE
number of blocks in the key cache, if successful,
0 - otherwise.
NOTES.
- If pkeycache points to an undefined handle (NULL), a new KEY_CACHE
- data structure is created and a pointer to it is returned as a new
- key cache handle, otherwise *pkeycache is considered as a reused
- handle for a key cache with new blocks.
+ if keycache->key_cache_inited != 0 we assume that the key cache
+ is already initialized. This is for now used by myisamchk, but shouldn't
+ be something that a program should rely on!
+
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,
- ulong use_mem, KEY_CACHE_VAR *env)
+int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
+ ulong use_mem, uint division_limit,
+ uint age_threshold)
{
uint blocks, hash_links, length;
int error;
- KEY_CACHE *keycache;
-
DBUG_ENTER("init_key_cache");
-
- if (!(keycache= (KEY_CACHE *) *pkeycache) &&
- !(keycache= (KEY_CACHE *) my_malloc(sizeof(KEY_CACHE),
- MYF(MY_ZEROFILL))))
- DBUG_RETURN(0);
-
- keycache->env= env;
+ DBUG_ASSERT(key_cache_block_size >= 512);
KEYCACHE_DEBUG_OPEN;
if (keycache->key_cache_inited && keycache->disk_blocks > 0)
@@ -324,38 +275,25 @@ int init_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
DBUG_PRINT("warning",("key cache already in use"));
DBUG_RETURN(0);
}
- if (env && ! keycache->key_cache_inited)
- {
- env->cache_w_requests= env->cache_r_requests= 0;
- env->cache_read= env->cache_write=0;
- }
+ keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
+ keycache->global_cache_read= keycache->global_cache_write= 0;
+ keycache->disk_blocks= -1;
if (! keycache->key_cache_inited)
{
- keycache->key_cache_inited= TRUE;
- keycache->disk_blocks= -1;
+ keycache->key_cache_inited= 1;
+ keycache->in_init= 0;
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));
}
-
- /*
- 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));
- keycache->block_mem= NULL;
- if (keycache->block_root)
- my_free((gptr) keycache->block_root, MYF(0));
- keycache->block_root= NULL;
+
+ keycache->key_cache_mem_size= use_mem;
+ keycache->key_cache_block_size= key_cache_block_size;
+ keycache->key_cache_shift= my_bit_log2(key_cache_block_size);
+ DBUG_PRINT("info", ("key_cache_block_size: %u",
+ key_cache_block_size));
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 +309,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,57 +340,53 @@ 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;
- if (env)
- env->blocks_used= env->blocks_changed= 0;
-#if defined(KEYCACHE_DEBUG)
- keycache->blocks_available=0;
-#endif
+
+ keycache->global_blocks_used= keycache->global_blocks_changed= 0;
+ keycache->blocks_available=0; /* For debugging */
+
/* The LRU chain is empty after initialization */
keycache->used_last= NULL;
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= (division_limit ?
+ blocks * division_limit / 100 + 1 :
+ blocks);
+ keycache->age_threshold= (age_threshold ?
+ blocks * 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);
+ bzero((gptr) keycache->file_blocks,
+ sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
}
- bzero((gptr) keycache->changed_blocks,
- sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
- bzero((gptr) keycache->file_blocks,
- sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
-
- if (env)
- env->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
- *pkeycache= keycache;
+
+ keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
DBUG_RETURN((int) blocks);
err:
error= my_errno;
keycache->disk_blocks= 0;
- if (env)
- env->blocks= 0;
+ keycache->blocks= 0;
if (keycache->block_mem)
{
my_free_lock((gptr) keycache->block_mem, MYF(0));
@@ -473,9 +407,11 @@ 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
- use_mem total memory to use for the new key cache
+ keycache in/out 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
+ division_limit new division limit (if not zero)
+ age_threshold new age threshold (if not zero)
RETURN VALUE
number of blocks in the key cache, if successful,
@@ -483,44 +419,50 @@ err:
NOTES.
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.
+ with the key cache values.
+
+ 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.
*/
-int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
- ulong use_mem)
+int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
+ ulong use_mem, uint division_limit,
+ uint age_threshold)
{
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)
- return keycache->disk_blocks;
+ if (!keycache->key_cache_inited ||
+ (key_cache_block_size == keycache->key_cache_block_size &&
+ use_mem == keycache->key_cache_mem_size))
+ DBUG_RETURN(keycache->disk_blocks);
keycache_pthread_mutex_lock(&keycache->cache_lock);
if (flush_all_key_blocks(keycache))
{
/* TODO: if this happens, we should write a warning in the log file ! */
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- return 0;
+ DBUG_RETURN(0);
}
+ end_key_cache(keycache, 0); /* Don't free mutex */
+ /* the following will work even if use_mem is 0 */
+ blocks= init_key_cache(keycache, key_cache_block_size, use_mem,
+ division_limit, age_threshold);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- end_key_cache(pkeycache, 0);
- /* the following will work even if memory is 0 */
- blocks=init_key_cache(pkeycache, key_cache_block_size, use_mem,
- 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 key cache handle
+ division_limit new division limit (if not zero)
+ age_threshold new age threshold (if not zero)
RETURN VALUE
none
@@ -528,23 +470,20 @@ int resize_key_cache(KEY_CACHE_HANDLE *pkeycache, uint key_cache_block_size,
NOTES.
Presently the function resets the key cache parameters
concerning midpoint insertion strategy - division_limit and
- age_threshold. It corresponding values are passed through
- the keycache->env structure.
+ age_threshold.
*/
-void change_key_cache_param(KEY_CACHE_HANDLE keycache)
+void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
+ uint age_threshold)
{
- 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 (division_limit)
+ keycache->min_warm_blocks= (keycache->disk_blocks *
+ division_limit / 100 + 1);
+ if (age_threshold)
+ keycache->age_threshold= (keycache->disk_blocks *
+ age_threshold / 100);
DBUG_VOID_RETURN;
}
@@ -554,23 +493,21 @@ void change_key_cache_param(KEY_CACHE_HANDLE keycache)
SYNOPSIS
end_key_cache()
- pkeycache in/out pointer to the key cache handle
- cleanup <-> the key cache data structure is freed as well
+ keycache key cache handle
+ cleanup Complete free (Free also mutex for key cache)
RETURN VALUE
none
-
- 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.
*/
-void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
+void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
{
- KEY_CACHE *keycache= *pkeycache;
- KEY_CACHE_VAR *env= keycache->env;
DBUG_ENTER("end_key_cache");
+ DBUG_PRINT("enter", ("key_cache: %lx", keycache));
+
+ if (!keycache->key_cache_inited)
+ DBUG_VOID_RETURN;
+
if (keycache->disk_blocks > 0)
{
if (keycache->block_mem)
@@ -581,21 +518,22 @@ void end_key_cache(KEY_CACHE_HANDLE *pkeycache, my_bool cleanup)
keycache->block_root= NULL;
}
keycache->disk_blocks= -1;
+ /* Reset blocks_changed to be safe if flush_all_key_blocks is called */
+ keycache->blocks_changed= 0;
}
- KEYCACHE_DEBUG_CLOSE;
- keycache->key_cache_inited= 0;
- if (env)
- DBUG_PRINT("status",
- ("used: %d changed: %d w_requests: %ld \
- writes: %ld r_requests: %ld reads: %ld",
- env->blocks_used, env->blocks_changed,
- env->cache_w_requests, env->cache_write,
- env->cache_r_requests, env->cache_read));
+
+ DBUG_PRINT("status",
+ ("used: %d changed: %d w_requests: %ld \
+writes: %ld r_requests: %ld reads: %ld",
+ keycache->global_blocks_used, keycache->global_blocks_changed,
+ keycache->global_cache_w_requests, keycache->global_cache_write,
+ keycache->global_cache_r_requests, keycache->global_cache_read));
+
if (cleanup)
{
pthread_mutex_destroy(&keycache->cache_lock);
- my_free((gptr) *pkeycache, MYF(0));
- *pkeycache= NULL;
+ keycache->key_cache_inited= 0;
+ KEYCACHE_DEBUG_CLOSE;
}
DBUG_VOID_RETURN;
} /* end_key_cache */
@@ -606,8 +544,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 +581,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 +615,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 +647,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 +656,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)
@@ -779,8 +717,7 @@ static void link_to_file_list(KEY_CACHE *keycache,
{
block->status&= ~BLOCK_CHANGED;
keycache->blocks_changed--;
- if (keycache->env)
- keycache->env->blocks_changed--;
+ keycache->global_blocks_changed--;
}
}
@@ -798,8 +735,7 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
&keycache->changed_blocks[FILE_HASH(block->hash_link->file)]);
block->status|=BLOCK_CHANGED;
keycache->blocks_changed++;
- if (keycache->env)
- keycache->env->blocks_changed++;
+ keycache->global_blocks_changed++;
}
@@ -809,7 +745,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 +754,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 +772,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 +817,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 +851,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 +874,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 +908,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 +1059,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 +1142,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 +1163,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,
@@ -1321,8 +1257,7 @@ restart:
block->offset= keycache->key_cache_block_size;
block->requests= 1;
keycache->blocks_used++;
- if (keycache->env)
- keycache->env->blocks_used++;
+ keycache->global_blocks_used++;
keycache->warm_blocks++;
block->hits_left= init_hits_left;
block->last_hit_time= 0;
@@ -1388,12 +1323,13 @@ 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++;
+ keycache->global_cache_write++;
}
block->status|= BLOCK_REASSIGNED;
@@ -1432,8 +1368,7 @@ restart:
PAGE_READ : PAGE_WAIT_TO_BE_READ;
}
}
- if (keycache->env)
- keycache->env->cache_read++;
+ keycache->global_cache_read++;
}
else
{
@@ -1465,12 +1400,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 +1486,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.
@@ -1573,13 +1508,15 @@ static void read_block(KEY_CACHE *keycache,
have to be a multiple of key_cache_block_size;
*/
-byte *key_cache_read(KEY_CACHE_HANDLE keycache,
+byte *key_cache_read(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
byte *buff, uint length,
uint block_length __attribute__((unused)),
int return_buffer __attribute__((unused)))
{
int error=0;
+ uint offset= 0;
+ byte *start= buff;
DBUG_ENTER("key_cache_read");
DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
(uint) file, (ulong) filepos, length));
@@ -1588,32 +1525,35 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
{
/* Key cache is used */
reg1 BLOCK_LINK *block;
- uint offset= (uint) (filepos & (keycache->key_cache_block_size-1));
- byte *start= buff;
uint read_length;
uint status;
int page_st;
-#ifndef THREAD
- if (block_length > keycache->key_cache_block_size || offset)
- return_buffer=0;
-#endif
-
/* Read data in key_cache_block_size increments */
- filepos-= offset;
do
{
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ if (keycache->disk_blocks <= 0) /* Resize failed */
+ {
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ goto no_key_cache;
+ }
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- if (keycache->env)
- keycache->env->cache_r_requests++;
+ offset= (uint) (filepos & (keycache->key_cache_block_size-1));
+ filepos-= offset;
+#ifndef THREAD
+ if (block_length > keycache->key_cache_block_size || offset)
+ return_buffer=0;
+#endif
+
+ keycache->global_cache_r_requests++;
block=find_key_block(keycache, file, filepos, level, 0, &page_st);
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));
}
@@ -1664,29 +1604,25 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
DBUG_RETURN((byte *) 0);
#ifndef THREAD
+ /* This is only true if we where able to read everything in one block */
if (return_buffer)
- return (block->buffer);
+ return (block->buffer);
#endif
-
buff+= read_length;
filepos+= read_length;
- offset= 0;
} while ((length-= read_length));
DBUG_RETURN(start);
}
- /* Key cache is not used */
- if (keycache->env)
- {
- statistic_increment(keycache->env->cache_r_requests,
- &keycache->cache_lock);
- statistic_increment(keycache->env->cache_read,
- &keycache->cache_lock);
- }
- if (my_pread(file, (byte*) buff, length, filepos, MYF(MY_NABP)))
+no_key_cache: /* Key cache is not used */
+
+ /* We can't use mutex here as the key cache may not be initialized */
+ keycache->global_cache_r_requests++;
+ keycache->global_cache_read++;
+ if (my_pread(file, (byte*) buff, length, filepos+offset, MYF(MY_NABP)))
error= 1;
- DBUG_RETURN(error? (byte*) 0 : buff);
+ DBUG_RETURN(error ? (byte*) 0 : start);
}
@@ -1694,20 +1630,23 @@ byte *key_cache_read(KEY_CACHE_HANDLE keycache,
Insert a block of file data from a buffer into key cache
SYNOPSIS
-
key_cache_insert()
- 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
-
+ 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
+
+ NOTES
+ This is used by MyISAM to move all blocks from a index file to the key
+ cache
+
RETURN VALUE
0 if a success, 1 - otherwise.
*/
-int key_cache_insert(KEY_CACHE_HANDLE keycache,
+int key_cache_insert(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
byte *buff, uint length)
{
@@ -1719,20 +1658,27 @@ int key_cache_insert(KEY_CACHE_HANDLE keycache,
{
/* Key cache is used */
reg1 BLOCK_LINK *block;
- uint offset= (uint) (filepos & (keycache->key_cache_block_size-1));
uint read_length;
int page_st;
+ int error;
- /* Read data into key cache from buff in key_cache_block_size increments */
- filepos-= offset;
do
{
+ uint offset;
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ if (keycache->disk_blocks <= 0) /* Resize failed */
+ {
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ DBUG_RETURN(0);
+ }
read_length= length > keycache->key_cache_block_size ?
keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- if (keycache->env)
- keycache->env->cache_r_requests++;
+ offset= (uint) (filepos & (keycache->key_cache_block_size-1));
+ /* Read data into key cache from buff in key_cache_block_size incr. */
+ filepos-= offset;
+
+ keycache->global_cache_r_requests++;
block= find_key_block(keycache, file, filepos, level, 0, &page_st);
if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
{
@@ -1761,14 +1707,14 @@ int key_cache_insert(KEY_CACHE_HANDLE keycache,
*/
unreg_request(keycache, block, 1);
+ error= (block->status & BLOCK_ERROR);
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- if (block->status & BLOCK_ERROR)
+ if (error)
DBUG_RETURN(1);
buff+= read_length;
filepos+= read_length;
- offset=0;
} while ((length-= read_length));
}
@@ -1777,20 +1723,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,12 +1744,12 @@ 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;
*/
-int key_cache_write(KEY_CACHE_HANDLE keycache,
+int key_cache_write(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
byte *buff, uint length,
uint block_length __attribute__((unused)),
@@ -1811,17 +1757,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)
- statistic_increment(keycache->env->cache_write,
- &keycache->cache_lock);
+ keycache->global_cache_write++;
if (my_pwrite(file, buff, length, filepos, MYF(MY_NABP | MY_WAIT_IF_FULL)))
DBUG_RETURN(1);
}
@@ -1835,19 +1780,25 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
{
/* Key cache is used */
uint read_length;
- uint offset= (uint) (filepos & (keycache->key_cache_block_size-1));
int page_st;
- /* Write data in key_cache_block_size increments */
- filepos-= offset;
do
{
+ uint offset;
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ if (keycache->disk_blocks <= 0) /* Resize failed */
+ {
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ goto no_key_cache;
+ }
read_length= length > keycache->key_cache_block_size ?
- keycache->key_cache_block_size : length;
+ keycache->key_cache_block_size : length;
KEYCACHE_DBUG_ASSERT(read_length > 0);
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- if (keycache->env)
- keycache->env->cache_w_requests++;
+ offset= (uint) (filepos & (keycache->key_cache_block_size-1));
+ /* Write data in key_cache_block_size increments */
+ filepos-= offset;
+
+ keycache->global_cache_w_requests++;
block= find_key_block(keycache, file, filepos, level, 1, &page_st);
if (block->status != BLOCK_ERROR && page_st != PAGE_READ &&
(offset || read_length < keycache->key_cache_block_size))
@@ -1872,7 +1823,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);
}
@@ -1897,25 +1848,21 @@ int key_cache_write(KEY_CACHE_HANDLE keycache,
offset= 0;
} while ((length-= read_length));
+ goto end;
}
- else
+
+no_key_cache:
+ /* Key cache is not used */
+ if (dont_write)
{
- /* Key cache is not used */
- if (dont_write)
- {
- if (keycache->env)
- {
- statistic_increment(keycache->env->cache_w_requests,
- &keycache->cache_lock);
- statistic_increment(keycache->env->cache_write,
- &keycache->cache_lock);
- }
- if (my_pwrite(file, (byte*) buff, length, filepos,
- MYF(MY_NABP | MY_WAIT_IF_FULL)))
- error=1;
- }
+ keycache->global_cache_w_requests++;
+ keycache->global_cache_write++;
+ if (my_pwrite(file, (byte*) buff, length, filepos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ error=1;
}
+end:
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("exec",
test_key_cache(keycache, "end of key_cache_write", 1););
@@ -1991,12 +1938,13 @@ 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)
- keycache->env->cache_write++;
+ keycache->global_cache_write++;
if (error)
{
block->status|= BLOCK_ERROR;
@@ -2007,8 +1955,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{
keycache->blocks_changed--;
- if (keycache->env)
- keycache->env->blocks_changed--;
+ keycache->global_blocks_changed--;
free_block(keycache, block);
}
else
@@ -2024,27 +1971,29 @@ 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
+ flush_key_blocks_int()
+ 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 *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 +2002,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 +2079,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;
/*
@@ -2148,8 +2095,7 @@ restart:
{
/* It's a temporary file */
keycache->blocks_changed--;
- if (keycache->env)
- keycache->env->blocks_changed--;
+ keycache->global_blocks_changed--;
free_block(keycache, block);
}
}
@@ -2214,13 +2160,6 @@ 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",
test_key_cache(keycache, "end of flush_key_blocks", 0););
@@ -2234,6 +2173,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 *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->disk_blocks <= 0)
+ 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 +2223,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..806f83dc7d8
--- /dev/null
+++ b/mysys/mf_keycaches.c
@@ -0,0 +1,360 @@
+/* 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 <keycache.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_key_cache);
+}
+
+
+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 *multi_key_cache_search(byte *key, uint length)
+{
+ if (!key_cache_hash.hash.records)
+ return dflt_key_cache;
+ return (KEY_CACHE*) 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 *key_cache)
+{
+ return safe_hash_set(&key_cache_hash, key, length, (byte*) key_cache);
+}
+
+
+void multi_key_cache_change(KEY_CACHE *old_data,
+ KEY_CACHE *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..830c62b349b 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -83,7 +83,7 @@ int handle_options(int *argc, char ***argv,
char *))
{
uint opt_found, argvpos= 0, length, i;
- my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used,
+ my_bool end_of_options= 0, must_be_var, set_maximum_value,
option_is_loose;
char **pos, **pos_end, *optend, *prev_found,
*opt_str, key_name[FN_REFLEN];
@@ -104,7 +104,6 @@ int handle_options(int *argc, char ***argv,
char *argument= 0;
must_be_var= 0;
set_maximum_value= 0;
- special_used= 0;
option_is_loose= 0;
cur_arg++; /* skip '-' */
@@ -202,7 +201,6 @@ int handle_options(int *argc, char ***argv,
/*
We were called with a special prefix, we can reuse opt_found
*/
- special_used= 1;
opt_str+= (special_opt_prefix_lengths[i] + 1);
if (i == OPT_LOOSE)
option_is_loose= 1;
@@ -682,60 +680,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/thr_alarm.c b/mysys/thr_alarm.c
index bf40ffc5b4d..54aa4d421f6 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -770,7 +770,9 @@ bool thr_got_alarm(thr_alarm_t *alrm_ptr)
void thr_end_alarm(thr_alarm_t *alrm_ptr)
{
thr_alarm_t alrm= *alrm_ptr;
+ /* alrm may be zero if thr_alarm aborted with an error */
if (alrm && alrm->crono)
+
{
KillTimer(NULL, alrm->crono);
alrm->crono = 0;
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index 3abac2dc737..474334efcc0 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -54,12 +54,15 @@ void safe_mutex_global_init(void)
int safe_mutex_init(safe_mutex_t *mp,
const pthread_mutexattr_t *attr __attribute__((unused)),
- const char *file __attribute__((unused)),
- uint line __attribute__((unused)))
+ const char *file,
+ uint line)
{
bzero((char*) mp,sizeof(*mp));
pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
pthread_mutex_init(&mp->mutex,attr);
+ /* Mark that mutex is initialized */
+ mp->file= file;
+ mp->line= line;
#ifdef SAFE_MUTEX_DETECT_DESTROY
/*
@@ -70,7 +73,7 @@ int safe_mutex_init(safe_mutex_t *mp,
{
struct st_safe_mutex_info_t *info =mp->info;
- info->init_file= (char *) file;
+ info->init_file= file;
info->init_line= line;
info->prev= NULL;
info->next= NULL;
@@ -92,6 +95,13 @@ int safe_mutex_init(safe_mutex_t *mp,
int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
{
int error;
+ if (!mp->file)
+ {
+ fprintf(stderr,"safe_mutex: Trying to lock unitialized mutex at %s, line %d", file, line);
+ fflush(stderr);
+ abort();
+ }
+
pthread_mutex_lock(&mp->global);
if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
{
@@ -117,7 +127,7 @@ line %d more than 1 time\n", file,line);
abort();
}
mp->thread=pthread_self();
- mp->file= (char*) file;
+ mp->file= file;
mp->line=line;
pthread_mutex_unlock(&mp->global);
return error;
@@ -204,7 +214,7 @@ int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
abort();
}
mp->thread=pthread_self();
- mp->file= (char*) file;
+ mp->file= file;
mp->line=line;
pthread_mutex_unlock(&mp->global);
return error;
@@ -242,7 +252,7 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
abort();
}
mp->thread=pthread_self();
- mp->file= (char*) file;
+ mp->file= file;
mp->line=line;
pthread_mutex_unlock(&mp->global);
return error;
@@ -268,6 +278,7 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
if (pthread_mutex_destroy(&mp->mutex))
error=1;
#endif
+ mp->file= 0; /* Mark destroyed */
#ifdef SAFE_MUTEX_DETECT_DESTROY
if (mp->info)
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)
{