summaryrefslogtreecommitdiff
path: root/storage/innobase/ha
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/ha')
-rw-r--r--storage/innobase/ha/ha0ha.cc (renamed from storage/innobase/ha/ha0ha.c)163
-rw-r--r--storage/innobase/ha/ha0storage.cc (renamed from storage/innobase/ha/ha0storage.c)12
-rw-r--r--storage/innobase/ha/hash0hash.c184
-rw-r--r--storage/innobase/ha/hash0hash.cc403
4 files changed, 529 insertions, 233 deletions
diff --git a/storage/innobase/ha/ha0ha.c b/storage/innobase/ha/ha0ha.cc
index 35f2293577f..b58dc486cfa 100644
--- a/storage/innobase/ha/ha0ha.c
+++ b/storage/innobase/ha/ha0ha.cc
@@ -11,13 +11,13 @@ 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., 59 Temple
-Place, Suite 330, Boston, MA 02111-1307 USA
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/********************************************************************//**
-@file ha/ha0ha.c
+@file ha/ha0ha.cc
The hash table with external chains
Created 8/22/1994 Heikki Tuuri
@@ -32,7 +32,9 @@ Created 8/22/1994 Heikki Tuuri
#ifdef UNIV_DEBUG
# include "buf0buf.h"
#endif /* UNIV_DEBUG */
-#include "btr0sea.h"
+#ifndef UNIV_HOTBACKUP
+# include "btr0sea.h"
+#endif /* !UNIV_HOTBACKUP */
#include "page0page.h"
/*************************************************************//**
@@ -45,45 +47,121 @@ ha_create_func(
/*===========*/
ulint n, /*!< in: number of array cells */
#ifdef UNIV_SYNC_DEBUG
- ulint mutex_level, /*!< in: level of the mutexes in the latching
- order: this is used in the debug version */
+ ulint sync_level, /*!< in: level of the mutexes or rw_locks
+ in the latching order: this is used in the
+ debug version */
#endif /* UNIV_SYNC_DEBUG */
- ulint n_mutexes) /*!< in: number of mutexes to protect the
- hash table: must be a power of 2, or 0 */
+ ulint n_sync_obj, /*!< in: number of mutexes or rw_locks
+ to protect the hash table: must be a
+ power of 2, or 0 */
+ ulint type) /*!< in: type of datastructure for which
+ the memory heap is going to be used e.g.:
+ MEM_HEAP_FOR_BTR_SEARCH or
+ MEM_HEAP_FOR_PAGE_HASH */
{
hash_table_t* table;
ulint i;
- ut_ad(ut_is_2pow(n_mutexes));
+ ut_a(type == MEM_HEAP_FOR_BTR_SEARCH
+ || type == MEM_HEAP_FOR_PAGE_HASH);
+
+ ut_ad(ut_is_2pow(n_sync_obj));
table = hash_create(n);
-#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- table->adaptive = TRUE;
-#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
but in practise it never should in this case, hence the asserts. */
- if (n_mutexes == 0) {
- table->heap = mem_heap_create_in_btr_search(
- ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
+ if (n_sync_obj == 0) {
+ table->heap = mem_heap_create_typed(
+ ut_min(4096, MEM_MAX_ALLOC_IN_BUF), type);
ut_a(table->heap);
return(table);
}
- hash_create_mutexes(table, n_mutexes, mutex_level);
+#ifndef UNIV_HOTBACKUP
+ if (type == MEM_HEAP_FOR_PAGE_HASH) {
+ /* We create a hash table protected by rw_locks for
+ buf_pool->page_hash. */
+ hash_create_sync_obj(table, HASH_TABLE_SYNC_RW_LOCK,
+ n_sync_obj, sync_level);
+ } else {
+ hash_create_sync_obj(table, HASH_TABLE_SYNC_MUTEX,
+ n_sync_obj, sync_level);
+ }
- table->heaps = mem_alloc(n_mutexes * sizeof(void*));
+ table->heaps = static_cast<mem_heap_t**>(
+ mem_alloc(n_sync_obj * sizeof(void*)));
- for (i = 0; i < n_mutexes; i++) {
- table->heaps[i] = mem_heap_create_in_btr_search(4096);
+ for (i = 0; i < n_sync_obj; i++) {
+ table->heaps[i] = mem_heap_create_typed(4096, type);
ut_a(table->heaps[i]);
}
+#endif /* !UNIV_HOTBACKUP */
return(table);
}
/*************************************************************//**
+Empties a hash table and frees the memory heaps. */
+UNIV_INTERN
+void
+ha_clear(
+/*=====*/
+ hash_table_t* table) /*!< in, own: hash table */
+{
+ ulint i;
+ ulint n;
+
+ ut_ad(table);
+ ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!table->adaptive
+ || rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
+#endif /* UNIV_SYNC_DEBUG */
+
+#ifndef UNIV_HOTBACKUP
+ /* Free the memory heaps. */
+ n = table->n_sync_obj;
+
+ for (i = 0; i < n; i++) {
+ mem_heap_free(table->heaps[i]);
+ }
+
+ if (table->heaps) {
+ mem_free(table->heaps);
+ }
+
+ switch (table->type) {
+ case HASH_TABLE_SYNC_MUTEX:
+ mem_free(table->sync_obj.mutexes);
+ table->sync_obj.mutexes = NULL;
+ break;
+
+ case HASH_TABLE_SYNC_RW_LOCK:
+ mem_free(table->sync_obj.rw_locks);
+ table->sync_obj.rw_locks = NULL;
+ break;
+
+ case HASH_TABLE_SYNC_NONE:
+ /* do nothing */
+ break;
+ }
+
+ table->n_sync_obj = 0;
+ table->type = HASH_TABLE_SYNC_NONE;
+
+#endif /* !UNIV_HOTBACKUP */
+
+ /* 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
is inserted. If btr_search_enabled is set to FALSE, we will only allow
@@ -101,7 +179,7 @@ ha_insert_for_fold_func(
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
buf_block_t* block, /*!< in: buffer block containing the data */
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- rec_t* data) /*!< in: data, must not be NULL */
+ const rec_t* data) /*!< in: data, must not be NULL */
{
hash_cell_t* cell;
ha_node_t* node;
@@ -114,17 +192,14 @@ ha_insert_for_fold_func(
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
ut_a(block->frame == page_align(data));
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
- ASSERT_HASH_MUTEX_OWN(table, fold);
+ hash_assert_can_modify(table, fold);
ut_ad(btr_search_enabled);
hash = hash_calc_hash(fold, table);
cell = hash_get_nth_cell(table, hash);
- prev_node = cell->node;
+ prev_node = static_cast<ha_node_t*>(cell->node);
while (prev_node != NULL) {
if (prev_node->fold == fold) {
@@ -140,7 +215,7 @@ ha_insert_for_fold_func(
prev_node->block = block;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- prev_node->data = data;
+ prev_node->data = (rec_t*) data;
return(TRUE);
}
@@ -150,7 +225,8 @@ ha_insert_for_fold_func(
/* We have to allocate a new chain node */
- node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
+ node = static_cast<ha_node_t*>(
+ mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)));
if (node == NULL) {
/* It was a btr search type memory heap and at the moment
@@ -161,7 +237,7 @@ ha_insert_for_fold_func(
return(FALSE);
}
- ha_node_set_data(node, block, data);
+ ha_node_set_data(node, block, (rec_t*) data);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
if (table->adaptive) {
@@ -173,7 +249,7 @@ ha_insert_for_fold_func(
node->next = NULL;
- prev_node = cell->node;
+ prev_node = static_cast<ha_node_t*>(cell->node);
if (prev_node == NULL) {
@@ -220,9 +296,10 @@ ha_delete_hash_node(
/*********************************************************//**
Looks for an element when we know the pointer to the data, and updates
-the pointer to data, if found. */
+the pointer to data, if found.
+@return TRUE if found */
UNIV_INTERN
-void
+ibool
ha_search_and_update_if_found_func(
/*===============================*/
hash_table_t* table, /*!< in/out: hash table */
@@ -237,7 +314,7 @@ ha_search_and_update_if_found_func(
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
- ASSERT_HASH_MUTEX_OWN(table, fold);
+ hash_assert_can_modify(table, fold);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
ut_a(new_block->frame == page_align(new_data));
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
@@ -246,7 +323,7 @@ ha_search_and_update_if_found_func(
#endif /* UNIV_SYNC_DEBUG */
if (!btr_search_enabled) {
- return;
+ return(FALSE);
}
node = ha_search_with_data(table, fold, data);
@@ -262,7 +339,11 @@ ha_search_and_update_if_found_func(
node->block = new_block;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
node->data = new_data;
+
+ return(TRUE);
}
+
+ return(FALSE);
}
/*****************************************************************//**
@@ -280,10 +361,7 @@ ha_remove_all_nodes_to_page(
ut_ad(table);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
- ASSERT_HASH_MUTEX_OWN(table, fold);
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
+ hash_assert_can_modify(table, fold);
ut_ad(btr_search_enabled);
node = ha_chain_get_first(table, fold);
@@ -329,8 +407,6 @@ ha_validate(
ulint start_index, /*!< in: start index */
ulint end_index) /*!< in: end index */
{
- hash_cell_t* cell;
- ha_node_t* node;
ibool ok = TRUE;
ulint i;
@@ -341,12 +417,15 @@ ha_validate(
ut_a(end_index < hash_get_n_cells(table));
for (i = start_index; i <= end_index; i++) {
+ ha_node_t* node;
+ hash_cell_t* cell;
cell = hash_get_nth_cell(table, i);
- node = cell->node;
+ for (node = static_cast<ha_node_t*>(cell->node);
+ node != 0;
+ node = node->next) {
- while (node) {
if (hash_calc_hash(node->fold, table) != i) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -357,8 +436,6 @@ ha_validate(
ok = FALSE;
}
-
- node = node->next;
}
}
diff --git a/storage/innobase/ha/ha0storage.c b/storage/innobase/ha/ha0storage.cc
index 698e34f1166..6820591f316 100644
--- a/storage/innobase/ha/ha0storage.c
+++ b/storage/innobase/ha/ha0storage.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2007, 2011, 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
@@ -11,13 +11,13 @@ 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., 59 Temple
-Place, Suite 330, Boston, MA 02111-1307 USA
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
-@file ha/ha0storage.c
+@file ha/ha0storage.cc
Hash storage.
Provides a data structure that stores chunks of data in
its own storage, avoiding duplicates.
@@ -51,7 +51,7 @@ ha_storage_get(
/* avoid repetitive calls to ut_fold_binary() in the HASH_SEARCH
macro */
- fold = ut_fold_binary(data, data_len);
+ fold = ut_fold_binary(static_cast<const byte*>(data), data_len);
#define IS_FOUND \
node->data_len == data_len && memcmp(node->data, data, data_len) == 0
@@ -128,7 +128,7 @@ ha_storage_put_memlim(
/* avoid repetitive calls to ut_fold_binary() in the HASH_INSERT
macro */
- fold = ut_fold_binary(data, data_len);
+ fold = ut_fold_binary(static_cast<const byte*>(data), data_len);
HASH_INSERT(
ha_storage_node_t, /* type used in the hash chain */
diff --git a/storage/innobase/ha/hash0hash.c b/storage/innobase/ha/hash0hash.c
deleted file mode 100644
index 9589da00454..00000000000
--- a/storage/innobase/ha/hash0hash.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1997, 2009, Innobase Oy. 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., 59 Temple
-Place, Suite 330, Boston, MA 02111-1307 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file ha/hash0hash.c
-The simple hash table utility
-
-Created 5/20/1997 Heikki Tuuri
-*******************************************************/
-
-#include "hash0hash.h"
-#ifdef UNIV_NONINL
-#include "hash0hash.ic"
-#endif
-
-#include "mem0mem.h"
-
-#ifndef UNIV_HOTBACKUP
-
-# ifdef UNIV_PFS_MUTEX
-UNIV_INTERN mysql_pfs_key_t hash_table_mutex_key;
-# endif /* UNIV_PFS_MUTEX */
-
-/************************************************************//**
-Reserves the mutex for a fold value in a hash table. */
-UNIV_INTERN
-void
-hash_mutex_enter(
-/*=============*/
- hash_table_t* table, /*!< in: hash table */
- ulint fold) /*!< in: fold */
-{
- mutex_enter(hash_get_mutex(table, fold));
-}
-
-/************************************************************//**
-Releases the mutex for a fold value in a hash table. */
-UNIV_INTERN
-void
-hash_mutex_exit(
-/*============*/
- hash_table_t* table, /*!< in: hash table */
- ulint fold) /*!< in: fold */
-{
- mutex_exit(hash_get_mutex(table, fold));
-}
-
-/************************************************************//**
-Reserves all the mutexes of a hash table, in an ascending order. */
-UNIV_INTERN
-void
-hash_mutex_enter_all(
-/*=================*/
- hash_table_t* table) /*!< in: hash table */
-{
- ulint i;
-
- for (i = 0; i < table->n_mutexes; i++) {
-
- mutex_enter(table->mutexes + i);
- }
-}
-
-/************************************************************//**
-Releases all the mutexes of a hash table. */
-UNIV_INTERN
-void
-hash_mutex_exit_all(
-/*================*/
- hash_table_t* table) /*!< in: hash table */
-{
- ulint i;
-
- for (i = 0; i < table->n_mutexes; i++) {
-
- mutex_exit(table->mutexes + i);
- }
-}
-#endif /* !UNIV_HOTBACKUP */
-
-/*************************************************************//**
-Creates a hash table with >= n array cells. The actual number of cells is
-chosen to be a prime number slightly bigger than n.
-@return own: created table */
-UNIV_INTERN
-hash_table_t*
-hash_create(
-/*========*/
- ulint n) /*!< in: number of array cells */
-{
- hash_cell_t* array;
- ulint prime;
- hash_table_t* table;
-
- prime = ut_find_prime(n);
-
- table = mem_alloc(sizeof(hash_table_t));
-
- array = ut_malloc(sizeof(hash_cell_t) * prime);
-
- table->array = array;
- table->n_cells = prime;
-#ifndef UNIV_HOTBACKUP
-# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- table->adaptive = FALSE;
-# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- table->n_mutexes = 0;
- table->mutexes = NULL;
- table->heaps = NULL;
-#endif /* !UNIV_HOTBACKUP */
- table->heap = NULL;
- ut_d(table->magic_n = HASH_TABLE_MAGIC_N);
-
- /* Initialize the cell array */
- hash_table_clear(table);
-
- return(table);
-}
-
-/*************************************************************//**
-Frees a hash table. */
-UNIV_INTERN
-void
-hash_table_free(
-/*============*/
- hash_table_t* table) /*!< in, own: hash table */
-{
- ut_ad(table);
- ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-#ifndef UNIV_HOTBACKUP
- ut_a(table->mutexes == NULL);
-#endif /* !UNIV_HOTBACKUP */
-
- ut_free(table->array);
- mem_free(table);
-}
-
-#ifndef UNIV_HOTBACKUP
-/*************************************************************//**
-Creates a mutex array to protect a hash table. */
-UNIV_INTERN
-void
-hash_create_mutexes_func(
-/*=====================*/
- hash_table_t* table, /*!< in: hash table */
-#ifdef UNIV_SYNC_DEBUG
- ulint sync_level, /*!< in: latching order level of the
- mutexes: used in the debug version */
-#endif /* UNIV_SYNC_DEBUG */
- ulint n_mutexes) /*!< in: number of mutexes, must be a
- power of 2 */
-{
- ulint i;
-
- ut_ad(table);
- ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
- ut_a(n_mutexes > 0);
- ut_a(ut_is_2pow(n_mutexes));
-
- table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
-
- for (i = 0; i < n_mutexes; i++) {
- mutex_create(hash_table_mutex_key,
- table->mutexes + i, sync_level);
- }
-
- table->n_mutexes = n_mutexes;
-}
-#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/ha/hash0hash.cc b/storage/innobase/ha/hash0hash.cc
new file mode 100644
index 00000000000..99128a676d5
--- /dev/null
+++ b/storage/innobase/ha/hash0hash.cc
@@ -0,0 +1,403 @@
+/*****************************************************************************
+
+Copyright (c) 1997, 2011, 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 ha/hash0hash.cc
+The simple hash table utility
+
+Created 5/20/1997 Heikki Tuuri
+*******************************************************/
+
+#include "hash0hash.h"
+#ifdef UNIV_NONINL
+#include "hash0hash.ic"
+#endif
+
+#include "mem0mem.h"
+
+#ifndef UNIV_HOTBACKUP
+
+# ifdef UNIV_PFS_MUTEX
+UNIV_INTERN mysql_pfs_key_t hash_table_mutex_key;
+# endif /* UNIV_PFS_MUTEX */
+
+# ifdef UNIV_PFS_RWLOCK
+UNIV_INTERN mysql_pfs_key_t hash_table_rw_lock_key;
+# endif /* UNIV_PFS_RWLOCK */
+/************************************************************//**
+Reserves the mutex for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_mutex_enter(
+/*=============*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+ ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+ mutex_enter(hash_get_mutex(table, fold));
+}
+
+/************************************************************//**
+Releases the mutex for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_mutex_exit(
+/*============*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+ ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+ mutex_exit(hash_get_mutex(table, fold));
+}
+
+/************************************************************//**
+Reserves all the mutexes of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_mutex_enter_all(
+/*=================*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ mutex_enter(table->sync_obj.mutexes + i);
+ }
+}
+
+/************************************************************//**
+Releases all the mutexes of a hash table. */
+UNIV_INTERN
+void
+hash_mutex_exit_all(
+/*================*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ mutex_exit(table->sync_obj.mutexes + i);
+ }
+}
+
+/************************************************************//**
+Releases all but the passed in mutex of a hash table. */
+UNIV_INTERN
+void
+hash_mutex_exit_all_but(
+/*====================*/
+ hash_table_t* table, /*!< in: hash table */
+ mutex_t* keep_mutex) /*!< in: mutex to keep */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ mutex_t* mutex = table->sync_obj.mutexes + i;
+ if (UNIV_LIKELY(keep_mutex != mutex)) {
+ mutex_exit(mutex);
+ }
+ }
+
+ ut_ad(mutex_own(keep_mutex));
+}
+
+/************************************************************//**
+s-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_s(
+/*========*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+
+ rw_lock_t* lock = hash_get_lock(table, fold);
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_s_lock(lock);
+}
+
+/************************************************************//**
+x-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_x(
+/*========*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+
+ rw_lock_t* lock = hash_get_lock(table, fold);
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_x_lock(lock);
+}
+
+/************************************************************//**
+unlock an s-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_s(
+/*==========*/
+
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+
+ rw_lock_t* lock = hash_get_lock(table, fold);
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_s_unlock(lock);
+}
+
+/************************************************************//**
+unlock x-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_x(
+/*==========*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+ rw_lock_t* lock = hash_get_lock(table, fold);
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_x_unlock(lock);
+}
+
+/************************************************************//**
+Reserves all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_lock_x_all(
+/*============*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_x_lock(lock);
+ }
+}
+
+/************************************************************//**
+Releases all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_unlock_x_all(
+/*==============*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rw_lock_x_unlock(lock);
+ }
+}
+
+/************************************************************//**
+Releases all but passed in lock of a hash table, */
+UNIV_INTERN
+void
+hash_unlock_x_all_but(
+/*==================*/
+ hash_table_t* table, /*!< in: hash table */
+ rw_lock_t* keep_lock) /*!< in: lock to keep */
+{
+ ulint i;
+
+ ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+ for (i = 0; i < table->n_sync_obj; i++) {
+
+ rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ if (UNIV_LIKELY(keep_lock != lock)) {
+ rw_lock_x_unlock(lock);
+ }
+ }
+}
+
+#endif /* !UNIV_HOTBACKUP */
+
+/*************************************************************//**
+Creates a hash table with >= n array cells. The actual number of cells is
+chosen to be a prime number slightly bigger than n.
+@return own: created table */
+UNIV_INTERN
+hash_table_t*
+hash_create(
+/*========*/
+ ulint n) /*!< in: number of array cells */
+{
+ hash_cell_t* array;
+ ulint prime;
+ hash_table_t* table;
+
+ prime = ut_find_prime(n);
+
+ table = static_cast<hash_table_t*>(mem_alloc(sizeof(hash_table_t)));
+
+ array = static_cast<hash_cell_t*>(
+ ut_malloc(sizeof(hash_cell_t) * prime));
+
+ /* The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.:
+ the caller is responsible for access control to the table. */
+ table->type = HASH_TABLE_SYNC_NONE;
+ table->array = array;
+ table->n_cells = prime;
+#ifndef UNIV_HOTBACKUP
+# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ table->adaptive = FALSE;
+# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ table->n_sync_obj = 0;
+ table->sync_obj.mutexes = NULL;
+ table->heaps = NULL;
+#endif /* !UNIV_HOTBACKUP */
+ table->heap = NULL;
+ ut_d(table->magic_n = HASH_TABLE_MAGIC_N);
+
+ /* Initialize the cell array */
+ hash_table_clear(table);
+
+ return(table);
+}
+
+/*************************************************************//**
+Frees a hash table. */
+UNIV_INTERN
+void
+hash_table_free(
+/*============*/
+ hash_table_t* table) /*!< in, own: hash table */
+{
+ ut_ad(table);
+ ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+
+ ut_free(table->array);
+ mem_free(table);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Creates a sync object array to protect a hash table.
+::sync_obj can be mutexes or rw_locks depening on the type of
+hash table. */
+UNIV_INTERN
+void
+hash_create_sync_obj_func(
+/*======================*/
+ hash_table_t* table, /*!< in: hash table */
+ enum hash_table_sync_t type, /*!< in: HASH_TABLE_SYNC_MUTEX
+ or HASH_TABLE_SYNC_RW_LOCK */
+#ifdef UNIV_SYNC_DEBUG
+ ulint sync_level,/*!< in: latching order level
+ of the mutexes: used in the
+ debug version */
+#endif /* UNIV_SYNC_DEBUG */
+ ulint n_sync_obj)/*!< in: number of sync objects,
+ must be a power of 2 */
+{
+ ulint i;
+
+ ut_ad(table);
+ ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+ ut_a(n_sync_obj > 0);
+ ut_a(ut_is_2pow(n_sync_obj));
+
+ table->type = type;
+
+ switch (type) {
+ case HASH_TABLE_SYNC_MUTEX:
+ table->sync_obj.mutexes = static_cast<mutex_t*>(
+ mem_alloc(n_sync_obj * sizeof(mutex_t)));
+
+ for (i = 0; i < n_sync_obj; i++) {
+ mutex_create(hash_table_mutex_key,
+ table->sync_obj.mutexes + i, sync_level);
+ }
+
+ break;
+
+ case HASH_TABLE_SYNC_RW_LOCK:
+ table->sync_obj.rw_locks = static_cast<rw_lock_t*>(
+ mem_alloc(n_sync_obj * sizeof(rw_lock_t)));
+
+ for (i = 0; i < n_sync_obj; i++) {
+ rw_lock_create(hash_table_rw_lock_key,
+ table->sync_obj.rw_locks + i, sync_level);
+ }
+
+ break;
+
+ case HASH_TABLE_SYNC_NONE:
+ ut_error;
+ }
+
+ table->n_sync_obj = n_sync_obj;
+}
+#endif /* !UNIV_HOTBACKUP */