diff options
Diffstat (limited to 'storage/xtradb/buf/buf0buddy.cc')
-rw-r--r-- | storage/xtradb/buf/buf0buddy.cc | 741 |
1 files changed, 0 insertions, 741 deletions
diff --git a/storage/xtradb/buf/buf0buddy.cc b/storage/xtradb/buf/buf0buddy.cc deleted file mode 100644 index 2ee39c6c992..00000000000 --- a/storage/xtradb/buf/buf0buddy.cc +++ /dev/null @@ -1,741 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file buf/buf0buddy.cc -Binary buddy allocator for compressed pages - -Created December 2006 by Marko Makela -*******************************************************/ - -#define THIS_MODULE -#include "buf0buddy.h" -#ifdef UNIV_NONINL -# include "buf0buddy.ic" -#endif -#undef THIS_MODULE -#include "buf0buf.h" -#include "buf0lru.h" -#include "buf0flu.h" -#include "page0zip.h" -#include "srv0start.h" - -/** When freeing a buf we attempt to coalesce by looking at its buddy -and deciding whether it is free or not. To ascertain if the buddy is -free we look for BUF_BUDDY_STAMP_FREE at BUF_BUDDY_STAMP_OFFSET -within the buddy. The question is how we can be sure that it is -safe to look at BUF_BUDDY_STAMP_OFFSET. -The answer lies in following invariants: -* All blocks allocated by buddy allocator are used for compressed -page frame. -* A compressed table always have space_id < SRV_LOG_SPACE_FIRST_ID -* BUF_BUDDY_STAMP_OFFSET always points to the space_id field in -a frame. - -- The above is true because we look at these fields when the - corresponding buddy block is free which implies that: - * The block we are looking at must have an address aligned at - the same size that its free buddy has. For example, if we have - a free block of 8K then its buddy's address must be aligned at - 8K as well. - * It is possible that the block we are looking at may have been - further divided into smaller sized blocks but its starting - address must still remain the start of a page frame i.e.: it - cannot be middle of a block. For example, if we have a free - block of size 8K then its buddy may be divided into blocks - of, say, 1K, 1K, 2K, 4K but the buddy's address will still be - the starting address of first 1K compressed page. - * What is important to note is that for any given block, the - buddy's address cannot be in the middle of a larger block i.e.: - in above example, our 8K block cannot have a buddy whose address - is aligned on 8K but it is part of a larger 16K block. -*/ - -/** Offset within buf_buddy_free_t where free or non_free stamps -are written.*/ -#define BUF_BUDDY_STAMP_OFFSET FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID - -/** Value that we stamp on all buffers that are currently on the zip_free -list. This value is stamped at BUF_BUDDY_STAMP_OFFSET offset */ -#define BUF_BUDDY_STAMP_FREE (SRV_LOG_SPACE_FIRST_ID) - -/** Stamp value for non-free buffers. Will be overwritten by a non-zero -value by the consumer of the block */ -#define BUF_BUDDY_STAMP_NONFREE (0XFFFFFFFF) - -#if BUF_BUDDY_STAMP_FREE >= BUF_BUDDY_STAMP_NONFREE -# error "BUF_BUDDY_STAMP_FREE >= BUF_BUDDY_STAMP_NONFREE" -#endif - -/** Return type of buf_buddy_is_free() */ -enum buf_buddy_state_t { - BUF_BUDDY_STATE_FREE, /*!< If the buddy to completely free */ - BUF_BUDDY_STATE_USED, /*!< Buddy currently in used */ - BUF_BUDDY_STATE_PARTIALLY_USED/*!< Some sub-blocks in the buddy - are in use */ -}; - -#ifdef UNIV_DEBUG_VALGRIND -/**********************************************************************//** -Invalidate memory area that we won't access while page is free */ -UNIV_INLINE -void -buf_buddy_mem_invalid( -/*==================*/ - buf_buddy_free_t* buf, /*!< in: block to check */ - ulint i) /*!< in: index of zip_free[] */ -{ - const size_t size = BUF_BUDDY_LOW << i; - ut_ad(i <= BUF_BUDDY_SIZES); - - UNIV_MEM_ASSERT_W(buf, size); - UNIV_MEM_INVALID(buf, size); -} -#else /* UNIV_DEBUG_VALGRIND */ -# define buf_buddy_mem_invalid(buf, i) ut_ad((i) <= BUF_BUDDY_SIZES) -#endif /* UNIV_DEBUG_VALGRIND */ - -/**********************************************************************//** -Check if a buddy is stamped free. -@return whether the buddy is free */ -UNIV_INLINE MY_ATTRIBUTE((warn_unused_result)) -bool -buf_buddy_stamp_is_free( -/*====================*/ - const buf_buddy_free_t* buf) /*!< in: block to check */ -{ - return(mach_read_from_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET) - == BUF_BUDDY_STAMP_FREE); -} - -/**********************************************************************//** -Stamps a buddy free. */ -UNIV_INLINE -void -buf_buddy_stamp_free( -/*=================*/ - buf_buddy_free_t* buf, /*!< in/out: block to stamp */ - ulint i) /*!< in: block size */ -{ - ut_d(memset(buf, static_cast<int>(i), BUF_BUDDY_LOW << i)); - buf_buddy_mem_invalid(buf, i); - mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, - BUF_BUDDY_STAMP_FREE); - buf->stamp.size = i; -} - -/**********************************************************************//** -Stamps a buddy nonfree. -@param[in/out] buf block to stamp -@param[in] i block size */ -#define buf_buddy_stamp_nonfree(buf, i) do { \ - buf_buddy_mem_invalid(buf, i); \ - memset(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, 0xff, 4); \ -} while (0) -#if BUF_BUDDY_STAMP_NONFREE != 0xffffffff -# error "BUF_BUDDY_STAMP_NONFREE != 0xffffffff" -#endif - -/**********************************************************************//** -Get the offset of the buddy of a compressed page frame. -@return the buddy relative of page */ -UNIV_INLINE -void* -buf_buddy_get( -/*==========*/ - byte* page, /*!< in: compressed page */ - ulint size) /*!< in: page size in bytes */ -{ - ut_ad(ut_is_2pow(size)); - ut_ad(size >= BUF_BUDDY_LOW); - ut_ad(BUF_BUDDY_LOW <= UNIV_ZIP_SIZE_MIN); - ut_ad(size < BUF_BUDDY_HIGH); - ut_ad(BUF_BUDDY_HIGH == UNIV_PAGE_SIZE); - ut_ad(!ut_align_offset(page, size)); - - if (((ulint) page) & size) { - return(page - size); - } else { - return(page + size); - } -} - -/** Validate a given zip_free list. */ -struct CheckZipFree { - ulint i; - CheckZipFree(ulint i) : i (i) {} - - void operator()(const buf_buddy_free_t* elem) const - { - ut_a(buf_buddy_stamp_is_free(elem)); - ut_a(elem->stamp.size <= i); - } -}; - -#define BUF_BUDDY_LIST_VALIDATE(bp, i) \ - UT_LIST_VALIDATE(list, buf_buddy_free_t, \ - bp->zip_free[i], CheckZipFree(i)) - -#ifdef UNIV_DEBUG -/**********************************************************************//** -Debug function to validate that a buffer is indeed free i.e.: in the -zip_free[]. -@return true if free */ -UNIV_INLINE -bool -buf_buddy_check_free( -/*=================*/ - buf_pool_t* buf_pool,/*!< in: buffer pool instance */ - const buf_buddy_free_t* buf, /*!< in: block to check */ - ulint i) /*!< in: index of buf_pool->zip_free[] */ -{ - const ulint size = BUF_BUDDY_LOW << i; - - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_ad(!ut_align_offset(buf, size)); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - - buf_buddy_free_t* itr; - - for (itr = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); - itr && itr != buf; - itr = UT_LIST_GET_NEXT(list, itr)) { - } - - return(itr == buf); -} -#endif /* UNIV_DEBUG */ - -/**********************************************************************//** -Checks if a buf is free i.e.: in the zip_free[]. -@retval BUF_BUDDY_STATE_FREE if fully free -@retval BUF_BUDDY_STATE_USED if currently in use -@retval BUF_BUDDY_STATE_PARTIALLY_USED if partially in use. */ -static MY_ATTRIBUTE((warn_unused_result)) -buf_buddy_state_t -buf_buddy_is_free( -/*==============*/ - buf_buddy_free_t* buf, /*!< in: block to check */ - ulint i) /*!< in: index of - buf_pool->zip_free[] */ -{ -#ifdef UNIV_DEBUG - const ulint size = BUF_BUDDY_LOW << i; - ut_ad(!ut_align_offset(buf, size)); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); -#endif /* UNIV_DEBUG */ - - /* We assume that all memory from buf_buddy_alloc() - is used for compressed page frames. */ - - /* We look inside the allocated objects returned by - buf_buddy_alloc() and assume that each block is a compressed - page that contains one of the following in space_id. - * BUF_BUDDY_STAMP_FREE if the block is in a zip_free list or - * BUF_BUDDY_STAMP_NONFREE if the block has been allocated but - not initialized yet or - * A valid space_id of a compressed tablespace - - The call below attempts to read from free memory. The memory - is "owned" by the buddy allocator (and it has been allocated - from the buffer pool), so there is nothing wrong about this. */ - if (!buf_buddy_stamp_is_free(buf)) { - return(BUF_BUDDY_STATE_USED); - } - - /* A block may be free but a fragment of it may still be in use. - To guard against that we write the free block size in terms of - zip_free index at start of stamped block. Note that we can - safely rely on this value only if the buf is free. */ - ut_ad(buf->stamp.size <= i); - return(buf->stamp.size == i - ? BUF_BUDDY_STATE_FREE - : BUF_BUDDY_STATE_PARTIALLY_USED); -} - -/**********************************************************************//** -Add a block to the head of the appropriate buddy free list. */ -UNIV_INLINE -void -buf_buddy_add_to_free( -/*==================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - buf_buddy_free_t* buf, /*!< in,own: block to be freed */ - ulint i) /*!< in: index of - buf_pool->zip_free[] */ -{ - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_ad(buf_pool->zip_free[i].start != buf); - - buf_buddy_stamp_free(buf, i); - UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], buf); - ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i)); -} - -/**********************************************************************//** -Remove a block from the appropriate buddy free list. */ -UNIV_INLINE -void -buf_buddy_remove_from_free( -/*=======================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - buf_buddy_free_t* buf, /*!< in,own: block to be freed */ - ulint i) /*!< in: index of - buf_pool->zip_free[] */ -{ - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_ad(buf_buddy_check_free(buf_pool, buf, i)); - - UT_LIST_REMOVE(list, buf_pool->zip_free[i], buf); - buf_buddy_stamp_nonfree(buf, i); -} - -/**********************************************************************//** -Try to allocate a block from buf_pool->zip_free[]. -@return allocated block, or NULL if buf_pool->zip_free[] was empty */ -static -buf_buddy_free_t* -buf_buddy_alloc_zip( -/*================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - ulint i) /*!< in: index of buf_pool->zip_free[] */ -{ - buf_buddy_free_t* buf; - - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_a(i < BUF_BUDDY_SIZES); - ut_a(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - - ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i)); - - buf = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); - - if (buf) { - buf_buddy_remove_from_free(buf_pool, buf, i); - } else if (i + 1 < BUF_BUDDY_SIZES) { - /* Attempt to split. */ - buf = buf_buddy_alloc_zip(buf_pool, i + 1); - - if (buf) { - buf_buddy_free_t* buddy = - reinterpret_cast<buf_buddy_free_t*>( - buf->stamp.bytes - + (BUF_BUDDY_LOW << i)); - - ut_ad(!buf_pool_contains_zip(buf_pool, buddy)); - buf_buddy_add_to_free(buf_pool, buddy, i); - } - } - - if (buf) { - /* Trash the page other than the BUF_BUDDY_STAMP_NONFREE. */ - UNIV_MEM_TRASH(buf, ~i, BUF_BUDDY_STAMP_OFFSET); - UNIV_MEM_TRASH(BUF_BUDDY_STAMP_OFFSET + 4 - + buf->stamp.bytes, ~i, - (BUF_BUDDY_LOW << i) - - (BUF_BUDDY_STAMP_OFFSET + 4)); - ut_ad(mach_read_from_4(buf->stamp.bytes - + BUF_BUDDY_STAMP_OFFSET) - == BUF_BUDDY_STAMP_NONFREE); - } - - return(buf); -} - -/**********************************************************************//** -Deallocate a buffer frame of UNIV_PAGE_SIZE. */ -static -void -buf_buddy_block_free( -/*=================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - void* buf) /*!< in: buffer frame to deallocate */ -{ - const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf); - buf_page_t* bpage; - buf_block_t* block; - - ut_ad(!mutex_own(&buf_pool->zip_mutex)); - ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE)); - - mutex_enter(&buf_pool->zip_hash_mutex); - - HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage, - ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY - && bpage->in_zip_hash && !bpage->in_page_hash), - ((buf_block_t*) bpage)->frame == buf); - ut_a(bpage); - ut_a(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY); - ut_ad(!bpage->in_page_hash); - ut_ad(bpage->in_zip_hash); - ut_d(bpage->in_zip_hash = FALSE); - HASH_DELETE(buf_page_t, hash, buf_pool->zip_hash, fold, bpage); - - mutex_exit(&buf_pool->zip_hash_mutex); - - ut_d(memset(buf, 0, UNIV_PAGE_SIZE)); - UNIV_MEM_INVALID(buf, UNIV_PAGE_SIZE); - - block = (buf_block_t*) bpage; - mutex_enter(&block->mutex); - buf_LRU_block_free_non_file_page(block); - mutex_exit(&block->mutex); - - ut_ad(buf_pool->buddy_n_frames > 0); - ut_d(buf_pool->buddy_n_frames--); -} - -/**********************************************************************//** -Allocate a buffer block to the buddy allocator. */ -static -void -buf_buddy_block_register( -/*=====================*/ - buf_block_t* block) /*!< in: buffer frame to allocate */ -{ - buf_pool_t* buf_pool = buf_pool_from_block(block); - const ulint fold = BUF_POOL_ZIP_FOLD(block); - ut_ad(!mutex_own(&buf_pool->zip_mutex)); - ut_ad(buf_block_get_state(block) == BUF_BLOCK_READY_FOR_USE); - - buf_block_set_state(block, BUF_BLOCK_MEMORY); - - ut_a(block->frame); - ut_a(!ut_align_offset(block->frame, UNIV_PAGE_SIZE)); - - ut_ad(!block->page.in_page_hash); - ut_ad(!block->page.in_zip_hash); - ut_d(block->page.in_zip_hash = TRUE); - - mutex_enter(&buf_pool->zip_hash_mutex); - HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page); - mutex_exit(&buf_pool->zip_hash_mutex); - - ut_d(buf_pool->buddy_n_frames++); -} - -/**********************************************************************//** -Allocate a block from a bigger object. -@return allocated block */ -static -void* -buf_buddy_alloc_from( -/*=================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - 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; - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_ad(j <= BUF_BUDDY_SIZES); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - ut_ad(j >= i); - ut_ad(!ut_align_offset(buf, offs)); - - /* Add the unused parts of the block to the free lists. */ - while (j > i) { - buf_buddy_free_t* zip_buf; - - offs >>= 1; - j--; - - zip_buf = reinterpret_cast<buf_buddy_free_t*>( - reinterpret_cast<byte*>(buf) + offs); - buf_buddy_add_to_free(buf_pool, zip_buf, j); - } - - buf_buddy_stamp_nonfree(reinterpret_cast<buf_buddy_free_t*>(buf), i); - return(buf); -} - -/**********************************************************************//** -Allocate a block. The thread calling this function must hold -buf_pool->LRU_list_mutex and must not hold buf_pool->zip_mutex or any -block->mutex. The buf_pool->LRU_list_mutex may be released and reacquired. -@return allocated block, never NULL */ -UNIV_INTERN -void* -buf_buddy_alloc_low( -/*================*/ - buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */ - ulint i, /*!< in: index of buf_pool->zip_free[], - or BUF_BUDDY_SIZES */ - ibool* lru) /*!< in: pointer to a variable that - will be assigned TRUE if storage was - allocated from the LRU list and - buf_pool->LRU_list_mutex was - temporarily released */ -{ - buf_block_t* block; - - ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); - ut_ad(!mutex_own(&buf_pool->zip_mutex)); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - - if (i < BUF_BUDDY_SIZES) { - /* Try to allocate from the buddy system. */ - mutex_enter(&buf_pool->zip_free_mutex); - block = (buf_block_t*) buf_buddy_alloc_zip(buf_pool, i); - - if (block) { - goto func_exit; - } - mutex_exit(&buf_pool->zip_free_mutex); - } - - /* Try allocating from the buf_pool->free list. */ - block = buf_LRU_get_free_only(buf_pool); - - if (block) { - - goto alloc_big; - } - - /* Try replacing an uncompressed page in the buffer pool. */ - mutex_exit(&buf_pool->LRU_list_mutex); - block = buf_LRU_get_free_block(buf_pool); - *lru = TRUE; - mutex_enter(&buf_pool->LRU_list_mutex); - -alloc_big: - buf_buddy_block_register(block); - - mutex_enter(&buf_pool->zip_free_mutex); - block = (buf_block_t*) buf_buddy_alloc_from( - buf_pool, block->frame, i, BUF_BUDDY_SIZES); - -func_exit: - buf_pool->buddy_stat[i].used++; - mutex_exit(&buf_pool->zip_free_mutex); - - return(block); -} - -/**********************************************************************//** -Try to relocate a block. The caller must hold zip_free_mutex, and this -function will release and lock it again. -@return true if relocated */ -static -bool -buf_buddy_relocate( -/*===============*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - 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; - ulint space; - ulint offset; - - ut_ad(mutex_own(&buf_pool->zip_free_mutex)); - ut_ad(!mutex_own(&buf_pool->zip_mutex)); - ut_ad(!ut_align_offset(src, size)); - ut_ad(!ut_align_offset(dst, size)); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - UNIV_MEM_ASSERT_W(dst, size); - - space = mach_read_from_4((const byte*) src - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - offset = mach_read_from_4((const byte*) src - + FIL_PAGE_OFFSET); - - /* Suppress Valgrind warnings about conditional jump - on uninitialized value. */ - UNIV_MEM_VALID(&space, sizeof space); - UNIV_MEM_VALID(&offset, sizeof offset); - - ut_ad(space != BUF_BUDDY_STAMP_FREE); - - mutex_exit(&buf_pool->zip_free_mutex); - - ulint fold = buf_page_address_fold(space, offset); - prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold); - - rw_lock_x_lock(hash_lock); - - bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - - if (!bpage || bpage->zip.data != src) { - /* The block has probably been freshly - allocated by buf_LRU_get_free_block() but not - added to buf_pool->page_hash yet. Obviously, - it cannot be relocated. */ - - rw_lock_x_unlock(hash_lock); - - mutex_enter(&buf_pool->zip_free_mutex); - return(false); - } - - if (page_zip_get_size(&bpage->zip) != size) { - /* The block is of different size. We would - have to relocate all blocks covered by src. - For the sake of simplicity, give up. */ - ut_ad(page_zip_get_size(&bpage->zip) < size); - - rw_lock_x_unlock(hash_lock); - - mutex_enter(&buf_pool->zip_free_mutex); - return(false); - } - - /* The block must have been allocated, but it may - contain uninitialized data. */ - UNIV_MEM_ASSERT_W(src, size); - - ib_mutex_t* block_mutex = buf_page_get_mutex(bpage); - - mutex_enter(block_mutex); - - mutex_enter(&buf_pool->zip_free_mutex); - - if (buf_page_can_relocate(bpage)) { - /* Relocate the compressed page. */ - ullint usec = ut_time_us(NULL); - - ut_a(bpage->zip.data == src); - - /* Note: This is potentially expensive, we need a better - solution here. We go with correctness for now. */ - ::memcpy(dst, src, size); - - bpage->zip.data = reinterpret_cast<page_zip_t*>(dst); - - rw_lock_x_unlock(hash_lock); - - mutex_exit(block_mutex); - - buf_buddy_mem_invalid( - reinterpret_cast<buf_buddy_free_t*>(src), i); - - buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[i]; - - ++buddy_stat->relocated; - - buddy_stat->relocated_usec += ut_time_us(NULL) - usec; - - return(true); - } - - rw_lock_x_unlock(hash_lock); - - mutex_exit(block_mutex); - - return(false); -} - -/**********************************************************************//** -Deallocate a block. */ -UNIV_INTERN -void -buf_buddy_free_low( -/*===============*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - void* buf, /*!< in: block to be freed, must not be - pointed to by the buffer pool */ - ulint i) /*!< in: index of buf_pool->zip_free[], - or BUF_BUDDY_SIZES */ -{ - buf_buddy_free_t* buddy; - - ut_ad(!mutex_own(&buf_pool->zip_mutex)); - ut_ad(i <= BUF_BUDDY_SIZES); - ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); - - mutex_enter(&buf_pool->zip_free_mutex); - - ut_ad(buf_pool->buddy_stat[i].used > 0); - buf_pool->buddy_stat[i].used--; -recombine: - UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i); - - if (i == BUF_BUDDY_SIZES) { - mutex_exit(&buf_pool->zip_free_mutex); - buf_buddy_block_free(buf_pool, buf); - return; - } - - ut_ad(i < BUF_BUDDY_SIZES); - ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i)); - ut_ad(!buf_pool_contains_zip(buf_pool, buf)); - - /* Do not recombine blocks if there are few free blocks. - We may waste up to 15360*max_len bytes to free blocks - (1024 + 2048 + 4096 + 8192 = 15360) */ - if (UT_LIST_GET_LEN(buf_pool->zip_free[i]) < 16) { - goto func_exit; - } - - /* Try to combine adjacent blocks. */ - buddy = reinterpret_cast<buf_buddy_free_t*>( - buf_buddy_get(reinterpret_cast<byte*>(buf), - BUF_BUDDY_LOW << i)); - - switch (buf_buddy_is_free(buddy, i)) { - case BUF_BUDDY_STATE_FREE: - /* The buddy is free: recombine */ - buf_buddy_remove_from_free(buf_pool, buddy, i); -buddy_is_free: - ut_ad(!buf_pool_contains_zip(buf_pool, buddy)); - i++; - buf = ut_align_down(buf, BUF_BUDDY_LOW << i); - - goto recombine; - - case BUF_BUDDY_STATE_USED: - ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i)); - - /* The buddy is not free. Is there a free block of - this size? */ - if (buf_buddy_free_t* zip_buf = - UT_LIST_GET_FIRST(buf_pool->zip_free[i])) { - - /* Remove the block from the free list, because - a successful buf_buddy_relocate() will overwrite - zip_free->list. */ - buf_buddy_remove_from_free(buf_pool, zip_buf, i); - - /* Try to relocate the buddy of buf to the free - block. */ - if (buf_buddy_relocate(buf_pool, buddy, zip_buf, i)) { - - goto buddy_is_free; - } - - buf_buddy_add_to_free(buf_pool, zip_buf, i); - } - - break; - case BUF_BUDDY_STATE_PARTIALLY_USED: - /* Some sub-blocks in the buddy are still in use. - Relocation will fail. No need to try. */ - break; - } - -func_exit: - /* Free the block to the buddy list. */ - buf_buddy_add_to_free(buf_pool, - reinterpret_cast<buf_buddy_free_t*>(buf), - i); - mutex_exit(&buf_pool->zip_free_mutex); -} |