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