107 #include "mysys_priv.h" 
  108 #include "mysys_err.h" 
  109 #include <keycache.h> 
  110 #include "my_static.h" 
  111 #include <m_string.h> 
  115 #include "probes_mysql.h" 
  155 #define STRUCT_PTR(TYPE, MEMBER, a)                                           \ 
  156           (TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER)) 
  159 #define  COND_FOR_REQUESTED 0 
  160 #define  COND_FOR_SAVED     1 
  161 #define  COND_FOR_READERS   2 
  183 #define BLOCK_ERROR           1  
  185 #define BLOCK_IN_SWITCH       4  
  186 #define BLOCK_REASSIGNED      8  
  187 #define BLOCK_IN_FLUSH       16  
  188 #define BLOCK_CHANGED        32  
  189 #define BLOCK_IN_USE         64  
  190 #define BLOCK_IN_EVICTION   128  
  191 #define BLOCK_IN_FLUSHWRITE 256  
  192 #define BLOCK_FOR_UPDATE    512  
  196 #define PAGE_TO_BE_READ         1 
  197 #define PAGE_WAIT_TO_BE_READ    2 
  200 enum BLOCK_TEMPERATURE { BLOCK_COLD  , BLOCK_WARM , BLOCK_HOT };
 
  206     *next_used, **prev_used;   
 
  208     *next_changed, **prev_changed; 
 
  216   enum BLOCK_TEMPERATURE temperature; 
 
  218   ulonglong last_hit_time; 
 
  223 KEY_CACHE *dflt_key_cache= &dflt_key_cache_var;
 
  225 #define FLUSH_CACHE         2000             
  227 static int flush_all_key_blocks(
KEY_CACHE *keycache);
 
  234 #if !defined(DBUG_OFF) 
  235 static void test_key_cache(
KEY_CACHE *keycache,
 
  236                            const char *where, my_bool lock);
 
  239 #define KEYCACHE_HASH(f, pos)                                                 \ 
  240 (((ulong) ((pos) / keycache->key_cache_block_size) +                          \ 
  241                                      (ulong) (f)) & (keycache->hash_entries-1)) 
  242 #define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1)) 
  244 #define DEFAULT_KEYCACHE_DEBUG_LOG  "keycache_debug.log" 
  246 #if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG) 
  247 #define KEYCACHE_DEBUG_LOG  DEFAULT_KEYCACHE_DEBUG_LOG 
  250 #if defined(KEYCACHE_DEBUG_LOG) 
  251 static FILE *keycache_debug_log=NULL;
 
  252 static void keycache_debug_print(
const char *
fmt,...);
 
  253 #define KEYCACHE_DEBUG_OPEN                                                   \ 
  254           if (!keycache_debug_log)                                            \ 
  256             keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w");               \ 
  257             (void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ);         \ 
  260 #define KEYCACHE_DEBUG_CLOSE                                                  \ 
  261           if (keycache_debug_log)                                             \ 
  263             fclose(keycache_debug_log);                                       \ 
  264             keycache_debug_log= 0;                                            \ 
  267 #define KEYCACHE_DEBUG_OPEN 
  268 #define KEYCACHE_DEBUG_CLOSE 
  271 #if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) 
  272 #define KEYCACHE_DBUG_PRINT(l, m)                                             \ 
  273             { if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \ 
  274               keycache_debug_print m; } 
  276 #define KEYCACHE_DBUG_ASSERT(a)                                               \ 
  277             { if (! (a) && keycache_debug_log) fclose(keycache_debug_log);    \ 
  280 #define KEYCACHE_DBUG_PRINT(l, m)  DBUG_PRINT(l, m) 
  281 #define KEYCACHE_DBUG_ASSERT(a)    DBUG_ASSERT(a) 
  284 #if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) 
  286 static long keycache_thread_id;
 
  287 #define KEYCACHE_THREAD_TRACE(l)                                              \ 
  288              KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id)) 
  290 #define KEYCACHE_THREAD_TRACE_BEGIN(l)                                        \ 
  291             { struct st_my_thread_var *thread_var= my_thread_var;             \ 
  292               keycache_thread_id= thread_var->id;                             \ 
  293               KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) } 
  295 #define KEYCACHE_THREAD_TRACE_END(l)                                          \ 
  296             KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id)) 
  298 #define KEYCACHE_THREAD_TRACE_BEGIN(l) 
  299 #define KEYCACHE_THREAD_TRACE_END(l) 
  300 #define KEYCACHE_THREAD_TRACE(l) 
  303 #define BLOCK_NUMBER(b)                                                       \ 
  304   ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK))) 
  305 #define HASH_LINK_NUMBER(h)                                                   \ 
  306   ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK))) 
  308 #if (defined(KEYCACHE_TIMEOUT) && !defined(__WIN__)) || defined(KEYCACHE_DEBUG) 
  309 static int keycache_pthread_cond_wait(
mysql_cond_t *cond,
 
  312 #define keycache_pthread_cond_wait(C, M) mysql_cond_wait(C, M) 
  315 #if defined(KEYCACHE_DEBUG) 
  316 static int keycache_pthread_mutex_lock(
mysql_mutex_t *mutex);
 
  317 static void keycache_pthread_mutex_unlock(
mysql_mutex_t *mutex);
 
  318 static int keycache_pthread_cond_signal(
mysql_cond_t *cond);
 
  320 #define keycache_pthread_mutex_lock(M) mysql_mutex_lock(M) 
  321 #define keycache_pthread_mutex_unlock(M) mysql_mutex_unlock(M) 
  322 #define keycache_pthread_cond_signal(C) mysql_cond_signal(C) 
  325 #if !defined(DBUG_OFF) 
  332 static int cache_empty(
KEY_CACHE *keycache);
 
  335 static inline uint next_power(uint value)
 
  337   return (uint) my_round_up_to_next_power((uint32) value) << 1;
 
  366 int init_key_cache(
KEY_CACHE *keycache, uint key_cache_block_size,
 
  367                    size_t use_mem, uint division_limit,
 
  370   ulong blocks, hash_links;
 
  373   DBUG_ENTER(
"init_key_cache");
 
  374   DBUG_ASSERT(key_cache_block_size >= 512);
 
  377   if (keycache->key_cache_inited && keycache->disk_blocks > 0)
 
  379     DBUG_PRINT(
"warning",(
"key cache already in use"));
 
  383   keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
 
  384   keycache->global_cache_read= keycache->global_cache_write= 0;
 
  385   keycache->disk_blocks= -1;
 
  386   if (! keycache->key_cache_inited)
 
  388     keycache->key_cache_inited= 1;
 
  393     keycache->in_resize= 0;
 
  394     keycache->resize_in_flush= 0;
 
  395     keycache->cnt_for_resize_op= 0;
 
  396     keycache->waiting_for_resize_cnt.last_thread= NULL;
 
  397     keycache->in_init= 0;
 
  399                      &keycache->cache_lock, MY_MUTEX_INIT_FAST);
 
  400     keycache->resize_queue.last_thread= NULL;
 
  403   keycache->key_cache_mem_size= use_mem;
 
  404   keycache->key_cache_block_size= key_cache_block_size;
 
  405   DBUG_PRINT(
"info", (
"key_cache_block_size: %u",
 
  406                       key_cache_block_size));
 
  409                               sizeof(
HASH_LINK*) * 5/4 + key_cache_block_size));
 
  416       if ((keycache->hash_entries= next_power(blocks)) < blocks * 5/4)
 
  417         keycache->hash_entries<<= 1;
 
  418       hash_links= 2 * blocks;
 
  419 #
