Commit eb032974 authored by marko's avatar marko

branches/zip: buf_page_init_for_read(): Defer the costly calls to

buf_buddy_alloc() until after the block has been found not to exist
in the buffer pool.

buf_buddy_alloc(), buf_buddy_alloc_low(): Make lru an output parameter.
Improve documentation.

buf_page_init_for_read(): Simplify the code.  Check buf_page_hash_get()
again if buf_buddy_alloc() released buf_pool->mutex.
parent b36300e1
...@@ -356,16 +356,21 @@ buf_buddy_alloc_clean( ...@@ -356,16 +356,21 @@ buf_buddy_alloc_clean(
} }
/************************************************************************** /**************************************************************************
Allocate a block. */ Allocate a block. The thread calling this function must hold
buf_pool->mutex and must not hold buf_pool->zip_mutex or any block->mutex.
The buf_pool->mutex may only be released and reacquired if lru != NULL. */
void* void*
buf_buddy_alloc_low( buf_buddy_alloc_low(
/*================*/ /*================*/
/* out: allocated block, or NULL /* out: allocated block,
if buf_pool->zip_free[] was empty */ possibly NULL if lru==NULL */
ulint i, /* in: index of buf_pool->zip_free[], ulint i, /* in: index of buf_pool->zip_free[],
or BUF_BUDDY_SIZES */ or BUF_BUDDY_SIZES */
ibool lru) /* in: TRUE=allocate from the LRU list if needed */ ibool* lru) /* in: pointer to a variable that will be assigned
TRUE if storage was allocated from the LRU list
and buf_pool->mutex was temporarily released,
or NULL if the LRU list should not be used */
{ {
buf_block_t* block; buf_block_t* block;
...@@ -407,6 +412,7 @@ buf_buddy_alloc_low( ...@@ -407,6 +412,7 @@ buf_buddy_alloc_low(
/* Try replacing an uncompressed page in the buffer pool. */ /* Try replacing an uncompressed page in the buffer pool. */
mutex_exit(&buf_pool->mutex); mutex_exit(&buf_pool->mutex);
block = buf_LRU_get_free_block(0); block = buf_LRU_get_free_block(0);
*lru = TRUE;
mutex_enter(&buf_pool->mutex); mutex_enter(&buf_pool->mutex);
alloc_big: alloc_big:
......
...@@ -2341,6 +2341,8 @@ buf_page_init_for_read( ...@@ -2341,6 +2341,8 @@ buf_page_init_for_read(
buf_block_t* block; buf_block_t* block;
buf_page_t* bpage; buf_page_t* bpage;
mtr_t mtr; mtr_t mtr;
ibool lru = FALSE;
void* data;
ut_ad(buf_pool); ut_ad(buf_pool);
...@@ -2365,46 +2367,25 @@ buf_page_init_for_read( ...@@ -2365,46 +2367,25 @@ buf_page_init_for_read(
} }
if (zip_size && UNIV_LIKELY(!recv_recovery_is_on())) { if (zip_size && UNIV_LIKELY(!recv_recovery_is_on())) {
void* data;
mutex_enter(&buf_pool->mutex);
/* This must be allocated before bpage, in order to
avoid the invocation of buf_buddy_relocate_block()
on uninitialized data. */
data = buf_buddy_alloc(zip_size, TRUE);
bpage = buf_buddy_alloc(sizeof *bpage, TRUE);
page_zip_des_init(&bpage->zip);
page_zip_set_size(&bpage->zip, zip_size);
bpage->zip.data = data;
block = NULL; block = NULL;
mutex_enter(&buf_pool->zip_mutex);
} else { } else {
block = buf_LRU_get_free_block(0); block = buf_LRU_get_free_block(0);
ut_ad(block); ut_ad(block);
bpage = &block->page;
mutex_enter(&buf_pool->mutex);
mutex_enter(&block->mutex);
} }
mutex_enter(&buf_pool->mutex);
if (buf_page_hash_get(space, offset)) { if (buf_page_hash_get(space, offset)) {
/* The page is already in the buffer pool. */ /* The page is already in the buffer pool. */
err_exit: err_exit:
if (block) { if (block) {
mutex_enter(&block->mutex);
buf_LRU_block_free_non_file_page(block); buf_LRU_block_free_non_file_page(block);
mutex_exit(&buf_pool->mutex);
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
} else { }
void* data = bpage->zip.data;
bpage->zip.data = NULL;
mutex_exit(&buf_pool->zip_mutex); err_exit2:
buf_buddy_free(data, zip_size);
buf_buddy_free(bpage, sizeof *bpage);
mutex_exit(&buf_pool->mutex); mutex_exit(&buf_pool->mutex);
}
if (mode == BUF_READ_IBUF_PAGES_ONLY) { if (mode == BUF_READ_IBUF_PAGES_ONLY) {
...@@ -2424,7 +2405,9 @@ buf_page_init_for_read( ...@@ -2424,7 +2405,9 @@ buf_page_init_for_read(
} }
if (block) { if (block) {
buf_page_init(space, offset, (buf_block_t*) bpage); bpage = &block->page;
mutex_enter(&block->mutex);
buf_page_init(space, offset, block);
/* The block must be put to the LRU list, to the old blocks */ /* The block must be put to the LRU list, to the old blocks */
buf_LRU_add_block(bpage, TRUE/* to old blocks */); buf_LRU_add_block(bpage, TRUE/* to old blocks */);
...@@ -2438,12 +2421,11 @@ buf_page_init_for_read( ...@@ -2438,12 +2421,11 @@ buf_page_init_for_read(
read is completed. The x-lock is cleared by the read is completed. The x-lock is cleared by the
io-handler thread. */ io-handler thread. */
rw_lock_x_lock_gen(&((buf_block_t*) bpage)->lock, BUF_IO_READ); rw_lock_x_lock_gen(&block->lock, BUF_IO_READ);
if (UNIV_UNLIKELY(zip_size)) { if (UNIV_UNLIKELY(zip_size)) {
void* data;
page_zip_set_size(&block->page.zip, zip_size); page_zip_set_size(&block->page.zip, zip_size);
mutex_exit(&block->mutex);
/* buf_pool->mutex may be released and /* buf_pool->mutex may be released and
reacquired by buf_buddy_alloc(). Thus, we reacquired by buf_buddy_alloc(). Thus, we
must release block->mutex in order not to must release block->mutex in order not to
...@@ -2452,27 +2434,51 @@ buf_page_init_for_read( ...@@ -2452,27 +2434,51 @@ buf_page_init_for_read(
operation until after the block descriptor has operation until after the block descriptor has
been added to buf_pool->LRU and been added to buf_pool->LRU and
buf_pool->page_hash. */ buf_pool->page_hash. */
data = buf_buddy_alloc(zip_size, TRUE); mutex_exit(&block->mutex);
data = buf_buddy_alloc(zip_size, &lru);
mutex_enter(&block->mutex); mutex_enter(&block->mutex);
block->page.zip.data = data; block->page.zip.data = data;
} }
buf_page_set_io_fix(bpage, BUF_IO_READ); buf_page_set_io_fix(bpage, BUF_IO_READ);
buf_pool->n_pend_reads++;
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
mutex_exit(&buf_pool->mutex);
} else { } else {
/* Defer buf_buddy_alloc() until after the block has
been found not to exist. The buf_buddy_alloc() and
buf_buddy_free() calls may be expensive because of
buf_buddy_relocate(). */
/* The compressed page must be allocated before the
control block (bpage), in order to avoid the
invocation of buf_buddy_relocate_block() on
uninitialized data. */
data = buf_buddy_alloc(zip_size, &lru);
bpage = buf_buddy_alloc(sizeof *bpage, &lru);
/* If buf_buddy_alloc() allocated storage from the LRU list,
it released and reacquired buf_pool->mutex. Thus, we must
check the page_hash again, as it may have been modified. */
if (UNIV_UNLIKELY(lru)
&& UNIV_LIKELY_NULL(buf_page_hash_get(space, offset))) {
/* The block was added by some other thread. */
buf_buddy_free(data, zip_size);
buf_buddy_free(bpage, sizeof *bpage);
goto err_exit2;
}
page_zip_des_init(&bpage->zip);
page_zip_set_size(&bpage->zip, zip_size);
bpage->zip.data = data;
mutex_enter(&buf_pool->zip_mutex);
UNIV_MEM_DESC(bpage->zip.data, UNIV_MEM_DESC(bpage->zip.data,
page_zip_get_size(&bpage->zip), bpage); page_zip_get_size(&bpage->zip), bpage);
buf_page_init_low(bpage); buf_page_init_low(bpage);
bpage->state = BUF_BLOCK_ZIP_PAGE; bpage->state = BUF_BLOCK_ZIP_PAGE;
bpage->space = space; bpage->space = space;
bpage->offset = offset; bpage->offset = offset;
#ifdef UNIV_DEBUG_FILE_ACCESSES
bpage->file_page_was_freed = FALSE;
#endif /* UNIV_DEBUG_FILE_ACCESSES */
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
bpage->in_page_hash = FALSE; bpage->in_page_hash = FALSE;
...@@ -2492,12 +2498,12 @@ buf_page_init_for_read( ...@@ -2492,12 +2498,12 @@ buf_page_init_for_read(
buf_page_set_io_fix(bpage, BUF_IO_READ); buf_page_set_io_fix(bpage, BUF_IO_READ);
buf_pool->n_pend_reads++;
mutex_exit(&buf_pool->zip_mutex); mutex_exit(&buf_pool->zip_mutex);
mutex_exit(&buf_pool->mutex);
} }
buf_pool->n_pend_reads++;
mutex_exit(&buf_pool->mutex);
if (mode == BUF_READ_IBUF_PAGES_ONLY) { if (mode == BUF_READ_IBUF_PAGES_ONLY) {
mtr_commit(&mtr); mtr_commit(&mtr);
...@@ -2575,6 +2581,7 @@ buf_page_create( ...@@ -2575,6 +2581,7 @@ buf_page_create(
if (zip_size) { if (zip_size) {
void* data; void* data;
ibool lru;
/* Prevent race conditions during buf_buddy_alloc(), /* Prevent race conditions during buf_buddy_alloc(),
which may release and reacquire buf_pool->mutex, which may release and reacquire buf_pool->mutex,
...@@ -2591,7 +2598,7 @@ buf_page_create( ...@@ -2591,7 +2598,7 @@ buf_page_create(
the reacquisition of buf_pool->mutex. We also must the reacquisition of buf_pool->mutex. We also must
defer this operation until after the block descriptor defer this operation until after the block descriptor
has been added to buf_pool->LRU and buf_pool->page_hash. */ has been added to buf_pool->LRU and buf_pool->page_hash. */
data = buf_buddy_alloc(zip_size, TRUE); data = buf_buddy_alloc(zip_size, &lru);
mutex_enter(&block->mutex); mutex_enter(&block->mutex);
block->page.zip.data = data; block->page.zip.data = data;
......
...@@ -492,8 +492,9 @@ buf_LRU_get_free_block( ...@@ -492,8 +492,9 @@ buf_LRU_get_free_block(
block->page.zip.n_blobs = 0; block->page.zip.n_blobs = 0;
if (zip_size) { if (zip_size) {
ibool lru;
page_zip_set_size(&block->page.zip, zip_size); page_zip_set_size(&block->page.zip, zip_size);
block->page.zip.data = buf_buddy_alloc(zip_size, TRUE); block->page.zip.data = buf_buddy_alloc(zip_size, &lru);
UNIV_MEM_DESC(block->page.zip.data, zip_size, block); UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
} else { } else {
page_zip_set_size(&block->page.zip, 0); page_zip_set_size(&block->page.zip, 0);
...@@ -924,9 +925,9 @@ buf_LRU_free_block( ...@@ -924,9 +925,9 @@ buf_LRU_free_block(
If it cannot be allocated (without freeing a block If it cannot be allocated (without freeing a block
from the LRU list), refuse to free bpage. */ from the LRU list), refuse to free bpage. */
alloc: alloc:
b = buf_buddy_alloc(sizeof *b, FALSE); b = buf_buddy_alloc(sizeof *b, NULL);
if (!b) { if (UNIV_UNLIKELY(!b)) {
return(FALSE); return(FALSE);
} }
} }
......
...@@ -18,14 +18,21 @@ Created December 2006 by Marko Makela ...@@ -18,14 +18,21 @@ Created December 2006 by Marko Makela
#include "buf0types.h" #include "buf0types.h"
/************************************************************************** /**************************************************************************
Allocate a block. */ Allocate a block. The thread calling this function must hold
buf_pool->mutex and must not hold buf_pool->zip_mutex or any block->mutex.
The buf_pool->mutex may only be released and reacquired if
lru == BUF_BUDDY_USE_LRU. */
UNIV_INLINE UNIV_INLINE
void* void*
buf_buddy_alloc( buf_buddy_alloc(
/*============*/ /*============*/
/* out: pointer to the start of the block */ /* out: allocated block,
possibly NULL if lru == NULL */
ulint size, /* in: block size, up to UNIV_PAGE_SIZE */ ulint size, /* in: block size, up to UNIV_PAGE_SIZE */
ibool lru) /* in: TRUE=allocate from the LRU list if needed */ ibool* lru) /* in: pointer to a variable that will be assigned
TRUE if storage was allocated from the LRU list
and buf_pool->mutex was temporarily released,
or NULL if the LRU list should not be used */
__attribute__((malloc)); __attribute__((malloc));
/************************************************************************** /**************************************************************************
......
...@@ -17,15 +17,22 @@ Created December 2006 by Marko Makela ...@@ -17,15 +17,22 @@ Created December 2006 by Marko Makela
#include "sync0sync.h" #include "sync0sync.h"
/************************************************************************** /**************************************************************************
Allocate a block. */ Allocate a block. The thread calling this function must hold
buf_pool->mutex and must not hold buf_pool->zip_mutex or any block->mutex.
The buf_pool->mutex may only be released and reacquired if
lru == BUF_BUDDY_USE_LRU. */
void* void*
buf_buddy_alloc_low( buf_buddy_alloc_low(
/*================*/ /*================*/
/* out: pointer to the start of the block */ /* out: allocated block,
possibly NULL if lru==NULL */
ulint i, /* in: index of buf_pool->zip_free[], ulint i, /* in: index of buf_pool->zip_free[],
or BUF_BUDDY_SIZES */ or BUF_BUDDY_SIZES */
ibool lru) /* in: TRUE=allocate from the LRU list if needed */ ibool* lru) /* in: pointer to a variable that will be assigned
TRUE if storage was allocated from the LRU list
and buf_pool->mutex was temporarily released,
or NULL if the LRU list should not be used */
__attribute__((malloc)); __attribute__((malloc));
/************************************************************************** /**************************************************************************
...@@ -60,14 +67,21 @@ buf_buddy_get_slot( ...@@ -60,14 +67,21 @@ buf_buddy_get_slot(
} }
/************************************************************************** /**************************************************************************
Allocate a block. */ Allocate a block. The thread calling this function must hold
buf_pool->mutex and must not hold buf_pool->zip_mutex or any block->mutex.
The buf_pool->mutex may only be released and reacquired if
lru == BUF_BUDDY_USE_LRU. */
UNIV_INLINE UNIV_INLINE
void* void*
buf_buddy_alloc( buf_buddy_alloc(
/*============*/ /*============*/
/* out: pointer to the start of the block */ /* out: allocated block,
possibly NULL if lru == NULL */
ulint size, /* in: block size, up to UNIV_PAGE_SIZE */ ulint size, /* in: block size, up to UNIV_PAGE_SIZE */
ibool lru) /* in: TRUE=allocate from the LRU list if needed */ ibool* lru) /* in: pointer to a variable that will be assigned
TRUE if storage was allocated from the LRU list
and buf_pool->mutex was temporarily released,
or NULL if the LRU list should not be used */
{ {
ut_ad(mutex_own(&buf_pool->mutex)); ut_ad(mutex_own(&buf_pool->mutex));
......
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