#!!! notice !!!
# Any small change to this file in the main branch
# should be done or reviewed by the maintainer!
-diff -ruN a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c
---- a/storage/innobase/btr/btr0sea.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/btr/btr0sea.c 2010-12-03 15:45:47.503988924 +0900
-@@ -1185,6 +1185,132 @@
+--- a/storage/innobase/btr/btr0sea.c
++++ b/storage/innobase/btr/btr0sea.c
+@@ -1187,6 +1187,178 @@
mem_free(folds);
}
+/*=====================================*/
+ dict_index_t* index) /* in: record descriptor */
+{
-+ buf_page_t* bpage;
++
+ hash_table_t* table;
+ buf_block_t* block;
+ ulint n_fields;
+ ulint i, j;
+ mem_heap_t* heap = NULL;
+ ulint* offsets;
++ ibool released_search_latch;
+
-+ rw_lock_x_lock(&btr_search_latch);
-+ buf_pool_mutex_enter_all();
++ rw_lock_s_lock(&btr_search_latch);
+
+ table = btr_search_sys->hash_index;
+
+
+ buf_pool = buf_pool_from_array(j);
+
-+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
++ do {
++ buf_chunk_t* chunks = buf_pool->chunks;
++ buf_chunk_t* chunk = chunks + buf_pool->n_chunks;
++
++ released_search_latch = FALSE;
++
++ while (--chunk >= chunks) {
++ block = chunk->blocks;
++ i = chunk->size;
++
++retry:
++ for (; i--; block++) {
++ if (buf_block_get_state(block)
++ != BUF_BLOCK_FILE_PAGE
++ || block->index != index
++ || !block->index) {
++ continue;
++ }
++
++ page = block->frame;
++
++ /* from btr_search_drop_page_hash_index() */
++ n_fields = block->curr_n_fields;
++ n_bytes = block->curr_n_bytes;
+
-+ while (bpage != NULL) {
-+ block = (buf_block_t*) bpage;
-+ if (block->index == index && block->is_hashed) {
-+ page = block->frame;
+
-+ /* from btr_search_drop_page_hash_index() */
-+ n_fields = block->curr_n_fields;
-+ n_bytes = block->curr_n_bytes;
++ /* keeping latch order */
++ rw_lock_s_unlock(&btr_search_latch);
++ released_search_latch = TRUE;
++ rw_lock_x_lock(&block->lock);
+
-+ ut_a(n_fields + n_bytes > 0);
+
-+ n_recs = page_get_n_recs(page);
++ ut_a(n_fields + n_bytes > 0);
+
-+ /* Calculate and cache fold values into an array for fast deletion
-+ from the hash index */
++ n_recs = page_get_n_recs(page);
+
-+ folds = mem_alloc(n_recs * sizeof(ulint));
++ /* Calculate and cache fold values into an array for fast deletion
++ from the hash index */
+
-+ n_cached = 0;
++ folds = mem_alloc(n_recs * sizeof(ulint));
+
-+ rec = page_get_infimum_rec(page);
-+ rec = page_rec_get_next_low(rec, page_is_comp(page));
++ n_cached = 0;
+
-+ index_id = btr_page_get_index_id(page);
++ rec = page_get_infimum_rec(page);
++ rec = page_rec_get_next_low(rec, page_is_comp(page));
++
++ index_id = btr_page_get_index_id(page);
+
-+ ut_a(index_id == index->id);
++ ut_a(index_id == index->id);
+
-+ prev_fold = 0;
++ prev_fold = 0;
+
-+ offsets = NULL;
++ offsets = NULL;
+
-+ while (!page_rec_is_supremum(rec)) {
-+ offsets = rec_get_offsets(rec, index, offsets,
-+ n_fields + (n_bytes > 0), &heap);
-+ ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0));
-+ fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id);
++ while (!page_rec_is_supremum(rec)) {
++ offsets = rec_get_offsets(rec, index, offsets,
++ n_fields + (n_bytes > 0), &heap);
++ ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0));
++ fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id);
+
-+ if (fold == prev_fold && prev_fold != 0) {
++ if (fold == prev_fold && prev_fold != 0) {
+
-+ goto next_rec;
-+ }
++ goto next_rec;
++ }
+
-+ /* Remove all hash nodes pointing to this page from the
-+ hash chain */
++ /* Remove all hash nodes pointing to this page from the
++ hash chain */
+
-+ folds[n_cached] = fold;
-+ n_cached++;
++ folds[n_cached] = fold;
++ n_cached++;
+next_rec:
-+ rec = page_rec_get_next_low(rec, page_rec_is_comp(rec));
-+ prev_fold = fold;
-+ }
++ rec = page_rec_get_next_low(rec, page_rec_is_comp(rec));
++ prev_fold = fold;
++ }
+
-+ for (i = 0; i < n_cached; i++) {
++ if (UNIV_LIKELY_NULL(heap)) {
++ mem_heap_empty(heap);
++ }
+
-+ ha_remove_all_nodes_to_page(table, folds[i], page);
-+ }
++ rw_lock_x_lock(&btr_search_latch);
+
-+ ut_a(index->search_info->ref_count > 0);
-+ index->search_info->ref_count--;
++ if (UNIV_UNLIKELY(!block->index)) {
++ goto cleanup;
++ }
+
-+ block->is_hashed = FALSE;
-+ block->index = NULL;
-+
++ ut_a(block->index == index);
++
++ if (UNIV_UNLIKELY(block->curr_n_fields != n_fields)
++ || UNIV_UNLIKELY(block->curr_n_bytes != n_bytes)) {
++ rw_lock_x_unlock(&btr_search_latch);
++ rw_lock_x_unlock(&block->lock);
++
++ mem_free(folds);
++
++ rw_lock_s_lock(&btr_search_latch);
++ goto retry;
++ }
++
++ for (i = 0; i < n_cached; i++) {
++
++ ha_remove_all_nodes_to_page(table, folds[i], page);
++ }
++
++ ut_a(index->search_info->ref_count > 0);
++ index->search_info->ref_count--;
++
++ block->index = NULL;
++
++cleanup:
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
-+ if (UNIV_UNLIKELY(block->n_pointers)) {
-+ /* Corruption */
-+ ut_print_timestamp(stderr);
-+ fprintf(stderr,
-+" InnoDB: Corruption of adaptive hash index. After dropping\n"
-+"InnoDB: the hash index to a page of %s, still %lu hash nodes remain.\n",
-+ index->name, (ulong) block->n_pointers);
-+ }
++ if (UNIV_UNLIKELY(block->n_pointers)) {
++ /* Corruption */
++ ut_print_timestamp(stderr);
++ fprintf(stderr,
++"InnoDB: The adaptive hash index is corrupted. After dropping\n"
++"InnoDB: the hash index to a page of %s, %lu hash nodes still remain.\n",
++ index->name, (ulong) block->n_pointers);
++ }
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
++ rw_lock_x_unlock(&btr_search_latch);
++ rw_lock_x_unlock(&block->lock);
+
-+ mem_free(folds);
-+ }
++ mem_free(folds);
+
-+ bpage = UT_LIST_GET_PREV(LRU, bpage);
-+ }
++ rw_lock_s_lock(&btr_search_latch);
++ }
++ }
++ } while (released_search_latch);
+ }
+
-+ buf_pool_mutex_exit_all();
-+ rw_lock_x_unlock(&btr_search_latch);
++ rw_lock_s_unlock(&btr_search_latch);
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+}
+
/********************************************************************//**
- Drops a page hash index when a page is freed from a fseg to the file system.
- Drops possible hash index if the page happens to be in the buffer pool. */
-diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c
---- a/storage/innobase/dict/dict0boot.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/dict/dict0boot.c 2010-12-03 15:45:47.503988924 +0900
+ Drops a possible page hash index when a page is evicted from the buffer pool
+ or freed in a file segment. */
+--- a/storage/innobase/buf/buf0buf.c
++++ b/storage/innobase/buf/buf0buf.c
+@@ -294,14 +294,14 @@
+ # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */
+ #endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */
+
+-/** 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 */
+-};
++/** A chunk of buffers. The buffer pool is allocated in chunks. (moved to buf0buf.h)*/
++//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 */
++//};
+ #endif /* !UNIV_HOTBACKUP */
+
+ /********************************************************************//**
+--- a/storage/innobase/dict/dict0boot.c
++++ b/storage/innobase/dict/dict0boot.c
@@ -284,6 +284,7 @@
system tables */
/*-------------------------*/
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
-diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c
---- a/storage/innobase/dict/dict0crea.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/dict/dict0crea.c 2010-12-03 15:45:47.521955810 +0900
-@@ -1210,6 +1210,9 @@
+--- a/storage/innobase/dict/dict0crea.c
++++ b/storage/innobase/dict/dict0crea.c
+@@ -1209,6 +1209,9 @@
/* Foreign constraint system tables have already been
created, and they are ok */
mutex_exit(&(dict_sys->mutex));
return(DB_SUCCESS);
-@@ -1291,6 +1294,11 @@
+@@ -1290,6 +1293,11 @@
trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
-diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
---- a/storage/innobase/dict/dict0dict.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/dict/dict0dict.c 2010-12-03 15:45:47.525953769 +0900
-@@ -625,6 +625,8 @@
+--- a/storage/innobase/dict/dict0dict.c
++++ b/storage/innobase/dict/dict0dict.c
+@@ -626,6 +626,8 @@
table = dict_table_get_on_id_low(table_id);
mutex_exit(&(dict_sys->mutex));
return(table);
-@@ -743,6 +745,8 @@
+@@ -744,6 +746,8 @@
table->n_mysql_handles_opened++;
}
mutex_exit(&(dict_sys->mutex));
if (table != NULL) {
-@@ -1256,6 +1260,64 @@
+@@ -1264,6 +1268,64 @@
dict_mem_table_free(table);
}
/****************************************************************//**
If the given column name is reserved for InnoDB system columns, return
TRUE.
-@@ -1719,6 +1781,11 @@
+@@ -1768,6 +1830,11 @@
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mutex_own(&(dict_sys->mutex)));
/* We always create search info whether or not adaptive
hash index is enabled or not. */
info = index->search_info;
-diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
---- a/storage/innobase/handler/ha_innodb.cc 2010-12-03 15:43:57.294986852 +0900
-+++ b/storage/innobase/handler/ha_innodb.cc 2010-12-03 15:45:47.534959966 +0900
-@@ -655,6 +655,8 @@
+--- a/storage/innobase/handler/ha_innodb.cc
++++ b/storage/innobase/handler/ha_innodb.cc
+@@ -677,6 +677,8 @@
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
{"dblwr_writes",
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
{"have_atomic_builtins",
(char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
{"log_waits",
-@@ -11543,6 +11545,11 @@
- "Number of extra user rollback segments which are used in a round-robin fashion.",
- NULL, NULL, 127, 0, 127, 0);
+@@ -11813,6 +11815,11 @@
+ NULL, NULL, 0, 0, 1, 0);
+ #endif
+static MYSQL_SYSVAR_ULONG(dict_size_limit, srv_dict_size_limit,
+ PLUGIN_VAR_RQCMDARG,
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(autoextend_increment),
-@@ -11611,6 +11618,7 @@
+@@ -11882,6 +11889,7 @@
+ MYSQL_SYSVAR(flush_neighbor_pages),
+ MYSQL_SYSVAR(read_ahead),
MYSQL_SYSVAR(adaptive_flushing_method),
- MYSQL_SYSVAR(enable_unsafe_group_commit),
- MYSQL_SYSVAR(extra_rsegments),
+ MYSQL_SYSVAR(dict_size_limit),
MYSQL_SYSVAR(use_sys_malloc),
MYSQL_SYSVAR(use_native_aio),
MYSQL_SYSVAR(change_buffering),
-diff -ruN a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c
---- a/storage/innobase/ibuf/ibuf0ibuf.c 2010-12-03 15:18:48.889024455 +0900
-+++ b/storage/innobase/ibuf/ibuf0ibuf.c 2010-12-03 15:45:47.553025057 +0900
-@@ -578,6 +578,7 @@
+--- a/storage/innobase/ibuf/ibuf0ibuf.c
++++ b/storage/innobase/ibuf/ibuf0ibuf.c
+@@ -575,6 +575,7 @@
/* Use old-style record format for the insert buffer. */
table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0);
dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
-diff -ruN a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
---- a/storage/innobase/include/btr0sea.h 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/btr0sea.h 2010-12-03 15:45:47.555024229 +0900
+--- a/storage/innobase/include/btr0sea.h
++++ b/storage/innobase/include/btr0sea.h
@@ -140,6 +140,13 @@
s- or x-latched, or an index page
for which we know that
+/*=====================================*/
+ dict_index_t* index); /* in: record descriptor */
/********************************************************************//**
- Drops a page hash index when a page is freed from a fseg to the file system.
- Drops possible hash index if the page happens to be in the buffer pool. */
-diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
---- a/storage/innobase/include/dict0dict.h 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/dict0dict.h 2010-12-03 15:45:47.558024515 +0900
-@@ -1158,6 +1158,12 @@
+ Drops a possible page hash index when a page is evicted from the buffer pool
+ or freed in a file segment. */
+--- a/storage/innobase/include/buf0buf.h
++++ b/storage/innobase/include/buf0buf.h
+@@ -1595,6 +1595,15 @@
+ #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b))
+ /* @} */
+
++/** 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 */
++};
++
+ /** @brief The buffer pool statistics structure. */
+ struct buf_pool_stat_struct{
+ ulint n_page_gets; /*!< number of page gets performed;
+--- a/storage/innobase/include/dict0dict.h
++++ b/storage/innobase/include/dict0dict.h
+@@ -1200,6 +1200,12 @@
/*====================================*/
dict_table_t* table, /*!< in: table */
const char* name); /*!< in: name of the index to find */
/* Buffers for storing detailed information about the latest foreign key
and unique key errors */
extern FILE* dict_foreign_err_file;
-diff -ruN a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
---- a/storage/innobase/include/dict0dict.ic 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/dict0dict.ic 2010-12-03 15:45:47.560024398 +0900
-@@ -824,6 +824,13 @@
+--- a/storage/innobase/include/dict0dict.ic
++++ b/storage/innobase/include/dict0dict.ic
+@@ -825,6 +825,13 @@
HASH_SEARCH(name_hash, dict_sys->table_hash, table_fold,
dict_table_t*, table, ut_ad(table->cached),
!strcmp(table->name, table_name));
return(table);
}
-@@ -877,6 +884,12 @@
+@@ -918,6 +925,12 @@
table = dict_load_table_on_id(table_id);
}
ut_ad(!table || table->cached);
/* TODO: should get the type information from MySQL */
-diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
---- a/storage/innobase/include/srv0srv.h 2010-12-03 15:43:57.297067100 +0900
-+++ b/storage/innobase/include/srv0srv.h 2010-12-03 15:45:47.562024404 +0900
-@@ -228,7 +228,7 @@
+--- a/storage/innobase/include/srv0srv.h
++++ b/storage/innobase/include/srv0srv.h
+@@ -234,6 +234,7 @@
+ extern ulint srv_read_ahead;
extern ulint srv_adaptive_flushing_method;
- extern ulint srv_extra_rsegments;
--
+extern ulint srv_dict_size_limit;
/*-------------------------------------------*/
extern ulint srv_n_rows_inserted;
-@@ -700,6 +700,7 @@
+@@ -717,6 +718,7 @@
ulint innodb_data_writes; /*!< I/O write requests */
ulint innodb_data_written; /*!< Data bytes written */
ulint innodb_data_reads; /*!< I/O read requests */
ulint innodb_buffer_pool_pages_total; /*!< Buffer pool size */
ulint innodb_buffer_pool_pages_data; /*!< Data pages */
ulint innodb_buffer_pool_pages_dirty; /*!< Dirty data pages */
-diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
---- a/storage/innobase/srv/srv0srv.c 2010-12-03 15:43:57.301024390 +0900
-+++ b/storage/innobase/srv/srv0srv.c 2010-12-03 15:45:47.565023830 +0900
-@@ -414,6 +414,7 @@
+--- a/storage/innobase/srv/srv0srv.c
++++ b/storage/innobase/srv/srv0srv.c
+@@ -417,6 +417,8 @@
+ UNIV_INTERN ulint srv_enable_unsafe_group_commit = 0; /* 0:disable 1:enable */
+ UNIV_INTERN ulint srv_read_ahead = 3; /* 1: random 2: linear 3: Both */
UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */
-
- UNIV_INTERN ulint srv_extra_rsegments = 127; /* extra rseg for users */
++
+UNIV_INTERN ulint srv_dict_size_limit = 0;
/*-------------------------------------------*/
UNIV_INTERN ulong srv_n_spin_wait_rounds = 30;
UNIV_INTERN ulong srv_n_free_tickets_to_enter = 500;
-@@ -2192,6 +2193,7 @@
+@@ -2225,6 +2227,7 @@
export_vars.innodb_data_reads = os_n_file_reads;
export_vars.innodb_data_writes = os_n_file_writes;
export_vars.innodb_data_written = srv_data_written;
export_vars.innodb_buffer_pool_read_requests = stat.n_page_gets;
export_vars.innodb_buffer_pool_write_requests
= srv_buf_pool_write_requests;
+--- /dev/null
++++ b/mysql-test/suite/sys_vars/r/innodb_dict_size_limit_basic.result
+@@ -0,0 +1,3 @@
++SELECT @@global.innodb_dict_size_limit;
++@@global.innodb_dict_size_limit
++0
+--- /dev/null
++++ b/mysql-test/suite/sys_vars/t/innodb_dict_size_limit_basic.test
+@@ -0,0 +1 @@
++SELECT @@global.innodb_dict_size_limit;