if defined(MAX_THREADS)
 
  420       if (hash_links < MAX_THREADS + blocks - 1)
 
  421         hash_links= MAX_THREADS + blocks - 1;
 
  423       while ((length= (ALIGN_SIZE(blocks * 
sizeof(
BLOCK_LINK)) +
 
  424                        ALIGN_SIZE(hash_links * 
sizeof(
HASH_LINK)) +
 
  426                                   keycache->hash_entries))) +
 
  427              ((size_t) blocks * keycache->key_cache_block_size) > use_mem)
 
  430       if ((keycache->block_mem=
 
  431            my_large_malloc((
size_t) blocks * keycache->key_cache_block_size,
 
  438         if ((keycache->block_root= (
BLOCK_LINK*) my_malloc(length,
 
  441         my_large_free(keycache->block_mem);
 
  442         keycache->block_mem= 0;
 
  447         my_error(EE_OUTOFMEMORY, MYF(ME_FATALERROR),
 
  448                  blocks * keycache->key_cache_block_size);
 
  451       blocks= blocks / 4*3;
 
  453     keycache->blocks_unused= blocks;
 
  454     keycache->disk_blocks= (int) blocks;
 
  455     keycache->hash_links= hash_links;
 
  456     keycache->hash_root= (
HASH_LINK**) ((
char*) keycache->block_root +
 
  458     keycache->hash_link_root= (
HASH_LINK*) ((
char*) keycache->hash_root +
 
  460                                                         keycache->hash_entries)));
 
  461     memset(keycache->block_root, 0,
 
  463     memset(keycache->hash_root, 0,
 
  464           keycache->hash_entries * 
sizeof(
HASH_LINK*));
 
  465     memset(keycache->hash_link_root, 0,
 
  466           keycache->hash_links * 
sizeof(
HASH_LINK));
 
  467     keycache->hash_links_used= 0;
 
  468     keycache->free_hash_list= NULL;
 
  469     keycache->blocks_used= keycache->blocks_changed= 0;
 
  471     keycache->global_blocks_changed= 0;
 
  472     keycache->blocks_available=0;               
 
  475     keycache->used_last= NULL;
 
  476     keycache->used_ins= NULL;
 
  477     keycache->free_block_list= NULL;
 
  478     keycache->keycache_time= 0;
 
  479     keycache->warm_blocks= 0;
 
  480     keycache->min_warm_blocks= (division_limit ?
 
  481                                 blocks * division_limit / 100 + 1 :
 
  483     keycache->age_threshold= (age_threshold ?
 
  484                               blocks * age_threshold / 100 :
 
  487     keycache->can_be_used= 1;
 
  489     keycache->waiting_for_hash_link.last_thread= NULL;
 
  490     keycache->waiting_for_block.last_thread= NULL;
 
  492                (
"disk_blocks: %d  block_root: 0x%lx  hash_entries: %d\ 
  493  hash_root: 0x%lx  hash_links: %d  hash_link_root: 0x%lx",
 
  494                 keycache->disk_blocks,  (
long) keycache->block_root,
 
  495                 keycache->hash_entries, (
long) keycache->hash_root,
 
  496                 keycache->hash_links,   (
long) keycache->hash_link_root));
 
  497     memset(keycache->changed_blocks, 0,
 
  498           sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
 
  499     memset(keycache->file_blocks, 0,
 
  500           sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
 
  505     keycache->can_be_used= 0;
 
  508   keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
 
  509   DBUG_RETURN((
int) keycache->disk_blocks);
 
  513   keycache->disk_blocks= 0;
 
  515   if (keycache->block_mem)
 
  517     my_large_free((uchar*) keycache->block_mem);
 
  518     keycache->block_mem= NULL;
 
  520   if (keycache->block_root)
 
  522     my_free(keycache->block_root);
 
  523     keycache->block_root= NULL;
 
  526   keycache->can_be_used= 0;
 
  560 int resize_key_cache(
KEY_CACHE *keycache, uint key_cache_block_size,
 
  561                      size_t use_mem, uint division_limit,
 
  565   DBUG_ENTER(
"resize_key_cache");
 
  567   if (!keycache->key_cache_inited)
 
  568     DBUG_RETURN(keycache->disk_blocks);
 
  570   if(key_cache_block_size == keycache->key_cache_block_size &&
 
  571      use_mem == keycache->key_cache_mem_size)
 
  573     change_key_cache_param(keycache, division_limit, age_threshold);
 
  574     DBUG_RETURN(keycache->disk_blocks);
 
  577   keycache_pthread_mutex_lock(&keycache->cache_lock);
 
  585   while (keycache->in_resize)
 
  588     wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
 
  597   keycache->in_resize= 1;
 
  600   if (keycache->can_be_used)
 
  603     keycache->resize_in_flush= 1;
 
  605     if (flush_all_key_blocks(keycache))
 
  608       keycache->resize_in_flush= 0;
 
  610       keycache->can_be_used= 0;
 
  613     DBUG_ASSERT(cache_empty(keycache));
 
  616     keycache->resize_in_flush= 0;
 
  630   while (keycache->cnt_for_resize_op)
 
  631     wait_on_queue(&keycache->waiting_for_resize_cnt, &keycache->cache_lock);
 
  639   end_key_cache(keycache, 0);                   
 
  641   blocks= init_key_cache(keycache, key_cache_block_size, use_mem,
 
  642                          division_limit, age_threshold);
 
  649   keycache->in_resize= 0;
 
  652   release_whole_queue(&keycache->resize_queue);
 
  654   keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
  662 static inline void inc_counter_for_resize_op(
KEY_CACHE *keycache)
 
  664   keycache->cnt_for_resize_op++;
 
  672 static inline void dec_counter_for_resize_op(
KEY_CACHE *keycache)
 
  674   if (!--keycache->cnt_for_resize_op)
 
  675     release_whole_queue(&keycache->waiting_for_resize_cnt);
 
  696 void change_key_cache_param(
KEY_CACHE *keycache, uint division_limit,
 
  699   DBUG_ENTER(
"change_key_cache_param");
 
  701   keycache_pthread_mutex_lock(&keycache->cache_lock);
 
  703     keycache->min_warm_blocks= (keycache->disk_blocks *
 
  704                                 division_limit / 100 + 1);
 
  706     keycache->age_threshold=   (keycache->disk_blocks *
 
  707                                 age_threshold / 100);
 
  708   keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
  725 void end_key_cache(
KEY_CACHE *keycache, my_bool cleanup)
 
  727   DBUG_ENTER(
"end_key_cache");
 
  728   DBUG_PRINT(
"enter", (
"key_cache: 0x%lx", (
long) keycache));
 
  730   if (!keycache->key_cache_inited)
 
  733   if (keycache->disk_blocks > 0)
 
  735     if (keycache->block_mem)
 
  737       my_large_free((uchar*) keycache->block_mem);
 
  738       keycache->block_mem= NULL;
 
  739       my_free(keycache->block_root);
 
  740       keycache->block_root= NULL;
 
  742     keycache->disk_blocks= -1;
 
  744     keycache->blocks_changed= 0;
 
  747   DBUG_PRINT(
"status", (
"used: %lu  changed: %lu  w_requests: %lu  " 
  748                         "writes: %lu  r_requests: %lu  reads: %lu",
 
  749                         keycache->blocks_used, keycache->global_blocks_changed,
 
  750                         (ulong) keycache->global_cache_w_requests,
 
  751                         (ulong) keycache->global_cache_write,
 
  752                         (ulong) keycache->global_cache_r_requests,
 
  753                         (ulong) keycache->global_cache_read));
 
  759   keycache->blocks_used= 0;
 
  760   keycache->blocks_unused= 0;
 
  765     keycache->key_cache_inited= keycache->can_be_used= 0;
 
  766     KEYCACHE_DEBUG_CLOSE;
 
  794   DBUG_ASSERT(!thread->next && !thread->prev);
 
  795   if (! (last= wqueue->last_thread))
 
  798     thread->next= thread;
 
  799     thread->prev= &thread->next;
 
  803     thread->prev= last->next->prev;
 
  804     last->next->prev= &thread->next;
 
  805     thread->next= last->next;
 
  808   wqueue->last_thread= thread;
 
  829   KEYCACHE_DBUG_PRINT(
"unlink_from_queue", (
"thread %ld", thread->id));
 
  830   DBUG_ASSERT(thread->next && thread->prev);
 
  831   if (thread->next == thread)
 
  833     wqueue->last_thread= NULL;
 
  836     thread->next->prev= thread->prev;
 
  837     *thread->prev=thread->next;
 
  838     if (wqueue->last_thread == thread)
 
  843 #if !defined(DBUG_OFF) 
  883   DBUG_ASSERT(!thread->next);
 
  884   DBUG_ASSERT(!thread->prev); 
 
  885   if (! (last= wqueue->last_thread))
 
  886     thread->next= thread;
 
  889     thread->next= last->next;
 
  892   wqueue->last_thread= thread;
 
  900     KEYCACHE_DBUG_PRINT(
"wait", (
"suspend thread %ld", thread->id));
 
  901     keycache_pthread_cond_wait(&thread->suspend, mutex);
 
  903   while (thread->next);
 
  930   if (!(last= wqueue->last_thread))
 
  937     KEYCACHE_DBUG_PRINT(
"release_whole_queue: signal",
 
  938                         (
"thread %ld", thread->id));
 
  940     keycache_pthread_cond_signal(&thread->suspend);
 
  945   while (thread != last);
 
  948   wqueue->last_thread= NULL;
 
  958   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
  959   if (block->next_changed)
 
  960     block->next_changed->prev_changed= block->prev_changed;
 
  961   *block->prev_changed= block->next_changed;
 
  963 #if !defined(DBUG_OFF) 
  968   block->next_changed= NULL;
 
  969   block->prev_changed= NULL;
 
  980   DBUG_ASSERT(!block->next_changed);
 
  981   DBUG_ASSERT(!block->prev_changed);
 
  982   block->prev_changed= phead;
 
  983   if ((block->next_changed= *phead))
 
  984     (*phead)->prev_changed= &block->next_changed;
 
 1014 static void link_to_file_list(
KEY_CACHE *keycache,
 
 1016                               my_bool unlink_block)
 
 1018   DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 1019   DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
 1020   DBUG_ASSERT(block->hash_link->file == file);
 
 1022     unlink_changed(block);
 
 1023   link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
 
 1024   if (block->status & BLOCK_CHANGED)
 
 1026     block->status&= ~BLOCK_CHANGED;
 
 1027     keycache->blocks_changed--;
 
 1028     keycache->global_blocks_changed--;
 
 1055 static void link_to_changed_list(
KEY_CACHE *keycache,
 
 1058   DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 1059   DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
 1060   DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
 1062   unlink_changed(block);
 
 1064                &keycache->changed_blocks[FILE_HASH(block->hash_link->file)]);
 
 1065   block->status|=BLOCK_CHANGED;
 
 1066   keycache->blocks_changed++;
 
 1067   keycache->global_blocks_changed++;
 
 1116   DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
 1117   DBUG_ASSERT(block->hash_link); 
 
 1118   DBUG_ASSERT(!block->requests);
 
 1119   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 1120   DBUG_ASSERT(!block->next_used);
 
 1121   DBUG_ASSERT(!block->prev_used);
 
 1123   if (!hot && keycache->waiting_for_block.last_thread)
 
 1127                                keycache->waiting_for_block.last_thread;
 
 1134       thread= next_thread;
 
 1135       next_thread= thread->next;
 
 1140       if ((
HASH_LINK *) thread->opt_info == hash_link)
 
 1142         KEYCACHE_DBUG_PRINT(
"link_block: signal", (
"thread %ld", thread->id));
 
 1143         keycache_pthread_cond_signal(&thread->suspend);
 
 1144         unlink_from_queue(&keycache->waiting_for_block, thread);
 
 1148     while (thread != last_thread);
 
 1149     hash_link->block= 
block;
 
 1172     block->status|= BLOCK_IN_EVICTION;
 
 1173     KEYCACHE_THREAD_TRACE(
"link_block: after signaling");
 
 1174 #if defined(KEYCACHE_DEBUG) 
 1175     KEYCACHE_DBUG_PRINT(
"link_block",
 
 1176         (
"linked,unlinked block %u  status=%x  #requests=%u  #available=%u",
 
 1177          BLOCK_NUMBER(block), block->status,
 
 1178          block->requests, keycache->blocks_available));
 
 1183   pins= hot ? &keycache->used_ins : &keycache->used_last;
 
 1187     ins->next_used->prev_used= &block->next_used;
 
 1188     block->next_used= ins->next_used;
 
 1189     block->prev_used= &ins->next_used;
 
 1190     ins->next_used= 
block;
 
 1197     keycache->used_last= keycache->used_ins= block->next_used= 
block;
 
 1198     block->prev_used= &block->next_used;
 
 1200   KEYCACHE_THREAD_TRACE(
"link_block");
 
 1201 #if defined(KEYCACHE_DEBUG) 
 1202   keycache->blocks_available++;
 
 1203   KEYCACHE_DBUG_PRINT(
"link_block",
 
 1204       (
"linked block %u:%1u  status=%x  #requests=%u  #available=%u",
 
 1205        BLOCK_NUMBER(block), at_end, block->status,
 
 1206        block->requests, keycache->blocks_available));
 
 1207   KEYCACHE_DBUG_ASSERT((ulong) keycache->blocks_available <=
 
 1208                        keycache->blocks_used);
 
 1230   DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
 1231   DBUG_ASSERT(block->hash_link); 
 
 1232   DBUG_ASSERT(!block->requests);
 
 1233   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 1234   DBUG_ASSERT(block->next_used && block->prev_used &&
 
 1235               (block->next_used->prev_used == &block->next_used) &&
 
 1236               (*block->prev_used == block));
 
 1237   if (block->next_used == block)
 
 1239     keycache->used_last= keycache->used_ins= NULL;
 
 1242     block->next_used->prev_used= block->prev_used;
 
 1243     *block->prev_used= block->next_used;
 
 1244     if (keycache->used_last == block)
 
 1245       keycache->used_last= STRUCT_PTR(
BLOCK_LINK, next_used, block->prev_used);
 
 1246     if (keycache->used_ins == block)
 
 1247       keycache->used_ins=STRUCT_PTR(
BLOCK_LINK, next_used, block->prev_used);
 
 1249   block->next_used= NULL;
 
 1250 #if !defined(DBUG_OFF) 
 1255   block->prev_used= NULL;
 
 1258   KEYCACHE_THREAD_TRACE(
"unlink_block");
 
 1259 #if defined(KEYCACHE_DEBUG) 
 1260   KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
 
 1261   keycache->blocks_available--;
 
 1262   KEYCACHE_DBUG_PRINT(
"unlink_block",
 
 1263     (
"unlinked block %u  status=%x   #requests=%u  #available=%u",
 
 1264      BLOCK_NUMBER(block), block->status,
 
 1265      block->requests, keycache->blocks_available));
 
 1288   DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 1289   DBUG_ASSERT(block->hash_link);
 
 1291   if (!block->requests)
 
 1292     unlink_block(keycache, block);
 
 1293   block->requests+=count;
 
 1329 static void unreg_request(
KEY_CACHE *keycache,
 
 1332   DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 1333   DBUG_ASSERT(block->hash_link); 
 
 1334   DBUG_ASSERT(block->requests);
 
 1335   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 1336   DBUG_ASSERT(!block->next_used);
 
 1337   DBUG_ASSERT(!block->prev_used);
 
 1342   if (!--block->requests && !(block->status & BLOCK_ERROR))
 
 1345     if (block->hits_left)
 
 1347     hot= !block->hits_left && at_end &&
 
 1348       keycache->warm_blocks > keycache->min_warm_blocks;
 
 1351       if (block->temperature == BLOCK_WARM)
 
 1352         keycache->warm_blocks--;
 
 1353       block->temperature= BLOCK_HOT;
 
 1354       KEYCACHE_DBUG_PRINT(
"unreg_request", (
"#warm_blocks: %lu",
 
 1355                            keycache->warm_blocks));
 
 1357     link_block(keycache, block, hot, (my_bool)at_end);
 
 1358     block->last_hit_time= keycache->keycache_time;
 
 1359     keycache->keycache_time++;
 
 1375     block= keycache->used_ins;
 
 1376     if (block && keycache->keycache_time - block->last_hit_time >
 
 1377         keycache->age_threshold)
 
 1379       unlink_block(keycache, block);
 
 1380       link_block(keycache, block, 0, 0);
 
 1381       if (block->temperature != BLOCK_WARM)
 
 1383         keycache->warm_blocks++;
 
 1384         block->temperature= BLOCK_WARM;
 
 1386       KEYCACHE_DBUG_PRINT(
"unreg_request", (
"#warm_blocks: %lu",
 
 1387                            keycache->warm_blocks));
 
 1398   DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 1399   DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
 1400   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 1401   DBUG_ASSERT(!block->next_used);
 
 1402   DBUG_ASSERT(!block->prev_used);
 
 1403   DBUG_ASSERT(block->hash_link->requests);
 
 1405   if (! --block->hash_link->requests && block->condvar)
 
 1406     keycache_pthread_cond_signal(block->condvar);
 
 1415 static void wait_for_readers(
KEY_CACHE *keycache,
 
 1419   DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 1420   DBUG_ASSERT(!(block->status & (BLOCK_IN_FLUSH | BLOCK_CHANGED)));
 
 1421   DBUG_ASSERT(block->hash_link);
 
 1422   DBUG_ASSERT(block->hash_link->block == block);
 
 1424   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 1426   DBUG_ASSERT(!block->next_used);
 
 1427   DBUG_ASSERT(!block->prev_used);
 
 1428   while (block->hash_link->requests)
 
 1430     KEYCACHE_DBUG_PRINT(
"wait_for_readers: wait",
 
 1431                         (
"suspend thread %ld  block %u",
 
 1432                          thread->id, BLOCK_NUMBER(block)));
 
 1434     DBUG_ASSERT(!block->condvar);
 
 1435     block->condvar= &thread->suspend;
 
 1436     keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
 
 1437     block->condvar= NULL;
 
 1449     (*start)->prev= &hash_link->next;
 
 1450   hash_link->next= *start;
 
 1451   hash_link->prev= start;
 
 1462   KEYCACHE_DBUG_PRINT(
"unlink_hash", (
"fd: %u  pos_ %lu  #requests=%u",
 
 1463       (uint) hash_link->file,(ulong) hash_link->diskpos, hash_link->requests));
 
 1464   KEYCACHE_DBUG_ASSERT(hash_link->requests == 0);
 
 1465   if ((*hash_link->prev= hash_link->next))
 
 1466     hash_link->next->prev= hash_link->prev;
 
 1467   hash_link->block= NULL;
 
 1469   if (keycache->waiting_for_hash_link.last_thread)
 
 1473                                keycache->waiting_for_hash_link.last_thread;
 
 1479     hash_link->file= first_page->file;
 
 1480     hash_link->diskpos= first_page->filepos;
 
 1484       thread= next_thread;
 
 1486       next_thread= thread->next;
 
 1491       if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
 
 1493         KEYCACHE_DBUG_PRINT(
"unlink_hash: signal", (
"thread %ld", thread->id));
 
 1494         keycache_pthread_cond_signal(&thread->suspend);
 
 1495         unlink_from_queue(&keycache->waiting_for_hash_link, thread);
 
 1498     while (thread != last_thread);
 
 1499     link_hash(&keycache->hash_root[KEYCACHE_HASH(hash_link->file,
 
 1500                                                  hash_link->diskpos)],
 
 1504   hash_link->next= keycache->free_hash_list;
 
 1505   keycache->free_hash_list= hash_link;
 
 1514                                 int file, my_off_t filepos)
 
 1517 #if defined(KEYCACHE_DEBUG) 
 1521   KEYCACHE_DBUG_PRINT(
"get_hash_link", (
"fd: %u  pos: %lu",
 
 1522                       (uint) file,(ulong) filepos));
 
 1530   hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
 
 1531 #if defined(KEYCACHE_DEBUG) 
 1536          (hash_link->diskpos != filepos || hash_link->file != file))
 
 1538     hash_link= hash_link->next;
 
 1539 #if defined(KEYCACHE_DEBUG) 
 1541     if (! (cnt <= keycache->hash_links_used))
 
 1544       for (i=0, hash_link= *start ;
 
 1545            i < cnt ; i++, hash_link= hash_link->next)
 
 1547         KEYCACHE_DBUG_PRINT(
"get_hash_link", (
"fd: %u  pos: %lu",
 
 1548             (uint) hash_link->file,(ulong) hash_link->diskpos));
 
 1551     KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
 
 1557     if (keycache->free_hash_list)
 
 1559       hash_link= keycache->free_hash_list;
 
 1560       keycache->free_hash_list= hash_link->next;
 
 1562     else if (keycache->hash_links_used < keycache->hash_links)
 
 1564       hash_link= &keycache->hash_link_root[keycache->hash_links_used++];
 
 1571       KEYCACHE_DBUG_PRINT(
"get_hash_link", (
"waiting"));
 
 1573       page.filepos= filepos;
 
 1574       thread->opt_info= (
void *) &page;
 
 1575       link_into_queue(&keycache->waiting_for_hash_link, thread);
 
 1576       KEYCACHE_DBUG_PRINT(
"get_hash_link: wait",
 
 1577                         (
"suspend thread %ld", thread->id));
 
 1578       keycache_pthread_cond_wait(&thread->suspend,
 
 1579                                  &keycache->cache_lock);
 
 1580       thread->opt_info= NULL;
 
 1583     hash_link->file= 
file;
 
 1584     hash_link->diskpos= filepos;
 
 1585     link_hash(start, hash_link);
 
 1588   hash_link->requests++;
 
 1631                                   File file, my_off_t filepos,
 
 1633                                   int wrmode, 
int *page_st)
 
 1640   DBUG_ENTER(
"find_key_block");
 
 1641   KEYCACHE_THREAD_TRACE(
"find_key_block:begin");
 
 1642   DBUG_PRINT(
"enter", (
"fd: %d  pos: %lu  wrmode: %d",
 
 1643                        file, (ulong) filepos, wrmode));
 
 1644   KEYCACHE_DBUG_PRINT(
"find_key_block", (
"fd: %d  pos: %lu  wrmode: %d",
 
 1645                                          file, (ulong) filepos,
 
 1647 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) 
 1648   DBUG_EXECUTE(
"check_keycache2",
 
 1649                test_key_cache(keycache, 
"start of find_key_block", 0););
 
 1657   if (!keycache->can_be_used)
 
 1683   hash_link= get_hash_link(keycache, file, filepos);
 
 1684   DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
 
 1687   if ((block= hash_link->block) &&
 
 1688       block->hash_link == hash_link && (block->status & BLOCK_READ))
 
 1691     page_status= PAGE_READ;
 
 1700   if (keycache->in_resize)
 
 1715       if (hash_link->requests == 1)
 
 1721         hash_link->requests--;
 
 1722         unlink_hash(keycache, hash_link);
 
 1737       thread= my_thread_var;
 
 1738       thread->opt_info= (
void *) hash_link;
 
 1739       link_into_queue(&keycache->waiting_for_block, thread);
 
 1742         KEYCACHE_DBUG_PRINT(
"find_key_block: wait",
 
 1743                             (
"suspend thread %ld", thread->id));
 
 1744         keycache_pthread_cond_wait(&thread->suspend,
 
 1745                                    &keycache->cache_lock);
 
 1746       } 
while (thread->next);
 
 1747       thread->opt_info= NULL;
 
 1753       hash_link->requests--;
 
 1767     reg_requests(keycache, block, 1);
 
 1769     if (page_status != PAGE_READ)
 
 1790       DBUG_ASSERT(((block->hash_link != hash_link) &&
 
 1791                    (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
 
 1792                   ((block->hash_link == hash_link) &&
 
 1793                    !(block->status & BLOCK_READ)));
 
 1794       wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
 
 1805       DBUG_ASSERT(block->hash_link == hash_link);
 
 1806       DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 1807       DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
 
 1818       *page_st= PAGE_READ;
 
 1819       DBUG_ASSERT((hash_link->file == file) &&
 
 1820                   (hash_link->diskpos == filepos) &&
 
 1821                   (block->hash_link == hash_link));
 
 1829     DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
 1831     while (block->status & BLOCK_IN_FLUSH)
 
 1842       wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
 1847       if (!keycache->in_resize)
 
 1849         remove_reader(block);
 
 1850         unreg_request(keycache, block, 1);
 
 1853       DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 1854       DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
 1855       DBUG_ASSERT(block->hash_link == hash_link);
 
 1858     if (block->status & BLOCK_CHANGED)
 
 1867       *page_st= PAGE_READ;
 
 1868       DBUG_ASSERT((hash_link->file == file) &&
 
 1869                   (hash_link->diskpos == filepos) &&
 
 1870                   (block->hash_link == hash_link));
 
 1885     remove_reader(block);
 
 1888     if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 1901       free_block(keycache, block);
 
 1909       unreg_request(keycache, block, 1);
 
 1927         wait_on_queue(&block->wqueue[COND_FOR_SAVED],
 
 1928                       &keycache->cache_lock);
 
 1933         if (!keycache->in_resize)
 
 1935       } 
while (block->hash_link &&
 
 1936                (block->hash_link->file == file) &&
 
 1937                (block->hash_link->diskpos == filepos));
 
 1942   if (page_status == PAGE_READ &&
 
 1943       (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 1956     KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 1957                         (
"request for old page in block %u " 
 1958                          "wrmode: %d  block->status: %d",
 
 1959                          BLOCK_NUMBER(block), wrmode, block->status));
 
 1964     if (!wrmode && !(block->status & BLOCK_REASSIGNED))
 
 1971       reg_requests(keycache, block, 1);
 
 1988       DBUG_ASSERT(hash_link->requests);
 
 1989       hash_link->requests--;
 
 1990       KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 1991                           (
"request waiting for old page to be saved"));
 
 1992       wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
 1993       KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 1994                           (
"request for old page resubmitted"));
 
 2017       if (keycache->blocks_unused)
 
 2019         if (keycache->free_block_list)
 
 2022           block= keycache->free_block_list;
 
 2023           keycache->free_block_list= block->next_used;
 
 2024           block->next_used= NULL;
 
 2028           size_t block_mem_offset;
 
 2030           DBUG_ASSERT(keycache->blocks_used <
 
 2031                       (ulong) keycache->disk_blocks);
 
 2032           block= &keycache->block_root[keycache->blocks_used];
 
 2034            ((size_t) keycache->blocks_used) * keycache->key_cache_block_size;
 
 2035           block->buffer= ADD_TO_PTR(keycache->block_mem,
 
 2038           keycache->blocks_used++;
 
 2039           DBUG_ASSERT(!block->next_used);
 
 2041         DBUG_ASSERT(!block->prev_used);
 
 2042         DBUG_ASSERT(!block->next_changed);
 
 2043         DBUG_ASSERT(!block->prev_changed);
 
 2044         DBUG_ASSERT(!block->hash_link);
 
 2045         DBUG_ASSERT(!block->status);
 
 2046         DBUG_ASSERT(!block->requests);
 
 2047         keycache->blocks_unused--;
 
 2048         block->status= BLOCK_IN_USE;
 
 2050         block->offset= keycache->key_cache_block_size;
 
 2052         block->temperature= BLOCK_COLD;
 
 2053         block->hits_left= init_hits_left;
 
 2054         block->last_hit_time= 0;
 
 2055         block->hash_link= hash_link;
 
 2056         hash_link->block= 
block;
 
 2057         link_to_file_list(keycache, block, file, 0);
 
 2058         page_status= PAGE_TO_BE_READ;
 
 2059         KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 2060                             (
"got free or never used block %u",
 
 2061                              BLOCK_NUMBER(block)));
 
 2070         if (! keycache->used_last)
 
 2085           thread->opt_info= (
void *) hash_link;
 
 2086           link_into_queue(&keycache->waiting_for_block, thread);
 
 2089             KEYCACHE_DBUG_PRINT(
"find_key_block: wait",
 
 2090                                 (
"suspend thread %ld", thread->id));
 
 2091             keycache_pthread_cond_wait(&thread->suspend,
 
 2092                                        &keycache->cache_lock);
 
 2094           while (thread->next);
 
 2095           thread->opt_info= NULL;
 
 2097           DBUG_ASSERT(hash_link->block->requests);
 
 2099           DBUG_ASSERT(!hash_link->block->next_used);
 
 2100           DBUG_ASSERT(!hash_link->block->prev_used);
 
 2108         block= hash_link->block;
 
 2112           block= keycache->used_last->next_used;
 
 2113           block->hits_left= init_hits_left;
 
 2114           block->last_hit_time= 0;
 
 2115           hash_link->block= 
block;
 
 2120           DBUG_ASSERT(!block->requests);
 
 2121           reg_requests(keycache, block,1);
 
 2138         if (block->hash_link != hash_link &&
 
 2139             ! (block->status & BLOCK_IN_SWITCH) )
 
 2142           block->status|= BLOCK_IN_SWITCH;
 
 2144           KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 2145                         (
"got block %u for new page", BLOCK_NUMBER(block)));
 
 2147           if (block->status & BLOCK_CHANGED)
 
 2151             KEYCACHE_DBUG_PRINT(
"find_key_block", (
"block is dirty"));
 
 2152             if (block->status & BLOCK_IN_FLUSH)
 
 2161               wait_on_queue(&block->wqueue[COND_FOR_SAVED],
 
 2162                             &keycache->cache_lock);
 
 2167               DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2168               DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
 
 2170                                              BLOCK_FOR_UPDATE)));
 
 2174               block->status|= BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE;
 
 2179               DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
 
 2180                           (BLOCK_READ | BLOCK_IN_SWITCH |
 
 2181                            BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
 
 2182                            BLOCK_CHANGED | BLOCK_IN_USE));
 
 2183               DBUG_ASSERT(block->hash_link);
 
 2185               keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2190               error= my_pwrite(block->hash_link->file,
 
 2191                                block->buffer + block->offset,
 
 2192                                block->length - block->offset,
 
 2193                                block->hash_link->diskpos + block->offset,
 
 2194                                MYF(MY_NABP | MY_WAIT_IF_FULL));
 
 2195               keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2198               DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
 
 2199                           (BLOCK_READ | BLOCK_IN_SWITCH |
 
 2200                            BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
 
 2201                            BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
 
 2202               keycache->global_cache_write++;
 
 2206           block->status|= BLOCK_REASSIGNED;
 
 2211           DBUG_ASSERT(block->hash_link);
 
 2212           if (block->hash_link)
 
 2227             block->status&= ~(BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE);
 
 2228             link_to_file_list(keycache, block, block->hash_link->file, 1);
 
 2229             release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
 
 2237             wait_for_readers(keycache, block);
 
 2238             DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
 
 2239                         block->prev_changed);
 
 2241             DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
 2244             release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
 
 2247             unlink_hash(keycache, block->hash_link);
 
 2256             unlink_changed(block);
 
 2258           block->status= error ? BLOCK_ERROR : BLOCK_IN_USE ;
 
 2260           block->offset= keycache->key_cache_block_size;
 
 2261           block->hash_link= hash_link;
 
 2262           link_to_file_list(keycache, block, file, 0);
 
 2263           page_status= PAGE_TO_BE_READ;
 
 2265           KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
 
 2266           KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
 
 2284           KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 2285                               (
"block->hash_link: %p  hash_link: %p  " 
 2286                                "block->status: %u", block->hash_link,
 
 2287                                hash_link, block->status ));
 
 2288           page_status= (((block->hash_link == hash_link) &&
 
 2289                          (block->status & BLOCK_READ)) ?
 
 2290                         PAGE_READ : PAGE_WAIT_TO_BE_READ);
 
 2316       DBUG_ASSERT(((block->hash_link != hash_link) &&
 
 2317                    (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
 
 2318                   ((block->hash_link == hash_link) &&
 
 2319                    !(block->status & BLOCK_READ)) ||
 
 2320                   ((block->status & BLOCK_READ) &&
 
 2321                    !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
 
 2322       reg_requests(keycache, block, 1);
 
 2323       KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 2324                           (
"block->hash_link: %p  hash_link: %p  " 
 2325                            "block->status: %u", block->hash_link,
 
 2326                            hash_link, block->status ));
 
 2327       page_status= (((block->hash_link == hash_link) &&
 
 2328                      (block->status & BLOCK_READ)) ?
 
 2329                     PAGE_READ : PAGE_WAIT_TO_BE_READ);
 
 2333   KEYCACHE_DBUG_ASSERT(page_status != -1);
 
 2335   KEYCACHE_DBUG_ASSERT(block);
 
 2337   DBUG_ASSERT(block->requests);
 
 2338   DBUG_ASSERT(!block->next_used);
 
 2339   DBUG_ASSERT(!block->prev_used);
 
 2341   DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
 
 2342               ((block->hash_link->file == file) &&
 
 2343                (block->hash_link->diskpos == filepos)));
 
 2344   *page_st=page_status;
 
 2345   KEYCACHE_DBUG_PRINT(
"find_key_block",
 
 2346                       (
"fd: %d  pos: %lu  block->status: %u  page_status: %d",
 
 2347                        file, (ulong) filepos, block->status,
 
 2350 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) 
 2351   DBUG_EXECUTE(
"check_keycache2",
 
 2352                test_key_cache(keycache, 
"end of find_key_block",0););
 
 2354   KEYCACHE_THREAD_TRACE(
"find_key_block:end");
 
 2383 static void read_block(
KEY_CACHE *keycache,
 
 2385                        uint min_length, my_bool primary)
 
 2391   KEYCACHE_THREAD_TRACE(
"read_block");
 
 2400     DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
 
 2402     DBUG_ASSERT((block->length == 0) || fail_block(block));
 
 2403     DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
 2405     DBUG_ASSERT((block->requests > 0) || fail_block(block));
 
 2407     KEYCACHE_DBUG_PRINT(
"read_block",
 
 2408                         (
"page to be read by primary request"));
 
 2410     keycache->global_cache_read++;
 
 2412     keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2417     got_length= my_pread(block->hash_link->file, block->buffer,
 
 2418                          read_length, block->hash_link->diskpos, MYF(0));
 
 2419     keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2424     DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
 
 2425                                     BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
 
 2427     DBUG_ASSERT((block->length == 0) || fail_block(block));
 
 2428     DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
 2430     DBUG_ASSERT((block->requests > 0) || fail_block(block));
 
 2432     if (got_length < min_length)
 
 2433       block->status|= BLOCK_ERROR;
 
 2436       block->status|= BLOCK_READ;
 
 2437       block->length= got_length;
 
 2445     KEYCACHE_DBUG_PRINT(
"read_block",
 
 2446                         (
"primary request: new page in cache"));
 
 2448     release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
 
 2461     KEYCACHE_DBUG_PRINT(
"read_block",
 
 2462                       (
"secondary request waiting for new page to be read"));
 
 2463     wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
 
 2464     KEYCACHE_DBUG_PRINT(
"read_block",
 
 2465                         (
"secondary request: new page in cache"));
 
 2498 uchar *key_cache_read(
KEY_CACHE *keycache,
 
 2499                       File file, my_off_t filepos, 
int level,
 
 2500                       uchar *buff, uint length,
 
 2501                       uint block_length __attribute__((unused)),
 
 2502                       int return_buffer __attribute__((unused)))
 
 2504   my_bool locked_and_incremented= FALSE;
 
 2507   DBUG_ENTER(
"key_cache_read");
 
 2508   DBUG_PRINT(
"enter", (
"fd: %u  pos: %lu  length: %u",
 
 2509                (uint) file, (ulong) filepos, length));
 
 2511   if (keycache->key_cache_inited)
 
 2519     if (MYSQL_KEYCACHE_READ_START_ENABLED())
 
 2521       MYSQL_KEYCACHE_READ_START(my_filename(file), length,
 
 2522                                 (ulong) (keycache->blocks_used *
 
 2523                                          keycache->key_cache_block_size),
 
 2524                                 (ulong) (keycache->blocks_unused *
 
 2525                                          keycache->key_cache_block_size));
 
 2534     keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2549     while (keycache->in_resize && !keycache->resize_in_flush)
 
 2550       wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
 
 2552     inc_counter_for_resize_op(keycache);
 
 2553     locked_and_incremented= TRUE;
 
 2555     offset= (uint) (filepos % keycache->key_cache_block_size);
 
 2560       if (!keycache->can_be_used)
 
 2562         KEYCACHE_DBUG_PRINT(
"key_cache_read", (
"keycache cannot be used"));
 
 2568       read_length= length;
 
 2569       set_if_smaller(read_length, keycache->key_cache_block_size-offset);
 
 2570       KEYCACHE_DBUG_ASSERT(read_length > 0);
 
 2572       if (block_length > keycache->key_cache_block_size || offset)
 
 2576       keycache->global_cache_r_requests++;
 
 2578       MYSQL_KEYCACHE_READ_BLOCK(keycache->key_cache_block_size);
 
 2580       block=find_key_block(keycache, file, filepos, level, 0, &page_st);
 
 2588         keycache->global_cache_read++;
 
 2589         keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2590         error= (my_pread(file, (uchar*) buff, read_length,
 
 2591                          filepos + offset, MYF(MY_NABP)) != 0);
 
 2592         keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2595       if (!(block->status & BLOCK_ERROR))
 
 2597         if (page_st != PAGE_READ)
 
 2599           MYSQL_KEYCACHE_READ_MISS();
 
 2601           read_block(keycache, block,
 
 2602                      keycache->key_cache_block_size, read_length+offset,
 
 2603                      (my_bool)(page_st == PAGE_TO_BE_READ));
 
 2609           DBUG_ASSERT(keycache->can_be_used);
 
 2610           DBUG_ASSERT(block->hash_link->file == file);
 
 2611           DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
 2612           DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2614         else if (block->length < read_length + offset)
 
 2622           block->status|= BLOCK_ERROR;
 
 2626           MYSQL_KEYCACHE_READ_HIT();
 
 2631       if (!(block->status & BLOCK_ERROR))
 
 2634           DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2635 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 2636           keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2640           memcpy(buff, block->buffer+offset, (
size_t) read_length);
 
 2642 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 2643           keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2644           DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2649       remove_reader(block);
 
 2652       DBUG_EXECUTE_IF(
"key_cache_read_block_error",
 
 2653                       block->status|= BLOCK_ERROR;);
 
 2656       if (!(block->status & BLOCK_ERROR))
 
 2662         unreg_request(keycache, block, 1);
 
 2666         free_block(keycache, block);
 
 2673       filepos+= read_length+
offset;
 
 2676     } 
while ((length-= read_length));
 
 2677     if (MYSQL_KEYCACHE_READ_DONE_ENABLED())
 
 2679       MYSQL_KEYCACHE_READ_DONE((ulong) (keycache->blocks_used *
 
 2680                                         keycache->key_cache_block_size),
 
 2681                                (ulong) (keycache->blocks_unused *
 
 2682                                         keycache->key_cache_block_size));
 
 2686   KEYCACHE_DBUG_PRINT(
"key_cache_read", (
"keycache not initialized"));
 
 2691   keycache->global_cache_r_requests++;
 
 2692   keycache->global_cache_read++;
 
 2694   if (locked_and_incremented)
 
 2695     keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2696   if (my_pread(file, (uchar*) buff, length, filepos, MYF(MY_NABP)))
 
 2698   if (locked_and_incremented)
 
 2699     keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2702   if (locked_and_incremented)
 
 2704     dec_counter_for_resize_op(keycache);
 
 2705     keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2707   DBUG_PRINT(
"exit", (
"error: %d", error ));
 
 2708   DBUG_RETURN(error ? (uchar*) 0 : start);
 
 2732 int key_cache_insert(
KEY_CACHE *keycache,
 
 2733                      File file, my_off_t filepos, 
int level,
 
 2734                      uchar *buff, uint length)
 
 2737   DBUG_ENTER(
"key_cache_insert");
 
 2738   DBUG_PRINT(
"enter", (
"fd: %u  pos: %lu  length: %u",
 
 2739                (uint) file,(ulong) filepos, length));
 
 2741   if (keycache->key_cache_inited)
 
 2748     my_bool locked_and_incremented= FALSE;
 
 2756     keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2761     if (!keycache->can_be_used || keycache->in_resize)
 
 2764     inc_counter_for_resize_op(keycache);
 
 2765     locked_and_incremented= TRUE;
 
 2767     offset= (uint) (filepos % keycache->key_cache_block_size);
 
 2772       if (!keycache->can_be_used || keycache->in_resize)
 
 2777       read_length= length;
 
 2778       set_if_smaller(read_length, keycache->key_cache_block_size-offset);
 
 2779       KEYCACHE_DBUG_ASSERT(read_length > 0);
 
 2782       keycache->global_cache_read++;
 
 2784       keycache->global_cache_r_requests++;
 
 2785       block= find_key_block(keycache, file, filepos, level, 0, &page_st);
 
 2795       if (!(block->status & BLOCK_ERROR))
 
 2797         if ((page_st == PAGE_WAIT_TO_BE_READ) ||
 
 2798             ((page_st == PAGE_TO_BE_READ) &&
 
 2799              (offset || (read_length < keycache->key_cache_block_size))))
 
 2828           read_block(keycache, block, keycache->key_cache_block_size,
 
 2829                      read_length + offset, (page_st == PAGE_TO_BE_READ));
 
 2835           DBUG_ASSERT(keycache->can_be_used);
 
 2836           DBUG_ASSERT(block->hash_link->file == file);
 
 2837           DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
 2838           DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2840         else if (page_st == PAGE_TO_BE_READ)
 
 2846           DBUG_ASSERT(block->hash_link->requests);
 
 2847           DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 2848           DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
 
 2849                       (block->status & BLOCK_READ));
 
 2851 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 2852           keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2860           memcpy(block->buffer+offset, buff, (
size_t) read_length);
 
 2862 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 2863           keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 2864           DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 2865           DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
 
 2866                       (block->status & BLOCK_READ));
 
 2874           block->status|= BLOCK_READ;
 
 2875           block->length= read_length+
offset;
 
 2882           KEYCACHE_DBUG_PRINT(
"key_cache_insert",
 
 2883                               (
"primary request: new page in cache"));
 
 2885           release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
 
 2899           DBUG_ASSERT((page_st == PAGE_READ) &&
 
 2900                       (read_length + offset <= block->length));
 
 2908         DBUG_ASSERT(block->hash_link->file == file);
 
 2909         DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
 2910         DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 2913       remove_reader(block);
 
 2916       DBUG_EXECUTE_IF(
"key_cache_insert_block_error",
 
 2917                       block->status|= BLOCK_ERROR; errno=EIO;);
 
 2920       if (!(block->status & BLOCK_ERROR))
 
 2926         unreg_request(keycache, block, 1);
 
 2930         free_block(keycache, block);
 
 2936       filepos+= read_length+
offset;
 
 2939     } 
while ((length-= read_length));
 
 2942     if (locked_and_incremented)
 
 2943       dec_counter_for_resize_op(keycache);
 
 2944     keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 2979 int key_cache_write(
KEY_CACHE *keycache,
 
 2980                     File file, my_off_t filepos, 
int level,
 
 2981                     uchar *buff, uint length,
 
 2982                     uint block_length  __attribute__((unused)),
 
 2985   my_bool locked_and_incremented= FALSE;
 
 2987   DBUG_ENTER(
"key_cache_write");
 
 2989              (
"fd: %u  pos: %lu  length: %u  block_length: %u" 
 2990               "  key_block_length: %u",
 
 2991               (uint) file, (ulong) filepos, length, block_length,
 
 2992               keycache ? keycache->key_cache_block_size : 0));
 
 2999     keycache->global_cache_w_requests++;
 
 3000     keycache->global_cache_write++;
 
 3001     if (my_pwrite(file, buff, length, filepos, MYF(MY_NABP | MY_WAIT_IF_FULL)))
 
 3006 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) 
 3007   DBUG_EXECUTE(
"check_keycache",
 
 3008                test_key_cache(keycache, 
"start of key_cache_write", 1););
 
 3011   if (keycache->key_cache_inited)
 
 3019     if (MYSQL_KEYCACHE_WRITE_START_ENABLED())
 
 3021       MYSQL_KEYCACHE_WRITE_START(my_filename(file), length,
 
 3022                                  (ulong) (keycache->blocks_used *
 
 3023                                           keycache->key_cache_block_size),
 
 3024                                  (ulong) (keycache->blocks_unused *
 
 3025                                           keycache->key_cache_block_size));
 
 3034     keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3050     while (keycache->in_resize && !keycache->resize_in_flush)
 
 3051       wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
 
 3053     inc_counter_for_resize_op(keycache);
 
 3054     locked_and_incremented= TRUE;
 
 3056     offset= (uint) (filepos % keycache->key_cache_block_size);
 
 3061       if (!keycache->can_be_used)
 
 3064       MYSQL_KEYCACHE_WRITE_BLOCK(keycache->key_cache_block_size);
 
 3068       read_length= length;
 
 3069       set_if_smaller(read_length, keycache->key_cache_block_size-offset);
 
 3070       KEYCACHE_DBUG_ASSERT(read_length > 0);
 
 3073       keycache->global_cache_w_requests++;
 
 3074       block= find_key_block(keycache, file, filepos, level, 1, &page_st);
 
 3085           keycache->global_cache_write++;
 
 3086           keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3087           if (my_pwrite(file, (uchar*) buff, read_length, filepos + offset,
 
 3088                         MYF(MY_NABP | MY_WAIT_IF_FULL)))
 
 3090           keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3100       if (page_st != PAGE_WAIT_TO_BE_READ)
 
 3101         block->status|= BLOCK_FOR_UPDATE;
 
 3114       if (!(block->status & BLOCK_ERROR) &&
 
 3115           ((page_st == PAGE_TO_BE_READ &&
 
 3116             (offset || read_length < keycache->key_cache_block_size)) ||
 
 3117            (page_st == PAGE_WAIT_TO_BE_READ)))
 
 3119         read_block(keycache, block,
 
 3120                    offset + read_length >= keycache->key_cache_block_size?
 
 3121                    offset : keycache->key_cache_block_size,
 
 3122                    offset, (page_st == PAGE_TO_BE_READ));
 
 3123         DBUG_ASSERT(keycache->can_be_used);
 
 3124         DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 3130         block->status|= BLOCK_FOR_UPDATE;
 
 3136       DBUG_ASSERT(block->hash_link->file == file);
 
 3137       DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
 3138       DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
 3139       DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
 
 3148       DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
 3150       while (block->status & BLOCK_IN_FLUSHWRITE)
 
 3161         wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
 3162         DBUG_ASSERT(keycache->can_be_used);
 
 3163         DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
 3165         DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
 3166         DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
 
 3178       if (!(block->status & BLOCK_ERROR))
 
 3180 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 3181         keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3183         memcpy(block->buffer+offset, buff, (
size_t) read_length);
 
 3185 #if !defined(SERIALIZED_READ_FROM_CACHE) 
 3186         keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3193         if ((block->status & BLOCK_CHANGED) &&
 
 3194             (!offset && read_length >= keycache->key_cache_block_size))
 
 3195              link_to_file_list(keycache, block, block->hash_link->file, 1);
 
 3197       else if (! (block->status & BLOCK_CHANGED))
 
 3198         link_to_changed_list(keycache, block);
 
 3199       block->status|=BLOCK_READ;
 
 3205       block->status&= ~BLOCK_FOR_UPDATE;
 
 3206       set_if_smaller(block->offset, offset);
 
 3207       set_if_bigger(block->length, read_length+offset);
 
 3210       release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
 
 3220       remove_reader(block);
 
 3223       DBUG_EXECUTE_IF(
"key_cache_write_block_error",
 
 3224                       block->status|= BLOCK_ERROR;);
 
 3227       if (!(block->status & BLOCK_ERROR))
 
 3233         unreg_request(keycache, block, 1);
 
 3238         block->status&= ~(BLOCK_CHANGED);
 
 3239         free_block(keycache, block);
 
 3246       filepos+= read_length+
offset;
 
 3249     } 
while ((length-= read_length));
 
 3258     keycache->global_cache_w_requests++;
 
 3259     keycache->global_cache_write++;
 
 3260     if (locked_and_incremented)
 
 3261       keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3262     if (my_pwrite(file, (uchar*) buff, length, filepos,
 
 3263                   MYF(MY_NABP | MY_WAIT_IF_FULL)))
 
 3265     if (locked_and_incremented)
 
 3266       keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3270   if (locked_and_incremented)
 
 3272     dec_counter_for_resize_op(keycache);
 
 3273     keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3276   if (MYSQL_KEYCACHE_WRITE_DONE_ENABLED())
 
 3278     MYSQL_KEYCACHE_WRITE_DONE((ulong) (keycache->blocks_used *
 
 3279                                        keycache->key_cache_block_size),
 
 3280                               (ulong) (keycache->blocks_unused *
 
 3281                                        keycache->key_cache_block_size));
 
 3284 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) 
 3285   DBUG_EXECUTE(
"exec",
 
 3286                test_key_cache(keycache, 
"end of key_cache_write", 1););
 
 3321   KEYCACHE_THREAD_TRACE(
"free block");
 
 3322   KEYCACHE_DBUG_PRINT(
"free_block",
 
 3323                       (
"block %u to be freed, hash_link %p  status: %u",
 
 3324                        BLOCK_NUMBER(block), block->hash_link,
 
 3333   DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
 
 3334               !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 3335                                  BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
 
 3336                                  BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
 
 3338   DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 3340   DBUG_ASSERT(!block->next_used && !block->prev_used);
 
 3350   DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
 3351   if (block->hash_link)
 
 3359     block->status|= BLOCK_REASSIGNED;
 
 3360     wait_for_readers(keycache, block);
 
 3366     DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
 3367     DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
 
 3368                                   BLOCK_REASSIGNED)) &&
 
 3369                 !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 3370                                    BLOCK_IN_FLUSH | BLOCK_CHANGED |
 
 3371                                    BLOCK_FOR_UPDATE)));
 
 3372     DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
 3373     DBUG_ASSERT(!block->prev_used);
 
 3379     block->status&= ~BLOCK_REASSIGNED;
 
 3396   DBUG_ASSERT(block->requests == 1);
 
 3397   unreg_request(keycache, block, 0);
 
 3404   if (block->status & BLOCK_IN_EVICTION)
 
 3408   if (!(block->status & BLOCK_ERROR))
 
 3411     DBUG_ASSERT(block->next_used && block->prev_used &&
 
 3412                 *block->prev_used == block);
 
 3413     unlink_block(keycache, block);
 
 3415   if (block->temperature == BLOCK_WARM)
 
 3416     keycache->warm_blocks--;
 
 3417   block->temperature= BLOCK_COLD;
 
 3420   unlink_changed(block);
 
 3423   unlink_hash(keycache, block->hash_link);
 
 3424   block->hash_link= NULL;
 
 3428   block->offset= keycache->key_cache_block_size;
 
 3429   KEYCACHE_THREAD_TRACE(
"free block");
 
 3430   KEYCACHE_DBUG_PRINT(
"free_block", (
"block is freed"));
 
 3433   DBUG_ASSERT(!block->next_changed && !block->prev_changed);
 
 3435   DBUG_ASSERT(!block->next_used && !block->prev_used);
 
 3437   block->next_used= keycache->free_block_list;
 
 3438   keycache->free_block_list= 
