btr0sea.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:38k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /************************************************************************
  2. The index tree adaptive search
  3. (c) 1996 Innobase Oy
  4. Created 2/17/1996 Heikki Tuuri
  5. *************************************************************************/
  6. #include "btr0sea.h"
  7. #ifdef UNIV_NONINL
  8. #include "btr0sea.ic"
  9. #endif
  10. #include "buf0buf.h"
  11. #include "page0page.h"
  12. #include "page0cur.h"
  13. #include "btr0cur.h"
  14. #include "btr0pcur.h"
  15. #include "btr0btr.h"
  16. #include "ha0ha.h"
  17. ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
  18. compiler */
  19. #ifdef UNIV_SEARCH_PERF_STAT
  20. ulint btr_search_n_succ = 0;
  21. #endif /* UNIV_SEARCH_PERF_STAT */
  22. ulint btr_search_n_hash_fail = 0;
  23. byte btr_sea_pad1[64]; /* padding to prevent other memory update
  24. hotspots from residing on the same memory
  25. cache line as btr_search_latch */
  26. /* The latch protecting the adaptive search system: this latch protects the
  27. (1) positions of records on those pages where a hash index has been built.
  28. NOTE: It does not protect values of non-ordering fields within a record from
  29. being updated in-place! We can use fact (1) to perform unique searches to
  30. indexes. */
  31. rw_lock_t* btr_search_latch_temp; /* We will allocate the latch from
  32. dynamic memory to get it to the
  33. same DRAM page as other hotspot
  34. semaphores */
  35. byte btr_sea_pad2[64]; /* padding to prevent other memory update
  36. hotspots from residing on the same memory
  37. cache line */
  38. btr_search_sys_t* btr_search_sys;
  39. /* If the number of records on the page divided by this parameter
  40. would have been successfully accessed using a hash index, the index
  41. is then built on the page, assuming the global limit has been reached */
  42. #define BTR_SEARCH_PAGE_BUILD_LIMIT 16
  43. /* The global limit for consecutive potentially successful hash searches,
  44. before hash index building is started */
  45. #define BTR_SEARCH_BUILD_LIMIT 100
  46. /************************************************************************
  47. Builds a hash index on a page with the given parameters. If the page already
  48. has a hash index with different parameters, the old hash index is removed.
  49. If index is non-NULL, this function checks if n_fields and n_bytes are
  50. sensible values, and does not build a hash index if not. */
  51. static
  52. void
  53. btr_search_build_page_hash_index(
  54. /*=============================*/
  55. dict_index_t* index, /* in: index for which to build, or NULL if
  56. not known */
  57. page_t* page, /* in: index page, s- or x-latched */
  58. ulint n_fields,/* in: hash this many full fields */
  59. ulint n_bytes,/* in: hash this many bytes from the next
  60. field */
  61. ulint side); /* in: hash for searches from this side */
  62. /*********************************************************************
  63. This function should be called before reserving any btr search mutex, if
  64. the intended operation might add nodes to the search system hash table.
  65. Because of the latching order, once we have reserved the btr search system
  66. latch, we cannot allocate a free frame from the buffer pool. Checks that
  67. there is a free buffer frame allocated for hash table heap in the btr search
  68. system. If not, allocates a free frames for the heap. This check makes it
  69. probable that, when have reserved the btr search system latch and we need to
  70. allocate a new node to the hash table, it will succeed. However, the check
  71. will not guarantee success. */
  72. static
  73. void
  74. btr_search_check_free_space_in_heap(void)
  75. /*=====================================*/
  76. {
  77. buf_frame_t* frame;
  78. hash_table_t* table;
  79. mem_heap_t* heap;
  80. #ifdef UNIV_SYNC_DEBUG
  81. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
  82. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  83. #endif /* UNIV_SYNC_DEBUG */
  84. table = btr_search_sys->hash_index;
  85. heap = table->heap;
  86. /* Note that we peek the value of heap->free_block without reserving
  87. the latch: this is ok, because we will not guarantee that there will
  88. be enough free space in the hash table. */
  89. if (heap->free_block == NULL) {
  90. frame = buf_frame_alloc();
  91. rw_lock_x_lock(&btr_search_latch);
  92. if (heap->free_block == NULL) {
  93. heap->free_block = frame;
  94. } else {
  95. buf_frame_free(frame);
  96. }
  97. rw_lock_x_unlock(&btr_search_latch);
  98. }
  99. }
  100. /*********************************************************************
  101. Creates and initializes the adaptive search system at a database start. */
  102. void
  103. btr_search_sys_create(
  104. /*==================*/
  105. ulint hash_size) /* in: hash index hash table size */
  106. {
  107. /* We allocate the search latch from dynamic memory:
  108. see above at the global variable definition */
  109. btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t));
  110. rw_lock_create(&btr_search_latch);
  111. btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
  112. btr_search_sys->hash_index = ha_create(TRUE, hash_size, 0, 0);
  113. rw_lock_set_level(&btr_search_latch, SYNC_SEARCH_SYS);
  114. }
  115. /*********************************************************************
  116. Creates and initializes a search info struct. */
  117. btr_search_t*
  118. btr_search_info_create(
  119. /*===================*/
  120. /* out, own: search info struct */
  121. mem_heap_t* heap) /* in: heap where created */
  122. {
  123. btr_search_t* info;
  124. info = mem_heap_alloc(heap, sizeof(btr_search_t));
  125. info->magic_n = BTR_SEARCH_MAGIC_N;
  126. info->last_search = NULL;
  127. info->n_direction = 0;
  128. info->root_guess = NULL;
  129. info->hash_analysis = 0;
  130. info->n_hash_potential = 0;
  131. info->last_hash_succ = FALSE;
  132. info->n_hash_succ = 0;
  133. info->n_hash_fail = 0;
  134. info->n_patt_succ = 0;
  135. info->n_searches = 0;
  136. /* Set some sensible values */
  137. info->n_fields = 1;
  138. info->n_bytes = 0;
  139. info->side = BTR_SEARCH_LEFT_SIDE;
  140. return(info);
  141. }
  142. /*************************************************************************
  143. Updates the search info of an index about hash successes. NOTE that info
  144. is NOT protected by any semaphore, to save CPU time! Do not assume its fields
  145. are consistent. */
  146. static
  147. void
  148. btr_search_info_update_hash(
  149. /*========================*/
  150. btr_search_t* info, /* in: search info */
  151. btr_cur_t* cursor) /* in: cursor which was just positioned */
  152. {
  153. dict_index_t* index;
  154. ulint n_unique;
  155. int cmp;
  156. #ifdef UNIV_SYNC_DEBUG
  157. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
  158. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  159. #endif /* UNIV_SYNC_DEBUG */
  160. index = cursor->index;
  161. if (index->type & DICT_IBUF) {
  162. /* So many deletes are performed on an insert buffer tree
  163. that we do not consider a hash index useful on it: */
  164. return;
  165. }
  166. n_unique = dict_index_get_n_unique_in_tree(index);
  167. if (info->n_hash_potential == 0) {
  168. goto set_new_recomm;
  169. }
  170. /* Test if the search would have succeeded using the recommended
  171. hash prefix */
  172. if (info->n_fields >= n_unique && cursor->up_match >= n_unique) {
  173. info->n_hash_potential++;
  174. return;
  175. }
  176. cmp = ut_pair_cmp(info->n_fields, info->n_bytes,
  177. cursor->low_match, cursor->low_bytes);
  178. if ((info->side == BTR_SEARCH_LEFT_SIDE && cmp <= 0)
  179. || (info->side == BTR_SEARCH_RIGHT_SIDE && cmp > 0)) {
  180. goto set_new_recomm;
  181. }
  182. cmp = ut_pair_cmp(info->n_fields, info->n_bytes,
  183. cursor->up_match, cursor->up_bytes);
  184. if ((info->side == BTR_SEARCH_LEFT_SIDE && cmp > 0)
  185. || (info->side == BTR_SEARCH_RIGHT_SIDE && cmp <= 0)) {
  186.      goto set_new_recomm;
  187. }
  188. info->n_hash_potential++;
  189. return;
  190. set_new_recomm:
  191. /* We have to set a new recommendation; skip the hash analysis
  192. for a while to avoid unnecessary CPU time usage when there is no
  193. chance for success */
  194. info->hash_analysis = 0;
  195. cmp = ut_pair_cmp(cursor->up_match, cursor->up_bytes,
  196. cursor->low_match, cursor->low_bytes);
  197. if (cmp == 0) {
  198. info->n_hash_potential = 0;
  199. /* For extra safety, we set some sensible values here */
  200. info->n_fields = 1;
  201. info->n_bytes = 0;
  202. info->side = BTR_SEARCH_LEFT_SIDE;
  203. } else if (cmp > 0) {
  204. info->n_hash_potential = 1;
  205. if (cursor->up_match >= n_unique) {
  206. info->n_fields = n_unique;
  207. info->n_bytes = 0;
  208. } else if (cursor->low_match < cursor->up_match) {
  209. info->n_fields = cursor->low_match + 1;
  210. info->n_bytes = 0;
  211. } else {
  212. info->n_fields = cursor->low_match;
  213. info->n_bytes = cursor->low_bytes + 1;
  214. }
  215. info->side = BTR_SEARCH_LEFT_SIDE;
  216. } else {
  217. info->n_hash_potential = 1;
  218. if (cursor->low_match >= n_unique) {
  219. info->n_fields = n_unique;
  220. info->n_bytes = 0;
  221. } else if (cursor->low_match > cursor->up_match) {
  222. info->n_fields = cursor->up_match + 1;
  223. info->n_bytes = 0;
  224. } else {
  225. info->n_fields = cursor->up_match;
  226. info->n_bytes = cursor->up_bytes + 1;
  227. }
  228. info->side = BTR_SEARCH_RIGHT_SIDE;
  229. }
  230. }
  231. /*************************************************************************
  232. Updates the block search info on hash successes. NOTE that info and
  233. block->n_hash_helps, n_fields, n_bytes, side are NOT protected by any
  234. semaphore, to save CPU time! Do not assume the fields are consistent. */
  235. static
  236. ibool
  237. btr_search_update_block_hash_info(
  238. /*==============================*/
  239. /* out: TRUE if building a (new) hash index on
  240. the block is recommended */
  241. btr_search_t* info, /* in: search info */
  242. buf_block_t* block, /* in: buffer block */
  243. btr_cur_t* cursor) /* in: cursor */
  244. {
  245. #ifdef UNIV_SYNC_DEBUG
  246. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
  247. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  248. ut_ad(rw_lock_own(&((buf_block_t*) block)->lock, RW_LOCK_SHARED)
  249. || rw_lock_own(&((buf_block_t*) block)->lock, RW_LOCK_EX));
  250. #endif /* UNIV_SYNC_DEBUG */
  251. ut_ad(cursor);
  252. info->last_hash_succ = FALSE;
  253. ut_a(block->magic_n == BUF_BLOCK_MAGIC_N);
  254. ut_a(info->magic_n == BTR_SEARCH_MAGIC_N);
  255. if ((block->n_hash_helps > 0)
  256.     && (info->n_hash_potential > 0)
  257.     && (block->n_fields == info->n_fields)
  258.     && (block->n_bytes == info->n_bytes)
  259.     && (block->side == info->side)) {
  260. if ((block->is_hashed)
  261.     && (block->curr_n_fields == info->n_fields)
  262.     && (block->curr_n_bytes == info->n_bytes)
  263.     && (block->curr_side == info->side)) {
  264. /* The search would presumably have succeeded using
  265. the hash index */
  266.     
  267. info->last_hash_succ = TRUE;
  268. }
  269. block->n_hash_helps++;
  270. } else {
  271. block->n_hash_helps = 1;
  272. block->n_fields = info->n_fields;
  273. block->n_bytes = info->n_bytes;
  274. block->side = info->side;
  275. }
  276. if (cursor->index->table->does_not_fit_in_memory) {
  277. block->n_hash_helps = 0;
  278. }
  279. if ((block->n_hash_helps > page_get_n_recs(block->frame)
  280.      / BTR_SEARCH_PAGE_BUILD_LIMIT)
  281.     && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) {
  282.      if ((!block->is_hashed)
  283.     || (block->n_hash_helps
  284. > 2 * page_get_n_recs(block->frame))
  285.     || (block->n_fields != block->curr_n_fields)
  286.     || (block->n_bytes != block->curr_n_bytes)
  287.     || (block->side != block->curr_side)) {
  288.      /* Build a new hash index on the page */
  289.      return(TRUE);
  290. }
  291. }
  292. return(FALSE);
  293. }
  294. /*************************************************************************
  295. Updates a hash node reference when it has been unsuccessfully used in a
  296. search which could have succeeded with the used hash parameters. This can
  297. happen because when building a hash index for a page, we do not check
  298. what happens at page boundaries, and therefore there can be misleading
  299. hash nodes. Also, collisions in the fold value can lead to misleading
  300. references. This function lazily fixes these imperfections in the hash
  301. index. */
  302. static
  303. void
  304. btr_search_update_hash_ref(
  305. /*=======================*/
  306. btr_search_t* info, /* in: search info */
  307. buf_block_t* block, /* in: buffer block where cursor positioned */
  308. btr_cur_t* cursor) /* in: cursor */
  309. {
  310. ulint fold;
  311. rec_t* rec;
  312. dulint tree_id;
  313. ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
  314. #ifdef UNIV_SYNC_DEBUG
  315. ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  316. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
  317. || rw_lock_own(&(block->lock), RW_LOCK_EX));
  318. #endif /* UNIV_SYNC_DEBUG */
  319. if (block->is_hashed
  320.     && (info->n_hash_potential > 0)
  321.     && (block->curr_n_fields == info->n_fields)
  322.     && (block->curr_n_bytes == info->n_bytes)
  323.     && (block->curr_side == info->side)) {
  324.      rec = btr_cur_get_rec(cursor);
  325.      if (!page_rec_is_user_rec(rec)) {
  326.      return;
  327.      }
  328.     
  329. tree_id = ((cursor->index)->tree)->id;
  330. fold = rec_fold(rec, block->curr_n_fields,
  331. block->curr_n_bytes, tree_id);
  332. #ifdef UNIV_SYNC_DEBUG
  333. ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  334. #endif /* UNIV_SYNC_DEBUG */
  335. ha_insert_for_fold(btr_search_sys->hash_index, fold, rec);
  336. }
  337. }
  338. /*************************************************************************
  339. Updates the search info. */
  340. void
  341. btr_search_info_update_slow(
  342. /*========================*/
  343. btr_search_t* info, /* in: search info */
  344. btr_cur_t* cursor) /* in: cursor which was just positioned */
  345. {
  346. buf_block_t* block;
  347. ibool build_index;
  348. ulint* params;
  349. ulint* params2;
  350. #ifdef UNIV_SYNC_DEBUG
  351. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
  352. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  353. #endif /* UNIV_SYNC_DEBUG */
  354. block = buf_block_align(btr_cur_get_rec(cursor));
  355. /* NOTE that the following two function calls do NOT protect
  356. info or block->n_fields etc. with any semaphore, to save CPU time!
  357. We cannot assume the fields are consistent when we return from
  358. those functions! */
  359. btr_search_info_update_hash(info, cursor);
  360. build_index = btr_search_update_block_hash_info(info, block, cursor);
  361. if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) {
  362. btr_search_check_free_space_in_heap();
  363. }
  364. if (cursor->flag == BTR_CUR_HASH_FAIL) {
  365. /* Update the hash node reference, if appropriate */
  366. btr_search_n_hash_fail++;
  367. rw_lock_x_lock(&btr_search_latch);
  368. btr_search_update_hash_ref(info, block, cursor);
  369. rw_lock_x_unlock(&btr_search_latch);
  370. }
  371. if (build_index) {
  372. /* Note that since we did not protect block->n_fields etc.
  373. with any semaphore, the values can be inconsistent. We have
  374. to check inside the function call that they make sense. We
  375. also malloc an array and store the values there to make sure
  376. the compiler does not let the function call parameters change
  377. inside the called function. It might be that the compiler
  378. would optimize the call just to pass pointers to block. */
  379. params = mem_alloc(3 * sizeof(ulint));
  380. params[0] = block->n_fields;
  381. params[1] = block->n_bytes;
  382. params[2] = block->side;
  383. /* Make sure the compiler cannot deduce the values and do
  384. optimizations */
  385. params2 = params + btr_search_this_is_zero;
  386. btr_search_build_page_hash_index(cursor->index,
  387. block->frame,
  388. params2[0],
  389. params2[1],
  390. params2[2]);
  391. mem_free(params);
  392. }
  393. }
  394. /**********************************************************************
  395. Checks if a guessed position for a tree cursor is right. Note that if
  396. mode is PAGE_CUR_LE, which is used in inserts, and the function returns
  397. TRUE, then cursor->up_match and cursor->low_match both have sensible values. */
  398. static
  399. ibool
  400. btr_search_check_guess(
  401. /*===================*/
  402. /* out: TRUE if success */
  403. btr_cur_t* cursor, /* in: guessed cursor position */
  404. ibool           can_only_compare_to_cursor_rec,
  405.                         /* in: if we do not have a latch on the page
  406. of cursor, but only a latch on
  407.         btr_search_latch, then ONLY the columns
  408. of the record UNDER the cursor are
  409. protected, not the next or previous record
  410. in the chain: we cannot look at the next or
  411. previous record to check our guess! */
  412. dtuple_t*  tuple, /* in: data tuple */
  413. ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
  414. or PAGE_CUR_GE */
  415. mtr_t* mtr) /* in: mtr */
  416. {
  417. page_t* page;
  418. rec_t* rec;
  419. rec_t* prev_rec;
  420. rec_t* next_rec;
  421. ulint n_unique;
  422. ulint match;
  423. ulint bytes;
  424. int cmp;
  425. n_unique = dict_index_get_n_unique_in_tree(cursor->index);
  426. rec = btr_cur_get_rec(cursor);
  427. page = buf_frame_align(rec);
  428. ut_ad(page_rec_is_user_rec(rec));
  429. match = 0;
  430. bytes = 0;
  431. cmp = page_cmp_dtuple_rec_with_match(tuple, rec, &match, &bytes);
  432. if (mode == PAGE_CUR_GE) {
  433. if (cmp == 1) {
  434. return(FALSE);
  435. }
  436. cursor->up_match = match;
  437. if (match >= n_unique) {
  438. return(TRUE);
  439. }
  440. } else if (mode == PAGE_CUR_LE) {
  441. if (cmp == -1) {
  442. return(FALSE);
  443. }
  444. cursor->low_match = match;
  445. } else if (mode == PAGE_CUR_G) {
  446. if (cmp != -1) {
  447. return(FALSE);
  448. }
  449. } else if (mode == PAGE_CUR_L) {
  450. if (cmp != 1) {
  451. return(FALSE);
  452. }
  453. }
  454. if (can_only_compare_to_cursor_rec) {
  455.         /* Since we could not determine if our guess is right just by
  456.         looking at the record under the cursor, return FALSE */
  457.         return(FALSE);
  458. }
  459. match = 0;
  460. bytes = 0;
  461. if ((mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)) {
  462. ut_ad(rec != page_get_infimum_rec(page));
  463. prev_rec = page_rec_get_prev(rec);
  464. if (prev_rec == page_get_infimum_rec(page)) {
  465.      if (btr_page_get_prev(page, mtr) != FIL_NULL) {
  466. return(FALSE);
  467. }
  468. return(TRUE);
  469. }
  470. cmp = page_cmp_dtuple_rec_with_match(tuple, prev_rec,
  471. &match, &bytes);
  472. if (mode == PAGE_CUR_GE) {
  473. if (cmp != 1) {
  474. return(FALSE);
  475. }
  476. } else {
  477. if (cmp == -1) {
  478. return(FALSE);
  479. }
  480. }
  481. return(TRUE);
  482. }
  483. ut_ad(rec != page_get_supremum_rec(page));
  484. next_rec = page_rec_get_next(rec);
  485. if (next_rec == page_get_supremum_rec(page)) {
  486.      if (btr_page_get_next(page, mtr) == FIL_NULL) {
  487. cursor->up_match = 0;
  488. return(TRUE);
  489. }
  490. return(FALSE);
  491. }
  492. cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, &match, &bytes);
  493. if (mode == PAGE_CUR_LE) {
  494. if (cmp != -1) {
  495. return(FALSE);
  496. }
  497. cursor->up_match = match;
  498. } else {
  499. if (cmp == 1) {
  500. return(FALSE);
  501. }
  502. }
  503. return(TRUE);
  504. }
  505. /**********************************************************************
  506. Tries to guess the right search position based on the hash search info
  507. of the index. Note that if mode is PAGE_CUR_LE, which is used in inserts,
  508. and the function returns TRUE, then cursor->up_match and cursor->low_match
  509. both have sensible values. */
  510. ibool
  511. btr_search_guess_on_hash(
  512. /*=====================*/
  513. /* out: TRUE if succeeded */
  514. dict_index_t* index, /* in: index */
  515. btr_search_t* info, /* in: index search info */
  516. dtuple_t* tuple, /* in: logical record */
  517. ulint mode, /* in: PAGE_CUR_L, ... */
  518. ulint latch_mode,  /* in: BTR_SEARCH_LEAF, ...;
  519. NOTE that only if has_search_latch
  520. is 0, we will have a latch set on
  521. the cursor page, otherwise we assume
  522. the caller uses his search latch
  523. to protect the record! */
  524. btr_cur_t* cursor,  /* out: tree cursor */
  525. ulint has_search_latch,/* in: latch mode the caller
  526. currently has on btr_search_latch:
  527. RW_S_LATCH, RW_X_LATCH, or 0 */
  528. mtr_t* mtr) /* in: mtr */
  529. {
  530. buf_block_t* block;
  531. rec_t* rec;
  532. page_t* page;
  533. ibool success;
  534. ulint fold;
  535. ulint tuple_n_fields;
  536. dulint tree_id;
  537. ibool           can_only_compare_to_cursor_rec = TRUE;
  538. #ifdef notdefined
  539. btr_cur_t cursor2;
  540. btr_pcur_t pcur;
  541. #endif
  542. ut_ad(index && info && tuple && cursor && mtr);
  543. ut_ad((latch_mode == BTR_SEARCH_LEAF)
  544. || (latch_mode == BTR_MODIFY_LEAF));
  545. /* Note that, for efficiency, the struct info may not be protected by
  546. any latch here! */
  547. if (info->n_hash_potential == 0) {
  548. return(FALSE);
  549. }
  550. cursor->n_fields = info->n_fields;
  551. cursor->n_bytes = info->n_bytes;
  552. tuple_n_fields = dtuple_get_n_fields(tuple);
  553. if (tuple_n_fields < cursor->n_fields) {
  554. return(FALSE);
  555. }
  556. if ((cursor->n_bytes > 0) && (tuple_n_fields <= cursor->n_fields)) {
  557.      return(FALSE);
  558. }
  559. tree_id = (index->tree)->id;
  560. #ifdef UNIV_SEARCH_PERF_STAT
  561. info->n_hash_succ++;
  562. #endif
  563. fold = dtuple_fold(tuple, cursor->n_fields, cursor->n_bytes, tree_id);
  564. cursor->fold = fold;
  565. cursor->flag = BTR_CUR_HASH;
  566. if (!has_search_latch) {
  567. rw_lock_s_lock(&btr_search_latch);
  568. }
  569. ut_a(btr_search_latch.writer != RW_LOCK_EX);
  570. ut_a(btr_search_latch.reader_count > 0);
  571. rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
  572. if (!rec) {
  573. if (!has_search_latch) {
  574. rw_lock_s_unlock(&btr_search_latch);
  575. }
  576. goto failure;
  577. }
  578. page = buf_frame_align(rec);
  579. if (!has_search_latch) {
  580. success = buf_page_get_known_nowait(latch_mode, page,
  581. BUF_MAKE_YOUNG,
  582. __FILE__, __LINE__,
  583. mtr);
  584. rw_lock_s_unlock(&btr_search_latch);
  585. if (!success) {
  586. goto failure;
  587. }
  588. can_only_compare_to_cursor_rec = FALSE;
  589. #ifdef UNIV_SYNC_DEBUG
  590. buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH);
  591. #endif /* UNIV_SYNC_DEBUG */
  592. }
  593. block = buf_block_align(page);
  594. if (block->state == BUF_BLOCK_REMOVE_HASH) {
  595. if (!has_search_latch) {
  596. btr_leaf_page_release(page, latch_mode, mtr);
  597. }
  598. goto failure;
  599. }
  600. ut_a(block->state == BUF_BLOCK_FILE_PAGE);
  601. ut_a(page_rec_is_user_rec(rec));
  602. btr_cur_position(index, rec, cursor);
  603. /* Check the validity of the guess within the page */
  604. if (0 != ut_dulint_cmp(tree_id, btr_page_get_index_id(page))) {
  605. success = FALSE;
  606. /*
  607. fprintf(stderr, "Tree id %lu, page index id %lu fold %lun",
  608. ut_dulint_get_low(tree_id),
  609. ut_dulint_get_low(btr_page_get_index_id(page)),
  610. fold);
  611. */
  612. } else {
  613.         /* If we only have the latch on btr_search_latch, not on the
  614. page, it only protects the columns of the record the cursor
  615. is positioned on. We cannot look at the next of the previous
  616. record to determine if our guess for the cursor position is
  617. right. */
  618. success = btr_search_check_guess(cursor,
  619.                can_only_compare_to_cursor_rec,
  620.        tuple, mode, mtr);
  621. }
  622. if (!success) {
  623. if (!has_search_latch) {
  624.           btr_leaf_page_release(page, latch_mode, mtr);
  625. }
  626. goto failure;
  627. }
  628. if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) {
  629. info->n_hash_potential++;
  630. }
  631. if (info->last_hash_succ != TRUE) {
  632. info->last_hash_succ = TRUE;
  633. }
  634. #ifdef notdefined
  635. /* These lines of code can be used in a debug version to check
  636. the correctness of the searched cursor position: */
  637. info->last_hash_succ = FALSE;
  638. /* Currently, does not work if the following fails: */
  639. ut_a(!has_search_latch);
  640. btr_leaf_page_release(page, latch_mode, mtr);
  641. btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
  642. &cursor2, 0, mtr);
  643. if (mode == PAGE_CUR_GE
  644. && btr_cur_get_rec(&cursor2) == page_get_supremum_rec(
  645. buf_frame_align(btr_cur_get_rec(&cursor2)))) {
  646. /* If mode is PAGE_CUR_GE, then the binary search
  647. in the index tree may actually take us to the supremum
  648. of the previous page */
  649. info->last_hash_succ = FALSE;
  650. btr_pcur_open_on_user_rec(index, tuple, mode, latch_mode,
  651. &pcur, mtr);
  652. ut_a(btr_pcur_get_rec(&pcur) == btr_cur_get_rec(cursor));
  653. } else {
  654. ut_a(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor));
  655. }
  656. /* NOTE that it is theoretically possible that the above assertions
  657. fail if the page of the cursor gets removed from the buffer pool
  658. meanwhile! Thus it might not be a bug. */
  659. info->last_hash_succ = TRUE;
  660. #endif
  661. #ifdef UNIV_SEARCH_PERF_STAT
  662. btr_search_n_succ++;
  663. #endif
  664. if (!has_search_latch && buf_block_peek_if_too_old(block)) {
  665. buf_page_make_young(page);
  666. }
  667. /* Increment the page get statistics though we did not really
  668. fix the page: for user info only */
  669. buf_pool->n_page_gets++;
  670. return(TRUE);
  671. /*-------------------------------------------*/
  672. failure:
  673. info->n_hash_fail++;
  674. cursor->flag = BTR_CUR_HASH_FAIL;
  675. #ifdef UNIV_SEARCH_PERF_STAT
  676. if (info->n_hash_succ > 0) {
  677. info->n_hash_succ--;
  678. }
  679. #endif
  680. info->last_hash_succ = FALSE;
  681. return(FALSE);
  682. }
  683. /************************************************************************
  684. Drops a page hash index. */
  685. void
  686. btr_search_drop_page_hash_index(
  687. /*============================*/
  688. page_t* page) /* in: index page, s- or x-latched */
  689. {
  690. hash_table_t* table;
  691. buf_block_t* block;
  692. ulint n_fields;
  693. ulint n_bytes;
  694. rec_t* rec;
  695. rec_t* sup;
  696. ulint fold;
  697. ulint prev_fold;
  698. dulint tree_id;
  699. ulint n_cached;
  700. ulint n_recs;
  701. ulint* folds;
  702. ulint i;
  703. #ifdef UNIV_SYNC_DEBUG
  704. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
  705. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  706. #endif /* UNIV_SYNC_DEBUG */
  707. rw_lock_s_lock(&btr_search_latch);
  708. block = buf_block_align(page);
  709. if (!block->is_hashed) {
  710. rw_lock_s_unlock(&btr_search_latch);
  711. return;
  712. }
  713. table = btr_search_sys->hash_index;
  714. #ifdef UNIV_SYNC_DEBUG
  715. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
  716.        || rw_lock_own(&(block->lock), RW_LOCK_EX)
  717.        || (block->buf_fix_count == 0));
  718. #endif /* UNIV_SYNC_DEBUG */
  719. n_fields = block->curr_n_fields;
  720. n_bytes = block->curr_n_bytes;
  721. ut_a(n_fields + n_bytes > 0);
  722. rw_lock_s_unlock(&btr_search_latch);
  723. n_recs = page_get_n_recs(page);
  724. /* Calculate and cache fold values into an array for fast deletion
  725. from the hash index */
  726. folds = mem_alloc(n_recs * sizeof(ulint));
  727. n_cached = 0;
  728. sup = page_get_supremum_rec(page);
  729. rec = page_get_infimum_rec(page);
  730. rec = page_rec_get_next(rec);
  731. if (rec != sup) {
  732. ut_a(n_fields <= rec_get_n_fields(rec));
  733. if (n_bytes > 0) {
  734. ut_a(n_fields < rec_get_n_fields(rec));
  735. }
  736. }
  737. tree_id = btr_page_get_index_id(page);
  738. prev_fold = 0;
  739. while (rec != sup) {
  740. /* FIXME: in a mixed tree, not all records may have enough
  741. ordering fields: */
  742. fold = rec_fold(rec, n_fields, n_bytes, tree_id);
  743. if (fold == prev_fold && prev_fold != 0) {
  744. goto next_rec;
  745. }
  746. /* Remove all hash nodes pointing to this page from the
  747. hash chain */
  748. folds[n_cached] = fold;
  749. n_cached++;
  750. next_rec:
  751. rec = page_rec_get_next(rec);
  752. prev_fold = fold;
  753. }
  754. rw_lock_x_lock(&btr_search_latch);
  755. for (i = 0; i < n_cached; i++) {
  756. ha_remove_all_nodes_to_page(table, folds[i], page);
  757. }
  758. block->is_hashed = FALSE;
  759. rw_lock_x_unlock(&btr_search_latch);
  760. mem_free(folds);
  761. }
  762. /************************************************************************
  763. Drops a page hash index when a page is freed from a fseg to the file system.
  764. Drops possible hash index if the page happens to be in the buffer pool. */
  765. void
  766. btr_search_drop_page_hash_when_freed(
  767. /*=================================*/
  768. ulint space, /* in: space id */
  769. ulint page_no) /* in: page number */
  770. {
  771. ibool is_hashed;
  772. page_t* page;
  773. mtr_t mtr;
  774. is_hashed = buf_page_peek_if_search_hashed(space, page_no);
  775. if (!is_hashed) {
  776. return;
  777. }
  778. mtr_start(&mtr);
  779. /* We assume that if the caller has a latch on the page, then the
  780. caller has already dropped the hash index for the page, and we never
  781. get here. Therefore we can acquire the s-latch to the page without
  782. having to fear a deadlock. */
  783. page = buf_page_get_gen(space, page_no, RW_S_LATCH, NULL,
  784. BUF_GET_IF_IN_POOL, __FILE__, __LINE__,
  785. &mtr);
  786. #ifdef UNIV_SYNC_DEBUG
  787. buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH);
  788. #endif /* UNIV_SYNC_DEBUG */
  789. btr_search_drop_page_hash_index(page);
  790. mtr_commit(&mtr);
  791. }
  792. /************************************************************************
  793. Builds a hash index on a page with the given parameters. If the page already
  794. has a hash index with different parameters, the old hash index is removed.
  795. If index is non-NULL, this function checks if n_fields and n_bytes are
  796. sensible values, and does not build a hash index if not. */
  797. static
  798. void
  799. btr_search_build_page_hash_index(
  800. /*=============================*/
  801. dict_index_t* index, /* in: index for which to build, or NULL if
  802. not known */
  803. page_t* page, /* in: index page, s- or x-latched */
  804. ulint n_fields,/* in: hash this many full fields */
  805. ulint n_bytes,/* in: hash this many bytes from the next
  806. field */
  807. ulint side) /* in: hash for searches from this side */
  808. {
  809. hash_table_t* table;
  810. buf_block_t* block;
  811. rec_t* rec;
  812. rec_t* next_rec;
  813. rec_t* sup;
  814. ulint fold;
  815. ulint next_fold;
  816. dulint tree_id;
  817. ulint n_cached;
  818. ulint n_recs;
  819. ulint* folds;
  820. rec_t** recs;
  821. ulint i;
  822. block = buf_block_align(page);
  823. table = btr_search_sys->hash_index;
  824. #ifdef UNIV_SYNC_DEBUG
  825. ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
  826. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
  827. || rw_lock_own(&(block->lock), RW_LOCK_EX));
  828. #endif /* UNIV_SYNC_DEBUG */
  829. rw_lock_s_lock(&btr_search_latch);
  830. if (block->is_hashed && ((block->curr_n_fields != n_fields)
  831.          || (block->curr_n_bytes != n_bytes)
  832.          || (block->curr_side != side))) {
  833. rw_lock_s_unlock(&btr_search_latch);
  834. btr_search_drop_page_hash_index(page);
  835. } else {
  836. rw_lock_s_unlock(&btr_search_latch);
  837. }
  838. n_recs = page_get_n_recs(page);
  839. if (n_recs == 0) {
  840. return;
  841. }
  842. /* Check that the values for hash index build are sensible */
  843. if (n_fields + n_bytes == 0) {
  844. return;
  845. }
  846. if (index && (dict_index_get_n_unique_in_tree(index) < n_fields
  847.       || (dict_index_get_n_unique_in_tree(index) == n_fields
  848.           && n_bytes > 0))) {
  849. return;
  850. }
  851. /* Calculate and cache fold values and corresponding records into
  852. an array for fast insertion to the hash index */
  853. folds = mem_alloc(n_recs * sizeof(ulint));
  854. recs = mem_alloc(n_recs * sizeof(rec_t*));
  855. n_cached = 0;
  856. tree_id = btr_page_get_index_id(page);
  857. sup = page_get_supremum_rec(page);
  858. rec = page_get_infimum_rec(page);
  859. rec = page_rec_get_next(rec);
  860. if (rec != sup) {
  861. ut_a(n_fields <= rec_get_n_fields(rec));
  862. if (n_bytes > 0) {
  863. ut_a(n_fields < rec_get_n_fields(rec));
  864. }
  865. }
  866. /* FIXME: in a mixed tree, all records may not have enough ordering
  867. fields: */
  868. fold = rec_fold(rec, n_fields, n_bytes, tree_id);
  869. if (side == BTR_SEARCH_LEFT_SIDE) {
  870. folds[n_cached] = fold;
  871. recs[n_cached] = rec;
  872. n_cached++;
  873. }
  874. for (;;) {
  875. next_rec = page_rec_get_next(rec);
  876. if (next_rec == sup) {
  877. if (side == BTR_SEARCH_RIGHT_SIDE) {
  878. folds[n_cached] = fold;
  879. recs[n_cached] = rec;
  880. n_cached++;
  881. }
  882.   break;
  883. }
  884. next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id);
  885. if (fold != next_fold) {
  886. /* Insert an entry into the hash index */
  887. if (side == BTR_SEARCH_LEFT_SIDE) {
  888. folds[n_cached] = next_fold;
  889. recs[n_cached] = next_rec;
  890. n_cached++;
  891. } else {
  892. folds[n_cached] = fold;
  893. recs[n_cached] = rec;
  894. n_cached++;
  895. }
  896. }
  897. rec = next_rec;
  898. fold = next_fold;
  899. }
  900. btr_search_check_free_space_in_heap();
  901. rw_lock_x_lock(&btr_search_latch);
  902. if (block->is_hashed && ((block->curr_n_fields != n_fields)
  903.          || (block->curr_n_bytes != n_bytes)
  904.          || (block->curr_side != side))) {
  905. rw_lock_x_unlock(&btr_search_latch);
  906. mem_free(folds);
  907. mem_free(recs);
  908. return;
  909. }
  910. block->is_hashed = TRUE;
  911. block->n_hash_helps = 0;
  912. block->curr_n_fields = n_fields;
  913. block->curr_n_bytes = n_bytes;
  914. block->curr_side = side;
  915. for (i = 0; i < n_cached; i++) {
  916. ha_insert_for_fold(table, folds[i], recs[i]);
  917. }
  918. rw_lock_x_unlock(&btr_search_latch);
  919. mem_free(folds);
  920. mem_free(recs);
  921. }
  922. /************************************************************************
  923. Moves or deletes hash entries for moved records. If new_page is already hashed,
  924. then the hash index for page, if any, is dropped. If new_page is not hashed,
  925. and page is hashed, then a new hash index is built to new_page with the same
  926. parameters as page (this often happens when a page is split). */
  927. void
  928. btr_search_move_or_delete_hash_entries(
  929. /*===================================*/
  930. page_t* new_page, /* in: records are copied to this page */
  931. page_t* page) /* in: index page from which records were
  932. copied, and the copied records will be deleted
  933. from this page */
  934. {
  935. buf_block_t* block;
  936. buf_block_t* new_block;
  937. ulint n_fields;
  938. ulint n_bytes;
  939. ulint side;
  940. block = buf_block_align(page);
  941. new_block = buf_block_align(new_page);
  942. #ifdef UNIV_SYNC_DEBUG
  943. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
  944. ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
  945. #endif /* UNIV_SYNC_DEBUG */
  946. rw_lock_s_lock(&btr_search_latch);
  947. if (new_block->is_hashed) {
  948. rw_lock_s_unlock(&btr_search_latch);
  949. btr_search_drop_page_hash_index(page);
  950. return;
  951. }
  952. if (block->is_hashed) {
  953. n_fields = block->curr_n_fields;
  954. n_bytes = block->curr_n_bytes;
  955. side = block->curr_side;
  956. new_block->n_fields = block->curr_n_fields;
  957. new_block->n_bytes = block->curr_n_bytes;
  958. new_block->side = block->curr_side;
  959. rw_lock_s_unlock(&btr_search_latch);
  960. ut_a(n_fields + n_bytes > 0);
  961. btr_search_build_page_hash_index(NULL, new_page, n_fields,
  962. n_bytes, side);
  963. ut_a(n_fields == block->curr_n_fields);
  964. ut_a(n_bytes == block->curr_n_bytes);
  965. ut_a(side == block->curr_side);
  966. return;
  967. }
  968. rw_lock_s_unlock(&btr_search_latch);
  969. }
  970. /************************************************************************
  971. Updates the page hash index when a single record is deleted from a page. */
  972. void
  973. btr_search_update_hash_on_delete(
  974. /*=============================*/
  975. btr_cur_t* cursor) /* in: cursor which was positioned on the
  976. record to delete using btr_cur_search_...,
  977. the record is not yet deleted */
  978. {
  979. hash_table_t* table;
  980. buf_block_t* block;
  981. rec_t* rec;
  982. ulint fold;
  983. dulint tree_id;
  984. ibool found;
  985. rec = btr_cur_get_rec(cursor);
  986. block = buf_block_align(rec);
  987. #ifdef UNIV_SYNC_DEBUG
  988. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
  989. #endif /* UNIV_SYNC_DEBUG */
  990. if (!block->is_hashed) {
  991. return;
  992. }
  993. ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
  994. table = btr_search_sys->hash_index;
  995. tree_id = cursor->index->tree->id;
  996. fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes,
  997. tree_id);
  998. rw_lock_x_lock(&btr_search_latch);
  999. found = ha_search_and_delete_if_found(table, fold, rec);
  1000. rw_lock_x_unlock(&btr_search_latch);
  1001. }
  1002. /************************************************************************
  1003. Updates the page hash index when a single record is inserted on a page. */
  1004. void
  1005. btr_search_update_hash_node_on_insert(
  1006. /*==================================*/
  1007. btr_cur_t* cursor) /* in: cursor which was positioned to the
  1008. place to insert using btr_cur_search_...,
  1009. and the new record has been inserted next
  1010. to the cursor */
  1011. {
  1012. hash_table_t* table;
  1013. buf_block_t* block;
  1014. rec_t* rec;
  1015. rec = btr_cur_get_rec(cursor);
  1016. block = buf_block_align(rec);
  1017. #ifdef UNIV_SYNC_DEBUG
  1018. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
  1019. #endif /* UNIV_SYNC_DEBUG */
  1020. if (!block->is_hashed) {
  1021. return;
  1022. }
  1023. rw_lock_x_lock(&btr_search_latch);
  1024. if ((cursor->flag == BTR_CUR_HASH)
  1025.     && (cursor->n_fields == block->curr_n_fields)
  1026.     && (cursor->n_bytes == block->curr_n_bytes)
  1027.     && (block->curr_side == BTR_SEARCH_RIGHT_SIDE)) {
  1028.      table = btr_search_sys->hash_index;
  1029.     
  1030.      ha_search_and_update_if_found(table, cursor->fold, rec,
  1031. page_rec_get_next(rec));
  1032. rw_lock_x_unlock(&btr_search_latch);
  1033. } else {
  1034. rw_lock_x_unlock(&btr_search_latch);
  1035. btr_search_update_hash_on_insert(cursor);
  1036. }
  1037. }
  1038. /************************************************************************
  1039. Updates the page hash index when a single record is inserted on a page. */
  1040. void
  1041. btr_search_update_hash_on_insert(
  1042. /*=============================*/
  1043. btr_cur_t* cursor) /* in: cursor which was positioned to the
  1044. place to insert using btr_cur_search_...,
  1045. and the new record has been inserted next
  1046. to the cursor */
  1047. {
  1048. hash_table_t* table; 
  1049. buf_block_t* block;
  1050. page_t* page;
  1051. rec_t* rec;
  1052. rec_t* ins_rec;
  1053. rec_t* next_rec;
  1054. dulint tree_id;
  1055. ulint fold;
  1056. ulint ins_fold;
  1057. ulint next_fold = 0; /* remove warning (??? bug ???) */
  1058. ulint n_fields;
  1059. ulint n_bytes;
  1060. ulint side;
  1061. ibool locked = FALSE;
  1062. table = btr_search_sys->hash_index;
  1063. btr_search_check_free_space_in_heap();
  1064. rec = btr_cur_get_rec(cursor);
  1065. block = buf_block_align(rec);
  1066. #ifdef UNIV_SYNC_DEBUG
  1067. ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
  1068. #endif /* UNIV_SYNC_DEBUG */
  1069. if (!block->is_hashed) {
  1070. return;
  1071. }
  1072. tree_id = ((cursor->index)->tree)->id;
  1073. n_fields = block->curr_n_fields;
  1074. n_bytes = block->curr_n_bytes;
  1075. side = block->curr_side;
  1076. ins_rec = page_rec_get_next(rec);
  1077. next_rec = page_rec_get_next(ins_rec);
  1078. page = buf_frame_align(rec);
  1079. ins_fold = rec_fold(ins_rec, n_fields, n_bytes, tree_id);
  1080. if (next_rec != page_get_supremum_rec(page)) {
  1081. next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id);
  1082. }
  1083. if (rec != page_get_infimum_rec(page)) {
  1084. fold = rec_fold(rec, n_fields, n_bytes, tree_id);
  1085. } else {
  1086. if (side == BTR_SEARCH_LEFT_SIDE) {
  1087. rw_lock_x_lock(&btr_search_latch);
  1088. locked = TRUE;
  1089. ha_insert_for_fold(table, ins_fold, ins_rec);
  1090. }
  1091. goto check_next_rec;
  1092. }
  1093.   if (fold != ins_fold) {
  1094.   if (!locked) {
  1095. rw_lock_x_lock(&btr_search_latch);
  1096. locked = TRUE;
  1097. }
  1098. if (side == BTR_SEARCH_RIGHT_SIDE) {
  1099. ha_insert_for_fold(table, fold, rec);
  1100. } else {
  1101. ha_insert_for_fold(table, ins_fold, ins_rec);
  1102. }
  1103. }
  1104. check_next_rec:
  1105. if (next_rec == page_get_supremum_rec(page)) {
  1106. if (side == BTR_SEARCH_RIGHT_SIDE) {
  1107.   if (!locked) {
  1108. rw_lock_x_lock(&btr_search_latch);
  1109. locked = TRUE;
  1110. }
  1111. ha_insert_for_fold(table, ins_fold, ins_rec);
  1112. }
  1113. goto function_exit;
  1114. }
  1115. if (ins_fold != next_fold) {
  1116.   if (!locked) {
  1117. rw_lock_x_lock(&btr_search_latch);
  1118. locked = TRUE;
  1119. }
  1120. if (side == BTR_SEARCH_RIGHT_SIDE) {
  1121. ha_insert_for_fold(table, ins_fold, ins_rec);
  1122. /*
  1123. fputs("Hash insert for ", stderr);
  1124. dict_index_name_print(stderr, cursor->index);
  1125. fprintf(stderr, " fold %lun", ins_fold);
  1126. */
  1127. } else {
  1128. ha_insert_for_fold(table, next_fold, next_rec);
  1129. }
  1130. }
  1131. function_exit:
  1132. if (locked) {
  1133. rw_lock_x_unlock(&btr_search_latch);
  1134. }
  1135. }
  1136. /************************************************************************
  1137. Validates the search system. */
  1138. ibool
  1139. btr_search_validate(void)
  1140. /*=====================*/
  1141. /* out: TRUE if ok */
  1142. {
  1143. buf_block_t* block;
  1144. page_t* page;
  1145. ha_node_t* node;
  1146. ulint n_page_dumps = 0;
  1147. ibool ok = TRUE;
  1148. ulint i;
  1149. rw_lock_x_lock(&btr_search_latch);
  1150. for (i = 0; i < hash_get_n_cells(btr_search_sys->hash_index); i++) {
  1151. node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
  1152. while (node != NULL) {
  1153. block = buf_block_align(node->data);
  1154. page = buf_frame_align(node->data);
  1155. if (!block->is_hashed
  1156.     || node->fold != rec_fold((rec_t*)(node->data),
  1157. block->curr_n_fields,
  1158. block->curr_n_bytes,
  1159. btr_page_get_index_id(page))) {
  1160. ok = FALSE;
  1161. ut_print_timestamp(stderr);
  1162. fprintf(stderr,
  1163. "  InnoDB: Error in an adaptive hash index pointer to page %lun"
  1164. "ptr mem address %p index id %lu %lu, node fold %lu, rec fold %lun",
  1165. (ulong) buf_frame_get_page_no(page),
  1166. node->data,
  1167. (ulong) ut_dulint_get_high(btr_page_get_index_id(page)),
  1168. (ulong) ut_dulint_get_low(btr_page_get_index_id(page)),
  1169. (ulong) node->fold,
  1170. (ulong) rec_fold((rec_t*)(node->data),
  1171.      block->curr_n_fields,
  1172.      block->curr_n_bytes,
  1173.      btr_page_get_index_id(page)));
  1174. fputs("InnoDB: Record ", stderr);
  1175. rec_print(stderr, (rec_t*)(node->data));
  1176. fprintf(stderr, "nInnoDB: on that page."
  1177. "Page mem address %p, is hashed %lu, n fields %lu, n bytes %lun"
  1178. "side %lun",
  1179.         page, (ulong) block->is_hashed,
  1180.         (ulong) block->curr_n_fields,
  1181.         (ulong) block->curr_n_bytes, (ulong) block->curr_side);
  1182. if (n_page_dumps < 20) {
  1183. buf_page_print(page);
  1184. n_page_dumps++;
  1185. }
  1186. }
  1187. node = node->next;
  1188. }
  1189. }
  1190. if (!ha_validate(btr_search_sys->hash_index)) {
  1191. ok = FALSE;
  1192. }
  1193. rw_lock_x_unlock(&btr_search_latch);
  1194. return(ok);
  1195. }