1、自适应哈希索引初始化
在storage\innobase\buf\buf0buf.cc的函数buf_pool_init负责初始化Buffer pool, 会调用btr_search_sys_create来初始化AHI,并分配当前Buffer pool内存的1/64给AHI。
/** Creates the buffer pool. @param[in] total_size Size of the total pool in bytes. @param[in] n_instances Number of buffer pool instances to create. @return DB_SUCCESS if success, DB_ERROR if not enough memory or error */ dberr_t buf_pool_init(ulint total_size, ulint n_instances) { /** 初始化AHI并分片buffer pool的1/64内存给AHI **/ btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void *) / 64); }
在btr_search_sys_create中,会按照参数innodb_adaptive_hash_index_parts来设置hash_tabsles数量,并将内存平均分配给每个hash_table。
在创建每个hash_table时,会按照(hash_size / btr_ahi_parts)来设置hash_table的cells数量。
/** Creates and initializes the adaptive search system at a database start. @param[in] hash_size hash table size. */ void btr_search_sys_create(ulint hash_size) { /* Search System is divided into n parts. Each part controls access to distinct set of hash buckets from hash table through its own latch. */ /* Step-1: Allocate latches (1 per part). */ btr_search_latches = reinterpret_cast<rw_lock_t **>( ut_malloc(sizeof(rw_lock_t *) * btr_ahi_parts, mem_key_ahi)); for (ulint i = 0; i < btr_ahi_parts; ++i) { btr_search_latches[i] = reinterpret_cast<rw_lock_t *>( ut_malloc(sizeof(rw_lock_t), mem_key_ahi)); rw_lock_create(btr_search_latch_key, btr_search_latches[i], SYNC_SEARCH_SYS); } /* Step-2: Allocate hash tablees. */ btr_search_sys = reinterpret_cast<btr_search_sys_t *>( ut_malloc(sizeof(btr_search_sys_t), mem_key_ahi)); btr_search_sys->hash_tables = reinterpret_cast<hash_table_t **>( ut_malloc(sizeof(hash_table_t *) * btr_ahi_parts, mem_key_ahi)); for (ulint i = 0; i < btr_ahi_parts; ++i) { btr_search_sys->hash_tables[i] = ib_create((hash_size / btr_ahi_parts), LATCH_ID_HASH_TABLE_MUTEX, 0, MEM_HEAP_FOR_BTR_SEARCH); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG btr_search_sys->hash_tables[i]->adaptive = TRUE; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ } }
通过调用通用的ib_create函数来创建hast_table:
/** Creates a hash table with at least n array cells. The actual number of cells is chosen to be a prime number slightly bigger than n. @return own: created table */ hash_table_t *ib_create(ulint n, /*!< in: number of array cells */ latch_id_t id, /*!< in: latch ID */ ulint n_sync_obj, /*!< in: number of mutexes to protect the hash table: must be a power of 2, or 0 */ ulint type) /*!< in: type of datastructure for which MEM_HEAP_FOR_PAGE_HASH */ { hash_table_t *table; 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); /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail, but in practise it never should in this case, hence the asserts. */ if (n_sync_obj == 0) { table->heap = mem_heap_create_typed( ut_min(static_cast<ulint>(4096), MEM_MAX_ALLOC_IN_BUF / 2 - MEM_BLOCK_HEADER_SIZE - MEM_SPACE_NEEDED(0)), type); ut_a(table->heap); return (table); } 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, id, n_sync_obj); } else { hash_create_sync_obj(table, HASH_TABLE_SYNC_MUTEX, id, n_sync_obj); } table->heaps = static_cast<mem_heap_t **>(ut_malloc_nokey(n_sync_obj * sizeof(void *))); for (ulint i = 0; i < n_sync_obj; i++) { table->heaps[i] = mem_heap_create_typed( ut_min(static_cast<ulint>(4096), MEM_MAX_ALLOC_IN_BUF / 2 - MEM_BLOCK_HEADER_SIZE - MEM_SPACE_NEEDED(0)), type); ut_a(table->heaps[i]); } return (table); } /** 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 */ hash_table_t *hash_create(ulint n); /*!< in: number of array cells */ /* Fix Bug #13859: symbol collision between imap/mysql */ #define hash_create hash0_create
在hash_create函数中会跟进传入的cell数量重新计算,取一个大于"传入cell数量"的最小素数。
/** 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 */ 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 *>(ut_malloc_nokey(sizeof(hash_table_t))); array = static_cast<hash_cell_t *>(ut_malloc_nokey(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->cells = 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 = nullptr; table->heaps = nullptr; #endif /* !UNIV_HOTBACKUP */ table->heap = nullptr; ut_d(table->magic_n = HASH_TABLE_MAGIC_N); /* Initialize the cell array */ hash_table_clear(table); return (table); }