Commit f9a10f4c authored by marko's avatar marko

branches/zip: Implement the whole allocation algorithm of compressed pages.

buf_LRU_free_block(): Free compressed-only pages and their
descriptors with buf_buddy_free().

buf_LRU_get_free_only(): New function for returning a block from
buf_pool->free if one is available.  Split from buf_LRU_get_free_block().

buf_buddy_alloc_zip(): Rename from buf_buddy_alloc_low() and make static.
Remove parameter "split".  Always try to split.

buf_buddy_free_block(): Rename to buf_buddy_block_free().

buf_buddy_block_register(): New function for registering buf_block_t
objects reserved by the allocator.

buf_buddy_alloc_from(): New function for allocating an object from a
bigger object, and putting the unused parts on the free list.

buf_buddy_alloc_clean_zip(): New function for allocating memory by
replacing an unmodified compressed page.

buf_buddy_alloc_low(): New function for allocating memory, either from
the free lists of compressed pages, from the global free list, or from
unmodified pages in the buffer pool.
parent 9bf07dae
...@@ -16,18 +16,17 @@ Created December 2006 by Marko Makela ...@@ -16,18 +16,17 @@ Created December 2006 by Marko Makela
#include "buf0lru.h" #include "buf0lru.h"
#include "buf0flu.h" #include "buf0flu.h"
#include "page0page.h" #include "page0page.h"
#include "page0zip.h"
/************************************************************************** /**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */ Try to allocate a block from buf_pool->zip_free[]. */
static
void* void*
buf_buddy_alloc_low( buf_buddy_alloc_zip(
/*================*/ /*================*/
/* out: allocated block, or NULL /* out: allocated block, or NULL
if buf_pool->zip_free[] was empty */ if buf_pool->zip_free[] was empty */
ulint i, /* in: index of buf_pool->zip_free[] */ ulint i) /* in: index of buf_pool->zip_free[] */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
{ {
buf_page_t* bpage; buf_page_t* bpage;
...@@ -42,8 +41,9 @@ buf_buddy_alloc_low( ...@@ -42,8 +41,9 @@ buf_buddy_alloc_low(
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage); UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
} else if (split && i + 1 < BUF_BUDDY_SIZES) { } else if (i + 1 < BUF_BUDDY_SIZES) {
bpage = buf_buddy_alloc_low(i + 1, split); /* Attempt to split. */
bpage = buf_buddy_alloc_zip(i + 1);
if (bpage) { if (bpage) {
buf_page_t* buddy = bpage + (BUF_BUDDY_LOW << i); buf_page_t* buddy = bpage + (BUF_BUDDY_LOW << i);
...@@ -59,7 +59,7 @@ buf_buddy_alloc_low( ...@@ -59,7 +59,7 @@ buf_buddy_alloc_low(
Deallocate a buffer frame of UNIV_PAGE_SIZE. */ Deallocate a buffer frame of UNIV_PAGE_SIZE. */
static static
void void
buf_buddy_free_block( buf_buddy_block_free(
/*=================*/ /*=================*/
void* buf) /* in: buffer frame to deallocate */ void* buf) /* in: buffer frame to deallocate */
{ {
...@@ -83,6 +83,174 @@ buf_buddy_free_block( ...@@ -83,6 +83,174 @@ buf_buddy_free_block(
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
} }
/**************************************************************************
Allocate a buffer block to the buddy allocator. */
static
void
buf_buddy_block_register(
/*=====================*/
buf_block_t* block) /* in: buffer frame to allocate */
{
ulint fold;
#ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */
ut_a(buf_block_get_state(block) == BUF_BLOCK_MEMORY);
ut_a(block->frame);
ut_a(block->frame == ut_align_down(block->frame, UNIV_PAGE_SIZE));
fold = (ulint) block->frame / UNIV_PAGE_SIZE;
HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
}
/**************************************************************************
Allocate a block from a bigger object. */
static
void*
buf_buddy_alloc_from(
/*=================*/
/* out: allocated block */
void* buf, /* in: a block that is free to use */
ulint i, /* in: index of buf_pool->zip_free[] */
ulint j) /* in: size of buf as an index
of buf_pool->zip_free[] */
{
ulint offs = BUF_BUDDY_LOW << j;
/* Add the unused parts of the block to the free lists. */
while (j > i) {
buf_page_t* bpage;
offs >>= 1;
j--;
bpage = (buf_page_t*) ((byte*) buf + offs);
bpage->state = BUF_BLOCK_ZIP_FREE;
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[j], bpage);
}
return(buf);
}
/**************************************************************************
Try to allocate a block from an unmodified compressed page. */
static
void*
buf_buddy_alloc_clean_zip(
/*======================*/
/* out: allocated block, or NULL */
ulint i) /* in: index of buf_pool->zip_free[] */
{
buf_page_t* bpage;
buf_page_t* min_bpage = NULL;
ulint min_size = ULINT_MAX;
const ulint size = BUF_BUDDY_LOW << i;
ulint j;
#ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */
mutex_enter(&buf_pool->zip_mutex);
j = ut_min(UT_LIST_GET_LEN(buf_pool->zip_clean), 100);
bpage = UT_LIST_GET_FIRST(buf_pool->zip_clean);
/* Try to find a clean compressed page of the same size. */
for (; j--; bpage = UT_LIST_GET_NEXT(list, bpage)) {
ulint zip_size = page_zip_get_size(&bpage->zip);
if (zip_size < size) {
continue;
} else if (zip_size == size && buf_LRU_free_block(bpage)) {
/* reuse the block */
ut_a((buf_page_t*) bpage->zip.data
== UT_LIST_GET_FIRST(buf_pool->zip_free[i]));
mutex_exit(&buf_pool->zip_mutex);
bpage = (buf_page_t*) bpage->zip.data;
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
return(bpage);
} else if (zip_size < min_size) {
min_size = zip_size;
min_bpage = bpage;
}
}
mutex_exit(&buf_pool->zip_mutex);
/* Try to free the smallest clean compressed page of bigger size. */
if (min_bpage && buf_LRU_free_block(min_bpage)) {
j = buf_buddy_get_slot(min_size);
ut_a((buf_page_t*) min_bpage->zip.data
== UT_LIST_GET_FIRST(buf_pool->zip_free[j]));
bpage = (buf_page_t*) min_bpage->zip.data;
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
UT_LIST_REMOVE(list, buf_pool->zip_free[j], bpage);
return(buf_buddy_alloc_from(min_bpage->zip.data, i, j));
}
return(NULL);
}
/**************************************************************************
Allocate a block. */
void*
buf_buddy_alloc_low(
/*================*/
/* out: allocated block, or NULL
if buf_pool->zip_free[] was empty */
ulint i) /* in: index of buf_pool->zip_free[] */
{
buf_block_t* block;
#ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */
/* Try to allocate from the buddy system. */
block = buf_buddy_alloc_zip(i);
if (block) {
return(block);
}
/* Try allocating from the buf_pool->free list. */
block = buf_LRU_get_free_only();
if (block) {
goto alloc_big;
}
/* Try replacing a compressed-only page in the buffer pool. */
block = buf_buddy_alloc_clean_zip(i);
if (block) {
return(block);
}
/* Try replacing an uncompressed page in the buffer pool. */
block = buf_LRU_get_free_block(0);
alloc_big:
buf_buddy_block_register(block);
return(buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES));
}
/************************************************************************** /**************************************************************************
Try to relocate a block. */ Try to relocate a block. */
static static
...@@ -270,7 +438,7 @@ buddy_free: ...@@ -270,7 +438,7 @@ buddy_free:
} }
/* The whole block is free. */ /* The whole block is free. */
buf_buddy_free_block(buf); buf_buddy_block_free(buf);
return; return;
} }
......
...@@ -21,6 +21,7 @@ Created 11/5/1995 Heikki Tuuri ...@@ -21,6 +21,7 @@ Created 11/5/1995 Heikki Tuuri
#include "os0sync.h" #include "os0sync.h"
#include "fil0fil.h" #include "fil0fil.h"
#include "btr0btr.h" #include "btr0btr.h"
#include "buf0buddy.h"
#include "buf0buf.h" #include "buf0buf.h"
#include "buf0flu.h" #include "buf0flu.h"
#include "buf0rea.h" #include "buf0rea.h"
...@@ -248,7 +249,14 @@ buf_LRU_free_block( ...@@ -248,7 +249,14 @@ buf_LRU_free_block(
break; break;
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
/* TODO: free page_zip */ ut_ad(!bpage->in_free_list);
ut_ad(!bpage->in_LRU_list);
UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
buf_buddy_free(bpage->zip.data,
page_zip_get_size(&bpage->zip));
buf_buddy_free(bpage, sizeof(*bpage));
break; break;
default: default:
...@@ -371,6 +379,42 @@ buf_LRU_buf_pool_running_out(void) ...@@ -371,6 +379,42 @@ buf_LRU_buf_pool_running_out(void)
return(ret); return(ret);
} }
/**********************************************************************
Returns a free block from the buf_pool. The block is taken off the
free list. If it is empty, returns NULL. */
buf_block_t*
buf_LRU_get_free_only(void)
/*=======================*/
/* out: a free control block, or NULL
if the buf_block->free list is empty */
{
buf_block_t* block;
#ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */
block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
if (block) {
ut_ad(block->page.in_free_list);
ut_d(block->page.in_free_list = FALSE);
ut_ad(!block->page.in_LRU_list);
ut_a(!buf_page_in_file(&block->page));
UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
mutex_enter(&block->mutex);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
mutex_exit(&block->mutex);
}
return(block);
}
/********************************************************************** /**********************************************************************
Returns a free block from the buf_pool. The block is taken off the Returns a free block from the buf_pool. The block is taken off the
free list. If it is empty, blocks are moved from the end of the free list. If it is empty, blocks are moved from the end of the
...@@ -458,12 +502,8 @@ loop: ...@@ -458,12 +502,8 @@ loop:
/* If there is a block in the free list, take it */ /* If there is a block in the free list, take it */
if (UT_LIST_GET_LEN(buf_pool->free) > 0) { if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free); block = buf_LRU_get_free_only();
ut_ad(block->page.in_free_list); ut_a(block); /* We tested that buf_pool->free is nonempty. */
ut_d(block->page.in_free_list = FALSE);
ut_ad(!block->page.in_LRU_list);
ut_a(!buf_page_in_file(&block->page));
UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
if (buf_block_get_zip_size(block) != zip_size) { if (buf_block_get_zip_size(block) != zip_size) {
page_zip_set_size(&block->page.zip, zip_size); page_zip_set_size(&block->page.zip, zip_size);
...@@ -485,13 +525,6 @@ loop: ...@@ -485,13 +525,6 @@ loop:
} }
} }
mutex_enter(&block->mutex);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
mutex_exit(&block->mutex);
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
if (started_monitor) { if (started_monitor) {
......
...@@ -42,14 +42,13 @@ buf_buddy_get_slot( ...@@ -42,14 +42,13 @@ buf_buddy_get_slot(
ulint size); /* in: block size */ ulint size); /* in: block size */
/************************************************************************** /**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */ Allocate a block. */
UNIV_INLINE UNIV_INLINE
void* void*
buf_buddy_alloc( buf_buddy_alloc(
/*============*/ /*============*/
ulint size, /* in: block size, up to UNIV_PAGE_SIZE / 2 */ /* out: pointer to the start of the block */
ibool split) /* in: TRUE=attempt splitting, ulint size) /* in: block size, up to UNIV_PAGE_SIZE / 2 */
FALSE=try to allocate exact size */
__attribute__((malloc)); __attribute__((malloc));
/************************************************************************** /**************************************************************************
......
...@@ -15,16 +15,13 @@ Created December 2006 by Marko Makela ...@@ -15,16 +15,13 @@ Created December 2006 by Marko Makela
#include "ut0ut.h" #include "ut0ut.h"
/************************************************************************** /**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */ Allocate a block. */
void* void*
buf_buddy_alloc_low( buf_buddy_alloc_low(
/*================*/ /*================*/
/* out: allocated block, or NULL /* out: pointer to the start of the block */
if buf_pool->zip_free[] was empty */ ulint i) /* in: index of buf_pool->zip_free[] */
ulint i, /* in: index of buf_pool->zip_free[] */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
__attribute__((malloc)); __attribute__((malloc));
/************************************************************************** /**************************************************************************
...@@ -77,20 +74,19 @@ buf_buddy_get_slot( ...@@ -77,20 +74,19 @@ buf_buddy_get_slot(
} }
/************************************************************************** /**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */ Allocate a block. */
UNIV_INLINE UNIV_INLINE
void* void*
buf_buddy_alloc( buf_buddy_alloc(
/*============*/ /*============*/
ulint size, /* in: block size, up to UNIV_PAGE_SIZE / 2 */ /* out: pointer to the start of the block */
ibool split) /* in: TRUE=attempt splitting, ulint size) /* in: block size, up to UNIV_PAGE_SIZE / 2 */
FALSE=try to allocate exact size */
{ {
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex)); ut_a(mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
return(buf_buddy_alloc_low(buf_buddy_get_slot(size), split)); return(buf_buddy_alloc_low(buf_buddy_get_slot(size)));
} }
/************************************************************************** /**************************************************************************
......
...@@ -89,6 +89,15 @@ buf_LRU_search_and_free_block( ...@@ -89,6 +89,15 @@ buf_LRU_search_and_free_block(
of the LRU list */ of the LRU list */
/********************************************************************** /**********************************************************************
Returns a free block from the buf_pool. The block is taken off the Returns a free block from the buf_pool. The block is taken off the
free list. If it is empty, returns NULL. */
buf_block_t*
buf_LRU_get_free_only(void);
/*=======================*/
/* out: a free control block, or NULL
if the buf_block->free list is empty */
/**********************************************************************
Returns a free block from the buf_pool. The block is taken off the
free list. If it is empty, blocks are moved from the end of the free list. If it is empty, blocks are moved from the end of the
LRU list to the free list. */ LRU list to the free list. */
......
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