MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ha0ha.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /********************************************************************/
26 #include "ha0ha.h"
27 #ifdef UNIV_NONINL
28 #include "ha0ha.ic"
29 #endif
30 
31 #ifndef UNIV_HOTBACKUP
32 #ifdef UNIV_DEBUG
33 # include "buf0buf.h"
34 #endif /* UNIV_DEBUG */
35 # include "btr0sea.h"
36 #include "page0page.h"
37 
38 /*************************************************************/
42 UNIV_INTERN
45 /*===========*/
46  ulint n,
47 #ifdef UNIV_SYNC_DEBUG
48  ulint sync_level,
51 #endif /* UNIV_SYNC_DEBUG */
52  ulint n_sync_obj,
55  ulint type)
59 {
61  ulint i;
62 
63  ut_a(type == MEM_HEAP_FOR_BTR_SEARCH
64  || type == MEM_HEAP_FOR_PAGE_HASH);
65 
66  ut_ad(ut_is_2pow(n_sync_obj));
67  table = hash_create(n);
68 
69  /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
70  but in practise it never should in this case, hence the asserts. */
71 
72  if (n_sync_obj == 0) {
73  table->heap = mem_heap_create_typed(
74  ut_min(4096, MEM_MAX_ALLOC_IN_BUF), type);
75  ut_a(table->heap);
76 
77  return(table);
78  }
79 
80  if (type == MEM_HEAP_FOR_PAGE_HASH) {
81  /* We create a hash table protected by rw_locks for
82  buf_pool->page_hash. */
83  hash_create_sync_obj(table, HASH_TABLE_SYNC_RW_LOCK,
84  n_sync_obj, sync_level);
85  } else {
86  hash_create_sync_obj(table, HASH_TABLE_SYNC_MUTEX,
87  n_sync_obj, sync_level);
88  }
89 
90  table->heaps = static_cast<mem_heap_t**>(
91  mem_alloc(n_sync_obj * sizeof(void*)));
92 
93  for (i = 0; i < n_sync_obj; i++) {
94  table->heaps[i] = mem_heap_create_typed(4096, type);
95  ut_a(table->heaps[i]);
96  }
97 
98  return(table);
99 }
100 
101 /*************************************************************/
103 UNIV_INTERN
104 void
106 /*=====*/
108 {
109  ulint i;
110  ulint n;
111 
112  ut_ad(table);
113  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
114 #ifdef UNIV_SYNC_DEBUG
115  ut_ad(!table->adaptive
116  || rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
117 #endif /* UNIV_SYNC_DEBUG */
118 
119  /* Free the memory heaps. */
120  n = table->n_sync_obj;
121 
122  for (i = 0; i < n; i++) {
123  mem_heap_free(table->heaps[i]);
124  }
125 
126  if (table->heaps) {
127  mem_free(table->heaps);
128  }
129 
130  switch (table->type) {
132  mem_free(table->sync_obj.mutexes);
133  table->sync_obj.mutexes = NULL;
134  break;
135 
137  mem_free(table->sync_obj.rw_locks);
138  table->sync_obj.rw_locks = NULL;
139  break;
140 
142  /* do nothing */
143  break;
144  }
145 
146  table->n_sync_obj = 0;
147  table->type = HASH_TABLE_SYNC_NONE;
148 
149 
150  /* Clear the hash table. */
151  n = hash_get_n_cells(table);
152 
153  for (i = 0; i < n; i++) {
154  hash_get_nth_cell(table, i)->node = NULL;
155  }
156 }
157 
158 /*************************************************************/
164 UNIV_INTERN
165 ibool
167 /*====================*/
169  ulint fold,
173 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
174  buf_block_t* block,
175 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
176  const rec_t* data)
177 {
178  hash_cell_t* cell;
179  ha_node_t* node;
180  ha_node_t* prev_node;
181  ulint hash;
182 
183  ut_ad(data);
184  ut_ad(table);
185  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
186 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
187  ut_a(block->frame == page_align(data));
188 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
189  hash_assert_can_modify(table, fold);
191 
192  hash = hash_calc_hash(fold, table);
193 
194  cell = hash_get_nth_cell(table, hash);
195 
196  prev_node = static_cast<ha_node_t*>(cell->node);
197 
198  while (prev_node != NULL) {
199  if (prev_node->fold == fold) {
200 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
201  if (table->adaptive) {
202  buf_block_t* prev_block = prev_node->block;
203  ut_a(prev_block->frame
204  == page_align(prev_node->data));
205  ut_a(prev_block->n_pointers > 0);
206  prev_block->n_pointers--;
207  block->n_pointers++;
208  }
209 
210  prev_node->block = block;
211 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
212  prev_node->data = data;
213 
214  return(TRUE);
215  }
216 
217  prev_node = prev_node->next;
218  }
219 
220  /* We have to allocate a new chain node */
221 
222  node = static_cast<ha_node_t*>(
223  mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)));
224 
225  if (node == NULL) {
226  /* It was a btr search type memory heap and at the moment
227  no more memory could be allocated: return */
228 
229  ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
230 
231  return(FALSE);
232  }
233 
234  ha_node_set_data(node, block, data);
235 
236 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
237  if (table->adaptive) {
238  block->n_pointers++;
239  }
240 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
241 
242  node->fold = fold;
243 
244  node->next = NULL;
245 
246  prev_node = static_cast<ha_node_t*>(cell->node);
247 
248  if (prev_node == NULL) {
249 
250  cell->node = node;
251 
252  return(TRUE);
253  }
254 
255  while (prev_node->next != NULL) {
256 
257  prev_node = prev_node->next;
258  }
259 
260  prev_node->next = node;
261 
262  return(TRUE);
263 }
264 
265 /***********************************************************/
267 UNIV_INTERN
268 void
270 /*================*/
272  ha_node_t* del_node)
273 {
274  ut_ad(table);
275  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
276 #ifdef UNIV_SYNC_DEBUG
277  ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
278 #endif /* UNIV_SYNC_DEBUG */
280 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
281  if (table->adaptive) {
282  ut_a(del_node->block->frame = page_align(del_node->data));
283  ut_a(del_node->block->n_pointers > 0);
284  del_node->block->n_pointers--;
285  }
286 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
287 
288  HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
289 }
290 
291 /*********************************************************/
295 UNIV_INTERN
296 ibool
298 /*===============================*/
300  ulint fold,
301  const rec_t* data,
302 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
303  buf_block_t* new_block,
304 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
305  const rec_t* new_data)
306 {
307  ha_node_t* node;
308 
309  ut_ad(table);
310  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
311  hash_assert_can_modify(table, fold);
312 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
313  ut_a(new_block->frame == page_align(new_data));
314 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
315 #ifdef UNIV_SYNC_DEBUG
316  ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
317 #endif /* UNIV_SYNC_DEBUG */
318 
319  if (!btr_search_enabled) {
320  return(FALSE);
321  }
322 
323  node = ha_search_with_data(table, fold, data);
324 
325  if (node) {
326 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
327  if (table->adaptive) {
328  ut_a(node->block->n_pointers > 0);
329  node->block->n_pointers--;
330  new_block->n_pointers++;
331  }
332 
333  node->block = new_block;
334 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
335  node->data = new_data;
336 
337  return(TRUE);
338  }
339 
340  return(FALSE);
341 }
342 
343 /*****************************************************************/
346 UNIV_INTERN
347 void
349 /*========================*/
351  ulint fold,
352  const page_t* page)
353 {
354  ha_node_t* node;
355 
356  ut_ad(table);
357  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
358  hash_assert_can_modify(table, fold);
360 
361  node = ha_chain_get_first(table, fold);
362 
363  while (node) {
364  if (page_align(ha_node_get_data(node)) == page) {
365 
366  /* Remove the hash node */
367 
368  ha_delete_hash_node(table, node);
369 
370  /* Start again from the first node in the chain
371  because the deletion may compact the heap of
372  nodes and move other nodes! */
373 
374  node = ha_chain_get_first(table, fold);
375  } else {
376  node = ha_chain_get_next(node);
377  }
378  }
379 #ifdef UNIV_DEBUG
380  /* Check that all nodes really got deleted */
381 
382  node = ha_chain_get_first(table, fold);
383 
384  while (node) {
385  ut_a(page_align(ha_node_get_data(node)) != page);
386 
387  node = ha_chain_get_next(node);
388  }
389 #endif
390 }
391 
392 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
393 /*************************************************************/
396 UNIV_INTERN
397 ibool
398 ha_validate(
399 /*========*/
401  ulint start_index,
402  ulint end_index)
403 {
404  ibool ok = TRUE;
405  ulint i;
406 
407  ut_ad(table);
408  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
409  ut_a(start_index <= end_index);
410  ut_a(start_index < hash_get_n_cells(table));
411  ut_a(end_index < hash_get_n_cells(table));
412 
413  for (i = start_index; i <= end_index; i++) {
414  ha_node_t* node;
415  hash_cell_t* cell;
416 
417  cell = hash_get_nth_cell(table, i);
418 
419  for (node = static_cast<ha_node_t*>(cell->node);
420  node != 0;
421  node = node->next) {
422 
423  if (hash_calc_hash(node->fold, table) != i) {
424  ut_print_timestamp(stderr);
425  fprintf(stderr,
426  "InnoDB: Error: hash table node"
427  " fold value %lu does not\n"
428  "InnoDB: match the cell number %lu.\n",
429  (ulong) node->fold, (ulong) i);
430 
431  ok = FALSE;
432  }
433  }
434  }
435 
436  return(ok);
437 }
438 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
439 
440 /*************************************************************/
442 UNIV_INTERN
443 void
445 /*==========*/
446  FILE* file,
447  hash_table_t* table)
448 {
449 #ifdef UNIV_DEBUG
450 /* Some of the code here is disabled for performance reasons in production
451 builds, see http://bugs.mysql.com/36941 */
452 #define PRINT_USED_CELLS
453 #endif /* UNIV_DEBUG */
454 
455 #ifdef PRINT_USED_CELLS
456  hash_cell_t* cell;
457  ulint cells = 0;
458  ulint i;
459 #endif /* PRINT_USED_CELLS */
460  ulint n_bufs;
461 
462  ut_ad(table);
463  ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
464 #ifdef PRINT_USED_CELLS
465  for (i = 0; i < hash_get_n_cells(table); i++) {
466 
467  cell = hash_get_nth_cell(table, i);
468 
469  if (cell->node) {
470 
471  cells++;
472  }
473  }
474 #endif /* PRINT_USED_CELLS */
475 
476  fprintf(file, "Hash table size %lu",
477  (ulong) hash_get_n_cells(table));
478 
479 #ifdef PRINT_USED_CELLS
480  fprintf(file, ", used cells %lu", (ulong) cells);
481 #endif /* PRINT_USED_CELLS */
482 
483  if (table->heaps == NULL && table->heap != NULL) {
484 
485  /* This calculation is intended for the adaptive hash
486  index: how many buffer frames we have reserved? */
487 
488  n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
489 
490  if (table->heap->free_block) {
491  n_bufs++;
492  }
493 
494  fprintf(file, ", node heap has %lu buffer(s)\n",
495  (ulong) n_bufs);
496  }
497 }
498 #endif /* !UNIV_HOTBACKUP */