MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
btr0pcur.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2013, 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 "btr0pcur.h"
27 
28 #ifdef UNIV_NONINL
29 #include "btr0pcur.ic"
30 #endif
31 
32 #include "ut0byte.h"
33 #include "rem0cmp.h"
34 #include "trx0trx.h"
35 
36 /**************************************************************/
39 UNIV_INTERN
42 /*============================*/
43 {
45 
46  pcur = (btr_pcur_t*) mem_alloc(sizeof(btr_pcur_t));
47 
48  pcur->btr_cur.index = NULL;
49  btr_pcur_init(pcur);
50 
51  return(pcur);
52 }
53 
54 /**************************************************************/
57 UNIV_INTERN
58 void
60 /*===========*/
62 {
63  if (cursor->old_rec_buf != NULL) {
64 
65  mem_free(cursor->old_rec_buf);
66 
67  cursor->old_rec_buf = NULL;
68  }
69 
70  cursor->btr_cur.index = NULL;
71  cursor->btr_cur.page_cur.rec = NULL;
72  cursor->old_rec = NULL;
73  cursor->old_n_fields = 0;
74  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
75 
76  cursor->latch_mode = BTR_NO_LATCHES;
77  cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
78 }
79 
80 /**************************************************************/
82 UNIV_INTERN
83 void
85 /*====================*/
87 {
88  btr_pcur_reset(cursor);
89  mem_free(cursor);
90 }
91 
92 /**************************************************************/
99 UNIV_INTERN
100 void
102 /*====================*/
103  btr_pcur_t* cursor,
104  mtr_t* mtr)
105 {
106  page_cur_t* page_cursor;
108  rec_t* rec;
110  page_t* page;
111  ulint offs;
112 
113  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
114  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
115 
116  block = btr_pcur_get_block(cursor);
117  index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
118 
119  page_cursor = btr_pcur_get_page_cur(cursor);
120 
121  rec = page_cur_get_rec(page_cursor);
122  page = page_align(rec);
123  offs = page_offset(rec);
124 
125  ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
126  || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
127  ut_a(cursor->latch_mode != BTR_NO_LATCHES);
128 
129  if (page_is_empty(page)) {
130  /* It must be an empty index tree; NOTE that in this case
131  we do not store the modify_clock, but always do a search
132  if we restore the cursor position */
133 
134  ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
135  ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
136  ut_ad(page_is_leaf(page));
137  ut_ad(page_get_page_no(page) == index->page);
138 
139  cursor->old_stored = BTR_PCUR_OLD_STORED;
140 
141  if (page_rec_is_supremum_low(offs)) {
142 
143  cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
144  } else {
145  cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
146  }
147 
148  return;
149  }
150 
151  if (page_rec_is_supremum_low(offs)) {
152 
153  rec = page_rec_get_prev(rec);
154 
155  cursor->rel_pos = BTR_PCUR_AFTER;
156 
157  } else if (page_rec_is_infimum_low(offs)) {
158 
159  rec = page_rec_get_next(rec);
160 
161  cursor->rel_pos = BTR_PCUR_BEFORE;
162  } else {
163  cursor->rel_pos = BTR_PCUR_ON;
164  }
165 
166  cursor->old_stored = BTR_PCUR_OLD_STORED;
168  index, rec, &cursor->old_n_fields,
169  &cursor->old_rec_buf, &cursor->buf_size);
170 
171  cursor->block_when_stored = block;
172  cursor->modify_clock = buf_block_get_modify_clock(block);
173 }
174 
175 /**************************************************************/
177 UNIV_INTERN
178 void
180 /*==========================*/
181  btr_pcur_t* pcur_receive,
183  btr_pcur_t* pcur_donate)
185 {
186  if (pcur_receive->old_rec_buf) {
187  mem_free(pcur_receive->old_rec_buf);
188  }
189 
190  ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
191 
192  if (pcur_donate->old_rec_buf) {
193 
194  pcur_receive->old_rec_buf = (byte*)
195  mem_alloc(pcur_donate->buf_size);
196 
197  ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
198  pcur_donate->buf_size);
199  pcur_receive->old_rec = pcur_receive->old_rec_buf
200  + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
201  }
202 
203  pcur_receive->old_n_fields = pcur_donate->old_n_fields;
204 }
205 
206 /**************************************************************/
221 UNIV_INTERN
222 ibool
224 /*===========================*/
225  ulint latch_mode,
226  btr_pcur_t* cursor,
227  const char* file,
228  ulint line,
229  mtr_t* mtr)
230 {
232  dtuple_t* tuple;
233  ulint mode;
234  ulint old_mode;
235  mem_heap_t* heap;
236 
237  ut_ad(mtr);
238  ut_ad(mtr->state == MTR_ACTIVE);
239 
240  index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
241 
242  if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
243  || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
244  && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
245  ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
246  putc('\n', stderr);
247  if (cursor->trx_if_known) {
248  trx_print(stderr, cursor->trx_if_known, 0);
249  }
250 
251  ut_error;
252  }
253 
254  if (UNIV_UNLIKELY
255  (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
256  || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
257 
258  /* In these cases we do not try an optimistic restoration,
259  but always do a search */
260 
261  btr_cur_open_at_index_side(
262  cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
263  index, latch_mode,
264  btr_pcur_get_btr_cur(cursor), 0, mtr);
265 
266  cursor->latch_mode = latch_mode;
267  cursor->pos_state = BTR_PCUR_IS_POSITIONED;
268  cursor->block_when_stored = btr_pcur_get_block(cursor);
269 
270  return(FALSE);
271  }
272 
273  ut_a(cursor->old_rec);
274  ut_a(cursor->old_n_fields);
275 
276  if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
277  || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
278  /* Try optimistic restoration */
279 
280  if (UNIV_LIKELY(buf_page_optimistic_get(
281  latch_mode,
282  cursor->block_when_stored,
283  cursor->modify_clock,
284  file, line, mtr))) {
285  cursor->pos_state = BTR_PCUR_IS_POSITIONED;
286 
287  buf_block_dbg_add_level(
288  btr_pcur_get_block(cursor),
289  dict_index_is_ibuf(index)
290  ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
291 
292  if (cursor->rel_pos == BTR_PCUR_ON) {
293 #ifdef UNIV_DEBUG
294  const rec_t* rec;
295  const ulint* offsets1;
296  const ulint* offsets2;
297 #endif /* UNIV_DEBUG */
298  cursor->latch_mode = latch_mode;
299 #ifdef UNIV_DEBUG
300  rec = btr_pcur_get_rec(cursor);
301 
302  heap = mem_heap_create(256);
303  offsets1 = rec_get_offsets(
304  cursor->old_rec, index, NULL,
305  cursor->old_n_fields, &heap);
306  offsets2 = rec_get_offsets(
307  rec, index, NULL,
308  cursor->old_n_fields, &heap);
309 
310  ut_ad(!cmp_rec_rec(cursor->old_rec,
311  rec, offsets1, offsets2,
312  index));
313  mem_heap_free(heap);
314 #endif /* UNIV_DEBUG */
315  return(TRUE);
316  }
317 
318  return(FALSE);
319  }
320  }
321 
322  /* If optimistic restoration did not succeed, open the cursor anew */
323 
324  heap = mem_heap_create(256);
325 
326  tuple = dict_index_build_data_tuple(index, cursor->old_rec,
327  cursor->old_n_fields, heap);
328 
329  /* Save the old search mode of the cursor */
330  old_mode = cursor->search_mode;
331 
332  switch (cursor->rel_pos) {
333  case BTR_PCUR_ON:
334  mode = PAGE_CUR_LE;
335  break;
336  case BTR_PCUR_AFTER:
337  mode = PAGE_CUR_G;
338  break;
339  case BTR_PCUR_BEFORE:
340  mode = PAGE_CUR_L;
341  break;
342  default:
343  ut_error;
344  mode = 0;
345  }
346 
347  btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
348  cursor, 0, file, line, mtr);
349 
350  /* Restore the old search mode */
351  cursor->search_mode = old_mode;
352 
353  switch (cursor->rel_pos) {
354  case BTR_PCUR_ON:
355  if (btr_pcur_is_on_user_rec(cursor)
356  && !cmp_dtuple_rec(
357  tuple, btr_pcur_get_rec(cursor),
358  rec_get_offsets(btr_pcur_get_rec(cursor),
359  index, NULL,
360  ULINT_UNDEFINED, &heap))) {
361 
362  /* We have to store the NEW value for
363  the modify clock, since the cursor can
364  now be on a different page! But we can
365  retain the value of old_rec */
366 
367  cursor->block_when_stored =
368  btr_pcur_get_block(cursor);
369  cursor->modify_clock =
371  cursor->block_when_stored);
372  cursor->old_stored = BTR_PCUR_OLD_STORED;
373 
374  mem_heap_free(heap);
375 
376  return(TRUE);
377  }
378 #ifdef UNIV_DEBUG
379  /* fall through */
380  case BTR_PCUR_BEFORE:
381  case BTR_PCUR_AFTER:
382  break;
383  default:
384  ut_error;
385 #endif /* UNIV_DEBUG */
386  }
387 
388  mem_heap_free(heap);
389 
390  /* We have to store new position information, modify_clock etc.,
391  to the cursor because it can now be on a different page, the record
392  under it may have been removed, etc. */
393 
394  btr_pcur_store_position(cursor, mtr);
395 
396  return(FALSE);
397 }
398 
399 /*********************************************************/
404 UNIV_INTERN
405 void
407 /*=======================*/
408  btr_pcur_t* cursor,
410  mtr_t* mtr)
411 {
412  ulint next_page_no;
413  ulint space;
414  ulint zip_size;
415  page_t* page;
416  buf_block_t* next_block;
417  page_t* next_page;
418 
419  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
420  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
422 
423  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
424 
425  page = btr_pcur_get_page(cursor);
426  next_page_no = btr_page_get_next(page, mtr);
427  space = buf_block_get_space(btr_pcur_get_block(cursor));
428  zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
429 
430  ut_ad(next_page_no != FIL_NULL);
431 
432  next_block = btr_block_get(space, zip_size, next_page_no,
433  cursor->latch_mode,
434  btr_pcur_get_btr_cur(cursor)->index, mtr);
435  next_page = buf_block_get_frame(next_block);
436 #ifdef UNIV_BTR_DEBUG
437  ut_a(page_is_comp(next_page) == page_is_comp(page));
438  ut_a(btr_page_get_prev(next_page, mtr)
439  == buf_block_get_page_no(btr_pcur_get_block(cursor)));
440 #endif /* UNIV_BTR_DEBUG */
441  next_block->check_index_page_at_flush = TRUE;
442 
443  btr_leaf_page_release(btr_pcur_get_block(cursor),
444  cursor->latch_mode, mtr);
445 
446  page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
447 
448  page_check_dir(next_page);
449 }
450 
451 /*********************************************************/
460 UNIV_INTERN
461 void
463 /*=============================*/
464  btr_pcur_t* cursor,
466  mtr_t* mtr)
467 {
468  ulint prev_page_no;
469  page_t* page;
470  buf_block_t* prev_block;
471  ulint latch_mode;
472  ulint latch_mode2;
473 
474  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
475  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
478 
479  latch_mode = cursor->latch_mode;
480 
481  if (latch_mode == BTR_SEARCH_LEAF) {
482 
483  latch_mode2 = BTR_SEARCH_PREV;
484 
485  } else if (latch_mode == BTR_MODIFY_LEAF) {
486 
487  latch_mode2 = BTR_MODIFY_PREV;
488  } else {
489  latch_mode2 = 0; /* To eliminate compiler warning */
490  ut_error;
491  }
492 
493  btr_pcur_store_position(cursor, mtr);
494 
495  mtr_commit(mtr);
496 
497  mtr_start(mtr);
498 
499  btr_pcur_restore_position(latch_mode2, cursor, mtr);
500 
501  page = btr_pcur_get_page(cursor);
502 
503  prev_page_no = btr_page_get_prev(page, mtr);
504 
505  if (prev_page_no == FIL_NULL) {
506  } else if (btr_pcur_is_before_first_on_page(cursor)) {
507 
508  prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
509 
510  btr_leaf_page_release(btr_pcur_get_block(cursor),
511  latch_mode, mtr);
512 
513  page_cur_set_after_last(prev_block,
514  btr_pcur_get_page_cur(cursor));
515  } else {
516 
517  /* The repositioned cursor did not end on an infimum record on
518  a page. Cursor repositioning acquired a latch also on the
519  previous page, but we do not need the latch: release it. */
520 
521  prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
522 
523  btr_leaf_page_release(prev_block, latch_mode, mtr);
524  }
525 
526  cursor->latch_mode = latch_mode;
527 
528  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
529 }
530 
531 /*********************************************************/
535 UNIV_INTERN
536 ibool
538 /*==================*/
539  btr_pcur_t* cursor,
541  mtr_t* mtr)
542 {
543  ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
544  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
545 
546  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
547 
548  if (btr_pcur_is_before_first_on_page(cursor)) {
549 
550  if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
551 
552  return(FALSE);
553  }
554 
556 
557  return(TRUE);
558  }
559 
561 
562  return(TRUE);
563 }
564 
565 /**************************************************************/
572 UNIV_INTERN
573 void
575 /*===========================*/
577  const dtuple_t* tuple,
578  ulint mode,
579  ulint latch_mode,
581  btr_pcur_t* cursor,
583  const char* file,
584  ulint line,
585  mtr_t* mtr)
586 {
587  btr_pcur_open_low(index, 0, tuple, mode, latch_mode, cursor,
588  file, line, mtr);
589 
590  if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
591 
592  if (btr_pcur_is_after_last_on_page(cursor)) {
593 
594  btr_pcur_move_to_next_user_rec(cursor, mtr);
595  }
596  } else {
597  ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
598 
599  /* Not implemented yet */
600 
601  ut_error;
602  }
603 }