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");