mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
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.
This commit is contained in:
parent
9bf07dae11
commit
f9a10f4cef
5 changed files with 243 additions and 38 deletions
186
buf/buf0buddy.c
186
buf/buf0buddy.c
|
@ -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 @@ buddy_free:
|
|||
}
|
||||
|
||||
/* 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 @@ loop:
|
|||
/* 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 @@ 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));
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
|
|
@ -88,6 +88,15 @@ buf_LRU_search_and_free_block(
|
|||
of pages in the buffer pool from the end
|
||||
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. */
|
||||
|
|
Loading…
Reference in a new issue