1/*****************************************************************************
2
3Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
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/*********************************************************//**
98Invalidates a tree cursor by setting record pointer to NULL. */
99UNIV_INLINE
100void
101btr_cur_invalidate(
102/*===============*/
103	btr_cur_t*	cursor)	/*!< in: tree cursor */
104{
105	page_cur_invalidate(&(cursor->page_cur));
106}
107
108/*********************************************************//**
109Returns the page of a tree cursor.
110@return	pointer to page */
111UNIV_INLINE
112page_t*
113btr_cur_get_page(
114/*=============*/
115	btr_cur_t*	cursor)	/*!< in: tree cursor */
116{
117	return(page_align(page_cur_get_rec(&(cursor->page_cur))));
118}
119
120/*********************************************************//**
121Positions a tree cursor at a given record. */
122UNIV_INLINE
123void
124btr_cur_position(
125/*=============*/
126	dict_index_t*	index,	/*!< in: index */
127	rec_t*		rec,	/*!< in: record in tree */
128	buf_block_t*	block,	/*!< in: buffer block of rec */
129	btr_cur_t*	cursor)	/*!< out: cursor */
130{
131	ut_ad(page_align(rec) == block->frame);
132
133	page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
134
135	cursor->index = index;
136}
137
138/*********************************************************************//**
139Checks if compressing an index page where a btr cursor is placed makes
140sense.
141@return	TRUE if compression is recommended */
142UNIV_INLINE
143ibool
144btr_cur_compress_recommendation(
145/*============================*/
146	btr_cur_t*	cursor,	/*!< in: btr cursor */
147	mtr_t*		mtr)	/*!< in: mtr */
148{
149	const page_t*	page;
150
151	ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
152				MTR_MEMO_PAGE_X_FIX));
153
154	page = btr_cur_get_page(cursor);
155
156	LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page) * 2,
157				      return(FALSE));
158
159	if ((page_get_data_size(page) < BTR_CUR_PAGE_COMPRESS_LIMIT)
160	    || ((btr_page_get_next(page, mtr) == FIL_NULL)
161		&& (btr_page_get_prev(page, mtr) == FIL_NULL))) {
162
163		/* The page fillfactor has dropped below a predefined
164		minimum value OR the level in the B-tree contains just
165		one page: we recommend compression if this is not the
166		root page. */
167
168		return(dict_index_get_page(cursor->index)
169		       != page_get_page_no(page));
170	}
171
172	return(FALSE);
173}
174
175/*********************************************************************//**
176Checks if the record on which the cursor is placed can be deleted without
177making tree compression necessary (or, recommended).
178@return	TRUE if can be deleted without recommended compression */
179UNIV_INLINE
180ibool
181btr_cur_can_delete_without_compress(
182/*================================*/
183	btr_cur_t*	cursor,	/*!< in: btr cursor */
184	ulint		rec_size,/*!< in: rec_get_size(btr_cur_get_rec(cursor))*/
185	mtr_t*		mtr)	/*!< in: mtr */
186{
187	page_t*		page;
188
189	ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
190				MTR_MEMO_PAGE_X_FIX));
191
192	page = btr_cur_get_page(cursor);
193
194	if ((page_get_data_size(page) - rec_size < BTR_CUR_PAGE_COMPRESS_LIMIT)
195	    || ((btr_page_get_next(page, mtr) == FIL_NULL)
196		&& (btr_page_get_prev(page, mtr) == FIL_NULL))
197	    || (page_get_n_recs(page) < 2)) {
198
199		/* The page fillfactor will drop below a predefined
200		minimum value, OR the level in the B-tree contains just
201		one page, OR the page will become empty: we recommend
202		compression if this is not the root page. */
203
204		return(dict_index_get_page(cursor->index)
205		       == page_get_page_no(page));
206	}
207
208	return(TRUE);
209}
210
211/*******************************************************************//**
212Determine if an operation on off-page columns is an update.
213@return TRUE if op != BTR_STORE_INSERT */
214UNIV_INLINE
215ibool
216btr_blob_op_is_update(
217/*==================*/
218	enum blob_op	op)	/*!< in: operation */
219{
220	switch (op) {
221	case BTR_STORE_INSERT:
222		return(FALSE);
223	case BTR_STORE_INSERT_UPDATE:
224	case BTR_STORE_UPDATE:
225		return(TRUE);
226	}
227
228	ut_ad(0);
229	return(FALSE);
230}
231#endif /* !UNIV_HOTBACKUP */
232