polardbxengine/storage/innobase/include/btr0pcur.h

1027 lines
34 KiB
C++

/*****************************************************************************
Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Free Software Foundation.
This program is also distributed with certain software (including but not
limited to OpenSSL) that is licensed under separate terms, as designated in a
particular file or component or in included license documentation. The authors
of MySQL hereby grant you an additional permission to link the program and
your derivative works with the separately licensed software that they have
included with MySQL.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/** @file include/btr0pcur.h
The index tree persistent cursor
Created 2/23/1996 Heikki Tuuri
*******************************************************/
#ifndef btr0pcur_h
#define btr0pcur_h
#include "btr0btr.h"
#include "btr0cur.h"
#include "btr0types.h"
#include "data0data.h"
#include "dict0dict.h"
#include "mtr0mtr.h"
#include "page0cur.h"
#include "univ.i"
#ifndef UNIV_HOTBACKUP
#include "gis0rtree.h"
#endif /* UNIV_HOTBACKUP */
#include "lizard0cleanout.h"
/** Relative positions for a stored cursor position */
enum btr_pcur_pos_t {
BTR_PCUR_UNSET = 0,
BTR_PCUR_ON = 1,
BTR_PCUR_BEFORE = 2,
BTR_PCUR_AFTER = 3,
/* Note that if the tree is not empty, btr_pcur_store_position does
not use the following, but only uses the above three alternatives,
where the position is stored relative to a specific record: this makes
implementation of a scroll cursor easier */
BTR_PCUR_BEFORE_FIRST_IN_TREE = 4, /* in an empty tree */
BTR_PCUR_AFTER_LAST_IN_TREE = 5 /* in an empty tree */
};
#define btr_pcur_create_for_mysql() btr_pcur_t::create_for_mysql()
#define btr_pcur_free_for_mysql(p) btr_pcur_t::free_for_mysql(p)
#define btr_pcur_reset(p) (p)->reset();
#define btr_pcur_copy_stored_position(d, s) \
btr_pcur_t::copy_stored_position(d, s)
#define btr_pcur_free(p) (p)->free_rec_buf()
#define btr_pcur_open(i, t, md, l, p, m) \
(p)->open((i), 0, (t), (md), (l), m, __FILE__, __LINE__)
#define btr_pcur_init(p) (p)->init()
#define btr_pcur_close(p) (p)->close()
#define btr_pcur_open_at_rnd_pos(i, l, p, m) \
(p)->set_random_position((i), (l), (m), __FILE__, __LINE__)
#define btr_pcur_open_low(i, lv, md, lm, p, f, ln, mr) \
(p)->open((i), (lv), (t), (md), (lm), (mr), (f), (l))
#define btr_pcur_open_at_index_side(e, i, lm, p, ip, lv, m) \
(p)->open_at_side((e), (i), (lm), (ip), (lv), (m))
#define btr_pcur_open_on_user_rec(i, t, md, l, p, m) \
(p)->open_on_user_rec((i), (t), (md), (l), (m), __FILE__, __LINE__)
#define btr_pcur_open_with_no_init(i, t, md, l, p, has, m) \
(p)->open_no_init((i), (t), (md), (l), (has), (m), __FILE__, __LINE__)
#define btr_pcur_restore_position(l, p, mtr) \
(p)->restore_position(l, mtr, __FILE__, __LINE__)
#define btr_pcur_store_position(p, m) (p)->store_position(m)
#define btr_pcur_get_rel_pos(p) (p)->get_rel_pos()
#define btr_pcur_commit_specify_mtr(p, m) (p)->commit_specify_mtr(m)
#define btr_pcur_move_to_next(p, m) (p)->move_to_next(m)
#define btr_pcur_move_to_prev(p, m) (p)->move_to_prev(m)
#define btr_pcur_move_to_last_on_page(p, m) (p)->move_to_last_on_page(m)
#define btr_pcur_move_to_next_user_rec(p, m) \
((p)->move_to_next_user_rec(m) == DB_SUCCESS)
#define btr_pcur_move_to_next_page(p, m) (p)->move_to_next_page(m)
#define btr_pcur_get_btr_cur(p) (p)->get_btr_cur()
#define btr_pcur_get_page_cur(p) (p)->get_page_cur()
#define btr_pcur_get_page(p) (p)->get_page()
#define btr_pcur_get_block(p) (p)->get_block()
#define btr_pcur_get_rec(p) (p)->get_rec()
#define btr_pcur_is_on_user_rec(p) (p)->is_on_user_rec()
#define btr_pcur_is_after_last_on_page(p) (p)->is_after_last_on_page()
#define btr_pcur_is_before_first_on_page(p) (p)->is_before_first_on_page()
#define btr_pcur_is_before_first_in_tree(p, m) (p)->is_before_first_in_tree(m)
#define btr_pcur_is_after_last_in_tree(p, m) (p)->is_after_last_in_tree(m)
#define btr_pcur_move_to_next_on_page(p) (p)->move_to_next_on_page()
#define btr_pcur_move_to_prev_on_page(p) (p)->move_to_prev_on_page()
#define btr_pcur_move_before_first_on_page(p) (p)->move_before_first_on_page()
#define btr_pcur_get_low_match(p) (p)->get_low_match()
#define btr_pcur_get_up_match(p) (p)->get_up_match()
/** Position state of persistent B-tree cursor. */
enum pcur_pos_t {
/** The persistent cursor is not positioned. */
BTR_PCUR_NOT_POSITIONED = 0,
/** The persistent cursor was previously positioned.
TODO: currently, the state can be BTR_PCUR_IS_POSITIONED,
though it really should be BTR_PCUR_WAS_POSITIONED,
because we have no obligation to commit the cursor with
mtr; similarly latch_mode may be out of date. This can
lead to problems if btr_pcur is not used the right way;
all current code should be ok. */
BTR_PCUR_WAS_POSITIONED,
/** The persistent cursor is positioned by optimistic get to the same
record as it was positioned at. Not used for rel_pos == BTR_PCUR_ON.
It may need adjustment depending on previous/current search direction
and rel_pos. */
BTR_PCUR_IS_POSITIONED_OPTIMISTIC,
/** The persistent cursor is positioned by index search.
Or optimistic get for rel_pos == BTR_PCUR_ON. */
BTR_PCUR_IS_POSITIONED
};
/* The persistent B-tree cursor structure. This is used mainly for SQL
selects, updates, and deletes. */
struct btr_pcur_t {
/** Sets the old_rec_buf field to nullptr. */
void init();
/** @return the index of this persistent cursor */
dict_index_t *index() { return (m_btr_cur.index); }
/** Positions a cursor at a randomly chosen position within a B-tree.
@param[in] index Index to position on.
@param[in] latch_mode BTR_SEARCH_LEAF, ...
@param[in,out] mtr Mini transaction.
@param[in] file File name from where called.
@param[in] line Line number within filename
@return true if the index is available and we have put the cursor, false
if the index is unavailable */
bool set_random_position(dict_index_t *index, ulint latch_mode, mtr_t *mtr,
const char *file, ulint line);
/** Opens a persistent cursor at either end of an index.
@param[in] from_left true if open to the low end, false
if to the high end.
@param[in] index index
@param[in] latch_mode latch mode
@param[in] init_pcur whether to initialize pcur.
@param[in] level level to search for (0=leaf).
@param[in,out] mtr mini-transaction */
void open_at_side(bool from_left, dict_index_t *index, ulint latch_mode,
bool init_pcur, ulint level, mtr_t *mtr);
/** Opens a persistent cursor at first leaf page (low end). It will not call
init().
@param[in] index index
@param[in] latch_mode latch mode
@param[in,out] mtr mini-transaction */
void begin_leaf(dict_index_t *index, ulint latch_mode, mtr_t *mtr) {
open_at_side(true, index, latch_mode, false, 0, mtr);
}
/** Opens an persistent cursor to an index tree without initializing
the cursor.
@param[in] index Index.
@param[in] tuple Tuple on which search done.
@param[in] mode PAGE_CUR_L, ...;
NOTE that if the search is made using a unique
prefix of a record, mode should be
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page of the
record!
@param[in] latch_mode BTR_SEARCH_LEAF, ...;
NOTE that if has_search_latch != 0 then
we maybe do not acquire a latch on the cursor
page, but assume that the caller uses his
btr search latch to protect the record!
@param[in] has_search_latch latch mode the caller
currently has on search system: RW_S_LATCH, or 0
@param[in] mtr Mtr
@param[in] file File name.
@param[in] line Line where called */
void open_no_init(dict_index_t *index, const dtuple_t *tuple,
page_cur_mode_t mode, ulint latch_mode,
ulint has_search_latch, mtr_t *mtr, const char *file,
ulint line);
/** If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor
on the first user record satisfying the search condition, in the case
PAGE_CUR_L or PAGE_CUR_LE, on the last user record. If no such user
record exists, then in the first case sets the cursor after last in
tree, and in the latter case before first in tree. The latching mode
must be BTR_SEARCH_LEAF or BTR_MODIFY_LEAF.
@param[in] index Index
@param[in] tuple Tuple on which search done.
@param[in] mode PAGE_CUR_L, ...
@param[in] latch_mode BTR_SEARCH_LEAF or BTR_MODIFY_LEAF
@param[in] mtr Mini transaction.
@param[in] file File name from where called.
@param[in] line Line number in file from where
called.*/
void open_on_user_rec(dict_index_t *index, const dtuple_t *tuple,
page_cur_mode_t mode, ulint latch_mode, mtr_t *mtr,
const char *file, ulint line);
/** Allows setting the persistent cursor manually.
@param[in] cursor Page cursor where positioned.
@param[in] mode PAGE_CUR_L, ...
@param[in] latch_mode BTR_SEARCH_LEAF or BTR_MODIFY_LEAF */
void open_on_user_rec(const page_cur_t &cursor, page_cur_mode_t mode,
ulint latch_mode);
/** Initializes and opens a persistent cursor to an index tree
It should be closed with close().
@param[in] index Index.
@param[in] level Level in the btree.
@param[in] tuple Tuple on which search done.
@param[in] mode PAGE_CUR_L, ...;
NOTE that if the search is made using
a unique prefix of a record, mode
should be PAGE_CUR_LE, not PAGE_CUR_GE,
as the latter may end up on the
previous page from the record!
@param[in] latch_mode BTR_SEARCH_LEAF, ...
@param[in] mtr Mini-transaction.
@param[in] file File name
@param[in] line Line in file, from where called. */
void open(dict_index_t *index, ulint level, const dtuple_t *tuple,
page_cur_mode_t mode, ulint latch_mode, mtr_t *mtr,
const char *file, ulint line);
/** Restores the stored position of a persistent cursor bufferfixing
the page and obtaining the specified latches. If the cursor position
was saved when the
(1) cursor was positioned on a user record: this function restores
the position to the last record LESS OR EQUAL to the stored record;
(2) cursor was positioned on a page infimum record: restores the
position to the last record LESS than the user record which was the
successor of the page infimum;
(3) cursor was positioned on the page supremum: restores to the first
record GREATER than the user record which was the predecessor of the
supremum.
(4) cursor was positioned before the first or after the last in an
empty tree: restores to before first or after the last in the tree.
@param[in] latch_mode BTR_SEARCH_LEAF, ...
@param[in,out] mtr Mini transaction
@param[in] file File name.
@param[in] line Line where called.
@return true if the cursor position was stored when it was on a user
record and it can be restored on a user record whose ordering
fields are identical to the ones of the original user record */
bool restore_position(ulint latch_mode, mtr_t *mtr, const char *file,
ulint line);
/** Frees the possible memory heap of a persistent cursor and
sets the latch mode of the persistent cursor to BTR_NO_LATCHES.
WARNING: this function does not release the latch on the page where the
cursor is currently positioned. The latch is acquired by the
"move to next/previous" family of functions. Since recursive shared
locks are not allowed, you must take care (if using the cursor in
S-mode) to manually release the latch by either calling
btr_leaf_page_release(btr_pcur_get_block(&pcur), pcur.latch_mode, mtr)
or by committing the mini-transaction right after btr_pcur_close().
A subsequent attempt to crawl the same page in the same mtr would
cause an assertion failure. */
void close();
/** Free old_rec_buf. */
void free_rec_buf() {
ut_free(m_old_rec_buf);
m_old_rec_buf = nullptr;
}
#ifndef UNIV_HOTBACKUP
/** Gets the rel_pos field for a cursor whose position has been stored.
@return BTR_PCUR_ON, ... */
ulint get_rel_pos() const;
#endif /* !UNIV_HOTBACKUP */
/** @return the btree cursor (const version). */
const btr_cur_t *get_btr_cur() const;
/** @return the btree cursor (non const version). */
btr_cur_t *get_btr_cur();
/** @return the btree page cursor (non const version). */
page_cur_t *get_page_cur();
/** @return the btree cursor (const version). */
const page_cur_t *get_page_cur() const;
/** Returns the page of a persistent pcur (non const version).
@return pointer to the page */
page_t *get_page();
/** Returns the page of a persistent pcur (const version).
@return pointer to the page */
const page_t *get_page() const;
/** Returns the current buffer block (non const version).
@return pointer to the block */
buf_block_t *get_block();
/** Returns the current buffer block (const version).
@return pointer to the block */
const buf_block_t *get_block() const;
/** Returns the current record (non const version).
@return pointer to the record */
rec_t *get_rec();
/** Returns the current record (const version).
@return pointer to the record */
const rec_t *get_rec() const;
#ifndef UNIV_HOTBACKUP
/** Gets the up_match value for a pcur after a search.
@return number of matched fields at the cursor or to the right if
search mode was PAGE_CUR_GE, otherwise undefined */
ulint get_up_match() const;
/** Gets the low_match value for a pcur after a search.
@return number of matched fields at the cursor or to the right if
search mode was PAGE_CUR_LE, otherwise undefined */
ulint get_low_match() const;
/** Checks if the persistent cursor is after the last user record
on a page.
@return true if after last on page. */
bool is_after_last_on_page() const;
/** Checks if the persistent cursor is before the first user record
on a page.
@return true if before first on page. */
bool is_before_first_on_page() const;
/** Checks if the persistent cursor is on a user record.
@return true if on user record. */
bool is_on_user_rec() const;
/** Checks if the persistent cursor is before the first user record
in the index tree.
@param[in,out] mtr Mini transaction.
@return true if is before first in tree. */
bool is_before_first_in_tree(mtr_t *mtr) const;
/** Checks if the persistent cursor is after the last user record in
the index tree.
@param[in,out] mtr Mini transaction.
@return is after last in tree. */
bool is_after_last_in_tree(mtr_t *mtr) const;
/** Moves the persistent cursor to the next record on the same page. */
void move_to_next_on_page();
/** Moves the persistent cursor to the prev record on the same page. */
void move_to_prev_on_page();
/** Moves the persistent cursor to the last record on the same page.
@param[in,out] mtr Mini transaction. */
void move_to_last_on_page(mtr_t *mtr);
/** Moves the persistent cursor to the next user record in the tree.
If no user records are left, the cursor ends up 'after last in tree'.
@param[in,out] mtr Mini transaction.
@return DB_SUCCESS or DB_END_OF_INDEX. */
dberr_t move_to_next_user_rec(mtr_t *mtr);
/** Moves the persistent cursor to the next record in the tree. If no
records are left, the cursor stays 'after last in tree'.
Note: Function may release the page latch.
@param[in,out] mtr Mini transaction.
@return true if the cursor was not after last in tree */
bool move_to_next(mtr_t *mtr);
/** Moves the persistent cursor to the previous record in the tree.
If no records are left, the cursor stays 'before first in tree'.
Note: Function may release the page latch.
@param[in,out] mtr Mini transaction.
@return true if the cursor was not before first in tree */
bool move_to_prev(mtr_t *mtr);
/** Moves the persistent cursor to the first record on the next page.
Releases the latch on the current page, and bufferunfixes it.
Note that there must not be modifications on the current page, as
then the x-latch can be released only in mtr_commit.
@param[in,out] mtr Mini transaction. */
void move_to_next_page(mtr_t *mtr);
/** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES,
that is, the cursor becomes detached.
Function btr_pcur_store_position should be used before calling this,
if restoration of cursor is wanted later.
@param[in,out] mtr Mini transaction. */
void commit_specify_mtr(mtr_t *mtr);
/** Moves the persistent cursor to the infimum record on the same page. */
void move_before_first_on_page();
#endif /* !UNIV_HOTBACKUP */
/** The position of the cursor is stored by taking an initial segment
of the record the cursor is positioned on, before, or after, and
copying it to the cursor data structure, or just setting a flag if
the cursor id before the first in an EMPTY tree, or after the last
in an EMPTY tree. NOTE that the page where the cursor is positioned
must not be empty if the index tree is not totally empty!
@param[in,out] mtr Mini-transaction. */
void store_position(mtr_t *mtr);
/** @return true if the cursor is positioned. */
bool is_positioned() const {
return (m_old_stored && (m_pos_state == BTR_PCUR_IS_POSITIONED ||
m_pos_state == BTR_PCUR_WAS_POSITIONED));
}
/** @return true if the cursor is for a clustered index. */
bool is_clustered() const { return (m_btr_cur.index->is_clustered()); }
/** Resets a persistent cursor object, freeing "::old_rec_buf" if it is
allocated and resetting the other members to their initial values. */
void reset();
/** Copies the stored position of a pcur to another pcur.
@param[in,out] dst Which will receive the position
info.
@param[in] src From which the info is copied */
static void copy_stored_position(btr_pcur_t *dst, const btr_pcur_t *src);
/** Allocates memory for a persistent cursor object and initializes
the cursor.
@return own: persistent cursor */
static btr_pcur_t *create_for_mysql() {
auto pcur = UT_NEW_NOKEY(btr_pcur_t());
pcur->m_btr_cur.index = nullptr;
pcur->init();
return (pcur);
}
/** Frees the memory for a persistent cursor object and the cursor itself.
@param[in,out] pcur Cursor to free. */
static void free_for_mysql(btr_pcur_t *&pcur) {
pcur->free_rec_buf();
UT_DELETE(pcur);
pcur = nullptr;
}
/** Set the cursor access type: Normal or Scan.
@param[in] fetch_mode One of Page_fetch::NORMAL or Page_fetch::SCAN.
@return the old fetch mode. */
Page_fetch set_fetch_type(Page_fetch fetch_mode) {
ut_ad(fetch_mode == Page_fetch::NORMAL || fetch_mode == Page_fetch::SCAN);
auto old_fetch_mode = m_btr_cur.m_fetch_mode;
m_btr_cur.m_fetch_mode = fetch_mode;
return (old_fetch_mode);
}
private:
/** Moves the persistent cursor backward if it is on the first record
of the page. Commits mtr. Note that to prevent a possible deadlock, the
operation first stores the position of the cursor, commits mtr, acquires
the necessary latches and restores the cursor position again before
returning. The alphabetical position of the cursor is guaranteed to
be sensible on return, but it may happen that the cursor is not
positioned on the last record of any page, because the structure
of the tree may have changed during the time when the cursor had
no latches.
@param[in,out] mtr Mini-tranaction. */
void move_backward_from_page(mtr_t *mtr);
public:
/** a B-tree cursor */
btr_cur_t m_btr_cur;
/** see TODO note below!
BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES,
depending on the latching state of the page and tree where the cursor
is positioned; BTR_NO_LATCHES means that the cursor is not currently
positioned:
we say then that the cursor is detached; it can be restored to
attached if the old position was stored in old_rec */
ulint m_latch_mode{0};
/** true if old_rec is stored */
bool m_old_stored{false};
/** if cursor position is stored, contains an initial segment of the
latest record cursor was positioned either on, before or after */
rec_t *m_old_rec{nullptr};
/** number of fields in old_rec */
ulint m_old_n_fields{0};
/** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
whether cursor was on, before, or after the old_rec record */
btr_pcur_pos_t m_rel_pos{BTR_PCUR_UNSET};
/** buffer block when the position was stored */
buf_block_t *m_block_when_stored{nullptr};
/** the modify clock value of the buffer block when the cursor position
was stored */
uint64_t m_modify_clock{0};
/** the withdraw clock value of the buffer pool when the cursor
position was stored */
ulint m_withdraw_clock{0};
/** position() and restore_position() state. */
pcur_pos_t m_pos_state{BTR_PCUR_NOT_POSITIONED};
/** PAGE_CUR_G, ... */
page_cur_mode_t m_search_mode{PAGE_CUR_UNSUPP};
/** the transaction, if we know it; otherwise this field is not defined;
can ONLY BE USED in error prints in fatal assertion failures! */
trx_t *m_trx_if_known{nullptr};
/* NOTE that the following fields may possess dynamically allocated
memory which should be freed if not needed anymore! */
/** nullptr, or a dynamically allocated buffer for old_rec */
byte *m_old_rec_buf{nullptr};
/** old_rec_buf size if old_rec_buf is not nullptr */
size_t m_buf_size{0};
/** Collected pages that need to cleanout */
lizard::Cleanout_pages *m_cleanout_pages{nullptr};
/** Collected cursor that need to cleanout */
lizard::Cleanout_cursors *m_cleanout_cursors{nullptr};
/** Add constructor to init m_cleanout_pages, otherwise we have to init it
at many place.*/
btr_pcur_t() {
m_cleanout_pages = nullptr;
m_cleanout_cursors = nullptr;
}
};
inline void btr_pcur_t::init() {
set_fetch_type(Page_fetch::NORMAL);
m_old_stored = false;
m_old_rec_buf = nullptr;
m_old_rec = nullptr;
m_btr_cur.rtr_info = nullptr;
m_cleanout_pages = nullptr;
m_cleanout_cursors = nullptr;
}
/** Initializes and opens a persistent cursor to an index tree
It should be closed with btr_pcur_close.
@param[in] index Index.
@param[in] level Level in the btree.
@param[in] tuple Tuple on which search done.
@param[in] mode PAGE_CUR_L, ...; NOTE that if
the search is made using a unique prefix of a record, mode should be
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter may end up on the previous page from
the record!
@param[in] latch_mode BTR_SEARCH_LEAF, ...
@param[in] mtr Mini-transaction.
@param[in] file File name
@param[in] line Line in file, from where called. */
inline void btr_pcur_t::open(dict_index_t *index, ulint level,
const dtuple_t *tuple, page_cur_mode_t mode,
ulint latch_mode, mtr_t *mtr, const char *file,
ulint line) {
init();
m_search_mode = mode;
m_latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
/* Search with the tree cursor */
auto cur = get_btr_cur();
ut_ad(!dict_index_is_spatial(index));
if (index->table->is_intrinsic()) {
ut_ad((latch_mode & BTR_MODIFY_LEAF) || (latch_mode & BTR_SEARCH_LEAF) ||
(latch_mode & BTR_MODIFY_TREE));
btr_cur_search_to_nth_level_with_no_latch(
index, level, tuple, mode, cur, file, line, mtr,
(((latch_mode & BTR_MODIFY_LEAF) || (latch_mode & BTR_MODIFY_TREE))
? true
: false));
} else {
btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode, cur, 0,
file, line, mtr);
}
m_pos_state = BTR_PCUR_IS_POSITIONED;
m_trx_if_known = nullptr;
ut_ad(!m_cleanout_pages || m_cleanout_pages->is_empty());
ut_ad(!m_cleanout_cursors || m_cleanout_cursors->is_empty());
}
inline void btr_pcur_t::open_at_side(bool from_left, dict_index_t *index,
ulint latch_mode, bool init_pcur,
ulint level, mtr_t *mtr) {
m_latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
m_search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
if (init_pcur) {
init();
}
if (index->table->is_intrinsic()) {
btr_cur_open_at_index_side_with_no_latch(from_left, index, get_btr_cur(),
level, mtr);
} else {
btr_cur_open_at_index_side(from_left, index, latch_mode, get_btr_cur(),
level, mtr);
}
m_pos_state = BTR_PCUR_IS_POSITIONED;
m_old_stored = false;
m_trx_if_known = nullptr;
}
inline bool btr_pcur_t::set_random_position(dict_index_t *index,
ulint latch_mode, mtr_t *mtr,
const char *file, ulint line) {
m_latch_mode = latch_mode;
m_search_mode = PAGE_CUR_G;
init();
auto positioned = btr_cur_open_at_rnd_pos_func(
index, latch_mode, get_btr_cur(), file, line, mtr);
m_old_stored = false;
m_trx_if_known = nullptr;
m_pos_state = BTR_PCUR_IS_POSITIONED;
return (positioned);
}
inline void btr_pcur_t::open_no_init(dict_index_t *index, const dtuple_t *tuple,
page_cur_mode_t mode, ulint latch_mode,
ulint has_search_latch, mtr_t *mtr,
const char *file, ulint line) {
m_latch_mode = BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode);
m_search_mode = mode;
/* Search with the tree cursor */
auto cur = get_btr_cur();
if (index->table->is_intrinsic()) {
ut_ad((latch_mode & BTR_MODIFY_LEAF) || (latch_mode & BTR_SEARCH_LEAF));
btr_cur_search_to_nth_level_with_no_latch(
index, 0, tuple, mode, cur, file, line, mtr,
((latch_mode & BTR_MODIFY_LEAF) ? true : false));
} else {
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, cur,
has_search_latch, file, line, mtr);
}
m_pos_state = BTR_PCUR_IS_POSITIONED;
m_old_stored = false;
m_trx_if_known = nullptr;
}
inline const btr_cur_t *btr_pcur_t::get_btr_cur() const { return (&m_btr_cur); }
inline btr_cur_t *btr_pcur_t::get_btr_cur() {
return (const_cast<btr_cur_t *>(&m_btr_cur));
}
#ifdef UNIV_DEBUG
inline page_cur_t *btr_pcur_t::get_page_cur() {
return (btr_cur_get_page_cur(get_btr_cur()));
}
inline const page_cur_t *btr_pcur_t::get_page_cur() const {
return (btr_cur_get_page_cur(get_btr_cur()));
}
inline page_t *btr_pcur_t::get_page() {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
return (btr_cur_get_page(get_btr_cur()));
}
inline const page_t *btr_pcur_t::get_page() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
return (btr_cur_get_page(const_cast<btr_pcur_t *>(this)->get_btr_cur()));
}
inline buf_block_t *btr_pcur_t::get_block() {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
return (btr_cur_get_block(get_btr_cur()));
}
inline const buf_block_t *btr_pcur_t::get_block() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
return (btr_cur_get_block(get_btr_cur()));
}
inline rec_t *btr_pcur_t::get_rec() {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
return (btr_cur_get_rec(get_btr_cur()));
}
inline const rec_t *btr_pcur_t::get_rec() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
return (btr_cur_get_rec(get_btr_cur()));
}
#else
inline page_cur_t *btr_pcur_t::get_page_cur() { return (&m_btr_cur.page_cur); }
inline const page_cur_t *btr_pcur_t::get_page_cur() const {
return (&m_btr_cur.page_cur);
}
inline page_t *btr_pcur_t::get_page() {
return (m_btr_cur.page_cur.block->frame);
}
inline const page_t *btr_pcur_t::get_page() const {
return (m_btr_cur.page_cur.block->frame);
}
inline buf_block_t *btr_pcur_t::get_block() {
return (m_btr_cur.page_cur.block);
}
inline const buf_block_t *btr_pcur_t::get_block() const {
return (m_btr_cur.page_cur.block);
}
inline rec_t *btr_pcur_t::get_rec() { return (m_btr_cur.page_cur.rec); }
inline const rec_t *btr_pcur_t::get_rec() const {
return (m_btr_cur.page_cur.rec);
}
#endif /* UNIV_DEBUG */
#ifndef UNIV_HOTBACKUP
inline ulint btr_pcur_t::get_rel_pos() const {
ut_ad(m_old_rec != nullptr);
ut_ad(m_old_stored);
ut_ad(m_pos_state == BTR_PCUR_WAS_POSITIONED ||
m_pos_state == BTR_PCUR_IS_POSITIONED);
return (m_rel_pos);
}
inline void btr_pcur_t::close() {
free_rec_buf();
if (m_btr_cur.rtr_info != nullptr) {
rtr_clean_rtr_info(m_btr_cur.rtr_info, true);
m_btr_cur.rtr_info = nullptr;
}
m_old_rec = nullptr;
m_btr_cur.page_cur.rec = nullptr;
m_btr_cur.page_cur.block = nullptr;
m_old_rec = nullptr;
m_old_stored = false;
m_latch_mode = BTR_NO_LATCHES;
m_pos_state = BTR_PCUR_NOT_POSITIONED;
m_trx_if_known = nullptr;
}
inline ulint btr_pcur_t::get_up_match() const {
ut_ad(m_pos_state == BTR_PCUR_WAS_POSITIONED ||
m_pos_state == BTR_PCUR_IS_POSITIONED);
const auto cur = get_btr_cur();
ut_ad(cur->up_match != ULINT_UNDEFINED);
return (cur->up_match);
}
inline ulint btr_pcur_t::get_low_match() const {
ut_ad(m_pos_state == BTR_PCUR_WAS_POSITIONED ||
m_pos_state == BTR_PCUR_IS_POSITIONED);
const auto cur = get_btr_cur();
ut_ad(cur->low_match != ULINT_UNDEFINED);
return (cur->low_match);
}
inline bool btr_pcur_t::is_after_last_on_page() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
return (page_cur_is_after_last(get_page_cur()));
}
inline bool btr_pcur_t::is_before_first_on_page() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
return (page_cur_is_before_first(get_page_cur()));
}
inline bool btr_pcur_t::is_on_user_rec() const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
return (!is_before_first_on_page() && !is_after_last_on_page());
}
inline bool btr_pcur_t::is_before_first_in_tree(mtr_t *mtr) const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
if (btr_page_get_prev(get_page(), mtr) != FIL_NULL) {
return (false);
}
return (page_cur_is_before_first(get_page_cur()));
}
inline bool btr_pcur_t::is_after_last_in_tree(mtr_t *mtr) const {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
if (btr_page_get_next(get_page(), mtr) != FIL_NULL) {
return (false);
}
return (page_cur_is_after_last(get_page_cur()));
}
inline void btr_pcur_t::move_to_next_on_page() {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
page_cur_move_to_next(get_page_cur());
m_old_stored = false;
}
inline void btr_pcur_t::move_to_prev_on_page() {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
page_cur_move_to_prev(get_page_cur());
m_old_stored = false;
}
inline void btr_pcur_t::move_to_last_on_page(mtr_t *mtr) {
UT_NOT_USED(mtr);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
page_cur_set_after_last(get_block(), get_page_cur());
m_old_stored = false;
}
inline dberr_t btr_pcur_t::move_to_next_user_rec(mtr_t *mtr) {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
for (;;) {
m_old_stored = false;
if (is_after_last_on_page()) {
if (is_after_last_in_tree(mtr)) {
return (DB_END_OF_INDEX);
}
move_to_next_page(mtr);
} else {
move_to_next_on_page();
}
if (is_on_user_rec()) {
return (DB_SUCCESS);
}
}
}
inline bool btr_pcur_t::move_to_next(mtr_t *mtr) {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(m_latch_mode != BTR_NO_LATCHES);
m_old_stored = false;
if (is_after_last_on_page()) {
if (is_after_last_in_tree(mtr)) {
return (false);
}
move_to_next_page(mtr);
return (true);
}
move_to_next_on_page();
return (true);
}
inline void btr_pcur_t::commit_specify_mtr(mtr_t *mtr) {
ut_ad(m_pos_state == BTR_PCUR_IS_POSITIONED);
m_latch_mode = BTR_NO_LATCHES;
mtr_commit(mtr);
m_pos_state = BTR_PCUR_WAS_POSITIONED;
}
inline void btr_pcur_t::move_before_first_on_page() {
ut_ad(m_latch_mode != BTR_NO_LATCHES);
page_cur_set_before_first(get_block(), get_page_cur());
m_old_stored = false;
}
inline void btr_pcur_t::reset() {
free_rec_buf();
m_old_rec_buf = nullptr;
m_btr_cur.index = nullptr;
m_btr_cur.page_cur.rec = nullptr;
m_old_rec = nullptr;
m_old_n_fields = 0;
m_old_stored = false;
if (m_cleanout_pages) m_cleanout_pages->init();
if (m_cleanout_cursors) m_cleanout_cursors->init();
m_latch_mode = BTR_NO_LATCHES;
m_pos_state = BTR_PCUR_NOT_POSITIONED;
}
#endif /* !UNIV_HOTBACKUP */
#endif /* !btr0pcur_h */