summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorunknown <bell@desktop.sanja.is.com.ua>2008-01-30 22:42:19 +0200
committerunknown <bell@desktop.sanja.is.com.ua>2008-01-30 22:42:19 +0200
commitcaa0e9b18121c0e047b3fc7e7f827ebff0af7d4f (patch)
tree8a5afd4178fcbd837ec77a4d1792ed6e34d735dc /storage
parent25bccab91cc22e7204d225b3b10a4406baed93c6 (diff)
parentb51c819ce1f949a127dce99e1c63e541ebb80d03 (diff)
downloadmariadb-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.c293
-rw-r--r--storage/maria/ma_pagecache.h7
-rw-r--r--storage/maria/unittest/ma_pagecache_single.c13
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);