Commit 0663f35a authored by unknown's avatar unknown

Merge desktop.sanja.is.com.ua:/home/bell/mysql/bk/mysql-maria

into  desktop.sanja.is.com.ua:/home/bell/mysql/bk/work-maria-write


storage/maria/ma_pagecache.c:
  Auto merged
parents df03e791 25120a32
......@@ -298,7 +298,7 @@ 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;
void *write_locker;
ulonglong last_hit_time; /* timestamp of the last hit */
WQUEUE
wqueue[COND_SIZE]; /* queues on waiting requests for new/old pages */
......@@ -2196,9 +2196,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 +2203,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
void *locker= pthread_self();
#else
void *locker= NULL;
#endif
DBUG_ENTER("get_wrlock");
DBUG_PRINT("info", ("the block 0x%lx "
"files %d(%d) pages %lu(%lu)",
......@@ -2218,7 +2219,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 +2253,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 +2310,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 +2331,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 +2638,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 +2708,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 +2767,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 +2821,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 +2884,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 +3010,7 @@ uchar *pagecache_read(PAGECACHE *pagecache,
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 +3091,189 @@ uchar *pagecache_read(PAGECACHE *pagecache,
/*
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 +3317,7 @@ my_bool pagecache_delete(PAGECACHE *pagecache,
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 +3331,7 @@ my_bool pagecache_delete(PAGECACHE *pagecache,
/* 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 +3527,7 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
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 +3611,7 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
*/
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 +3820,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 +3853,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)
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment