Commit 0f852331 authored by marko's avatar marko

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.
parent 449de0f4
......@@ -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;
......
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