1/*****************************************************************************
2
3Copyright (c) 1994, 2018, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for 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 St, Fifth Floor, Boston, MA 02110-1301  USA
24
25*****************************************************************************/
26
27/** @file include/btr0cur.ic
28 The index tree cursor
29
30 Created 10/16/1994 Heikki Tuuri
31 *******************************************************/
32
33#ifndef UNIV_HOTBACKUP
34#endif /* !UNIV_HOTBACKUP */
35#include "btr0btr.h"
36
37#ifdef UNIV_DEBUG
38#define LIMIT_OPTIMISTIC_INSERT_DEBUG(NREC, CODE)               \
39  if (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/** Returns the page cursor component of a tree cursor.
49 @return pointer to page cursor component */
50UNIV_INLINE
51page_cur_t *btr_cur_get_page_cur(
52    const btr_cur_t *cursor) /*!< in: tree cursor */
53{
54  return (&((btr_cur_t *)cursor)->page_cur);
55}
56
57/** Returns the buffer block on which the tree cursor is positioned.
58 @return pointer to buffer block */
59UNIV_INLINE
60buf_block_t *btr_cur_get_block(const btr_cur_t *cursor) /*!< in: tree cursor */
61{
62  return (page_cur_get_block(btr_cur_get_page_cur(cursor)));
63}
64
65/** Returns the record pointer of a tree cursor.
66 @return pointer to record */
67UNIV_INLINE
68rec_t *btr_cur_get_rec(const btr_cur_t *cursor) /*!< in: tree cursor */
69{
70  return (page_cur_get_rec(btr_cur_get_page_cur(cursor)));
71}
72#endif /* UNIV_DEBUG */
73
74/** Returns the compressed page on which the tree cursor is positioned.
75 @return pointer to compressed page, or NULL if the page is not compressed */
76UNIV_INLINE
77page_zip_des_t *btr_cur_get_page_zip(btr_cur_t *cursor) /*!< in: tree cursor */
78{
79  return (buf_block_get_page_zip(btr_cur_get_block(cursor)));
80}
81
82/** Returns the page of a tree cursor.
83 @return pointer to page */
84UNIV_INLINE
85page_t *btr_cur_get_page(btr_cur_t *cursor) /*!< in: tree cursor */
86{
87  return (page_align(page_cur_get_rec(&(cursor->page_cur))));
88}
89
90/** Positions a tree cursor at a given record. */
91UNIV_INLINE
92void btr_cur_position(dict_index_t *index, /*!< in: index */
93                      rec_t *rec,          /*!< in: record in tree */
94                      buf_block_t *block,  /*!< in: buffer block of rec */
95                      btr_cur_t *cursor)   /*!< out: cursor */
96{
97  ut_ad(page_align(rec) == block->frame);
98
99  page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
100
101  cursor->index = index;
102}
103
104/** Checks if compressing an index page where a btr cursor is placed makes
105 sense.
106 @return true if compression is recommended */
107UNIV_INLINE
108ibool btr_cur_compress_recommendation(btr_cur_t *cursor, /*!< in: btr cursor */
109                                      mtr_t *mtr)        /*!< in: mtr */
110{
111  const page_t *page;
112
113  ut_ad(mtr_is_block_fix(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX,
114                         cursor->index->table));
115
116  page = btr_cur_get_page(cursor);
117
118  LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page) * 2, return (FALSE));
119
120  if ((page_get_data_size(page) < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) ||
121      ((btr_page_get_next(page, mtr) == FIL_NULL) &&
122       (btr_page_get_prev(page, mtr) == FIL_NULL))) {
123    /* The page fillfactor has dropped below a predefined
124    minimum value OR the level in the B-tree contains just
125    one page: we recommend compression if this is not the
126    root page. */
127
128    return (dict_index_get_page(cursor->index) != page_get_page_no(page));
129  }
130
131  return (FALSE);
132}
133
134/** Checks if the record on which the cursor is placed can be deleted without
135 making tree compression necessary (or, recommended).
136 @return true if can be deleted without recommended compression */
137UNIV_INLINE
138ibool btr_cur_can_delete_without_compress(
139    btr_cur_t *cursor, /*!< in: btr cursor */
140    ulint rec_size,    /*!< in: rec_get_size(btr_cur_get_rec(cursor))*/
141    mtr_t *mtr)        /*!< in: mtr */
142{
143  page_t *page;
144
145  ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX));
146
147  page = btr_cur_get_page(cursor);
148
149  if ((page_get_data_size(page) - rec_size <
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      (page_get_n_recs(page) < 2)) {
154    /* The page fillfactor will drop below a predefined
155    minimum value, OR the level in the B-tree contains just
156    one page, OR the page will become empty: we recommend
157    compression if this is not the root page. */
158
159    return (dict_index_get_page(cursor->index) == page_get_page_no(page));
160  }
161
162  return (TRUE);
163}
164
165UNIV_INLINE
166void btr_rec_set_deleted_flag(rec_t *rec, page_zip_des_t *page_zip,
167                              ulint flag) {
168  if (page_rec_is_comp(rec)) {
169    rec_set_deleted_flag_new(rec, page_zip, flag);
170  } else {
171    ut_ad(!page_zip);
172    rec_set_deleted_flag_old(rec, flag);
173  }
174}
175