diff --git a/buf/buf0buf.c b/buf/buf0buf.c index 9fb495e3178..25ad81505e4 100644 --- a/buf/buf0buf.c +++ b/buf/buf0buf.c @@ -215,6 +215,15 @@ ibool buf_debug_prints = FALSE; /* If this is set TRUE, read-ahead or flush occurs */ #endif /* UNIV_DEBUG */ +/* A chunk of buffers. The buffer pool is allocated in chunks. */ +struct buf_chunk_struct{ + ulint mem_size; /* allocated size of the chunk */ + ulint size; /* size of frames[] and blocks[] */ + void* mem; /* pointer to the memory area which + was allocated for the frames */ + buf_block_t* blocks; /* array of buffer control blocks */ +}; + /************************************************************************ Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value on @@ -626,19 +635,195 @@ buf_block_init( #endif /* UNIV_SYNC_DEBUG */ } +/************************************************************************ +Allocates a chunk of buffer frames. */ +static +buf_chunk_t* +buf_chunk_init( +/*===========*/ + /* out: chunk, or NULL on failure */ + buf_chunk_t* chunk, /* out: chunk of buffers */ + ulint mem_size) /* in: requested size in bytes */ +{ + buf_block_t* block; + byte* frame; + ulint i; + + /* Round down to a multiple of page size, + although it already should be. */ + mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE); + /* Reserve space for the block descriptors. */ + mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block) + + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); + + chunk->mem_size = mem_size; + chunk->mem = os_mem_alloc_large(&chunk->mem_size); + + if (UNIV_UNLIKELY(chunk->mem == NULL)) { + + return(NULL); + } + + /* Allocate the block descriptors from + the start of the memory block. */ + chunk->blocks = chunk->mem; + + /* Align pointer to the first frame */ + + frame = ut_align(chunk->mem, UNIV_PAGE_SIZE); + chunk->size = chunk->mem_size / UNIV_PAGE_SIZE + - (frame != chunk->mem); + + /* Subtract the space needed for block descriptors. */ + { + ulint size = chunk->size; + + while (frame < (byte*) (chunk->blocks + size)) { + frame += UNIV_PAGE_SIZE; + size--; + } + + chunk->size = size; + } + + /* Init block structs and assign frames for them. Then we + assign the frames to the first blocks (we already mapped the + memory above). */ + + block = chunk->blocks; + + for (i = chunk->size; i--; ) { + + buf_block_init(block, frame); + +#ifdef HAVE_purify + /* Wipe contents of frame to eliminate a Purify warning */ + memset(block->frame, '\0', UNIV_PAGE_SIZE); +#endif + /* Add the block to the free list */ + UT_LIST_ADD_LAST(free, buf_pool->free, block); + block->in_free_list = TRUE; + + block++; + frame += UNIV_PAGE_SIZE; + } + + return(chunk); +} + +/************************************************************************* +Checks that all file pages in the buffer chunk are in a replaceable state. */ +static +const buf_block_t* +buf_chunk_not_freed( +/*================*/ + /* out: address of a non-free block, + or NULL if all freed */ + buf_chunk_t* chunk) /* in: chunk being checked */ +{ + buf_block_t* block; + ulint i; + + ut_ad(buf_pool); +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(buf_pool->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + block = chunk->blocks; + + for (i = chunk->size; i--; block++) { + mutex_enter(&block->mutex); + + if (block->state == BUF_BLOCK_FILE_PAGE + && !buf_flush_ready_for_replace(block)) { + + mutex_exit(&block->mutex); + return(block); + } + + mutex_exit(&block->mutex); + } + + return(NULL); +} + +/************************************************************************* +Checks that all blocks in the buffer chunk are in BUF_BLOCK_NOT_USED state. */ +static +ibool +buf_chunk_all_free( +/*===============*/ + /* out: TRUE if all freed */ + const buf_chunk_t* chunk) /* in: chunk being checked */ +{ + const buf_block_t* block; + ulint i; + + ut_ad(buf_pool); +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(buf_pool->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + block = chunk->blocks; + + for (i = chunk->size; i--; block++) { + + if (block->state != BUF_BLOCK_NOT_USED) { + + return(FALSE); + } + } + + return(TRUE); +} + +/************************************************************************ +Frees a chunk of buffer frames. */ +static +void +buf_chunk_free( +/*===========*/ + buf_chunk_t* chunk) /* out: chunk of buffers */ +{ + buf_block_t* block; + const buf_block_t* block_end; + +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(buf_pool->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + block_end = chunk->blocks + chunk->size; + + for (block = chunk->blocks; block < block_end; block++) { + ut_a(block->state == BUF_BLOCK_NOT_USED); + ut_a(!block->page_zip.data); + + /* Remove the block from the free list. */ + ut_a(block->in_free_list); + UT_LIST_REMOVE(free, buf_pool->free, block); + + /* Free the latches. */ + mutex_free(&block->mutex); + rw_lock_free(&block->lock); +#ifdef UNIV_SYNC_DEBUG + rw_lock_free(&block->debug_latch); +#endif /* UNIV_SYNC_DEBUG */ + } + + os_mem_free_large(chunk->mem, chunk->mem_size); +} + /************************************************************************ Creates the buffer pool. */ buf_pool_t* -buf_pool_init( -/*==========*/ +buf_pool_init(void) +/*===============*/ /* out, own: buf_pool object, NULL if not enough memory or error */ - ulint curr_size) /* in: current size to use */ { - byte* frame; + buf_chunk_t* chunk; ulint i; - buf_block_t* block; buf_pool = mem_alloc(sizeof(buf_pool_t)); @@ -648,49 +833,23 @@ buf_pool_init( mutex_enter(&(buf_pool->mutex)); - buf_pool->frame_mem_size = (curr_size + 1) * UNIV_PAGE_SIZE; + buf_pool->n_chunks = 1; + buf_pool->chunks = chunk = mem_alloc(sizeof *chunk); - buf_pool->frame_mem = os_mem_alloc_large(&buf_pool->frame_mem_size); - - if (UNIV_UNLIKELY(buf_pool->frame_mem == NULL)) { + UT_LIST_INIT(buf_pool->free); + if (!buf_chunk_init(chunk, srv_buf_pool_size)) { + mem_free(chunk); + mem_free(buf_pool); + buf_pool = NULL; return(NULL); } - /* Align pointer to the first frame */ + srv_buf_pool_old_size = srv_buf_pool_size; + buf_pool->curr_size = chunk->size; + srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; - frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE); - - curr_size = buf_pool->frame_mem_size / UNIV_PAGE_SIZE - - (frame != buf_pool->frame_mem); - - buf_pool->blocks = ut_malloc(sizeof(buf_block_t) * curr_size); - - if (UNIV_UNLIKELY(buf_pool->blocks == NULL)) { - - os_mem_free_large(buf_pool->frame_mem, - buf_pool->frame_mem_size); - buf_pool->frame_mem = NULL; - - return(NULL); - } - - buf_pool->curr_size = curr_size; - - /* Init block structs and assign frames for them. Then we - assign the frames to the first blocks (we already mapped the - memory above). */ - - for (i = 0; i < curr_size; i++) { - - block = buf_pool_get_nth_block(buf_pool, i); - - buf_block_init(block, frame); - - frame += UNIV_PAGE_SIZE; - } - - buf_pool->page_hash = hash_create(2 * curr_size); + buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); buf_pool->n_pend_reads = 0; @@ -727,33 +886,130 @@ buf_pool_init( buf_pool->LRU_old = NULL; - /* Add control blocks to the free list */ - UT_LIST_INIT(buf_pool->free); - - for (i = 0; i < curr_size; i++) { - - block = buf_pool_get_nth_block(buf_pool, i); - - if (block->frame) { - /* Wipe contents of frame to eliminate a Purify - warning */ - -#ifdef HAVE_purify - memset(block->frame, '\0', UNIV_PAGE_SIZE); -#endif - } - - UT_LIST_ADD_LAST(free, buf_pool->free, block); - block->in_free_list = TRUE; - } - mutex_exit(&(buf_pool->mutex)); - btr_search_sys_create(curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64); + btr_search_sys_create(buf_pool->curr_size + * UNIV_PAGE_SIZE / sizeof(void*) / 64); return(buf_pool); } +/************************************************************************ +Resizes the buffer pool. */ + +void +buf_pool_resize(void) +/*=================*/ +{ + buf_chunk_t* chunks; + buf_chunk_t* chunk; + + mutex_enter(&buf_pool->mutex); + + if (srv_buf_pool_old_size == srv_buf_pool_size) { + + goto func_exit; + } + + if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) { + + /* Shrink the buffer pool by at least one megabyte */ + + ulint chunk_size + = (srv_buf_pool_curr_size - srv_buf_pool_size) + / UNIV_PAGE_SIZE; + ulint max_size; + buf_chunk_t* max_chunk; + +shrink_again: + if (buf_pool->n_chunks <= 1) { + + /* Cannot shrink if there is only one chunk */ + goto func_done; + } + + /* Search for the largest free chunk + not larger than the size difference */ + chunks = buf_pool->chunks; + chunk = chunks + buf_pool->n_chunks; + max_size = 0; + max_chunk = NULL; + + while (--chunk >= chunks) { + if (chunk->size <= chunk_size + && chunk->size > max_size + && buf_chunk_all_free(chunk)) { + max_size = chunk->size; + max_chunk = chunk; + } + } + + if (!max_size) { + + /* Cannot shrink: try again later + (do not assign srv_buf_pool_old_size) */ + goto func_exit; + } + + srv_buf_pool_old_size = srv_buf_pool_size; + + /* 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; + } + } 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; + + chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks); + + memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks + * sizeof *chunks); + + chunk = &chunks[buf_pool->n_chunks]; + + if (!buf_chunk_init(chunk, mem_size)) { + mem_free(chunks); + } else { + buf_pool->curr_size += chunk->size; + srv_buf_pool_curr_size = buf_pool->curr_size + * UNIV_PAGE_SIZE; + mem_free(buf_pool->chunks); + buf_pool->chunks = chunks; + buf_pool->n_chunks++; + } + } + + /* TODO: reinitialize buf_pool->page_hash */ + +func_done: + srv_buf_pool_old_size = srv_buf_pool_size; + +func_exit: + mutex_exit(&buf_pool->mutex); +} + /************************************************************************ Moves to the block to the start of the LRU list if there is a danger that the block would drift out of the buffer pool. */ @@ -1979,7 +2235,7 @@ ibool buf_validate(void) /*==============*/ { - buf_block_t* block; + buf_chunk_t* chunk; ulint i; ulint n_single_flush = 0; ulint n_lru_flush = 0; @@ -1993,58 +2249,67 @@ buf_validate(void) mutex_enter(&(buf_pool->mutex)); - for (i = 0; i < buf_pool->curr_size; i++) { + chunk = buf_pool->chunks; - block = buf_pool_get_nth_block(buf_pool, i); + for (i = buf_pool->n_chunks; i--; chunk++) { - mutex_enter(&block->mutex); + ulint j; + buf_block_t* block = chunk->blocks; - if (block->state == BUF_BLOCK_FILE_PAGE) { + for (j = chunk->size; j--; block++) { - ut_a(buf_page_hash_get(block->space, - block->offset) == block); - n_page++; + mutex_enter(&block->mutex); + + if (block->state == BUF_BLOCK_FILE_PAGE) { + + ut_a(buf_page_hash_get(block->space, + block->offset) + == block); + n_page++; #ifdef UNIV_IBUF_DEBUG - ut_a((block->io_fix == BUF_IO_READ) - || ibuf_count_get(block->space, block->offset) - == 0); + ut_a((block->io_fix == BUF_IO_READ) + || !ibuf_count_get(block->space, + block->offset)); #endif - if (block->io_fix == BUF_IO_WRITE) { + if (block->io_fix == BUF_IO_WRITE) { - if (block->flush_type == BUF_FLUSH_LRU) { - n_lru_flush++; - ut_a(rw_lock_is_locked( - &block->lock, - RW_LOCK_SHARED)); - } else if (block->flush_type - == BUF_FLUSH_LIST) { - n_list_flush++; - } else if (block->flush_type - == BUF_FLUSH_SINGLE_PAGE) { - n_single_flush++; - } else { - ut_error; + switch (block->flush_type) { + case BUF_FLUSH_LRU: + n_lru_flush++; + ut_a(rw_lock_is_locked( + &block->lock, + RW_LOCK_SHARED)); + break; + case BUF_FLUSH_LIST: + n_list_flush++; + break; + case BUF_FLUSH_SINGLE_PAGE: + n_single_flush++; + break; + default: + ut_error; + } + + } else if (block->io_fix == BUF_IO_READ) { + + ut_a(rw_lock_is_locked(&block->lock, + RW_LOCK_EX)); } - } else if (block->io_fix == BUF_IO_READ) { + n_lru++; - ut_a(rw_lock_is_locked(&(block->lock), - RW_LOCK_EX)); + if (ut_dulint_cmp(block->oldest_modification, + ut_dulint_zero) > 0) { + n_flush++; + } + + } else if (block->state == BUF_BLOCK_NOT_USED) { + n_free++; } - n_lru++; - - if (ut_dulint_cmp(block->oldest_modification, - ut_dulint_zero) > 0) { - n_flush++; - } - - } else if (block->state == BUF_BLOCK_NOT_USED) { - n_free++; + mutex_exit(&block->mutex); } - - mutex_exit(&block->mutex); } if (n_lru + n_free > buf_pool->curr_size) { @@ -2090,7 +2355,7 @@ buf_print(void) ulint j; dulint id; ulint n_found; - buf_frame_t* frame; + buf_chunk_t* chunk; dict_index_t* index; ut_ad(buf_pool); @@ -2125,30 +2390,38 @@ buf_print(void) n_found = 0; - for (i = 0; i < size; i++) { - frame = buf_pool_get_nth_block(buf_pool, i)->frame; + chunk = buf_pool->chunks; - if (fil_page_get_type(frame) == FIL_PAGE_INDEX) { + for (i = buf_pool->n_chunks; i--; chunk++) { + buf_block_t* block = chunk->blocks; + ulint n_blocks = chunk->size; - id = btr_page_get_index_id(frame); + for (; n_blocks--; block++) { + const buf_frame_t* frame = block->frame; - /* Look for the id in the index_ids array */ - j = 0; + if (fil_page_get_type(frame) == FIL_PAGE_INDEX) { - while (j < n_found) { + id = btr_page_get_index_id(frame); - if (ut_dulint_cmp(index_ids[j], id) == 0) { - counts[j]++; + /* Look for the id in the index_ids array */ + j = 0; - break; + while (j < n_found) { + + if (ut_dulint_cmp(index_ids[j], + id) == 0) { + counts[j]++; + + break; + } + j++; } - j++; - } - if (j == n_found) { - n_found++; - index_ids[j] = id; - counts[j] = 1; + if (j == n_found) { + n_found++; + index_ids[j] = id; + counts[j] = 1; + } } } } @@ -2184,17 +2457,26 @@ Returns the number of latched pages in the buffer pool. */ ulint buf_get_latched_pages_number(void) { - buf_block_t* block; + buf_chunk_t* chunk; ulint i; ulint fixed_pages_number = 0; mutex_enter(&(buf_pool->mutex)); - for (i = 0; i < buf_pool->curr_size; i++) { + chunk = buf_pool->chunks; - block = buf_pool_get_nth_block(buf_pool, i); + for (i = buf_pool->n_chunks; i--; chunk++) { + buf_block_t* block; + ulint j; + + block = chunk->blocks; + + for (j = chunk->size; j--; block++) { + if (block->magic_n != BUF_BLOCK_MAGIC_N) { + + continue; + } - if (block->magic_n == BUF_BLOCK_MAGIC_N) { mutex_enter(&block->mutex); if (block->buf_fix_count != 0 || block->io_fix != 0) { @@ -2340,32 +2622,26 @@ ibool buf_all_freed(void) /*===============*/ { - buf_block_t* block; + buf_chunk_t* chunk; ulint i; ut_ad(buf_pool); mutex_enter(&(buf_pool->mutex)); - for (i = 0; i < buf_pool->curr_size; i++) { + chunk = buf_pool->chunks; - block = buf_pool_get_nth_block(buf_pool, i); + for (i = buf_pool->n_chunks; i--; chunk++) { - mutex_enter(&block->mutex); + const buf_block_t* block = buf_chunk_not_freed(chunk); - if (block->state == BUF_BLOCK_FILE_PAGE) { - - if (!buf_flush_ready_for_replace(block)) { - - fprintf(stderr, - "Page %lu %lu still fixed or dirty\n", - (ulong) block->space, - (ulong) block->offset); - ut_error; - } + if (UNIV_LIKELY_NULL(block)) { + fprintf(stderr, + "Page %lu %lu still fixed or dirty\n", + (ulong) block->space, + (ulong) block->offset); + ut_error; } - - mutex_exit(&block->mutex); } mutex_exit(&(buf_pool->mutex)); diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 15c04ba728a..a5c3c82d603 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -157,7 +157,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_lock_wait_timeout, innobase_force_recovery, innobase_open_files; -longlong innobase_buffer_pool_size, innobase_log_file_size; +longlong innobase_log_file_size; /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -1404,7 +1404,7 @@ innobase_init(void *p) /* Check that values don't overflow on 32-bit systems. */ if (sizeof(ulint) == 4) { - if (innobase_buffer_pool_size > UINT_MAX32) { + if (srv_buf_pool_size > UINT_MAX32) { sql_print_error( "innobase_buffer_pool_size can't be over 4GB" " on 32-bit systems"); @@ -1533,14 +1533,6 @@ innobase_init(void *p) #endif /* UNIV_LOG_ARCHIVE */ srv_log_buffer_size = (ulint) innobase_log_buffer_size; - /* We set srv_pool_size here in units of 1 kB. InnoDB internally - changes the value so that it becomes the number of database pages. */ - - /* Careful here: we first convert the signed long int to ulint - and only after that divide */ - - srv_pool_size = ((ulint) innobase_buffer_pool_size) / 1024; - srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; srv_n_file_io_threads = (ulint) innobase_file_io_threads; diff --git a/handler/ha_innodb.h b/handler/ha_innodb.h index d20e8227311..9b17f13b303 100644 --- a/handler/ha_innodb.h +++ b/handler/ha_innodb.h @@ -207,7 +207,7 @@ extern SHOW_VAR innodb_status_variables[]; extern ulong innobase_fast_shutdown; extern ulong innobase_large_page_size; extern long innobase_mirrored_log_groups, innobase_log_files_in_group; -extern longlong innobase_buffer_pool_size, innobase_log_file_size; +extern longlong innobase_log_file_size; extern long innobase_log_buffer_size; extern long innobase_additional_mem_pool_size; extern long innobase_file_io_threads, innobase_lock_wait_timeout; @@ -225,6 +225,8 @@ extern my_bool innobase_log_archive, innobase_file_per_table, innobase_locks_unsafe_for_binlog, innobase_create_status_file; extern "C" { +extern ulong srv_buf_pool_curr_size; +extern ulong srv_buf_pool_size; extern ulong srv_max_buf_pool_modified_pct; extern ulong srv_max_purge_lag; extern ulong srv_auto_extend_increment; diff --git a/include/buf0buf.h b/include/buf0buf.h index 023fc6e3c00..5062cb328c7 100644 --- a/include/buf0buf.h +++ b/include/buf0buf.h @@ -69,11 +69,16 @@ extern ulint srv_buf_pool_write_requests; /* variable to count write request Creates the buffer pool. */ buf_pool_t* -buf_pool_init( -/*==========*/ +buf_pool_init(void); +/*===============*/ /* out, own: buf_pool object, NULL if not enough memory or error */ - ulint curr_size); /* in: current size to use */ +/************************************************************************ +Resizes the buffer pool. */ + +void +buf_pool_resize(void); +/*=================*/ /************************************************************************* Gets the current size of buffer buf_pool in bytes. */ UNIV_INLINE @@ -833,11 +838,8 @@ struct buf_pool_struct{ mutex_t mutex; /* mutex protecting the buffer pool struct and control blocks, except the read-write lock in them */ - byte* frame_mem; /* pointer to the memory area which - was allocated for the frames */ - ulint frame_mem_size; /* allocated length of frame_mem - in bytes */ - buf_block_t* blocks; /* array of buffer control blocks */ + ulint n_chunks; /* number of buffer pool chunks */ + buf_chunk_t* chunks; /* buffer pool chunks */ ulint curr_size; /* current pool size in pages */ hash_table_t* page_hash; /* hash table of the file pages */ diff --git a/include/buf0buf.ic b/include/buf0buf.ic index 3175efb0a34..6a82f1551cb 100644 --- a/include/buf0buf.ic +++ b/include/buf0buf.ic @@ -42,22 +42,6 @@ buf_pool_get_curr_size(void) return(buf_pool->curr_size * UNIV_PAGE_SIZE); } -/*********************************************************************** -Accessor function for block array. */ -UNIV_INLINE -buf_block_t* -buf_pool_get_nth_block( -/*===================*/ - /* out: pointer to block */ - buf_pool_t* buf_pool,/* in: buf_pool */ - ulint i) /* in: index of the block */ -{ - ut_ad(buf_pool); - ut_ad(i < buf_pool->curr_size); - - return(i + buf_pool->blocks); -} - /************************************************************************ Gets the smallest oldest_modification lsn for any page in the pool. Returns ut_dulint_zero if all modified pages have been flushed to disk. */ @@ -114,8 +98,6 @@ buf_block_get_frame( buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); - ut_ad(block >= buf_pool->blocks); - ut_ad(block < buf_pool->blocks + buf_pool->curr_size); ut_ad(block->state != BUF_BLOCK_NOT_USED); ut_ad((block->state != BUF_BLOCK_FILE_PAGE) || (block->buf_fix_count > 0)); @@ -133,8 +115,6 @@ buf_block_get_space( const buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); - ut_ad(block >= buf_pool->blocks); - ut_ad(block < buf_pool->blocks + buf_pool->curr_size); ut_a(block->state == BUF_BLOCK_FILE_PAGE); ut_ad(block->buf_fix_count > 0); @@ -151,8 +131,6 @@ buf_block_get_page_no( const buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); - ut_ad(block >= buf_pool->blocks); - ut_ad(block < buf_pool->blocks + buf_pool->curr_size); ut_a(block->state == BUF_BLOCK_FILE_PAGE); ut_ad(block->buf_fix_count > 0); diff --git a/include/buf0flu.h b/include/buf0flu.h index d5f872ef673..2c9a7cf3dea 100644 --- a/include/buf0flu.h +++ b/include/buf0flu.h @@ -94,8 +94,9 @@ ibool buf_flush_ready_for_replace( /*========================*/ /* out: TRUE if can replace immediately */ - buf_block_t* block); /* in: buffer control block, must be in state - BUF_BLOCK_FILE_PAGE and in the LRU list */ + buf_block_t* block); /* in: buffer control block, must + be in state BUF_BLOCK_FILE_PAGE + and in the LRU list */ /********************************************************************** Validates the flush list. */ diff --git a/include/buf0types.h b/include/buf0types.h index 44fdfa80e73..a35f5702d6a 100644 --- a/include/buf0types.h +++ b/include/buf0types.h @@ -10,6 +10,7 @@ Created 11/17/1995 Heikki Tuuri #define buf0types_h typedef struct buf_block_struct buf_block_t; +typedef struct buf_chunk_struct buf_chunk_t; typedef struct buf_pool_struct buf_pool_t; /* The 'type' used of a buffer frame */ diff --git a/include/srv0srv.h b/include/srv0srv.h index 0c51862dbd8..91861cdb408 100644 --- a/include/srv0srv.h +++ b/include/srv0srv.h @@ -84,7 +84,9 @@ extern ulong srv_flush_log_at_trx_commit; extern byte srv_latin1_ordering[256];/* The sort order table of the latin1 character set */ -extern ulint srv_pool_size; +extern ulong srv_buf_pool_size; /* requested size in kilobytes */ +extern ulong srv_buf_pool_old_size; /* previously requested size */ +extern ulong srv_buf_pool_curr_size; /* current size in kilobytes */ extern ulint srv_mem_pool_size; extern ulint srv_lock_table_size; @@ -153,7 +155,6 @@ extern ulong srv_thread_sleep_delay; extern ulint srv_spin_wait_delay; extern ibool srv_priority_boost; -extern ulint srv_pool_size; extern ulint srv_mem_pool_size; extern ulint srv_lock_table_size; diff --git a/innodb.patch b/innodb.patch new file mode 100644 index 00000000000..91edb47518f --- /dev/null +++ b/innodb.patch @@ -0,0 +1,52 @@ +Index: srv/srv0srv.c +=================================================================== +--- srv/srv0srv.c (revision 1010) ++++ srv/srv0srv.c (working copy) +@@ -2183,6 +2182,12 @@ loop: + /* ---- When there is database activity by users, we cycle in this + loop */ + ++ if (UNIV_UNLIKELY(srv_buf_pool_size != srv_buf_pool_old_size)) { ++ srv_main_thread_op_info = "resizing buffer pool"; ++ ++ buf_pool_resize(); ++ } ++ + srv_main_thread_op_info = "reserving kernel mutex"; + + n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read +@@ -2543,6 +2548,12 @@ flush_loop: + master thread to wait for more server activity */ + + suspend_thread: ++ if (UNIV_UNLIKELY(srv_buf_pool_size != srv_buf_pool_old_size)) { ++ srv_main_thread_op_info = "resizing buffer pool"; ++ ++ buf_pool_resize(); ++ } ++ + srv_main_thread_op_info = "suspending"; + + mutex_enter(&kernel_mutex); +@@ -2553,7 +2564,9 @@ suspend_thread: + goto loop; + } + ++#if 0 + event = srv_suspend_thread(); ++#endif + + mutex_exit(&kernel_mutex); + +@@ -2563,7 +2576,11 @@ suspend_thread: + manual also mentions this string in several places. */ + srv_main_thread_op_info = "waiting for server activity"; + ++#if 0 + os_event_wait(event); ++#else ++ os_thread_sleep(1000000); ++#endif + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + /* This is only extra safety, the thread should exit diff --git a/mysql.patch b/mysql.patch new file mode 100644 index 00000000000..dd64c980568 --- /dev/null +++ b/mysql.patch @@ -0,0 +1,72 @@ +diff -pu mysql-5.1-bk/sql/mysqld.cc mysql-5.1-zip/sql/mysqld.cc +--- mysql-5.1-bk/sql/mysqld.cc 2006-11-09 16:01:19.000000000 +0200 ++++ mysql-5.1-zip/sql/mysqld.cc 2006-11-13 12:54:04.000000000 +0200 +@@ -370,7 +370,6 @@ extern long innobase_lock_scan_time; + extern long innobase_mirrored_log_groups, innobase_log_files_in_group; + extern longlong innobase_log_file_size; + extern long innobase_log_buffer_size; +-extern longlong innobase_buffer_pool_size; + extern long innobase_additional_mem_pool_size; + extern long innobase_file_io_threads, innobase_lock_wait_timeout; + extern long innobase_force_recovery; +@@ -390,6 +389,8 @@ extern "C" { + extern ulong srv_max_buf_pool_modified_pct; + extern ulong srv_max_purge_lag; + extern ulong srv_auto_extend_increment; ++extern ulong srv_buf_pool_curr_size; ++extern ulong srv_buf_pool_size; + extern ulong srv_n_spin_wait_rounds; + extern ulong srv_n_free_tickets_to_enter; + extern ulong srv_thread_sleep_delay; +@@ -5801,9 +5802,9 @@ log and this option does nothing anymore + (gptr*) &srv_auto_extend_increment, + 0, GET_LONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, + {"innodb_buffer_pool_size", OPT_INNODB_BUFFER_POOL_SIZE, +- "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", +- (gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0, +- GET_LL, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, LONGLONG_MAX, 0, ++ "The requested size of the memory buffer InnoDB uses to cache data and indexes of its tables.", ++ (gptr*) &srv_buf_pool_size, (gptr*) &srv_buf_pool_size, 0, ++ GET_LL, REQUIRED_ARG, 8*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 0, + 1024*1024L, 0}, + {"innodb_commit_concurrency", OPT_INNODB_COMMIT_CONCURRENCY, + "Helps in performance tuning in heavily concurrent environments.", +diff -pu mysql-5.1-bk/sql/set_var.cc mysql-5.1-zip/sql/set_var.cc +--- mysql-5.1-bk/sql/set_var.cc 2006-11-09 16:01:19.000000000 +0200 ++++ mysql-5.1-zip/sql/set_var.cc 2006-11-13 12:54:05.000000000 +0200 +@@ -65,7 +65,6 @@ extern ulong innobase_fast_shutdown; + extern long innobase_mirrored_log_groups, innobase_log_files_in_group; + extern longlong innobase_log_file_size; + extern long innobase_log_buffer_size; +-extern longlong innobase_buffer_pool_size; + extern long innobase_additional_mem_pool_size; + extern long innobase_file_io_threads, innobase_lock_wait_timeout; + extern long innobase_force_recovery; +@@ -81,6 +80,8 @@ extern my_bool innobase_log_archive, + innobase_locks_unsafe_for_binlog; + + extern "C" { ++extern ulong srv_buf_pool_curr_size; ++extern ulong srv_buf_pool_size; + extern ulong srv_max_buf_pool_modified_pct; + extern ulong srv_max_purge_lag; + extern ulong srv_auto_extend_increment; +@@ -499,6 +500,8 @@ sys_var_thd_bool sys_innodb_support_xa(" + &SV::innodb_support_xa); + sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", + &srv_auto_extend_increment); ++sys_var_long_ptr sys_innodb_buffer_pool_size("innodb_buffer_pool_size", ++ &srv_buf_pool_size); + sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops", + &srv_n_spin_wait_rounds); + sys_var_long_ptr sys_innodb_concurrency_tickets("innodb_concurrency_tickets", +@@ -818,7 +821,8 @@ SHOW_VAR init_vars[]= { + #ifdef WITH_INNOBASE_STORAGE_ENGINE + {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG }, + {sys_innodb_autoextend_increment.name, (char*) &sys_innodb_autoextend_increment, SHOW_SYS}, +- {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONGLONG }, ++ {sys_innodb_buffer_pool_size.name, (char*) &sys_innodb_buffer_pool_size, SHOW_SYS }, ++ {"innodb_buffer_pool_curr_size", (char*) &srv_buf_pool_curr_size, SHOW_LONGLONG }, + {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL}, + {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, + {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS}, diff --git a/srv/srv0srv.c b/srv/srv0srv.c index 69cd7920b43..89995e22ff3 100644 --- a/srv/srv0srv.c +++ b/srv/srv0srv.c @@ -159,10 +159,11 @@ byte srv_latin1_ordering[256] /* The sort order table of the latin1 , 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xFF }; -ulint srv_pool_size = ULINT_MAX; /* size in pages; MySQL inits - this to size in kilobytes but - we normalize this to pages in - srv_boot() */ +ulong srv_buf_pool_size = ULINT_MAX; /* requested size + in kilobytes */ +ulong srv_buf_pool_old_size; /* previously requested size */ +ulong srv_buf_pool_curr_size = 0; /* current size + in kilobytes */ ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ ulint srv_lock_table_size = ULINT_MAX; @@ -1233,9 +1234,7 @@ srv_normalize_init_values(void) srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE; - srv_pool_size = srv_pool_size / (UNIV_PAGE_SIZE / 1024); - - srv_lock_table_size = 5 * srv_pool_size; + srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE); return(DB_SUCCESS); } diff --git a/srv/srv0start.c b/srv/srv0start.c index e1364d6862f..9741fea450d 100644 --- a/srv/srv0start.c +++ b/srv/srv0start.c @@ -1132,7 +1132,7 @@ innobase_start_or_create_for_mysql(void) } /* Note that the call srv_boot() also changes the values of - srv_pool_size etc. to the units used by InnoDB internally */ + some variables to the units used by InnoDB internally */ /* Set the maximum number of threads which can wait for a semaphore inside InnoDB: this is the 'sync wait array' size, as well as the @@ -1147,15 +1147,12 @@ innobase_start_or_create_for_mysql(void) NetWare. */ srv_max_n_threads = 1000; #else - if (srv_pool_size >= 1000 * 1024) { - /* Here we still have srv_pool_size counted - in kilobytes (in 4.0 this was in bytes) - srv_boot() converts the value to - pages; if buffer pool is less than 1000 MB, + if (srv_buf_pool_size >= 1000 * 1024 * 1024) { + /* If buffer pool is less than 1000 MB, assume fewer threads. */ srv_max_n_threads = 50000; - } else if (srv_pool_size >= 8 * 1024) { + } else if (srv_buf_pool_size >= 8 * 1024 * 1024) { srv_max_n_threads = 10000; } else { @@ -1164,7 +1161,7 @@ innobase_start_or_create_for_mysql(void) computers */ } #endif - err = srv_boot(); /* This changes srv_pool_size to units of a page */ + err = srv_boot(); if (err != DB_SUCCESS) { @@ -1230,7 +1227,7 @@ innobase_start_or_create_for_mysql(void) fil_init(srv_max_n_open_files); - ret = buf_pool_init(srv_pool_size); + ret = buf_pool_init(); if (ret == NULL) { fprintf(stderr,