mirror of
https://github.com/MariaDB/server.git
synced 2025-02-01 03:21:53 +01:00
branches/zip: buf_buddy_free_low(): Attempt to relocate the buddy of a
free block in order to create two adjacent free blocks that can be recombined. Add some debug assertions. buf_buddy_relocate(): New function: Try to relocate a free block.
This commit is contained in:
parent
07d7f05ff6
commit
5b24b43055
1 changed files with 146 additions and 1 deletions
147
buf/buf0buddy.c
147
buf/buf0buddy.c
|
@ -13,6 +13,8 @@ Created December 2006 by Marko Makela
|
|||
#endif
|
||||
#undef THIS_MODULE
|
||||
#include "buf0buf.h"
|
||||
#include "buf0flu.h"
|
||||
#include "page0page.h"
|
||||
|
||||
/**************************************************************************
|
||||
Try to allocate a block from buf_pool->zip_free[]. */
|
||||
|
@ -52,6 +54,97 @@ buf_buddy_alloc_low(
|
|||
return(bpage);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Try to relocate a block. */
|
||||
static
|
||||
ibool
|
||||
buf_buddy_relocate(
|
||||
/*===============*/
|
||||
/* out: TRUE if relocated */
|
||||
const void* src, /* in: block to relocate */
|
||||
void* dst, /* in: free block to relocate to */
|
||||
ulint i) /* in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
const ulint size = BUF_BUDDY_LOW << i;
|
||||
|
||||
ut_ad(src == ut_align_down(src, size));
|
||||
ut_ad(dst == ut_align_down(dst, size));
|
||||
ut_ad((((ulint) src) ^ ((ulint) dst)) == size);
|
||||
|
||||
/* We assume that all memory from buf_buddy_alloc()
|
||||
is used for either compressed pages or buf_page_t
|
||||
objects covering compressed pages. */
|
||||
|
||||
if (size >= PAGE_ZIP_MIN_SIZE) {
|
||||
/* This is a compressed page. */
|
||||
mutex_t* mutex;
|
||||
|
||||
bpage = buf_page_hash_get(page_get_space_id(src),
|
||||
page_get_page_no(src));
|
||||
ut_a(bpage);
|
||||
mutex = buf_page_get_mutex(bpage);
|
||||
|
||||
mutex_enter(mutex);
|
||||
|
||||
if (buf_flush_ready_for_replace(bpage)) {
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
case BUF_BLOCK_REMOVE_HASH:
|
||||
ut_error;
|
||||
break;
|
||||
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
/* Relocate the compressed page. */
|
||||
ut_a(bpage->zip.data == src);
|
||||
memcpy(dst, src, size);
|
||||
bpage->zip.data = dst;
|
||||
mutex_exit(mutex);
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(mutex);
|
||||
} else {
|
||||
/* This must be a buf_page_t object. */
|
||||
bpage = (buf_page_t*) src;
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
case BUF_BLOCK_REMOVE_HASH:
|
||||
ut_error;
|
||||
break;
|
||||
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
/* Cannot relocate dirty pages. */
|
||||
break;
|
||||
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
mutex_enter(&buf_pool->zip_mutex);
|
||||
|
||||
if (buf_flush_ready_for_replace(bpage)) {
|
||||
memcpy(dst, src, size);
|
||||
/* TODO: relocate bpage->list, bpage->LRU */
|
||||
}
|
||||
|
||||
mutex_exit(&buf_pool->zip_mutex);
|
||||
/* TODO: return(TRUE); */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Release a block to buf_pool->zip_free[]. */
|
||||
|
||||
|
@ -76,12 +169,31 @@ recombine:
|
|||
|
||||
/* Try to combine adjacent blocks. */
|
||||
|
||||
buddy = buf_buddy_get(buf, BUF_BUDDY_LOW << i);
|
||||
buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
|
||||
|
||||
for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
bpage; bpage = UT_LIST_GET_NEXT(list, bpage)) {
|
||||
|
||||
ut_ad(bpage->in_LRU_list);
|
||||
#ifdef UNIV_DEBUG
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
goto state_ok;
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
case BUF_BLOCK_REMOVE_HASH:
|
||||
break;
|
||||
}
|
||||
ut_error;
|
||||
state_ok:
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
if (bpage == buddy) {
|
||||
buddy_free:
|
||||
/* The buddy is free: recombine */
|
||||
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
|
||||
buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
|
||||
|
@ -98,6 +210,39 @@ recombine:
|
|||
ut_a(bpage != buf);
|
||||
}
|
||||
|
||||
/* The buddy is not free. Is there a free block of this size? */
|
||||
bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
|
||||
if (bpage) {
|
||||
/* Try to relocate the buddy of buf to the free block. */
|
||||
if (buf_buddy_relocate(buddy, bpage, i)) {
|
||||
|
||||
goto buddy_free;
|
||||
}
|
||||
|
||||
/* Try to relocate the buddy of the free block to buf. */
|
||||
buddy = buf_buddy_get(bpage, BUF_BUDDY_LOW << i);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
{
|
||||
const buf_page_t* b;
|
||||
|
||||
/* The buddy must not be free, because we always
|
||||
recombine adjacent free blocks. */
|
||||
for (b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
b; b = UT_LIST_GET_NEXT(list, b)) {
|
||||
|
||||
ut_a(b != buddy);
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
if (buf_buddy_relocate(buddy, buf, i)) {
|
||||
|
||||
goto buddy_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the block to the buddy list. */
|
||||
bpage = buf;
|
||||
bpage->state = BUF_BLOCK_ZIP_FREE;
|
||||
|
|
Loading…
Add table
Reference in a new issue