diff options
author | unknown <bell@desktop.sanja.is.com.ua> | 2008-01-30 22:42:19 +0200 |
---|---|---|
committer | unknown <bell@desktop.sanja.is.com.ua> | 2008-01-30 22:42:19 +0200 |
commit | caa0e9b18121c0e047b3fc7e7f827ebff0af7d4f (patch) | |
tree | 8a5afd4178fcbd837ec77a4d1792ed6e34d735dc /storage | |
parent | 25bccab91cc22e7204d225b3b10a4406baed93c6 (diff) | |
parent | b51c819ce1f949a127dce99e1c63e541ebb80d03 (diff) | |
download | mariadb-git-caa0e9b18121c0e047b3fc7e7f827ebff0af7d4f.tar.gz |
Merge abelkin@bk-internal.mysql.com:/home/bk/mysql-maria
into desktop.sanja.is.com.ua:/home/bell/mysql/bk/work-maria-assert
Diffstat (limited to 'storage')
-rw-r--r-- | storage/maria/ma_pagecache.c | 293 | ||||
-rw-r--r-- | storage/maria/ma_pagecache.h | 7 | ||||
-rw-r--r-- | storage/maria/unittest/ma_pagecache_single.c | 13 |
3 files changed, 224 insertions, 89 deletions
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 34912853a70..47f6cd68cb7 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -298,7 +298,12 @@ struct st_pagecache_block_link #endif KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */ uchar *buffer; /* buffer for the block page */ - PAGECACHE_FILE *write_locker; +#ifdef THREAD + pthread_t write_locker; +#else + int write_locker; +#endif + ulonglong last_hit_time; /* timestamp of the last hit */ WQUEUE wqueue[COND_SIZE]; /* queues on waiting requests for new/old pages */ @@ -2196,9 +2201,6 @@ static void info_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl) get_wrlock() pagecache pointer to a page cache data structure block the block to work with - user_file Unique handler per handler file. Used to check if - we request many write locks withing the same - statement RETURN 0 - OK @@ -2206,11 +2208,15 @@ static void info_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl) */ static my_bool get_wrlock(PAGECACHE *pagecache, - PAGECACHE_BLOCK_LINK *block, - PAGECACHE_FILE *user_file) + PAGECACHE_BLOCK_LINK *block) { PAGECACHE_FILE file= block->hash_link->file; pgcache_page_no_t pageno= block->hash_link->pageno; +#ifdef THREAD + pthread_t locker= pthread_self(); +#else + int locker= 0; +#endif DBUG_ENTER("get_wrlock"); DBUG_PRINT("info", ("the block 0x%lx " "files %d(%d) pages %lu(%lu)", @@ -2218,7 +2224,7 @@ static my_bool get_wrlock(PAGECACHE *pagecache, file.file, block->hash_link->file.file, (ulong) pageno, (ulong) block->hash_link->pageno)); PCBLOCK_INFO(block); - while (block->wlocks && block->write_locker != user_file) + while (block->wlocks && block->write_locker != locker) { /* Lock failed we will wait */ #ifdef THREAD @@ -2252,7 +2258,7 @@ static my_bool get_wrlock(PAGECACHE *pagecache, } /* we are doing it by global cache mutex protection, so it is OK */ block->wlocks++; - block->write_locker= user_file; + block->write_locker= locker; DBUG_PRINT("info", ("WR lock set, block 0x%lx", (ulong)block)); DBUG_RETURN(0); } @@ -2309,8 +2315,7 @@ static void release_wrlock(PAGECACHE_BLOCK_LINK *block) static my_bool make_lock_and_pin(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block, enum pagecache_page_lock lock, - enum pagecache_page_pin pin, - PAGECACHE_FILE *file) + enum pagecache_page_pin pin) { DBUG_ENTER("make_lock_and_pin"); @@ -2331,7 +2336,7 @@ static my_bool make_lock_and_pin(PAGECACHE *pagecache, switch (lock) { case PAGECACHE_LOCK_WRITE: /* free -> write */ /* Writelock and pin the buffer */ - if (get_wrlock(pagecache, block, file)) + if (get_wrlock(pagecache, block)) { /* can't lock => need retry */ goto retry; @@ -2638,7 +2643,7 @@ void pagecache_unlock(PAGECACHE *pagecache, (ulong) block)); } - if (make_lock_and_pin(pagecache, block, lock, pin, file)) + if (make_lock_and_pin(pagecache, block, lock, pin)) { DBUG_ASSERT(0); /* should not happend */ } @@ -2708,7 +2713,7 @@ void pagecache_unpin(PAGECACHE *pagecache, */ if (make_lock_and_pin(pagecache, block, PAGECACHE_LOCK_LEFT_READLOCKED, - PAGECACHE_UNPIN, file)) + PAGECACHE_UNPIN)) DBUG_ASSERT(0); /* should not happend */ remove_reader(block); @@ -2767,8 +2772,7 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache, if (pin == PAGECACHE_PIN_LEFT_UNPINNED && lock == PAGECACHE_LOCK_READ_UNLOCK) { - /* block do not need here so we do not provide it */ - if (make_lock_and_pin(pagecache, 0, lock, pin, 0)) + if (make_lock_and_pin(pagecache, block, lock, pin)) DBUG_ASSERT(0); /* should not happend */ DBUG_VOID_RETURN; } @@ -2822,7 +2826,7 @@ void pagecache_unlock_by_link(PAGECACHE *pagecache, (ulong) block)); } - if (make_lock_and_pin(pagecache, block, lock, pin, 0)) + if (make_lock_and_pin(pagecache, block, lock, pin)) DBUG_ASSERT(0); /* should not happend */ /* @@ -2885,7 +2889,7 @@ void pagecache_unpin_by_link(PAGECACHE *pagecache, */ if (make_lock_and_pin(pagecache, block, PAGECACHE_LOCK_LEFT_READLOCKED, - PAGECACHE_UNPIN, 0)) + PAGECACHE_UNPIN)) DBUG_ASSERT(0); /* should not happend */ /* @@ -3011,7 +3015,7 @@ restart: DBUG_PRINT("info", ("read is done")); } - if (make_lock_and_pin(pagecache, block, lock, pin, file)) + if (make_lock_and_pin(pagecache, block, lock, pin)) { /* We failed to write lock the block, cache is unlocked, @@ -3092,23 +3096,189 @@ no_key_cache: /* Key cache is not used */ /* - Delete page from the buffer + @brief Delete page from the buffer (common part for link and file/page) - SYNOPSIS - pagecache_delete() - pagecache pointer to a page cache data structure - file handler for the file for the block of data to be read - pageno number of the block of data in the file - lock lock change - flush flush page if it is dirty + @param pagecache pointer to a page cache data structure + @param block direct link to page (returned by read or write) + @param page_link hash link of the block + @param flush flush page if it is dirty - RETURN VALUE - 0 - deleted or was not present at all - 1 - error + @retval 0 deleted or was not present at all + @retval 1 error - NOTES. - lock can be only PAGECACHE_LOCK_LEFT_WRITELOCKED (page was write locked - before) or PAGECACHE_LOCK_WRITE (delete will write lock page before delete) +*/ + +static my_bool pagecache_delete_internal(PAGECACHE *pagecache, + PAGECACHE_BLOCK_LINK *block, + PAGECACHE_HASH_LINK *page_link, + my_bool flush) +{ + int error= 0; + if (block->status & PCBLOCK_CHANGED) + { + if (flush) + { + /* The block contains a dirty page - push it out of the cache */ + + KEYCACHE_DBUG_PRINT("find_block", ("block is dirty")); + + pagecache_pthread_mutex_unlock(&pagecache->cache_lock); + /* + The call is thread safe because only the current + thread might change the block->hash_link value + */ + DBUG_ASSERT(block->pins == 1); + error= pagecache_fwrite(pagecache, + &block->hash_link->file, + block->buffer, + block->hash_link->pageno, + block->type, + pagecache->readwrite_flags); + pagecache_pthread_mutex_lock(&pagecache->cache_lock); + pagecache->global_cache_write++; + + if (error) + { + block->status|= PCBLOCK_ERROR; + my_debug_put_break_here(); + goto err; + } + } + pagecache->blocks_changed--; + pagecache->global_blocks_changed--; + /* + free_block() will change the status and rec_lsn of the block so no + need to change them here. + */ + } + /* Cache is locked, so we can relese page before freeing it */ + make_lock_and_pin(pagecache, block, + PAGECACHE_LOCK_WRITE_UNLOCK, + PAGECACHE_UNPIN); + DBUG_ASSERT(block->hash_link->requests > 0); + page_link->requests--; + /* See NOTE for pagecache_unlock about registering requests. */ + free_block(pagecache, block); + +err: + dec_counter_for_resize_op(pagecache); + return error; +} + + +/* + @brief Delete page from the buffer by link + + @param pagecache pointer to a page cache data structure + @param link direct link to page (returned by read or write) + @param lock lock change + @param flush flush page if it is dirty + + @retval 0 deleted or was not present at all + @retval 1 error + + @note lock can be only PAGECACHE_LOCK_LEFT_WRITELOCKED (page was + write locked before) or PAGECACHE_LOCK_WRITE (delete will write + lock page before delete) +*/ + +my_bool pagecache_delete_by_link(PAGECACHE *pagecache, + PAGECACHE_BLOCK_LINK *block, + enum pagecache_page_lock lock, + my_bool flush) +{ + int error= 0; + enum pagecache_page_pin pin= PAGECACHE_PIN_LEFT_PINNED; + DBUG_ENTER("pagecache_delete_by_link"); + DBUG_PRINT("enter", ("fd: %d block 0x%lx %s %s", + block->hash_link->file.file, + (ulong) block, + page_cache_page_lock_str[lock], + page_cache_page_pin_str[pin])); + DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE || + lock == PAGECACHE_LOCK_LEFT_WRITELOCKED); + DBUG_ASSERT(block->pins != 0); /* should be pinned */ + +restart: + + if (pagecache->can_be_used) + { + pagecache_pthread_mutex_lock(&pagecache->cache_lock); + if (!pagecache->can_be_used) + goto end; + + if (make_lock_and_pin(pagecache, block, lock, pin)) + { + /* + We failed to writelock the block, cache is unlocked, and last write + lock is released, we will try to get the block again. + */ + pagecache_pthread_mutex_unlock(&pagecache->cache_lock); + DBUG_PRINT("info", ("restarting...")); + goto restart; + } + + /* + get_present_hash_link() side effect emulation before call + pagecache_delete_internal() + */ + block->hash_link->requests++; + + error= pagecache_delete_internal(pagecache, block, block->hash_link, + flush); +end: + pagecache_pthread_mutex_unlock(&pagecache->cache_lock); + } + + DBUG_RETURN(error); +} + + +/** + @brief Returns "hits" for promotion + + @return "hits" for promotion +*/ + +uint pagacache_pagelevel(PAGECACHE_BLOCK_LINK *block) +{ + return block->hits_left; +} + +/* + @brief Adds "hits" to the page + + @param link direct link to page (returned by read or write) + @param level number of "hits" which we add to the page +*/ + +void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block, + uint level) +{ + DBUG_ASSERT(block->pins != 0); /* should be pinned */ + /* + Operation is just for statistics so it is not really important + if it interfere with other hit increasing => we are doing it without + locking the pagecache. + */ + block->hits_left+= level; +} + +/* + @brief Delete page from the buffer + + @param pagecache pointer to a page cache data structure + @param file handler for the file for the block of data to be read + @param pageno number of the block of data in the file + @param lock lock change + @param flush flush page if it is dirty + + @retval 0 deleted or was not present at all + @retval 1 error + + @note lock can be only PAGECACHE_LOCK_LEFT_WRITELOCKED (page was + write locked before) or PAGECACHE_LOCK_WRITE (delete will write + lock page before delete) */ my_bool pagecache_delete(PAGECACHE *pagecache, PAGECACHE_FILE *file, @@ -3152,7 +3322,7 @@ restart: if (pin == PAGECACHE_PIN) reg_requests(pagecache, block, 1); DBUG_ASSERT(block != 0); - if (make_lock_and_pin(pagecache, block, lock, pin, file)) + if (make_lock_and_pin(pagecache, block, lock, pin)) { /* We failed to writelock the block, cache is unlocked, and last write @@ -3166,54 +3336,7 @@ restart: /* we can't delete with opened direct link for write */ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0); - if (block->status & PCBLOCK_CHANGED) - { - if (flush) - { - /* The block contains a dirty page - push it out of the cache */ - - KEYCACHE_DBUG_PRINT("find_block", ("block is dirty")); - - pagecache_pthread_mutex_unlock(&pagecache->cache_lock); - /* - The call is thread safe because only the current - thread might change the block->hash_link value - */ - DBUG_ASSERT(block->pins == 1); - error= pagecache_fwrite(pagecache, - &block->hash_link->file, - block->buffer, - block->hash_link->pageno, - block->type, - pagecache->readwrite_flags); - pagecache_pthread_mutex_lock(&pagecache->cache_lock); - pagecache->global_cache_write++; - - if (error) - { - block->status|= PCBLOCK_ERROR; - my_debug_put_break_here(); - goto err; - } - } - pagecache->blocks_changed--; - pagecache->global_blocks_changed--; - /* - free_block() will change the status and rec_lsn of the block so no - need to change them here. - */ - } - /* Cache is locked, so we can relese page before freeing it */ - make_lock_and_pin(pagecache, block, - PAGECACHE_LOCK_WRITE_UNLOCK, - PAGECACHE_UNPIN, file); - DBUG_ASSERT(page_link->requests > 0); - page_link->requests--; - /* See NOTE for pagecache_unlock about registering requests. */ - free_block(pagecache, block); - -err: - dec_counter_for_resize_op(pagecache); + error= pagecache_delete_internal(pagecache, block, page_link, flush); end: pagecache_pthread_mutex_unlock(&pagecache->cache_lock); } @@ -3409,7 +3532,7 @@ restart: write_lock_change_table[lock].new_lock, (need_lock_change ? write_pin_change_table[pin].new_pin : - pin), file)) + pin))) { /* We failed to writelock the block, cache is unlocked, and last write @@ -3493,7 +3616,7 @@ restart: */ if (make_lock_and_pin(pagecache, block, write_lock_change_table[lock].unlock_lock, - write_pin_change_table[pin].unlock_pin, file)) + write_pin_change_table[pin].unlock_pin)) DBUG_ASSERT(0); } @@ -3702,7 +3825,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache, DBUG_ASSERT(block->wlocks == 0); DBUG_ASSERT(block->pins == 0); if (make_lock_and_pin(pagecache, block, - PAGECACHE_LOCK_WRITE, PAGECACHE_PIN, 0)) + PAGECACHE_LOCK_WRITE, PAGECACHE_PIN)) DBUG_ASSERT(0); KEYCACHE_DBUG_PRINT("flush_cached_blocks", @@ -3735,7 +3858,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache, make_lock_and_pin(pagecache, block, PAGECACHE_LOCK_WRITE_UNLOCK, - PAGECACHE_UNPIN, 0); + PAGECACHE_UNPIN); pagecache->global_cache_write++; if (error) diff --git a/storage/maria/ma_pagecache.h b/storage/maria/ma_pagecache.h index 4c6f6e3897d..d3705cc657c 100644 --- a/storage/maria/ma_pagecache.h +++ b/storage/maria/ma_pagecache.h @@ -283,6 +283,10 @@ extern my_bool pagecache_delete(PAGECACHE *pagecache, pgcache_page_no_t pageno, enum pagecache_page_lock lock, my_bool flush); +extern my_bool pagecache_delete_by_link(PAGECACHE *pagecache, + PAGECACHE_BLOCK_LINK *link, + enum pagecache_page_lock lock, + my_bool flush); extern my_bool pagecache_delete_pages(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, @@ -296,6 +300,9 @@ extern my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache, extern int reset_pagecache_counters(const char *name, PAGECACHE *pagecache); extern uchar *pagecache_block_link_to_buffer(PAGECACHE_BLOCK_LINK *block); +extern uint pagacache_pagelevel(PAGECACHE_BLOCK_LINK *block); +extern void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block, + uint level); /* Functions to handle multiple key caches */ extern my_bool multi_pagecache_init(void); diff --git a/storage/maria/unittest/ma_pagecache_single.c b/storage/maria/unittest/ma_pagecache_single.c index 1212de73932..724aa5bbcfb 100644 --- a/storage/maria/unittest/ma_pagecache_single.c +++ b/storage/maria/unittest/ma_pagecache_single.c @@ -453,6 +453,7 @@ int simple_delete_flush_test() { unsigned char *buffw= malloc(PAGE_SIZE); unsigned char *buffr= malloc(PAGE_SIZE); + PAGECACHE_BLOCK_LINK *link; int res; DBUG_ENTER("simple_delete_flush_test"); /* prepare the file */ @@ -462,7 +463,7 @@ int simple_delete_flush_test() PAGECACHE_LOCK_WRITE, PAGECACHE_PIN, PAGECACHE_WRITE_DELAY, - 0, LSN_IMPOSSIBLE); + &link, LSN_IMPOSSIBLE); flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE); /* test */ bfill(buffw, PAGE_SIZE, '\2'); @@ -472,12 +473,16 @@ int simple_delete_flush_test() PAGECACHE_PIN_LEFT_PINNED, PAGECACHE_WRITE_DELAY, 0, LSN_IMPOSSIBLE); - pagecache_delete(&pagecache, &file1, 0, - PAGECACHE_LOCK_LEFT_WRITELOCKED, 1); + if (pagecache_delete_by_link(&pagecache, link, + PAGECACHE_LOCK_LEFT_WRITELOCKED, 1)) + { + diag("simple_delete_flush_test: error during delete"); + exit(1); + } flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE); ok((res= test(test_file(file1, file1_name, PAGE_SIZE, PAGE_SIZE, simple_delete_flush_test_file))), - "Simple delete-forget page file"); + "Simple delete flush (link) page file"); if (res) reset_file(&file1, file1_name); free(buffw); |