Drizzled Public API Documentation

btr0pcur.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1996, 2010, Innobase Oy. 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., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 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
41 btr_pcur_create_for_mysql(void)
42 /*============================*/
43 {
44  btr_pcur_t* pcur;
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 /**************************************************************/
56 UNIV_INTERN
57 void
58 btr_pcur_free_for_mysql(
59 /*====================*/
60  btr_pcur_t* cursor)
61 {
62  if (cursor->old_rec_buf != NULL) {
63 
64  mem_free(cursor->old_rec_buf);
65 
66  cursor->old_rec_buf = NULL;
67  }
68 
69  cursor->btr_cur.page_cur.rec = NULL;
70  cursor->old_rec = NULL;
71  cursor->old_n_fields = 0;
72  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
73 
74  cursor->latch_mode = BTR_NO_LATCHES;
75  cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
76 
77  mem_free(cursor);
78 }
79 
80 /**************************************************************/
87 UNIV_INTERN
88 void
89 btr_pcur_store_position(
90 /*====================*/
91  btr_pcur_t* cursor,
92  mtr_t* mtr)
93 {
94  page_cur_t* page_cursor;
95  buf_block_t* block;
96  rec_t* rec;
97  dict_index_t* index;
98  page_t* page;
99  ulint offs;
100 
101  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
102  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
103 
104  block = btr_pcur_get_block(cursor);
105  index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
106 
107  page_cursor = btr_pcur_get_page_cur(cursor);
108 
109  rec = page_cur_get_rec(page_cursor);
110  page = page_align(rec);
111  offs = page_offset(rec);
112 
113  ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
114  || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
115  ut_a(cursor->latch_mode != BTR_NO_LATCHES);
116 
117  if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
118  /* It must be an empty index tree; NOTE that in this case
119  we do not store the modify_clock, but always do a search
120  if we restore the cursor position */
121 
122  ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
123  ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
124 
125  cursor->old_stored = BTR_PCUR_OLD_STORED;
126 
127  if (page_rec_is_supremum_low(offs)) {
128 
129  cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
130  } else {
131  cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
132  }
133 
134  return;
135  }
136 
137  if (page_rec_is_supremum_low(offs)) {
138 
139  rec = page_rec_get_prev(rec);
140 
141  cursor->rel_pos = BTR_PCUR_AFTER;
142 
143  } else if (page_rec_is_infimum_low(offs)) {
144 
145  rec = page_rec_get_next(rec);
146 
147  cursor->rel_pos = BTR_PCUR_BEFORE;
148  } else {
149  cursor->rel_pos = BTR_PCUR_ON;
150  }
151 
152  cursor->old_stored = BTR_PCUR_OLD_STORED;
153  cursor->old_rec = dict_index_copy_rec_order_prefix(
154  index, rec, &cursor->old_n_fields,
155  &cursor->old_rec_buf, &cursor->buf_size);
156 
157  cursor->block_when_stored = block;
158  cursor->modify_clock = buf_block_get_modify_clock(block);
159 }
160 
161 /**************************************************************/
163 UNIV_INTERN
164 void
165 btr_pcur_copy_stored_position(
166 /*==========================*/
167  btr_pcur_t* pcur_receive,
169  btr_pcur_t* pcur_donate)
171 {
172  if (pcur_receive->old_rec_buf) {
173  mem_free(pcur_receive->old_rec_buf);
174  }
175 
176  ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
177 
178  if (pcur_donate->old_rec_buf) {
179 
180  pcur_receive->old_rec_buf = (unsigned char *)mem_alloc(pcur_donate->buf_size);
181 
182  ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
183  pcur_donate->buf_size);
184  pcur_receive->old_rec = pcur_receive->old_rec_buf
185  + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
186  }
187 
188  pcur_receive->old_n_fields = pcur_donate->old_n_fields;
189 }
190 
191 /**************************************************************/
206 UNIV_INTERN
207 ibool
208 btr_pcur_restore_position_func(
209 /*===========================*/
210  ulint latch_mode,
211  btr_pcur_t* cursor,
212  const char* file,
213  ulint line,
214  mtr_t* mtr)
215 {
216  dict_index_t* index;
217  dtuple_t* tuple;
218  ulint mode;
219  ulint old_mode;
220  mem_heap_t* heap;
221 
222  ut_ad(mtr);
223  ut_ad(mtr->state == MTR_ACTIVE);
224 
225  index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
226 
227  if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
228  || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
229  && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
230  ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
231  putc('\n', stderr);
232  if (cursor->trx_if_known) {
233  trx_print(stderr, cursor->trx_if_known, 0);
234  }
235 
236  ut_error;
237  }
238 
239  if (UNIV_UNLIKELY
240  (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
241  || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
242 
243  /* In these cases we do not try an optimistic restoration,
244  but always do a search */
245 
246  btr_cur_open_at_index_side(
247  cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
248  index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
249 
250  cursor->latch_mode = latch_mode;
251  cursor->pos_state = BTR_PCUR_IS_POSITIONED;
252  cursor->block_when_stored = btr_pcur_get_block(cursor);
253 
254  return(FALSE);
255  }
256 
257  ut_a(cursor->old_rec);
258  ut_a(cursor->old_n_fields);
259 
260  if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
261  || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
262  /* Try optimistic restoration */
263 
264  if (UNIV_LIKELY(buf_page_optimistic_get(
265  latch_mode,
266  cursor->block_when_stored,
267  cursor->modify_clock,
268  file, line, mtr))) {
269  cursor->pos_state = BTR_PCUR_IS_POSITIONED;
270 
271  buf_block_dbg_add_level(btr_pcur_get_block(cursor),
272  SYNC_TREE_NODE);
273 
274  if (cursor->rel_pos == BTR_PCUR_ON) {
275 #ifdef UNIV_DEBUG
276  const rec_t* rec;
277  const ulint* offsets1;
278  const ulint* offsets2;
279 #endif /* UNIV_DEBUG */
280  cursor->latch_mode = latch_mode;
281 #ifdef UNIV_DEBUG
282  rec = btr_pcur_get_rec(cursor);
283 
284  heap = mem_heap_create(256);
285  offsets1 = rec_get_offsets(
286  cursor->old_rec, index, NULL,
287  cursor->old_n_fields, &heap);
288  offsets2 = rec_get_offsets(
289  rec, index, NULL,
290  cursor->old_n_fields, &heap);
291 
292  ut_ad(!cmp_rec_rec(cursor->old_rec,
293  rec, offsets1, offsets2,
294  index));
295  mem_heap_free(heap);
296 #endif /* UNIV_DEBUG */
297  return(TRUE);
298  }
299 
300  return(FALSE);
301  }
302  }
303 
304  /* If optimistic restoration did not succeed, open the cursor anew */
305 
306  heap = mem_heap_create(256);
307 
308  tuple = dict_index_build_data_tuple(index, cursor->old_rec,
309  cursor->old_n_fields, heap);
310 
311  /* Save the old search mode of the cursor */
312  old_mode = cursor->search_mode;
313 
314  if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
315  mode = PAGE_CUR_LE;
316  } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
317  mode = PAGE_CUR_G;
318  } else {
319  ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
320  mode = PAGE_CUR_L;
321  }
322 
323  btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
324  cursor, 0, file, line, mtr);
325 
326  /* Restore the old search mode */
327  cursor->search_mode = old_mode;
328 
329  if (cursor->rel_pos == BTR_PCUR_ON
330  && btr_pcur_is_on_user_rec(cursor)
331  && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
332  rec_get_offsets(
333  btr_pcur_get_rec(cursor), index,
334  NULL, ULINT_UNDEFINED, &heap))) {
335 
336  /* We have to store the NEW value for the modify clock, since
337  the cursor can now be on a different page! But we can retain
338  the value of old_rec */
339 
340  cursor->block_when_stored = btr_pcur_get_block(cursor);
342  cursor->block_when_stored);
343  cursor->old_stored = BTR_PCUR_OLD_STORED;
344 
345  mem_heap_free(heap);
346 
347  return(TRUE);
348  }
349 
350  mem_heap_free(heap);
351 
352  /* We have to store new position information, modify_clock etc.,
353  to the cursor because it can now be on a different page, the record
354  under it may have been removed, etc. */
355 
356  btr_pcur_store_position(cursor, mtr);
357 
358  return(FALSE);
359 }
360 
361 /**************************************************************/
367 UNIV_INTERN
368 void
369 btr_pcur_release_leaf(
370 /*==================*/
371  btr_pcur_t* cursor,
372  mtr_t* mtr)
373 {
374  buf_block_t* block;
375 
376  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
377  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
378 
379  block = btr_pcur_get_block(cursor);
380 
381  btr_leaf_page_release(block, cursor->latch_mode, mtr);
382 
383  cursor->latch_mode = BTR_NO_LATCHES;
384 
385  cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
386 }
387 
388 /*********************************************************/
393 UNIV_INTERN
394 void
395 btr_pcur_move_to_next_page(
396 /*=======================*/
397  btr_pcur_t* cursor,
399  mtr_t* mtr)
400 {
401  ulint next_page_no;
402  ulint space;
403  ulint zip_size;
404  page_t* page;
405  buf_block_t* next_block;
406  page_t* next_page;
407 
408  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
409  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
411 
412  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
413 
414  page = btr_pcur_get_page(cursor);
415  next_page_no = btr_page_get_next(page, mtr);
416  space = buf_block_get_space(btr_pcur_get_block(cursor));
417  zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
418 
419  ut_ad(next_page_no != FIL_NULL);
420 
421  next_block = btr_block_get(space, zip_size, next_page_no,
422  cursor->latch_mode, mtr);
423  next_page = buf_block_get_frame(next_block);
424 #ifdef UNIV_BTR_DEBUG
425  ut_a(page_is_comp(next_page) == page_is_comp(page));
426  ut_a(btr_page_get_prev(next_page, mtr)
427  == buf_block_get_page_no(btr_pcur_get_block(cursor)));
428 #endif /* UNIV_BTR_DEBUG */
429  next_block->check_index_page_at_flush = TRUE;
430 
431  btr_leaf_page_release(btr_pcur_get_block(cursor),
432  cursor->latch_mode, mtr);
433 
434  page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
435 
436  page_check_dir(next_page);
437 }
438 
439 /*********************************************************/
448 UNIV_INTERN
449 void
450 btr_pcur_move_backward_from_page(
451 /*=============================*/
452  btr_pcur_t* cursor,
454  mtr_t* mtr)
455 {
456  ulint prev_page_no;
457  page_t* page;
458  buf_block_t* prev_block;
459  ulint latch_mode;
460  ulint latch_mode2;
461 
462  ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
463  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
466 
467  latch_mode = cursor->latch_mode;
468 
469  if (latch_mode == BTR_SEARCH_LEAF) {
470 
471  latch_mode2 = BTR_SEARCH_PREV;
472 
473  } else if (latch_mode == BTR_MODIFY_LEAF) {
474 
475  latch_mode2 = BTR_MODIFY_PREV;
476  } else {
477  latch_mode2 = 0; /* To eliminate compiler warning */
478  ut_error;
479  }
480 
481  btr_pcur_store_position(cursor, mtr);
482 
483  mtr_commit(mtr);
484 
485  mtr_start(mtr);
486 
487  btr_pcur_restore_position(latch_mode2, cursor, mtr);
488 
489  page = btr_pcur_get_page(cursor);
490 
491  prev_page_no = btr_page_get_prev(page, mtr);
492 
493  if (prev_page_no == FIL_NULL) {
494  } else if (btr_pcur_is_before_first_on_page(cursor)) {
495 
496  prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
497 
498  btr_leaf_page_release(btr_pcur_get_block(cursor),
499  latch_mode, mtr);
500 
501  page_cur_set_after_last(prev_block,
502  btr_pcur_get_page_cur(cursor));
503  } else {
504 
505  /* The repositioned cursor did not end on an infimum record on
506  a page. Cursor repositioning acquired a latch also on the
507  previous page, but we do not need the latch: release it. */
508 
509  prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
510 
511  btr_leaf_page_release(prev_block, latch_mode, mtr);
512  }
513 
514  cursor->latch_mode = latch_mode;
515 
516  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
517 }
518 
519 /*********************************************************/
523 UNIV_INTERN
524 ibool
525 btr_pcur_move_to_prev(
526 /*==================*/
527  btr_pcur_t* cursor,
529  mtr_t* mtr)
530 {
531  ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
532  ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
533 
534  cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
535 
536  if (btr_pcur_is_before_first_on_page(cursor)) {
537 
538  if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
539 
540  return(FALSE);
541  }
542 
543  btr_pcur_move_backward_from_page(cursor, mtr);
544 
545  return(TRUE);
546  }
547 
549 
550  return(TRUE);
551 }
552 
553 /**************************************************************/
560 UNIV_INTERN
561 void
562 btr_pcur_open_on_user_rec_func(
563 /*===========================*/
564  dict_index_t* index,
565  const dtuple_t* tuple,
566  ulint mode,
567  ulint latch_mode,
569  btr_pcur_t* cursor,
571  const char* file,
572  ulint line,
573  mtr_t* mtr)
574 {
575  btr_pcur_open_func(index, tuple, mode, latch_mode, cursor,
576  file, line, mtr);
577 
578  if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
579 
580  if (btr_pcur_is_after_last_on_page(cursor)) {
581 
582  btr_pcur_move_to_next_user_rec(cursor, mtr);
583  }
584  } else {
585  ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
586 
587  /* Not implemented yet */
588 
589  ut_error;
590  }
591 }