Drizzled Public API Documentation

ha0ha.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /********************************************************************/
00026 #include "ha0ha.h"
00027 #ifdef UNIV_NONINL
00028 #include "ha0ha.ic"
00029 #endif
00030 
00031 #ifdef UNIV_DEBUG
00032 # include "buf0buf.h"
00033 #endif /* UNIV_DEBUG */
00034 #include "btr0sea.h"
00035 #include "page0page.h"
00036 
00037 /*************************************************************/
00041 UNIV_INTERN
00042 hash_table_t*
00043 ha_create_func(
00044 /*===========*/
00045   ulint n,    
00046 #ifdef UNIV_SYNC_DEBUG
00047   ulint mutex_level,  
00049 #endif /* UNIV_SYNC_DEBUG */
00050   ulint n_mutexes)  
00052 {
00053   hash_table_t* table;
00054 #ifndef UNIV_HOTBACKUP
00055   ulint   i;
00056 #endif /* !UNIV_HOTBACKUP */
00057 
00058   ut_ad(ut_is_2pow(n_mutexes));
00059   table = hash_create(n);
00060 
00061 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00062 # ifndef UNIV_HOTBACKUP
00063   table->adaptive = TRUE;
00064 # endif /* !UNIV_HOTBACKUP */
00065 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00066   /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
00067   but in practise it never should in this case, hence the asserts. */
00068 
00069   if (n_mutexes == 0) {
00070     table->heap = mem_heap_create_in_btr_search(
00071       ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
00072     ut_a(table->heap);
00073 
00074     return(table);
00075   }
00076 
00077 #ifndef UNIV_HOTBACKUP
00078   hash_create_mutexes(table, n_mutexes, mutex_level);
00079 
00080   table->heaps = static_cast<mem_block_info_t **>(mem_alloc(n_mutexes * sizeof(mem_block_info_t *)));
00081 
00082   for (i = 0; i < n_mutexes; i++) {
00083     table->heaps[i] = mem_heap_create_in_btr_search(4096);
00084     ut_a(table->heaps[i]);
00085   }
00086 #endif /* !UNIV_HOTBACKUP */
00087 
00088   return(table);
00089 }
00090 
00091 /*************************************************************/
00093 UNIV_INTERN
00094 void
00095 ha_clear(
00096 /*=====*/
00097   hash_table_t* table)  
00098 {
00099   ulint i;
00100   ulint n;
00101 
00102   ut_ad(table);
00103   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00104 #ifdef UNIV_SYNC_DEBUG
00105   ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
00106 #endif /* UNIV_SYNC_DEBUG */
00107 
00108 #ifndef UNIV_HOTBACKUP
00109   /* Free the memory heaps. */
00110   n = table->n_mutexes;
00111 
00112   for (i = 0; i < n; i++) {
00113     mem_heap_free(table->heaps[i]);
00114   }
00115 #endif /* !UNIV_HOTBACKUP */
00116 
00117   /* Clear the hash table. */
00118   n = hash_get_n_cells(table);
00119 
00120   for (i = 0; i < n; i++) {
00121     hash_get_nth_cell(table, i)->node = NULL;
00122   }
00123 }
00124 
00125 /*************************************************************/
00131 UNIV_INTERN
00132 ibool
00133 ha_insert_for_fold_func(
00134 /*====================*/
00135   hash_table_t* table,  
00136   ulint   fold, 
00140 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00141   buf_block_t*  block,  
00142 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00143   void*   data) 
00144 {
00145   hash_cell_t*  cell;
00146   ha_node_t*  node;
00147   ha_node_t*  prev_node;
00148   ulint   hash;
00149 
00150   ut_ad(data);
00151   ut_ad(table);
00152   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00153 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00154   ut_a(block->frame == page_align(data));
00155 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00156   ASSERT_HASH_MUTEX_OWN(table, fold);
00157 
00158   hash = hash_calc_hash(fold, table);
00159 
00160   cell = hash_get_nth_cell(table, hash);
00161 
00162   prev_node = static_cast<ha_node_t *>(cell->node);
00163 
00164   while (prev_node != NULL) {
00165     if (prev_node->fold == fold) {
00166 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00167 # ifndef UNIV_HOTBACKUP
00168       if (table->adaptive) {
00169         buf_block_t* prev_block = prev_node->block;
00170         ut_a(prev_block->frame
00171              == page_align(prev_node->data));
00172         ut_a(prev_block->n_pointers > 0);
00173         prev_block->n_pointers--;
00174         block->n_pointers++;
00175       }
00176       ut_ad(!btr_search_fully_disabled);
00177 # endif /* !UNIV_HOTBACKUP */
00178 
00179       prev_node->block = block;
00180 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00181       prev_node->data = data;
00182 
00183       return(TRUE);
00184     }
00185 
00186     prev_node = prev_node->next;
00187   }
00188 
00189   /* We are in the process of disabling hash index, do not add
00190   new chain node */
00191   if (!btr_search_enabled) {
00192     ut_ad(!btr_search_fully_disabled);
00193     return(TRUE);
00194   }
00195 
00196   /* We have to allocate a new chain node */
00197 
00198   node = static_cast<ha_node_t *>(mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)));
00199 
00200   if (node == NULL) {
00201     /* It was a btr search type memory heap and at the moment
00202     no more memory could be allocated: return */
00203 
00204     ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
00205 
00206     return(FALSE);
00207   }
00208 
00209   ha_node_set_data(node, block, data);
00210 
00211 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00212 # ifndef UNIV_HOTBACKUP
00213   if (table->adaptive) {
00214     block->n_pointers++;
00215   }
00216 # endif /* !UNIV_HOTBACKUP */
00217 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00218 
00219   node->fold = fold;
00220 
00221   node->next = NULL;
00222 
00223   prev_node = static_cast<ha_node_t *>(cell->node);
00224 
00225   if (prev_node == NULL) {
00226 
00227     cell->node = node;
00228 
00229     return(TRUE);
00230   }
00231 
00232   while (prev_node->next != NULL) {
00233 
00234     prev_node = prev_node->next;
00235   }
00236 
00237   prev_node->next = node;
00238 
00239   return(TRUE);
00240 }
00241 
00242 /***********************************************************/
00244 UNIV_INTERN
00245 void
00246 ha_delete_hash_node(
00247 /*================*/
00248   hash_table_t* table,    
00249   ha_node_t*  del_node) 
00250 {
00251   ut_ad(table);
00252   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00253 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00254 # ifndef UNIV_HOTBACKUP
00255   if (table->adaptive) {
00256     ut_a(del_node->block->frame = page_align(del_node->data));
00257     ut_a(del_node->block->n_pointers > 0);
00258     del_node->block->n_pointers--;
00259   }
00260 # endif /* !UNIV_HOTBACKUP */
00261 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00262 
00263   HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
00264 }
00265 
00266 /*********************************************************/
00269 UNIV_INTERN
00270 void
00271 ha_search_and_update_if_found_func(
00272 /*===============================*/
00273   hash_table_t* table,  
00274   ulint   fold, 
00275   void*   data, 
00276 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00277   buf_block_t*  new_block,
00278 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00279   void*   new_data)
00280 {
00281   ha_node_t*  node;
00282 
00283   ut_ad(table);
00284   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00285   ASSERT_HASH_MUTEX_OWN(table, fold);
00286 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00287   ut_a(new_block->frame == page_align(new_data));
00288 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00289 
00290   node = ha_search_with_data(table, fold, data);
00291 
00292   if (node) {
00293 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00294 # ifndef UNIV_HOTBACKUP
00295     if (table->adaptive) {
00296       ut_a(node->block->n_pointers > 0);
00297       node->block->n_pointers--;
00298       new_block->n_pointers++;
00299     }
00300 # endif /* !UNIV_HOTBACKUP */
00301 
00302     node->block = new_block;
00303 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00304     node->data = new_data;
00305   }
00306 }
00307 
00308 #ifndef UNIV_HOTBACKUP
00309 /*****************************************************************/
00312 UNIV_INTERN
00313 void
00314 ha_remove_all_nodes_to_page(
00315 /*========================*/
00316   hash_table_t* table,  
00317   ulint   fold, 
00318   const page_t* page) 
00319 {
00320   ha_node_t*  node;
00321 
00322   ut_ad(table);
00323   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00324   ASSERT_HASH_MUTEX_OWN(table, fold);
00325 
00326   node = ha_chain_get_first(table, fold);
00327 
00328   while (node) {
00329     if (page_align(ha_node_get_data(node)) == page) {
00330 
00331       /* Remove the hash node */
00332 
00333       ha_delete_hash_node(table, node);
00334 
00335       /* Start again from the first node in the chain
00336       because the deletion may compact the heap of
00337       nodes and move other nodes! */
00338 
00339       node = ha_chain_get_first(table, fold);
00340     } else {
00341       node = ha_chain_get_next(node);
00342     }
00343   }
00344 #ifdef UNIV_DEBUG
00345   /* Check that all nodes really got deleted */
00346 
00347   node = ha_chain_get_first(table, fold);
00348 
00349   while (node) {
00350     ut_a(page_align(ha_node_get_data(node)) != page);
00351 
00352     node = ha_chain_get_next(node);
00353   }
00354 #endif
00355 }
00356 
00357 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00358 /*************************************************************/
00361 UNIV_INTERN
00362 ibool
00363 ha_validate(
00364 /*========*/
00365   hash_table_t* table,    
00366   ulint   start_index,  
00367   ulint   end_index)  
00368 {
00369   hash_cell_t*  cell;
00370   ha_node_t*  node;
00371   ibool   ok  = TRUE;
00372   ulint   i;
00373 
00374   ut_ad(table);
00375   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00376   ut_a(start_index <= end_index);
00377   ut_a(start_index < hash_get_n_cells(table));
00378   ut_a(end_index < hash_get_n_cells(table));
00379 
00380   for (i = start_index; i <= end_index; i++) {
00381 
00382     cell = hash_get_nth_cell(table, i);
00383 
00384     node = cell->node;
00385 
00386     while (node) {
00387       if (hash_calc_hash(node->fold, table) != i) {
00388         ut_print_timestamp(stderr);
00389         fprintf(stderr,
00390           "InnoDB: Error: hash table node"
00391           " fold value %lu does not\n"
00392           "InnoDB: match the cell number %lu.\n",
00393           (ulong) node->fold, (ulong) i);
00394 
00395         ok = FALSE;
00396       }
00397 
00398       node = node->next;
00399     }
00400   }
00401 
00402   return(ok);
00403 }
00404 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
00405 
00406 /*************************************************************/
00408 UNIV_INTERN
00409 void
00410 ha_print_info(
00411 /*==========*/
00412   FILE*   file, 
00413   hash_table_t* table)  
00414 {
00415   ut_ad(table);
00416   ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
00417 #ifdef UNIV_DEBUG
00418 /* Some of the code here is disabled for performance reasons in production
00419 builds, see http://bugs.mysql.com/36941 */
00420 #define PRINT_USED_CELLS
00421 #endif /* UNIV_DEBUG */
00422 
00423 #ifdef PRINT_USED_CELLS
00424   hash_cell_t*  cell;
00425   ulint   cells = 0;
00426   ulint   i;
00427 #endif /* PRINT_USED_CELLS */
00428   ulint   n_bufs;
00429 
00430 #ifdef PRINT_USED_CELLS
00431   for (i = 0; i < hash_get_n_cells(table); i++) {
00432 
00433     cell = hash_get_nth_cell(table, i);
00434 
00435     if (cell->node) {
00436 
00437       cells++;
00438     }
00439   }
00440 #endif /* PRINT_USED_CELLS */
00441 
00442   fprintf(file, "Hash table size %lu",
00443     (ulong) hash_get_n_cells(table));
00444 
00445 #ifdef PRINT_USED_CELLS
00446   fprintf(file, ", used cells %lu", (ulong) cells);
00447 #endif /* PRINT_USED_CELLS */
00448 
00449   if (table->heaps == NULL && table->heap != NULL) {
00450 
00451     /* This calculation is intended for the adaptive hash
00452     index: how many buffer frames we have reserved? */
00453 
00454     n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
00455 
00456     if (table->heap->free_block) {
00457       n_bufs++;
00458     }
00459 
00460     fprintf(file, ", node heap has %lu buffer(s)\n",
00461       (ulong) n_bufs);
00462   }
00463 }
00464 #endif /* !UNIV_HOTBACKUP */