1/*****************************************************************************
2
3Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2018, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file include/btr0cur.ic
22The index tree cursor
23
24Created 10/16/1994 Heikki Tuuri
25*******************************************************/
26
27#include "btr0btr.h"
28
29#ifdef UNIV_DEBUG
30# define LIMIT_OPTIMISTIC_INSERT_DEBUG(NREC, CODE)\
31if (btr_cur_limit_optimistic_insert_debug > 1\
32 && (NREC) >= btr_cur_limit_optimistic_insert_debug) {\
33 CODE;\
34}
35#else
36# define LIMIT_OPTIMISTIC_INSERT_DEBUG(NREC, CODE)
37#endif /* UNIV_DEBUG */
38
39#ifdef UNIV_DEBUG
40/*********************************************************//**
41Returns the page cursor component of a tree cursor.
42@return pointer to page cursor component */
43UNIV_INLINE
44page_cur_t*
45btr_cur_get_page_cur(
46/*=================*/
47 const btr_cur_t* cursor) /*!< in: tree cursor */
48{
49 return(&((btr_cur_t*) cursor)->page_cur);
50}
51
52/*********************************************************//**
53Returns the buffer block on which the tree cursor is positioned.
54@return pointer to buffer block */
55UNIV_INLINE
56buf_block_t*
57btr_cur_get_block(
58/*==============*/
59 const btr_cur_t* cursor) /*!< in: tree cursor */
60{
61 return(page_cur_get_block(btr_cur_get_page_cur(cursor)));
62}
63
64/*********************************************************//**
65Returns the record pointer of a tree cursor.
66@return pointer to record */
67UNIV_INLINE
68rec_t*
69btr_cur_get_rec(
70/*============*/
71 const btr_cur_t* cursor) /*!< in: tree cursor */
72{
73 return(page_cur_get_rec(btr_cur_get_page_cur(cursor)));
74}
75#endif /* UNIV_DEBUG */
76
77/*********************************************************//**
78Returns the compressed page on which the tree cursor is positioned.
79@return pointer to compressed page, or NULL if the page is not compressed */
80UNIV_INLINE
81page_zip_des_t*
82btr_cur_get_page_zip(
83/*=================*/
84 btr_cur_t* cursor) /*!< in: tree cursor */
85{
86 return(buf_block_get_page_zip(btr_cur_get_block(cursor)));
87}
88
89/*********************************************************//**
90Returns the page of a tree cursor.
91@return pointer to page */
92UNIV_INLINE
93page_t*
94btr_cur_get_page(
95/*=============*/
96 btr_cur_t* cursor) /*!< in: tree cursor */
97{
98 return(page_align(page_cur_get_rec(&(cursor->page_cur))));
99}
100
101/*********************************************************//**
102Positions a tree cursor at a given record. */
103UNIV_INLINE
104void
105btr_cur_position(
106/*=============*/
107 dict_index_t* index, /*!< in: index */
108 rec_t* rec, /*!< in: record in tree */
109 buf_block_t* block, /*!< in: buffer block of rec */
110 btr_cur_t* cursor) /*!< out: cursor */
111{
112 ut_ad(page_align(rec) == block->frame);
113
114 page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
115
116 cursor->index = index;
117}
118
119/*********************************************************************//**
120Checks if compressing an index page where a btr cursor is placed makes
121sense.
122@return TRUE if compression is recommended */
123UNIV_INLINE
124ibool
125btr_cur_compress_recommendation(
126/*============================*/
127 btr_cur_t* cursor, /*!< in: btr cursor */
128 mtr_t* mtr) /*!< in: mtr */
129{
130 const page_t* page;
131
132 ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
133 MTR_MEMO_PAGE_X_FIX));
134
135 page = btr_cur_get_page(cursor);
136
137 LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page) * 2U,
138 return(FALSE));
139
140 if (page_get_data_size(page)
141 < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)
142 || !page_has_siblings(page)) {
143
144 /* The page fillfactor has dropped below a predefined
145 minimum value OR the level in the B-tree contains just
146 one page: we recommend compression if this is not the
147 root page. */
148
149 return(dict_index_get_page(cursor->index)
150 != page_get_page_no(page));
151 }
152
153 return(FALSE);
154}
155
156/*********************************************************************//**
157Checks if the record on which the cursor is placed can be deleted without
158making tree compression necessary (or, recommended).
159@return TRUE if can be deleted without recommended compression */
160UNIV_INLINE
161ibool
162btr_cur_can_delete_without_compress(
163/*================================*/
164 btr_cur_t* cursor, /*!< in: btr cursor */
165 ulint rec_size,/*!< in: rec_get_size(btr_cur_get_rec(cursor))*/
166 mtr_t* mtr) /*!< in: mtr */
167{
168 page_t* page;
169
170 ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
171 MTR_MEMO_PAGE_X_FIX));
172
173 page = btr_cur_get_page(cursor);
174
175 if (page_get_data_size(page) - rec_size
176 < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)
177 || !page_has_siblings(page) || page_get_n_recs(page) < 2) {
178
179 /* The page fillfactor will drop below a predefined
180 minimum value, OR the level in the B-tree contains just
181 one page, OR the page will become empty: we recommend
182 compression if this is not the root page. */
183
184 return(dict_index_get_page(cursor->index)
185 == page_get_page_no(page));
186 }
187
188 return(TRUE);
189}
190
191/*******************************************************************//**
192Determine if an operation on off-page columns is an update.
193@return TRUE if op != BTR_STORE_INSERT */
194UNIV_INLINE
195ibool
196btr_blob_op_is_update(
197/*==================*/
198 enum blob_op op) /*!< in: operation */
199{
200 switch (op) {
201 case BTR_STORE_INSERT:
202 case BTR_STORE_INSERT_BULK:
203 return(FALSE);
204 case BTR_STORE_INSERT_UPDATE:
205 case BTR_STORE_UPDATE:
206 return(TRUE);
207 }
208
209 ut_ad(0);
210 return(FALSE);
211}
212
213/******************************************************//**
214The following function is used to set the deleted bit of a record. */
215UNIV_INLINE
216void
217btr_rec_set_deleted_flag(
218/*=====================*/
219 rec_t* rec, /*!< in/out: physical record */
220 page_zip_des_t* page_zip,/*!< in/out: compressed page (or NULL) */
221 ulint flag) /*!< in: nonzero if delete marked */
222{
223 if (page_rec_is_comp(rec)) {
224 rec_set_deleted_flag_new(rec, page_zip, flag);
225 } else {
226 ut_ad(!page_zip);
227 rec_set_deleted_flag_old(rec, flag);
228 }
229}
230