Commit 97c15d9f authored by marko's avatar marko

branches/zip: When shrinking the buffer pool, disable and purge the adaptive

hash index, because it might occupy the chunk we would like to free.

TODO: In btr_search_check_free_space_in_heap(), release the block if
btr_search_latch is not immediately available.

buf_pool_shrink(): Split from buf_pool_resize().

btr_search_disabled: New variable, similar to srv_use_adaptive_hash_indexes
that was removed earlier.

btr_search_disable(): New function: disable and purge the adaptive hash index.

btr_search_enable(): New function: enable the adaptive hash index.

ha_clear(): New function: Empty a hash table and free the memory heaps.
parent a9ffc8a7
......@@ -369,6 +369,7 @@ btr_cur_search_to_nth_level(
#ifdef PAGE_CUR_LE_OR_EXTENDS
&& mode != PAGE_CUR_LE_OR_EXTENDS
#endif /* PAGE_CUR_LE_OR_EXTENDS */
&& !UNIV_UNLIKELY(btr_search_disabled)
&& btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor,
has_search_latch, mtr)) {
......@@ -603,7 +604,10 @@ retry_page_get:
cursor->up_bytes = up_bytes;
#ifdef BTR_CUR_ADAPT
btr_search_info_update(index, cursor);
if (!UNIV_UNLIKELY(btr_search_disabled)) {
btr_search_info_update(index, cursor);
}
#endif
ut_ad(cursor->up_match != ULINT_UNDEFINED
|| mode != PAGE_CUR_GE);
......
......@@ -19,6 +19,9 @@ Created 2/17/1996 Heikki Tuuri
#include "btr0btr.h"
#include "ha0ha.h"
/* Flag: has the search system been disabled? */
ibool btr_search_disabled = FALSE;
ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
compiler */
......@@ -143,6 +146,31 @@ btr_search_sys_create(
}
/************************************************************************
Disable the adaptive hash search system and empty the index. */
void
btr_search_disable(void)
/*====================*/
{
btr_search_disabled = TRUE;
rw_lock_x_lock(&btr_search_latch);
ha_clear(btr_search_sys->hash_index);
rw_lock_x_unlock(&btr_search_latch);
}
/************************************************************************
Enable the adaptive hash search system. */
void
btr_search_enable(void)
/*====================*/
{
btr_search_disabled = FALSE;
}
/*********************************************************************
Creates and initializes a search info struct. */
......
......@@ -900,163 +900,191 @@ buf_pool_init(void)
}
/************************************************************************
Resizes the buffer pool. */
Shrinks the buffer pool. */
static
void
buf_pool_resize(void)
/*=================*/
buf_pool_shrink(
/*============*/
/* out: TRUE if shrunk */
ulint chunk_size) /* in: number of pages to remove */
{
buf_chunk_t* chunks;
buf_chunk_t* chunk;
ulint max_size;
ulint max_free_size;
buf_chunk_t* max_chunk;
buf_chunk_t* max_free_chunk;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!mutex_own(&buf_pool->mutex));
#endif /* UNIV_SYNC_DEBUG */
try_again:
btr_search_disable(); /* Empty the adaptive hash index again */
mutex_enter(&buf_pool->mutex);
if (srv_buf_pool_old_size == srv_buf_pool_size) {
shrink_again:
if (buf_pool->n_chunks <= 1) {
goto func_exit;
/* Cannot shrink if there is only one chunk */
goto func_done;
}
if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) {
/* Search for the largest free chunk
not larger than the size difference */
chunks = buf_pool->chunks;
chunk = chunks + buf_pool->n_chunks;
max_size = max_free_size = 0;
max_chunk = max_free_chunk = NULL;
while (--chunk >= chunks) {
if (chunk->size <= chunk_size
&& chunk->size > max_free_size) {
if (chunk->size > max_size) {
max_size = chunk->size;
max_chunk = chunk;
}
/* Shrink the buffer pool by at least one megabyte */
if (buf_chunk_all_free(chunk)) {
max_free_size = chunk->size;
max_free_chunk = chunk;
}
}
}
ulint chunk_size
= (srv_buf_pool_curr_size - srv_buf_pool_size)
/ UNIV_PAGE_SIZE;
ulint max_size;
ulint max_free_size;
buf_chunk_t* max_chunk;
buf_chunk_t* max_free_chunk;
if (!max_free_size) {
shrink_again:
if (buf_pool->n_chunks <= 1) {
ulint dirty = 0;
ulint nonfree = 0;
buf_block_t* block;
buf_block_t* bend;
/* Cannot shrink: try again later
(do not assign srv_buf_pool_old_size) */
if (!max_chunk) {
/* Cannot shrink if there is only one chunk */
goto func_done;
goto func_exit;
}
/* Search for the largest free chunk
not larger than the size difference */
chunks = buf_pool->chunks;
chunk = chunks + buf_pool->n_chunks;
max_size = max_free_size = 0;
max_chunk = max_free_chunk = NULL;
while (--chunk >= chunks) {
if (chunk->size <= chunk_size
&& chunk->size > max_free_size) {
if (chunk->size > max_size) {
max_size = chunk->size;
max_chunk = chunk;
}
block = max_chunk->blocks;
bend = block + max_chunk->size;
if (buf_chunk_all_free(chunk)) {
max_free_size = chunk->size;
max_free_chunk = chunk;
}
/* Move the blocks of chunk to the end of the
LRU list and try to flush them. */
for (; block < bend; block++) {
switch (block->state) {
case BUF_BLOCK_NOT_USED:
continue;
case BUF_BLOCK_FILE_PAGE:
break;
default:
nonfree++;
continue;
}
mutex_enter(&block->mutex);
/* The following calls will temporarily
release block->mutex and buf_pool->mutex.
Therefore, we have to always retry,
even if !dirty && !nonfree. */
if (!buf_flush_ready_for_replace(block)) {
buf_LRU_make_block_old(block);
dirty++;
} else if (!buf_LRU_free_block(block)) {
nonfree++;
}
mutex_exit(&block->mutex);
}
if (!max_free_size) {
mutex_exit(&buf_pool->mutex);
ulint dirty = 0;
ulint nonfree = 0;
buf_block_t* block;
buf_block_t* bend;
/* Request for a flush of the chunk if it helps.
Do not flush if there are non-free blocks, since
flushing will not make the chunk freeable. */
if (nonfree) {
/* Avoid busy-waiting. */
os_thread_sleep(100000);
} else if (dirty
&& buf_flush_batch(BUF_FLUSH_LRU, dirty,
ut_dulint_zero)
== ULINT_UNDEFINED) {
buf_flush_wait_batch_end(BUF_FLUSH_LRU);
}
/* Cannot shrink: try again later
(do not assign srv_buf_pool_old_size) */
if (!max_chunk) {
goto try_again;
}
goto func_exit;
}
max_size = max_free_size;
max_chunk = max_free_chunk;
block = max_chunk->blocks;
bend = block + max_chunk->size;
srv_buf_pool_old_size = srv_buf_pool_size;
/* Move the blocks of chunk to the end of the
LRU list and try to flush them. */
for (; block < bend; block++) {
switch (block->state) {
case BUF_BLOCK_NOT_USED:
continue;
case BUF_BLOCK_FILE_PAGE:
break;
default:
nonfree++;
continue;
}
/* Rewrite buf_pool->chunks. Copy everything but max_chunk. */
chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks);
memcpy(chunks, buf_pool->chunks,
(max_chunk - buf_pool->chunks) * sizeof *chunks);
memcpy(chunks + (max_chunk - buf_pool->chunks),
max_chunk + 1,
buf_pool->chunks + buf_pool->n_chunks
- (max_chunk + 1));
ut_a(buf_pool->curr_size > max_chunk->size);
buf_pool->curr_size -= max_chunk->size;
srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
chunk_size -= max_chunk->size;
buf_chunk_free(max_chunk);
mem_free(buf_pool->chunks);
buf_pool->chunks = chunks;
buf_pool->n_chunks--;
mutex_enter(&block->mutex);
/* The following calls will temporarily
release block->mutex and buf_pool->mutex.
Therefore, we have to always retry,
even if !dirty && !nonfree. */
/* Allow a slack of one megabyte. */
if (chunk_size > 1048576 / UNIV_PAGE_SIZE) {
if (!buf_flush_ready_for_replace(block)) {
goto shrink_again;
}
buf_LRU_make_block_old(block);
dirty++;
} else if (!buf_LRU_free_block(block)) {
nonfree++;
}
func_done:
srv_buf_pool_old_size = srv_buf_pool_size;
func_exit:
mutex_exit(&buf_pool->mutex);
btr_search_enable();
}
mutex_exit(&block->mutex);
}
/************************************************************************
Resizes the buffer pool. */
mutex_exit(&buf_pool->mutex);
void
buf_pool_resize(void)
/*=================*/
{
mutex_enter(&buf_pool->mutex);
/* Request for a flush of the chunk if it helps.
Do not flush if there are non-free blocks, since
flushing will not make the chunk freeable. */
if (nonfree) {
/* Avoid busy-waiting. */
os_thread_sleep(100000);
} else if (dirty
&& buf_flush_batch(BUF_FLUSH_LRU, dirty,
ut_dulint_zero)
== ULINT_UNDEFINED) {
buf_flush_wait_batch_end(BUF_FLUSH_LRU);
}
if (srv_buf_pool_old_size == srv_buf_pool_size) {
goto try_again;
}
mutex_exit(&buf_pool->mutex);
return;
}
max_size = max_free_size;
max_chunk = max_free_chunk;
if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) {
srv_buf_pool_old_size = srv_buf_pool_size;
mutex_exit(&buf_pool->mutex);
/* Rewrite buf_pool->chunks. Copy everything but max_chunk. */
chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks);
memcpy(chunks, buf_pool->chunks,
(max_chunk - buf_pool->chunks) * sizeof *chunks);
memcpy(chunks + (max_chunk - buf_pool->chunks),
max_chunk + 1,
buf_pool->chunks + buf_pool->n_chunks
- (max_chunk + 1));
ut_a(buf_pool->curr_size > max_chunk->size);
buf_pool->curr_size -= max_chunk->size;
srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
chunk_size -= max_chunk->size;
buf_chunk_free(max_chunk);
mem_free(buf_pool->chunks);
buf_pool->chunks = chunks;
buf_pool->n_chunks--;
/* Allow a slack of one megabyte. */
if (chunk_size > 1048576 / UNIV_PAGE_SIZE) {
goto shrink_again;
}
/* Disable adaptive hash indexes and empty the index
in order to free up memory in the buffer pool chunks. */
buf_pool_shrink((srv_buf_pool_curr_size - srv_buf_pool_size)
/ UNIV_PAGE_SIZE);
return;
} else if (srv_buf_pool_curr_size + 1048576 < srv_buf_pool_size) {
/* Enlarge the buffer pool by at least one megabyte */
ulint mem_size
= srv_buf_pool_size - srv_buf_pool_curr_size;
buf_chunk_t* chunks;
buf_chunk_t* chunk;
chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks);
......@@ -1075,15 +1103,12 @@ shrink_again:
buf_pool->chunks = chunks;
buf_pool->n_chunks++;
}
srv_buf_pool_old_size = srv_buf_pool_size;
mutex_exit(&buf_pool->mutex);
}
/* TODO: reinitialize buf_pool->page_hash */
func_done:
srv_buf_pool_old_size = srv_buf_pool_size;
func_exit:
mutex_exit(&buf_pool->mutex);
}
/************************************************************************
......
......@@ -62,6 +62,36 @@ ha_create_func(
return(table);
}
/*****************************************************************
Empties a hash table and frees the memory heaps. */
void
ha_clear(
/*=====*/
hash_table_t* table) /* in, own: hash table */
{
ulint i;
ulint n;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
#endif /* UNIV_SYNC_DEBUG */
/* Free the memory heaps. */
n = table->n_mutexes;
for (i = 0; i < n; i++) {
mem_heap_free(table->heaps[i]);
}
/* Clear the hash table. */
n = hash_get_n_cells(table);
for (i = 0; i < n; i++) {
hash_get_nth_cell(table, i)->node = NULL;
}
}
/*****************************************************************
Inserts an entry into a hash table. If an entry with the same fold number
is found, its node is updated to point to the new data, and no new node
......
......@@ -24,6 +24,20 @@ void
btr_search_sys_create(
/*==================*/
ulint hash_size); /* in: hash index hash table size */
/************************************************************************
Disable the adaptive hash search system and empty the index. */
void
btr_search_disable(void);
/*====================*/
/************************************************************************
Enable the adaptive hash search system. */
void
btr_search_enable(void);
/*====================*/
/************************************************************************
Returns search info for an index. */
UNIV_INLINE
......@@ -140,6 +154,9 @@ btr_search_validate(void);
/*======================*/
/* out: TRUE if ok */
/* Flag: has the search system been disabled? */
extern ibool btr_search_disabled;
/* The search info struct in an index */
struct btr_search_struct{
......
......@@ -68,6 +68,15 @@ ha_create_func(
#else /* UNIV_SYNC_DEBUG */
# define ha_create(n_c,n_m,level) ha_create_func(n_c,n_m)
#endif /* UNIV_SYNC_DEBUG */
/*****************************************************************
Empties a hash table and frees the memory heaps. */
void
ha_clear(
/*=====*/
hash_table_t* table); /* in, own: hash table */
/*****************************************************************
Inserts an entry into a hash table. If an entry with the same fold number
is found, its node is updated to point to the new data, and no new node
......
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