diff --git a/buf/buf0buddy.c b/buf/buf0buddy.c index a55ac764f50..63cf980471f 100644 --- a/buf/buf0buddy.c +++ b/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; } diff --git a/buf/buf0lru.c b/buf/buf0lru.c index da1623191b3..702a69c2868 100644 --- a/buf/buf0lru.c +++ b/buf/buf0lru.c @@ -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) { diff --git a/include/buf0buddy.h b/include/buf0buddy.h index 336b67d7e42..f52911fca1a 100644 --- a/include/buf0buddy.h +++ b/include/buf0buddy.h @@ -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)); /************************************************************************** diff --git a/include/buf0buddy.ic b/include/buf0buddy.ic index fd055f2e979..97e19dabfc4 100644 --- a/include/buf0buddy.ic +++ b/include/buf0buddy.ic @@ -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))); } /************************************************************************** diff --git a/include/buf0lru.h b/include/buf0lru.h index 926170f04e5..d18bba9861b 100644 --- a/include/buf0lru.h +++ b/include/buf0lru.h @@ -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. */