Commit 8e3e3d16 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 edaacca0
......@@ -16,18 +16,17 @@ Created December 2006 by Marko Makela
#include "buf0lru.h"
#include "buf0flu.h"
#include "page0page.h"
#include "page0zip.h"
/**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */
static
void*
buf_buddy_alloc_low(
buf_buddy_alloc_zip(
/*================*/
/* out: allocated block, or NULL
if buf_pool->zip_free[] was empty */
ulint i, /* in: index of buf_pool->zip_free[] */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
ulint i) /* in: index of buf_pool->zip_free[] */
{
buf_page_t* bpage;
......@@ -42,8 +41,9 @@ buf_buddy_alloc_low(
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
} else if (split && i + 1 < BUF_BUDDY_SIZES) {
bpage = buf_buddy_alloc_low(i + 1, split);
} else if (i + 1 < BUF_BUDDY_SIZES) {
/* Attempt to split. */
bpage = buf_buddy_alloc_zip(i + 1);
if (bpage) {
buf_page_t* buddy = bpage + (BUF_BUDDY_LOW << i);
......@@ -59,7 +59,7 @@ buf_buddy_alloc_low(
Deallocate a buffer frame of UNIV_PAGE_SIZE. */
static
void
buf_buddy_free_block(
buf_buddy_block_free(
/*=================*/
void* buf) /* in: buffer frame to deallocate */
{
......@@ -83,6 +83,174 @@ buf_buddy_free_block(
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. */
static
......@@ -270,7 +438,7 @@ buf_buddy_free_low(
}
/* The whole block is free. */
buf_buddy_free_block(buf);
buf_buddy_block_free(buf);
return;
}
......
......@@ -21,6 +21,7 @@ Created 11/5/1995 Heikki Tuuri
#include "os0sync.h"
#include "fil0fil.h"
#include "btr0btr.h"
#include "buf0buddy.h"
#include "buf0buf.h"
#include "buf0flu.h"
#include "buf0rea.h"
......@@ -248,7 +249,14 @@ buf_LRU_free_block(
break;
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;
default:
......@@ -371,6 +379,42 @@ buf_LRU_buf_pool_running_out(void)
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
free list. If it is empty, blocks are moved from the end of the
......@@ -458,12 +502,8 @@ buf_LRU_get_free_block(
/* If there is a block in the free list, take it */
if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
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));
block = buf_LRU_get_free_only();
ut_a(block); /* We tested that buf_pool->free is nonempty. */
if (buf_block_get_zip_size(block) != zip_size) {
page_zip_set_size(&block->page.zip, zip_size);
......@@ -485,13 +525,6 @@ buf_LRU_get_free_block(
}
}
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));
if (started_monitor) {
......
......@@ -42,14 +42,13 @@ buf_buddy_get_slot(
ulint size); /* in: block size */
/**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */
Allocate a block. */
UNIV_INLINE
void*
buf_buddy_alloc(
/*============*/
ulint size, /* in: block size, up to UNIV_PAGE_SIZE / 2 */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
/* out: pointer to the start of the block */
ulint size) /* in: block size, up to UNIV_PAGE_SIZE / 2 */
__attribute__((malloc));
/**************************************************************************
......
......@@ -15,16 +15,13 @@ Created December 2006 by Marko Makela
#include "ut0ut.h"
/**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */
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[] */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
/* out: pointer to the start of the block */
ulint i) /* in: index of buf_pool->zip_free[] */
__attribute__((malloc));
/**************************************************************************
......@@ -77,20 +74,19 @@ buf_buddy_get_slot(
}
/**************************************************************************
Try to allocate a block from buf_pool->zip_free[]. */
Allocate a block. */
UNIV_INLINE
void*
buf_buddy_alloc(
/*============*/
ulint size, /* in: block size, up to UNIV_PAGE_SIZE / 2 */
ibool split) /* in: TRUE=attempt splitting,
FALSE=try to allocate exact size */
/* out: pointer to the start of the block */
ulint size) /* in: block size, up to UNIV_PAGE_SIZE / 2 */
{
#ifdef UNIV_SYNC_DEBUG
ut_a(mutex_own(&buf_pool->mutex));
#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(
of the LRU list */
/**********************************************************************
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
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