1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License, version 2.0, as published by the
8 Free Software Foundation.
9 
10 This program is also distributed with certain software (including but not
11 limited to OpenSSL) that is licensed under separate terms, as designated in a
12 particular file or component or in included license documentation. The authors
13 of MySQL hereby grant you an additional permission to link the program and
14 your derivative works with the separately licensed software that they have
15 included with MySQL.
16 
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20 for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
25 
26 *****************************************************************************/
27 
28 /** @file include/btr0btr.h
29  The B-tree
30 
31  Created 6/2/1994 Heikki Tuuri
32  *******************************************************/
33 
34 #ifndef btr0btr_h
35 #define btr0btr_h
36 
37 #include "btr0types.h"
38 #include "data0data.h"
39 #include "dict0dict.h"
40 #include "gis0type.h"
41 #include "mtr0mtr.h"
42 #include "page0cur.h"
43 #include "univ.i"
44 
45 /** Maximum record size which can be stored on a page, without using the
46 special big record storage structure */
47 #define BTR_PAGE_MAX_REC_SIZE (UNIV_PAGE_SIZE / 2 - 200)
48 
49 /** @brief Maximum depth of a B-tree in InnoDB.
50 
51 Note that this isn't a maximum as such; none of the tree operations
52 avoid producing trees bigger than this. It is instead a "max depth
53 that other code must work with", useful for e.g.  fixed-size arrays
54 that must store some information about each level in a tree. In other
55 words: if a B-tree with bigger depth than this is encountered, it is
56 not acceptable for it to lead to mysterious memory corruption, but it
57 is acceptable for the program to die with a clear assert failure. */
58 #define BTR_MAX_LEVELS 100
59 
60 /** Latching modes for btr_cur_search_to_nth_level(). */
61 enum btr_latch_mode : size_t {
62   /** Search a record on a leaf page and S-latch it. */
63   BTR_SEARCH_LEAF = RW_S_LATCH,
64   /** (Prepare to) modify a record on a leaf page and X-latch it. */
65   BTR_MODIFY_LEAF = RW_X_LATCH,
66   /** Obtain no latches. */
67   BTR_NO_LATCHES = RW_NO_LATCH,
68   /** Start modifying the entire B-tree. */
69   BTR_MODIFY_TREE = 33,
70   /** Continue modifying the entire B-tree. */
71   BTR_CONT_MODIFY_TREE = 34,
72   /** Search the previous record. */
73   BTR_SEARCH_PREV = 35,
74   /** Modify the previous record. */
75   BTR_MODIFY_PREV = 36,
76   /** Start searching the entire B-tree. */
77   BTR_SEARCH_TREE = 37,
78   /** Continue searching the entire B-tree. */
79   BTR_CONT_SEARCH_TREE = 38
80 };
81 
82 /* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually exclusive. */
83 
84 /** If this is ORed to btr_latch_mode, it means that the search tuple
85 will be inserted to the index, at the searched position.
86 When the record is not in the buffer pool, try to use the insert buffer. */
87 constexpr size_t BTR_INSERT = 512;
88 
89 /** This flag ORed to btr_latch_mode says that we do the search in query
90 optimization */
91 constexpr size_t BTR_ESTIMATE = 1024;
92 
93 /** This flag ORed to BTR_INSERT says that we can ignore possible
94 UNIQUE definition on secondary indexes when we decide if we can use
95 the insert buffer to speed up inserts */
96 constexpr size_t BTR_IGNORE_SEC_UNIQUE = 2048;
97 
98 /** Try to delete mark the record at the searched position using the
99 insert/delete buffer when the record is not in the buffer pool. */
100 constexpr size_t BTR_DELETE_MARK = 4096;
101 
102 /** Try to purge the record at the searched position using the insert/delete
103 buffer when the record is not in the buffer pool. */
104 constexpr size_t BTR_DELETE = 8192;
105 
106 /** In the case of BTR_SEARCH_LEAF or BTR_MODIFY_LEAF, the caller is
107 already holding an S latch on the index tree */
108 constexpr size_t BTR_ALREADY_S_LATCHED = 16384;
109 
110 /** In the case of BTR_MODIFY_TREE, the caller specifies the intention
111 to insert record only. It is used to optimize block->lock range.*/
112 constexpr size_t BTR_LATCH_FOR_INSERT = 32768;
113 
114 /** In the case of BTR_MODIFY_TREE, the caller specifies the intention
115 to delete record only. It is used to optimize block->lock range.*/
116 constexpr size_t BTR_LATCH_FOR_DELETE = 65536;
117 
118 /** This flag is for undo insert of rtree. For rtree, we need this flag
119 to find proper rec to undo insert.*/
120 constexpr size_t BTR_RTREE_UNDO_INS = 131072;
121 
122 /** In the case of BTR_MODIFY_LEAF, the caller intends to allocate or
123 free the pages of externally stored fields. */
124 constexpr size_t BTR_MODIFY_EXTERNAL = 262144;
125 
126 /** Try to delete mark the record at the searched position when the
127 record is in spatial index */
128 constexpr size_t BTR_RTREE_DELETE_MARK = 524288;
129 
130 #define BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode)                            \
131   ((latch_mode) &                                                           \
132    ~(BTR_INSERT | BTR_DELETE_MARK | BTR_RTREE_UNDO_INS |                    \
133      BTR_RTREE_DELETE_MARK | BTR_DELETE | BTR_ESTIMATE |                    \
134      BTR_IGNORE_SEC_UNIQUE | BTR_ALREADY_S_LATCHED | BTR_LATCH_FOR_INSERT | \
135      BTR_LATCH_FOR_DELETE | BTR_MODIFY_EXTERNAL))
136 
137 #define BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode) \
138   ((latch_mode) &                                    \
139    ~(BTR_LATCH_FOR_INSERT | BTR_LATCH_FOR_DELETE | BTR_MODIFY_EXTERNAL))
140 
141 /** Report that an index page is corrupted. */
142 void btr_corruption_report(const buf_block_t *block, /*!< in: corrupted block */
143                            const dict_index_t *index) /*!< in: index tree */
144     UNIV_COLD;
145 
146 /** Assert that a B-tree page is not corrupted.
147 @param block buffer block containing a B-tree page
148 @param index the B-tree index */
149 #define btr_assert_not_corrupted(block, index)              \
150   if ((ibool) !!page_is_comp(buf_block_get_frame(block)) != \
151       dict_table_is_comp((index)->table)) {                 \
152     btr_corruption_report(block, index);                    \
153     ut_error;                                               \
154   }
155 
156 /** Gets the root node of a tree and sx-latches it for segment access.
157  @return root page, sx-latched */
158 page_t *btr_root_get(const dict_index_t *index, /*!< in: index tree */
159                      mtr_t *mtr);               /*!< in: mtr */
160 
161 /** Checks and adjusts the root node of a tree during IMPORT TABLESPACE.
162  @return error code, or DB_SUCCESS */
163 dberr_t btr_root_adjust_on_import(
164     const dict_index_t *index) /*!< in: index tree */
165     MY_ATTRIBUTE((warn_unused_result));
166 
167 /** Gets the height of the B-tree (the level of the root, when the leaf
168  level is assumed to be 0). The caller must hold an S or X latch on
169  the index.
170  @return tree height (level of the root) */
171 ulint btr_height_get(dict_index_t *index, /*!< in: index tree */
172                      mtr_t *mtr)          /*!< in/out: mini-transaction */
173     MY_ATTRIBUTE((warn_unused_result));
174 
175 /** Gets a buffer page and declares its latching order level.
176 @param[in]	page_id		page id
177 @param[in]	page_size	page size
178 @param[in]	mode		latch mode
179 @param[in]	file		file name
180 @param[in]	line		line where called */
181 #ifdef UNIV_DEBUG
182 /**
183 @param[in]	index		index tree, may be NULL if it is not an insert
184                                 buffer tree */
185 #endif /* UNIV_DEBUG */
186 /**
187 @param[in,out]	mtr		mini-transaction
188 @return block */
189 UNIV_INLINE
190 buf_block_t *btr_block_get_func(const page_id_t &page_id,
191                                 const page_size_t &page_size, ulint mode,
192                                 const char *file, ulint line,
193 #ifdef UNIV_DEBUG
194                                 const dict_index_t *index,
195 #endif /* UNIV_DEBUG */
196                                 mtr_t *mtr);
197 
198 #ifdef UNIV_DEBUG
199 /** Gets a buffer page and declares its latching order level.
200 @param page_id tablespace/page identifier
201 @param page_size page size
202 @param mode latch mode
203 @param index index tree, may be NULL if not the insert buffer tree
204 @param mtr mini-transaction handle
205 @return the block descriptor */
206 #define btr_block_get(page_id, page_size, mode, index, mtr) \
207   btr_block_get_func(page_id, page_size, mode, __FILE__, __LINE__, index, mtr)
208 #else /* UNIV_DEBUG */
209 /** Gets a buffer page and declares its latching order level.
210 @param page_id tablespace/page identifier
211 @param page_size page size
212 @param mode latch mode
213 @param index index tree, may be NULL if not the insert buffer tree
214 @param mtr mini-transaction handle
215 @return the block descriptor */
216 #define btr_block_get(page_id, page_size, mode, index, mtr) \
217   btr_block_get_func(page_id, page_size, mode, __FILE__, __LINE__, mtr)
218 #endif /* UNIV_DEBUG */
219 /** Gets a buffer page and declares its latching order level.
220 @param page_id tablespace/page identifier
221 @param page_size page size
222 @param mode latch mode
223 @param index index tree, may be NULL if not the insert buffer tree
224 @param mtr mini-transaction handle
225 @return the uncompressed page frame */
226 #define btr_page_get(page_id, page_size, mode, index, mtr) \
227   buf_block_get_frame(btr_block_get(page_id, page_size, mode, index, mtr))
228 /** Gets the index id field of a page.
229  @return index id */
230 UNIV_INLINE
231 space_index_t btr_page_get_index_id(const page_t *page) /*!< in: index page */
232     MY_ATTRIBUTE((warn_unused_result));
233 /** Gets the node level field in an index page.
234  @return level, leaf level == 0 */
235 UNIV_INLINE
236 ulint btr_page_get_level_low(const page_t *page) /*!< in: index page */
237     MY_ATTRIBUTE((warn_unused_result));
238 #define btr_page_get_level(page, mtr) btr_page_get_level_low(page)
239 /** Gets the next index page number.
240  @return next page number */
241 UNIV_INLINE
242 page_no_t btr_page_get_next(const page_t *page, /*!< in: index page */
243                             mtr_t *mtr) /*!< in: mini-transaction handle */
244     MY_ATTRIBUTE((warn_unused_result));
245 /** Gets the previous index page number.
246  @return prev page number */
247 UNIV_INLINE
248 page_no_t btr_page_get_prev(const page_t *page, /*!< in: index page */
249                             mtr_t *mtr) /*!< in: mini-transaction handle */
250     MY_ATTRIBUTE((warn_unused_result));
251 
252 /** Releases the latch on a leaf page and bufferunfixes it.
253 @param[in]	block		buffer block
254 @param[in]	latch_mode	BTR_SEARCH_LEAF or BTR_MODIFY_LEAF
255 @param[in]	mtr		mtr */
256 UNIV_INLINE
257 void btr_leaf_page_release(buf_block_t *block, ulint latch_mode, mtr_t *mtr);
258 
259 /** Gets the child node file address in a node pointer.
260  NOTE: the offsets array must contain all offsets for the record since
261  we read the last field according to offsets and assume that it contains
262  the child page number. In other words offsets must have been retrieved
263  with rec_get_offsets(n_fields=ULINT_UNDEFINED).
264  @return child node address */
265 UNIV_INLINE
266 page_no_t btr_node_ptr_get_child_page_no(
267     const rec_t *rec,     /*!< in: node pointer record */
268     const ulint *offsets) /*!< in: array returned by rec_get_offsets() */
269     MY_ATTRIBUTE((warn_unused_result));
270 
271 /** Returns the child page of a node pointer and sx-latches it.
272 @param[in]  node_ptr  node pointer
273 @param[in]  index index
274 @param[in]  offsets array returned by rec_get_offsets()
275 @param[in]  mtr mtr
276 @param[in]  type latch type
277 @return child page, latched as per the type */
278 buf_block_t *btr_node_ptr_get_child(const rec_t *node_ptr, dict_index_t *index,
279                                     const ulint *offsets, mtr_t *mtr,
280                                     rw_lock_type_t type = RW_SX_LATCH);
281 
282 /** Create the root node for a new index tree.
283 @param[in]	type			type of the index
284 @param[in]	space			space where created
285 @param[in]	page_size		page size
286 @param[in]	index_id		index id
287 @param[in]	index			index tree
288 @param[in,out]	mtr			mini-transaction
289 @return page number of the created root
290 @retval FIL_NULL if did not succeed */
291 ulint btr_create(ulint type, space_id_t space, const page_size_t &page_size,
292                  space_index_t index_id, dict_index_t *index, mtr_t *mtr);
293 
294 /** Free a persistent index tree if it exists.
295 @param[in]	page_id		root page id
296 @param[in]	page_size	page size
297 @param[in]	index_id	PAGE_INDEX_ID contents
298 @param[in,out]	mtr		mini-transaction */
299 void btr_free_if_exists(const page_id_t &page_id, const page_size_t &page_size,
300                         space_index_t index_id, mtr_t *mtr);
301 
302 /** Free an index tree in a temporary tablespace.
303 @param[in]	page_id		root page id
304 @param[in]	page_size	page size */
305 void btr_free(const page_id_t &page_id, const page_size_t &page_size);
306 
307 /** Truncate an index tree. We just free all except the root.
308 Currently, this function is only specific for clustered indexes and the only
309 caller is DDTableBuffer which manages a table with only a clustered index.
310 It is up to the caller to ensure atomicity and to implement recovery by
311 calling btr_truncate_recover().
312 @param[in]	index		clustered index */
313 void btr_truncate(const dict_index_t *index);
314 
315 /** Recovery function for btr_truncate. We will check if there is a
316 crash during btr_truncate, if so, do recover it, if not, do nothing.
317 @param[in]	index		clustered index */
318 void btr_truncate_recover(const dict_index_t *index);
319 
320 /** Makes tree one level higher by splitting the root, and inserts
321  the tuple. It is assumed that mtr contains an x-latch on the tree.
322  NOTE that the operation of this function must always succeed,
323  we cannot reverse it: therefore enough free disk space must be
324  guaranteed to be available before this function is called.
325  @return inserted record */
326 rec_t *btr_root_raise_and_insert(
327     uint32_t flags,        /*!< in: undo logging and locking flags */
328     btr_cur_t *cursor,     /*!< in: cursor at which to insert: must be
329                            on the root page; when the function returns,
330                            the cursor is positioned on the predecessor
331                            of the inserted record */
332     ulint **offsets,       /*!< out: offsets on inserted record */
333     mem_heap_t **heap,     /*!< in/out: pointer to memory heap
334                            that can be emptied, or NULL */
335     const dtuple_t *tuple, /*!< in: tuple to insert */
336     mtr_t *mtr)            /*!< in: mtr */
337     MY_ATTRIBUTE((warn_unused_result));
338 /** Reorganizes an index page.
339 
340  IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
341  if this is a compressed leaf page in a secondary index. This has to
342  be done either within the same mini-transaction, or by invoking
343  ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
344  IBUF_BITMAP_FREE is unaffected by reorganization.
345 
346  @retval true if the operation was successful
347  @retval false if it is a compressed page, and recompression failed */
348 bool btr_page_reorganize_low(
349     bool recovery,       /*!< in: true if called in recovery:
350                         locks should not be updated, i.e.,
351                         there cannot exist locks on the
352                         page, and a hash index should not be
353                         dropped: it cannot exist */
354     ulint z_level,       /*!< in: compression level to be used
355                          if dealing with compressed page */
356     page_cur_t *cursor,  /*!< in/out: page cursor */
357     dict_index_t *index, /*!< in: the index tree of the page */
358     mtr_t *mtr)          /*!< in/out: mini-transaction */
359     MY_ATTRIBUTE((warn_unused_result));
360 /** Reorganizes an index page.
361 
362  IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
363  if this is a compressed leaf page in a secondary index. This has to
364  be done either within the same mini-transaction, or by invoking
365  ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
366  IBUF_BITMAP_FREE is unaffected by reorganization.
367 
368  @retval true if the operation was successful
369  @retval false if it is a compressed page, and recompression failed */
370 bool btr_page_reorganize(
371     page_cur_t *cursor,  /*!< in/out: page cursor */
372     dict_index_t *index, /*!< in: the index tree of the page */
373     mtr_t *mtr);         /*!< in/out: mini-transaction */
374 /** Decides if the page should be split at the convergence point of
375  inserts converging to left.
376  @return true if split recommended */
377 ibool btr_page_get_split_rec_to_left(
378     btr_cur_t *cursor, /*!< in: cursor at which to insert */
379     rec_t **split_rec) /*!< out: if split recommended,
380                      the first record on upper half page,
381                      or NULL if tuple should be first */
382     MY_ATTRIBUTE((warn_unused_result));
383 /** Decides if the page should be split at the convergence point of
384  inserts converging to right.
385  @return true if split recommended */
386 ibool btr_page_get_split_rec_to_right(
387     btr_cur_t *cursor, /*!< in: cursor at which to insert */
388     rec_t **split_rec) /*!< out: if split recommended,
389                      the first record on upper half page,
390                      or NULL if tuple should be first */
391     MY_ATTRIBUTE((warn_unused_result));
392 
393 /** Splits an index page to halves and inserts the tuple. It is assumed
394  that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is
395  released within this function! NOTE that the operation of this
396  function must always succeed, we cannot reverse it: therefore enough
397  free disk space (2 pages) must be guaranteed to be available before
398  this function is called.
399 
400  @return inserted record */
401 rec_t *btr_page_split_and_insert(
402     uint32_t flags,        /*!< in: undo logging and locking flags */
403     btr_cur_t *cursor,     /*!< in: cursor at which to insert; when the
404                            function returns, the cursor is positioned
405                            on the predecessor of the inserted record */
406     ulint **offsets,       /*!< out: offsets on inserted record */
407     mem_heap_t **heap,     /*!< in/out: pointer to memory heap
408                            that can be emptied, or NULL */
409     const dtuple_t *tuple, /*!< in: tuple to insert */
410     mtr_t *mtr)            /*!< in: mtr */
411     MY_ATTRIBUTE((warn_unused_result));
412 /** Inserts a data tuple to a tree on a non-leaf level. It is assumed
413  that mtr holds an x-latch on the tree. */
414 void btr_insert_on_non_leaf_level_func(
415     uint32_t flags,      /*!< in: undo logging and locking flags */
416     dict_index_t *index, /*!< in: index */
417     ulint level,         /*!< in: level, must be > 0 */
418     dtuple_t *tuple,     /*!< in: the record to be inserted */
419     const char *file,    /*!< in: file name */
420     ulint line,          /*!< in: line where called */
421     mtr_t *mtr);         /*!< in: mtr */
422 #define btr_insert_on_non_leaf_level(f, i, l, t, m) \
423   btr_insert_on_non_leaf_level_func(f, i, l, t, __FILE__, __LINE__, m)
424 /** Sets a record as the predefined minimum record. */
425 void btr_set_min_rec_mark(rec_t *rec,  /*!< in/out: record */
426                           mtr_t *mtr); /*!< in: mtr */
427 /** Deletes on the upper level the node pointer to a page. */
428 void btr_node_ptr_delete(
429     dict_index_t *index, /*!< in: index tree */
430     buf_block_t *block,  /*!< in: page whose node pointer is deleted */
431     mtr_t *mtr);         /*!< in: mtr */
432 #ifdef UNIV_DEBUG
433 /** Checks that the node pointer to a page is appropriate.
434  @return true */
435 ibool btr_check_node_ptr(dict_index_t *index, /*!< in: index tree */
436                          buf_block_t *block,  /*!< in: index page */
437                          mtr_t *mtr)          /*!< in: mtr */
438     MY_ATTRIBUTE((warn_unused_result));
439 #endif /* UNIV_DEBUG */
440 /** Tries to merge the page first to the left immediate brother if such a
441  brother exists, and the node pointers to the current page and to the
442  brother reside on the same page. If the left brother does not satisfy these
443  conditions, looks at the right brother. If the page is the only one on that
444  level lifts the records of the page to the father page, thus reducing the
445  tree height. It is assumed that mtr holds an x-latch on the tree and on the
446  page. If cursor is on the leaf level, mtr must also hold x-latches to
447  the brothers, if they exist.
448  @return true on success */
449 ibool btr_compress(
450     btr_cur_t *cursor, /*!< in/out: cursor on the page to merge
451                        or lift; the page must not be empty:
452                        when deleting records, use btr_discard_page()
453                        if the page would become empty */
454     ibool adjust,      /*!< in: TRUE if should adjust the
455                        cursor position even if compression occurs */
456     mtr_t *mtr);       /*!< in/out: mini-transaction */
457 /** Discards a page from a B-tree. This is used to remove the last record from
458  a B-tree page: the whole page must be removed at the same time. This cannot
459  be used for the root page, which is allowed to be empty. */
460 void btr_discard_page(btr_cur_t *cursor, /*!< in: cursor on the page to discard:
461                                          not on the root page */
462                       mtr_t *mtr);       /*!< in: mtr */
463 /** Parses the redo log record for setting an index record as the predefined
464  minimum record.
465  @return end of log record or NULL */
466 byte *btr_parse_set_min_rec_mark(
467     byte *ptr,     /*!< in: buffer */
468     byte *end_ptr, /*!< in: buffer end */
469     ulint comp,    /*!< in: nonzero=compact page format */
470     page_t *page,  /*!< in: page or NULL */
471     mtr_t *mtr)    /*!< in: mtr or NULL */
472     MY_ATTRIBUTE((warn_unused_result));
473 /** Parses a redo log record of reorganizing a page.
474  @return end of log record or NULL */
475 byte *btr_parse_page_reorganize(
476     byte *ptr,           /*!< in: buffer */
477     byte *end_ptr,       /*!< in: buffer end */
478     dict_index_t *index, /*!< in: record descriptor */
479     bool compressed,     /*!< in: true if compressed page */
480     buf_block_t *block,  /*!< in: page to be reorganized, or NULL */
481     mtr_t *mtr)          /*!< in: mtr or NULL */
482     MY_ATTRIBUTE((warn_unused_result));
483 /** Gets the number of pages in a B-tree.
484  @return number of pages, or ULINT_UNDEFINED if the index is unavailable */
485 ulint btr_get_size(dict_index_t *index, /*!< in: index */
486                    ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
487                    mtr_t *mtr) /*!< in/out: mini-transaction where index
488                                is s-latched */
489     MY_ATTRIBUTE((warn_unused_result));
490 /** Allocates a new file page to be used in an index tree. NOTE: we assume
491  that the caller has made the reservation for free extents!
492  @retval NULL if no page could be allocated
493  @retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
494  (init_mtr == mtr, or the page was not previously freed in mtr)
495  @retval block (not allocated or initialized) otherwise */
496 buf_block_t *btr_page_alloc(
497     dict_index_t *index,    /*!< in: index tree */
498     page_no_t hint_page_no, /*!< in: hint of a good page */
499     byte file_direction,    /*!< in: direction where a possible
500                             page split is made */
501     ulint level,            /*!< in: level where the page is placed
502                             in the tree */
503     mtr_t *mtr,             /*!< in/out: mini-transaction
504                             for the allocation */
505     mtr_t *init_mtr)        /*!< in/out: mini-transaction
506                             for x-latching and initializing
507                             the page */
508     MY_ATTRIBUTE((warn_unused_result));
509 /** Frees a file page used in an index tree. NOTE: cannot free field external
510  storage pages because the page must contain info on its level. */
511 void btr_page_free(dict_index_t *index, /*!< in: index tree */
512                    buf_block_t *block,  /*!< in: block to be freed, x-latched */
513                    mtr_t *mtr);         /*!< in: mtr */
514 /** Creates a new index page (not the root, and also not
515  used in page reorganization).  @see btr_page_empty(). */
516 void btr_page_create(
517     buf_block_t *block,       /*!< in/out: page to be created */
518     page_zip_des_t *page_zip, /*!< in/out: compressed page, or NULL */
519     dict_index_t *index,      /*!< in: index */
520     ulint level,              /*!< in: the B-tree level of the page */
521     mtr_t *mtr);              /*!< in: mtr */
522 /** Frees a file page used in an index tree. Can be used also to BLOB
523  external storage pages. */
524 void btr_page_free_low(
525     dict_index_t *index, /*!< in: index tree */
526     buf_block_t *block,  /*!< in: block to be freed, x-latched */
527     ulint level,         /*!< in: page level (ULINT_UNDEFINED=BLOB) */
528     mtr_t *mtr);         /*!< in: mtr */
529 /** Gets the root node of a tree and x- or s-latches it.
530  @return root page, x- or s-latched */
531 buf_block_t *btr_root_block_get(
532     const dict_index_t *index, /*!< in: index tree */
533     ulint mode,                /*!< in: either RW_S_LATCH
534                                or RW_X_LATCH */
535     mtr_t *mtr);               /*!< in: mtr */
536 
537 #ifdef UNIV_BTR_PRINT
538 /** Prints size info of a B-tree. */
539 void btr_print_size(dict_index_t *index); /*!< in: index tree */
540 /** Prints directories and other info of all nodes in the index. */
541 void btr_print_index(dict_index_t *index, /*!< in: index */
542                      ulint width); /*!< in: print this many entries from start
543                                    and end */
544 #endif                             /* UNIV_BTR_PRINT */
545 /** Checks the size and number of fields in a record based on the definition of
546  the index.
547  @return true if ok */
548 ibool btr_index_rec_validate(const rec_t *rec,          /*!< in: index record */
549                              const dict_index_t *index, /*!< in: index */
550                              ibool dump_on_error) /*!< in: TRUE if the function
551                                                   should print hex dump of
552                                                   record and page on error */
553     MY_ATTRIBUTE((warn_unused_result));
554 /** Checks the consistency of an index tree.
555  @return true if ok */
556 bool btr_validate_index(
557     dict_index_t *index, /*!< in: index */
558     const trx_t *trx,    /*!< in: transaction or 0 */
559     bool lockout)        /*!< in: true if X-latch index is intended */
560     MY_ATTRIBUTE((warn_unused_result));
561 
562 /** Creates SDI index and stores the root page numbers in page 1 & 2
563 @param[in]	space_id	tablespace id
564 @param[in]	dict_locked	true if dict_sys mutex is acquired
565 @return DB_SUCCESS on success, else DB_ERROR on failure */
566 dberr_t btr_sdi_create_index(space_id_t space_id, bool dict_locked);
567 
568 #define BTR_N_LEAF_PAGES 1
569 #define BTR_TOTAL_SIZE 2
570 
571 #include "btr0btr.ic"
572 
573 #endif
574