block;
 
 3440   keycache->blocks_unused++;
 
 3443   release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
 
 3449   return (((*a)->hash_link->diskpos < (*b)->hash_link->diskpos) ? -1 :
 
 3450       ((*a)->hash_link->diskpos > (*b)->hash_link->diskpos) ? 1 : 0);
 
 3459 static int flush_cached_blocks(
KEY_CACHE *keycache,
 
 3462                                enum flush_type 
type)
 
 3466   uint count= (uint) (end-cache);
 
 3469   keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3474   my_qsort((uchar*) cache, count, 
sizeof(*cache), (qsort_cmp) cmp_sec_link);
 
 3476   keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3482   for ( ; cache != end ; cache++)
 
 3486     KEYCACHE_DBUG_PRINT(
"flush_cached_blocks",
 
 3487                         (
"block %u to be flushed", BLOCK_NUMBER(block)));
 
 3493     if (!(block->status & BLOCK_FOR_UPDATE))
 
 3496       DBUG_ASSERT(block->hash_link);
 
 3497       DBUG_ASSERT(block->hash_link->block == block);
 
 3498       DBUG_ASSERT(block->hash_link->file == file);
 
 3499       DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
 
 3500                   (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
 
 3501       block->status|= BLOCK_IN_FLUSHWRITE;
 
 3502       keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 3503       error= my_pwrite(file, block->buffer+block->offset,
 
 3504                        block->length - block->offset,
 
 3505                        block->hash_link->diskpos+ block->offset,
 
 3506                        MYF(MY_NABP | MY_WAIT_IF_FULL));
 
 3507       keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 3508       keycache->global_cache_write++;
 
 3511         block->status|= BLOCK_ERROR;
 
 3513           last_errno= errno ? errno : -1;
 
 3515       block->status&= ~BLOCK_IN_FLUSHWRITE;
 
 3517       DBUG_ASSERT(block->hash_link);
 
 3518       DBUG_ASSERT(block->hash_link->block == block);
 
 3519       DBUG_ASSERT(block->hash_link->file == file);
 
 3520       DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
 
 3521                   (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
 
 3529       link_to_file_list(keycache, block, file, 1);
 
 3531     block->status&= ~BLOCK_IN_FLUSH;
 
 3536     release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
 
 3538     if (!(type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE) &&
 
 3539         !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 3546       free_block(keycache, block);
 
 3556       unreg_request(keycache, block, 1);
 
 3587 static int flush_key_blocks_int(
KEY_CACHE *keycache,
 
 3588                                 File file, 
enum flush_type type)
 
 3593   DBUG_ENTER(
"flush_key_blocks_int");
 
 3594   DBUG_PRINT(
"enter",(
"file: %d  blocks_used: %lu  blocks_changed: %lu",
 
 3595               file, keycache->blocks_used, keycache->blocks_changed));
 
 3597 #if !defined(DBUG_OFF) && defined(EXTRA_DEBUG) 
 3598   DBUG_EXECUTE(
"check_keycache",
 
 3599                test_key_cache(keycache, 
"start of flush_key_blocks", 0););
 
 3603   if (keycache->disk_blocks > 0 &&
 
 3604       (!my_disable_flush_key_blocks || type != FLUSH_KEEP))
 
 3608     uint count= FLUSH_CACHE;
 
 3614 #if defined(KEYCACHE_DEBUG) 
 3618     if (type != FLUSH_IGNORE_CHANGED)
 
 3625       for (block= keycache->changed_blocks[FILE_HASH(file)] ;
 
 3627            block= block->next_changed)
 
 3629         if ((block->hash_link->file == file) &&
 
 3630             !(block->status & BLOCK_IN_FLUSH))
 
 3633           KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
 
 3641       if ((count > FLUSH_CACHE) &&
 
 3649       if (cache == cache_buff)
 
 3655     last_in_flush= NULL;
 
 3656     last_for_update= NULL;
 
 3657     end= (pos= cache)+count;
 
 3658     for (block= keycache->changed_blocks[FILE_HASH(file)] ;
 
 3662 #if defined(KEYCACHE_DEBUG) 
 3664       KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
 3666       next= block->next_changed;
 
 3667       if (block->hash_link->file == file)
 
 3669         if (!(block->status & (BLOCK_IN_FLUSH | BLOCK_FOR_UPDATE)))
 
 3676           if (!(block->status & BLOCK_IN_SWITCH))
 
 3684             reg_requests(keycache, block, 1);
 
 3685             if (type != FLUSH_IGNORE_CHANGED)
 
 3695                 unreg_request(keycache, block, 0);
 
 3700                 if ((error= flush_cached_blocks(keycache, file, cache,
 
 3704                   if ((last_errno == error) && (++last_errcnt > 5))
 
 3722               block->status|= BLOCK_IN_FLUSH;
 
 3729               DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
 3736               link_to_file_list(keycache, block, file, 1);
 
 3737               if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)))
 
 3740                 free_block(keycache, block);
 
 3750                 unreg_request(keycache, block, 1);
 
 3765             unlink_changed(block);
 
 3766             link_changed(block, &first_in_switch);
 
 3769         else if (type != FLUSH_KEEP)
 
 3779           if (block->status & BLOCK_IN_FLUSH)
 
 3782             last_in_flush= 
block;
 
 3787             last_for_update= 
block;
 
 3794       if ((error= flush_cached_blocks(keycache, file, cache, pos, type)))
 
 3797         if ((last_errno == error) && (++last_errcnt > 5))
 
 3808       if (type != FLUSH_KEEP)
 
 3820       if (last_in_flush->status & BLOCK_IN_FLUSH)
 
 3821         wait_on_queue(&last_in_flush->wqueue[COND_FOR_SAVED],
 
 3822                       &keycache->cache_lock);
 
 3826     if (last_for_update)
 
 3835       if (last_for_update->status & BLOCK_FOR_UPDATE)
 
 3836         wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
 
 3837                       &keycache->cache_lock);
 
 3847     while (first_in_switch)
 
 3849 #if defined(KEYCACHE_DEBUG) 
 3852       wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
 
 3853                     &keycache->cache_lock);
 
 3854 #if defined(KEYCACHE_DEBUG) 
 3856       KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
 3866     if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
 
 3870       uint total_found= 0;
 
 3880         for (block= keycache->file_blocks[FILE_HASH(file)] ;
 
 3885           next= block->next_changed;
 
 3888           DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
 3889           if (block->hash_link->file == file)
 
 3892             if (block->status & BLOCK_FOR_UPDATE)
 
 3894               last_for_update= 
block;
 
 3903             if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
 
 3907               my_off_t UNINIT_VAR(next_diskpos);
 
 3908               File UNINIT_VAR(next_file);
 
 3909               uint UNINIT_VAR(next_status);
 
 3910               uint UNINIT_VAR(hash_requests);
 
 3914               KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
 
 3921               reg_requests(keycache, block, 1);
 
 3929               if (next && (hash_requests= block->hash_link->requests))
 
 3932                 next_status=    next->status;
 
 3933                 next_hash_link= next->hash_link;
 
 3934                 next_diskpos=   next_hash_link->diskpos;
 
 3935                 next_file=      next_hash_link->file;
 
 3936                 DBUG_ASSERT(next == next_hash_link->block);
 
 3939               free_block(keycache, block);
 
 3951               if (next && hash_requests &&
 
 3952                   ((next_status    != next->status) ||
 
 3953                    (next_hash_link != next->hash_link) ||
 
 3954                    (next_file      != next_hash_link->file) ||
 
 3955                    (next_diskpos   != next_hash_link->diskpos) ||
 
 3956                    (next           != next_hash_link->block)))
 
 3961               last_in_switch= 
block;
 
 3980       if (last_for_update)
 
 3983         DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
 
 3984         wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
 
 3985                       &keycache->cache_lock);
 
 3996         DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
 
 3999         wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
 
 4000                       &keycache->cache_lock);
 
 4009   DBUG_EXECUTE(
"check_keycache",
 
 4010                test_key_cache(keycache, 
"end of flush_key_blocks", 0););
 
 4013   if (cache != cache_buff)
 
 4017   DBUG_RETURN(last_errno != 0);
 
 4036 int flush_key_blocks(
KEY_CACHE *keycache,
 
 4037                      File file, 
enum flush_type type)
 
 4040   DBUG_ENTER(
"flush_key_blocks");
 
 4041   DBUG_PRINT(
"enter", (
"keycache: 0x%lx", (
long) keycache));
 
 4043   if (!keycache->key_cache_inited)
 
 4046   keycache_pthread_mutex_lock(&keycache->cache_lock);
 
 4048   if (keycache->disk_blocks > 0)
 
 4050     inc_counter_for_resize_op(keycache);
 
 4051     res= flush_key_blocks_int(keycache, file, type);
 
 4052     dec_counter_for_resize_op(keycache);
 
 4054   keycache_pthread_mutex_unlock(&keycache->cache_lock);
 
 4091 static int flush_all_key_blocks(
KEY_CACHE *keycache)
 
 4097   DBUG_ENTER(
"flush_all_key_blocks");
 
 4112       for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
 4123         if ((block= keycache->changed_blocks[idx]))
 
 4130           if (flush_key_blocks_int(keycache, block->hash_link->file,
 
 4150       for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
 4160         if ((block= keycache->file_blocks[idx]))
 
 4164           if (flush_key_blocks_int(keycache, block->hash_link->file,
 
 4178   } 
while (total_found);
 
 4182   for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
 4184     DBUG_ASSERT(!keycache->changed_blocks[idx]);
 
 4185     DBUG_ASSERT(!keycache->file_blocks[idx]);
 
 4209 int reset_key_cache_counters(
const char *
name __attribute__((unused)),
 
 4212   DBUG_ENTER(
"reset_key_cache_counters");
 
 4213   if (!key_cache->key_cache_inited)
 
 4215     DBUG_PRINT(
"info", (
"Key cache %s not initialized.", 
name));
 
 4218   DBUG_PRINT(
"info", (
"Resetting counters for key cache %s.", 
name));
 
 4220   key_cache->global_blocks_changed= 0;   
 
 4221   key_cache->global_cache_r_requests= 0; 
 
 4222   key_cache->global_cache_read= 0;       
 
 4223   key_cache->global_cache_w_requests= 0; 
 
 4224   key_cache->global_cache_write= 0;      
 
 4233 static void test_key_cache(
KEY_CACHE *keycache __attribute__((unused)),
 
 4234                            const char *where __attribute__((unused)),
 
 4235                            my_bool lock __attribute__((unused)))
 
 4241 #if defined(KEYCACHE_TIMEOUT) 
 4243 #define KEYCACHE_DUMP_FILE  "keycache_dump.txt" 
 4244 #define MAX_QUEUE_LEN  100 
 4247 static void keycache_dump(
KEY_CACHE *keycache)
 
 4249   FILE *keycache_dump_file=fopen(KEYCACHE_DUMP_FILE, 
"w");
 
 4257   fprintf(keycache_dump_file, 
"thread:%u\n", thread->id);
 
 4260   thread=last=waiting_for_hash_link.last_thread;
 
 4261   fprintf(keycache_dump_file, 
"queue of threads waiting for hash link\n");
 
 4265       thread=thread->next;
 
 4267       fprintf(keycache_dump_file,
 
 4268               "thread:%u, (file,filepos)=(%u,%lu)\n",
 
 4269               thread->id,(uint) page->file,(ulong) page->filepos);
 
 4270       if (++i == MAX_QUEUE_LEN)
 
 4273     while (thread != last);
 
 4276   thread=last=waiting_for_block.last_thread;
 
 4277   fprintf(keycache_dump_file, 
"queue of threads waiting for block\n");
 
 4281       thread=thread->next;
 
 4282       hash_link= (
HASH_LINK *) thread->opt_info;
 
 4283       fprintf(keycache_dump_file,
 
 4284         "thread:%u hash_link:%u (file,filepos)=(%u,%lu)\n",
 
 4285         thread->id, (uint) HASH_LINK_NUMBER(hash_link),
 
 4286         (uint) hash_link->file,(ulong) hash_link->diskpos);
 
 4287       if (++i == MAX_QUEUE_LEN)
 
 4290     while (thread != last);
 
 4292   for (i=0 ; i< keycache->blocks_used ; i++)
 
 4295     block= &keycache->block_root[
i];
 
 4296     hash_link= block->hash_link;
 
 4297     fprintf(keycache_dump_file,
 
 4298             "block:%u hash_link:%d status:%x #requests=%u waiting_for_readers:%d\n",
 
 4299             i, (
int) (hash_link ? HASH_LINK_NUMBER(hash_link) : -1),
 
 4300             block->status, block->requests, block->condvar ? 1 : 0);
 
 4301     for (j=0 ; j < 2; j++)
 
 4304       thread= last= wqueue->last_thread;
 
 4305       fprintf(keycache_dump_file, 
"queue #%d\n", j);
 
 4310           thread=thread->next;
 
 4311           fprintf(keycache_dump_file,
 
 4312                   "thread:%u\n", thread->id);
 
 4313           if (++i == MAX_QUEUE_LEN)
 
 4316         while (thread != last);
 
 4320   fprintf(keycache_dump_file, 
"LRU chain:");
 
 4321   block= keycache= used_last;
 
 4326       block= block->next_used;
 
 4327       fprintf(keycache_dump_file,
 
 4328               "block:%u, ", BLOCK_NUMBER(block));
 
 4330     while (block != keycache->used_last);
 
 4332   fprintf(keycache_dump_file, 
"\n");
 
 4334   fclose(keycache_dump_file);
 
 4339 #if defined(KEYCACHE_TIMEOUT) && !defined(__WIN__) 
 4342 static int keycache_pthread_cond_wait(
mysql_cond_t *cond,
 
 4349 #if defined(KEYCACHE_DEBUG) 
 4354   gettimeofday(&now, &tz);
 
 4356   timeout.tv_sec= now.tv_sec + KEYCACHE_TIMEOUT;
 
 4362   timeout.tv_nsec= now.tv_usec * 1000;
 
 4363   KEYCACHE_THREAD_TRACE_END(
"started waiting");
 
 4364 #if defined(KEYCACHE_DEBUG) 
 4367     fprintf(keycache_debug_log, 
"waiting...\n");
 
 4368     fflush(keycache_debug_log);
 
 4371   KEYCACHE_THREAD_TRACE_BEGIN(
"finished waiting");
 
 4372   if (rc == ETIMEDOUT || rc == ETIME)
 
 4374 #if defined(KEYCACHE_DEBUG) 
 4375     fprintf(keycache_debug_log,
"aborted by keycache timeout\n");
 
 4376     fclose(keycache_debug_log);
 
 4382 #if defined(KEYCACHE_DEBUG) 
 4383   KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
 
 4385   assert(rc != ETIMEDOUT);
 
 4390 #if defined(KEYCACHE_DEBUG) 
 4391 static int keycache_pthread_cond_wait(
mysql_cond_t *cond,
 
 4395   KEYCACHE_THREAD_TRACE_END(
"started waiting");
 
 4397   KEYCACHE_THREAD_TRACE_BEGIN(
"finished waiting");
 
 4403 #if defined(KEYCACHE_DEBUG) 
 4406 static int keycache_pthread_mutex_lock(
mysql_mutex_t *mutex)
 
 4410   KEYCACHE_THREAD_TRACE_BEGIN(
"");
 
 4415 static void keycache_pthread_mutex_unlock(
mysql_mutex_t *mutex)
 
 4417   KEYCACHE_THREAD_TRACE_END(
"");
 
 4422 static int keycache_pthread_cond_signal(
mysql_cond_t *cond)
 
 4425   KEYCACHE_THREAD_TRACE(
"signal");
 
 4431 #if defined(KEYCACHE_DEBUG_LOG) 
 4434 static void keycache_debug_print(
const char * 
fmt,...)
 
 4438   if (keycache_debug_log)
 
 4440     (void) vfprintf(keycache_debug_log, fmt, args);
 
 4441     (void) fputc(
'\n',keycache_debug_log);
 
 4447 #if defined(KEYCACHE_DEBUG_LOG) 
 4450 void keycache_debug_log_close(
void)
 
 4452   if (keycache_debug_log)
 
 4453     fclose(keycache_debug_log);
 
 4459 #if !defined(DBUG_OFF) 
 4460 #define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_)) 
 4464   F_B_PRT(
"block->next_used:    %lx\n", (ulong) block->next_used);
 
 4465   F_B_PRT(
"block->prev_used:    %lx\n", (ulong) block->prev_used);
 
 4466   F_B_PRT(
"block->next_changed: %lx\n", (ulong) block->next_changed);
 
 4467   F_B_PRT(
"block->prev_changed: %lx\n", (ulong) block->prev_changed);
 
 4468   F_B_PRT(
"block->hash_link:    %lx\n", (ulong) block->hash_link);
 
 4469   F_B_PRT(
"block->status:       %u\n", block->status);
 
 4470   F_B_PRT(
"block->length:       %u\n", block->length);
 
 4471   F_B_PRT(
"block->offset:       %u\n", block->offset);
 
 4472   F_B_PRT(
"block->requests:     %u\n", block->requests);
 
 4473   F_B_PRT(
"block->temperature:  %u\n", block->temperature);
 
 4479   F_B_PRT(
"hlink->next:    %lx\n", (ulong) hlink->next);
 
 4480   F_B_PRT(
"hlink->prev:    %lx\n", (ulong) hlink->prev);
 
 4481   F_B_PRT(
"hlink->block:   %lx\n", (ulong) hlink->block);
 
 4482   F_B_PRT(
"hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
 
 4483   F_B_PRT(
"hlink->file:    %d\n", hlink->file);
 
 4487 static int cache_empty(
KEY_CACHE *keycache)
 
 4491   if (keycache->disk_blocks <= 0)
 
 4493   for (idx= 0; idx < keycache->disk_blocks; idx++)
 
 4495     BLOCK_LINK *block= keycache->block_root + idx;
 
 4496     if (block->status || block->requests || block->hash_link)
 
 4498       fprintf(stderr, 
"block index: %u\n", idx);
 
 4503   for (idx= 0; idx < keycache->hash_links; idx++)
 
 4505     HASH_LINK *hash_link= keycache->hash_link_root + idx;
 
 4506     if (hash_link->requests || hash_link->block)
 
 4508       fprintf(stderr, 
"hash_link index: %u\n", idx);
 
 4509       fail_hlink(hash_link);
 
 4515     fprintf(stderr, 
"blocks: %d  used: %lu\n",
 
 4516             keycache->disk_blocks, keycache->blocks_used);
 
 4517     fprintf(stderr, 
"hash_links: %d  used: %d\n",
 
 4518             keycache->hash_links, keycache->hash_links_used);
 
 4519     fprintf(stderr, 
"\n");