1/*****************************************************************************
2
3Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2018, 2020, 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, Fifth Floor, 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_flagged(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_has_siblings(page)
141	    || page_get_data_size(page)
142	    < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) {
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 cursor->index->page
150			!= btr_cur_get_block(cursor)->page.id().page_no();
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_flagged(btr_cur_get_block(cursor),
171					 MTR_MEMO_PAGE_X_FIX));
172
173	page = btr_cur_get_page(cursor);
174
175	if (!page_has_siblings(page) || page_get_n_recs(page) < 2
176	    || page_get_data_size(page) - rec_size
177	    < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) {
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 cursor->index->page
185			== btr_cur_get_block(cursor)->page.id().page_no();
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