1
/******************************************************
2
The index tree persistent cursor
6
Created 2/23/1996 Heikki Tuuri
7
*******************************************************/
12
#include "btr0pcur.ic"
19
/******************************************************************
20
Allocates memory for a persistent cursor object and initializes the cursor. */
23
btr_pcur_create_for_mysql(void)
24
/*============================*/
25
/* out, own: persistent cursor */
29
pcur = mem_alloc(sizeof(btr_pcur_t));
31
pcur->btr_cur.index = NULL;
37
/******************************************************************
38
Frees the memory for a persistent cursor object. */
41
btr_pcur_free_for_mysql(
42
/*====================*/
43
btr_pcur_t* cursor) /* in, own: persistent cursor */
45
if (cursor->old_rec_buf != NULL) {
47
mem_free(cursor->old_rec_buf);
49
cursor->old_rec_buf = NULL;
52
cursor->btr_cur.page_cur.rec = NULL;
53
cursor->old_rec = NULL;
54
cursor->old_n_fields = 0;
55
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
57
cursor->latch_mode = BTR_NO_LATCHES;
58
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
63
/******************************************************************
64
The position of the cursor is stored by taking an initial segment of the
65
record the cursor is positioned on, before, or after, and copying it to the
66
cursor data structure, or just setting a flag if the cursor id before the
67
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
68
page where the cursor is positioned must not be empty if the index tree is
72
btr_pcur_store_position(
73
/*====================*/
74
btr_pcur_t* cursor, /* in: persistent cursor */
75
mtr_t* mtr) /* in: mtr */
77
page_cur_t* page_cursor;
84
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
85
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
87
block = btr_pcur_get_block(cursor);
88
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
90
page_cursor = btr_pcur_get_page_cur(cursor);
92
rec = page_cur_get_rec(page_cursor);
93
page = page_align(rec);
94
offs = page_offset(rec);
96
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
97
|| mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
98
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
100
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
101
/* It must be an empty index tree; NOTE that in this case
102
we do not store the modify_clock, but always do a search
103
if we restore the cursor position */
105
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
106
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
108
cursor->old_stored = BTR_PCUR_OLD_STORED;
110
if (page_rec_is_supremum_low(offs)) {
112
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
114
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
120
if (page_rec_is_supremum_low(offs)) {
122
rec = page_rec_get_prev(rec);
124
cursor->rel_pos = BTR_PCUR_AFTER;
126
} else if (page_rec_is_infimum_low(offs)) {
128
rec = page_rec_get_next(rec);
130
cursor->rel_pos = BTR_PCUR_BEFORE;
132
cursor->rel_pos = BTR_PCUR_ON;
135
cursor->old_stored = BTR_PCUR_OLD_STORED;
136
cursor->old_rec = dict_index_copy_rec_order_prefix(
137
index, rec, &cursor->old_n_fields,
138
&cursor->old_rec_buf, &cursor->buf_size);
140
cursor->block_when_stored = block;
141
cursor->modify_clock = buf_block_get_modify_clock(block);
144
/******************************************************************
145
Copies the stored position of a pcur to another pcur. */
148
btr_pcur_copy_stored_position(
149
/*==========================*/
150
btr_pcur_t* pcur_receive, /* in: pcur which will receive the
152
btr_pcur_t* pcur_donate) /* in: pcur from which the info is
155
if (pcur_receive->old_rec_buf) {
156
mem_free(pcur_receive->old_rec_buf);
159
ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
161
if (pcur_donate->old_rec_buf) {
163
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
165
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
166
pcur_donate->buf_size);
167
pcur_receive->old_rec = pcur_receive->old_rec_buf
168
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf);
171
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
174
/******************************************************************
175
Restores the stored position of a persistent cursor bufferfixing the page and
176
obtaining the specified latches. If the cursor position was saved when the
177
(1) cursor was positioned on a user record: this function restores the position
178
to the last record LESS OR EQUAL to the stored record;
179
(2) cursor was positioned on a page infimum record: restores the position to
180
the last record LESS than the user record which was the successor of the page
182
(3) cursor was positioned on the page supremum: restores to the first record
183
GREATER than the user record which was the predecessor of the supremum.
184
(4) cursor was positioned before the first or after the last in an empty tree:
185
restores to before first or after the last in the tree. */
188
btr_pcur_restore_position(
189
/*======================*/
190
/* out: TRUE if the cursor position
191
was stored when it was on a user record
192
and it can be restored on a user record
193
whose ordering fields are identical to
194
the ones of the original user record */
195
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
196
btr_pcur_t* cursor, /* in: detached persistent cursor */
197
mtr_t* mtr) /* in: mtr */
205
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
207
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
208
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
209
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
210
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
211
if (cursor->trx_if_known) {
212
trx_print(stderr, cursor->trx_if_known, 0);
219
(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
220
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
222
/* In these cases we do not try an optimistic restoration,
223
but always do a search */
225
btr_cur_open_at_index_side(
226
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
227
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
229
cursor->block_when_stored = btr_pcur_get_block(cursor);
234
ut_a(cursor->old_rec);
235
ut_a(cursor->old_n_fields);
237
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
238
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
239
/* Try optimistic restoration */
241
if (UNIV_LIKELY(buf_page_optimistic_get(
243
cursor->block_when_stored,
244
cursor->modify_clock, mtr))) {
245
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
246
#ifdef UNIV_SYNC_DEBUG
247
buf_block_dbg_add_level(btr_pcur_get_block(cursor),
249
#endif /* UNIV_SYNC_DEBUG */
250
if (cursor->rel_pos == BTR_PCUR_ON) {
253
const ulint* offsets1;
254
const ulint* offsets2;
255
#endif /* UNIV_DEBUG */
256
cursor->latch_mode = latch_mode;
258
rec = btr_pcur_get_rec(cursor);
260
heap = mem_heap_create(256);
261
offsets1 = rec_get_offsets(
262
cursor->old_rec, index, NULL,
263
cursor->old_n_fields, &heap);
264
offsets2 = rec_get_offsets(
266
cursor->old_n_fields, &heap);
268
ut_ad(!cmp_rec_rec(cursor->old_rec,
269
rec, offsets1, offsets2,
272
#endif /* UNIV_DEBUG */
280
/* If optimistic restoration did not succeed, open the cursor anew */
282
heap = mem_heap_create(256);
284
tuple = dict_index_build_data_tuple(index, cursor->old_rec,
285
cursor->old_n_fields, heap);
287
/* Save the old search mode of the cursor */
288
old_mode = cursor->search_mode;
290
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
292
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
295
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
299
btr_pcur_open_with_no_init(index, tuple, mode, latch_mode,
302
/* Restore the old search mode */
303
cursor->search_mode = old_mode;
305
if (cursor->rel_pos == BTR_PCUR_ON
306
&& btr_pcur_is_on_user_rec(cursor)
307
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
309
btr_pcur_get_rec(cursor), index,
310
NULL, ULINT_UNDEFINED, &heap))) {
312
/* We have to store the NEW value for the modify clock, since
313
the cursor can now be on a different page! But we can retain
314
the value of old_rec */
316
cursor->block_when_stored = btr_pcur_get_block(cursor);
317
cursor->modify_clock = buf_block_get_modify_clock(
318
cursor->block_when_stored);
319
cursor->old_stored = BTR_PCUR_OLD_STORED;
328
/* We have to store new position information, modify_clock etc.,
329
to the cursor because it can now be on a different page, the record
330
under it may have been removed, etc. */
332
btr_pcur_store_position(cursor, mtr);
337
/******************************************************************
338
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
339
releases the page latch and bufferfix reserved by the cursor.
340
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
341
made by the current mini-transaction to the data protected by the
342
cursor latch, as then the latch must not be released until mtr_commit. */
345
btr_pcur_release_leaf(
346
/*==================*/
347
btr_pcur_t* cursor, /* in: persistent cursor */
348
mtr_t* mtr) /* in: mtr */
352
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
353
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
355
block = btr_pcur_get_block(cursor);
357
btr_leaf_page_release(block, cursor->latch_mode, mtr);
359
cursor->latch_mode = BTR_NO_LATCHES;
361
cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
364
/*************************************************************
365
Moves the persistent cursor to the first record on the next page. Releases the
366
latch on the current page, and bufferunfixes it. Note that there must not be
367
modifications on the current page, as then the x-latch can be released only in
371
btr_pcur_move_to_next_page(
372
/*=======================*/
373
btr_pcur_t* cursor, /* in: persistent cursor; must be on the
374
last record of the current page */
375
mtr_t* mtr) /* in: mtr */
381
buf_block_t* next_block;
384
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
385
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
386
ut_ad(btr_pcur_is_after_last_on_page(cursor));
388
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
390
page = btr_pcur_get_page(cursor);
391
next_page_no = btr_page_get_next(page, mtr);
392
space = buf_block_get_space(btr_pcur_get_block(cursor));
393
zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
395
ut_ad(next_page_no != FIL_NULL);
397
next_block = btr_block_get(space, zip_size, next_page_no,
398
cursor->latch_mode, mtr);
399
next_page = buf_block_get_frame(next_block);
400
#ifdef UNIV_BTR_DEBUG
401
ut_a(page_is_comp(next_page) == page_is_comp(page));
402
ut_a(btr_page_get_prev(next_page, mtr)
403
== buf_block_get_page_no(btr_pcur_get_block(cursor)));
404
#endif /* UNIV_BTR_DEBUG */
405
next_block->check_index_page_at_flush = TRUE;
407
btr_leaf_page_release(btr_pcur_get_block(cursor),
408
cursor->latch_mode, mtr);
410
page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
412
page_check_dir(next_page);
415
/*************************************************************
416
Moves the persistent cursor backward if it is on the first record of the page.
417
Commits mtr. Note that to prevent a possible deadlock, the operation
418
first stores the position of the cursor, commits mtr, acquires the necessary
419
latches and restores the cursor position again before returning. The
420
alphabetical position of the cursor is guaranteed to be sensible on
421
return, but it may happen that the cursor is not positioned on the last
422
record of any page, because the structure of the tree may have changed
423
during the time when the cursor had no latches. */
426
btr_pcur_move_backward_from_page(
427
/*=============================*/
428
btr_pcur_t* cursor, /* in: persistent cursor, must be on the first
429
record of the current page */
430
mtr_t* mtr) /* in: mtr */
435
buf_block_t* prev_block;
439
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
440
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
441
ut_ad(btr_pcur_is_before_first_on_page(cursor));
442
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
444
latch_mode = cursor->latch_mode;
446
if (latch_mode == BTR_SEARCH_LEAF) {
448
latch_mode2 = BTR_SEARCH_PREV;
450
} else if (latch_mode == BTR_MODIFY_LEAF) {
452
latch_mode2 = BTR_MODIFY_PREV;
454
latch_mode2 = 0; /* To eliminate compiler warning */
458
btr_pcur_store_position(cursor, mtr);
464
btr_pcur_restore_position(latch_mode2, cursor, mtr);
466
page = btr_pcur_get_page(cursor);
468
prev_page_no = btr_page_get_prev(page, mtr);
469
space = buf_block_get_space(btr_pcur_get_block(cursor));
471
if (prev_page_no == FIL_NULL) {
472
} else if (btr_pcur_is_before_first_on_page(cursor)) {
474
prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
476
btr_leaf_page_release(btr_pcur_get_block(cursor),
479
page_cur_set_after_last(prev_block,
480
btr_pcur_get_page_cur(cursor));
483
/* The repositioned cursor did not end on an infimum record on
484
a page. Cursor repositioning acquired a latch also on the
485
previous page, but we do not need the latch: release it. */
487
prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
489
btr_leaf_page_release(prev_block, latch_mode, mtr);
492
cursor->latch_mode = latch_mode;
494
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
497
/*************************************************************
498
Moves the persistent cursor to the previous record in the tree. If no records
499
are left, the cursor stays 'before first in tree'. */
502
btr_pcur_move_to_prev(
503
/*==================*/
504
/* out: TRUE if the cursor was not before first
506
btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the
507
function may release the page latch */
508
mtr_t* mtr) /* in: mtr */
510
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
511
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
513
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
515
if (btr_pcur_is_before_first_on_page(cursor)) {
517
if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
522
btr_pcur_move_backward_from_page(cursor, mtr);
527
btr_pcur_move_to_prev_on_page(cursor);
532
/******************************************************************
533
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
534
user record satisfying the search condition, in the case PAGE_CUR_L or
535
PAGE_CUR_LE, on the last user record. If no such user record exists, then
536
in the first case sets the cursor after last in tree, and in the latter case
537
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
541
btr_pcur_open_on_user_rec(
542
/*======================*/
543
dict_index_t* index, /* in: index */
544
const dtuple_t* tuple, /* in: tuple on which search done */
545
ulint mode, /* in: PAGE_CUR_L, ... */
546
ulint latch_mode, /* in: BTR_SEARCH_LEAF or
548
btr_pcur_t* cursor, /* in: memory buffer for persistent
550
mtr_t* mtr) /* in: mtr */
552
btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr);
554
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
556
if (btr_pcur_is_after_last_on_page(cursor)) {
558
btr_pcur_move_to_next_user_rec(cursor, mtr);
561
ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
563
/* Not implemented yet */