diff options
Diffstat (limited to 'storage/innobase/page/page0cur.cc')
-rw-r--r-- | storage/innobase/page/page0cur.cc | 1123 |
1 files changed, 854 insertions, 269 deletions
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index 97405261392..7f592b50154 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -24,6 +24,8 @@ The page cursor Created 10/4/1994 Heikki Tuuri *************************************************************************/ +#include "ha_prototypes.h" + #include "page0cur.h" #ifdef UNIV_NONINL #include "page0cur.ic" @@ -33,9 +35,11 @@ Created 10/4/1994 Heikki Tuuri #include "btr0btr.h" #include "mtr0log.h" #include "log0recv.h" -#include "ut0ut.h" #ifndef UNIV_HOTBACKUP #include "rem0cmp.h" +#include "gis0rtree.h" + +#include <algorithm> #ifdef PAGE_CUR_ADAPT # ifdef UNIV_SEARCH_PERF_STAT @@ -53,7 +57,7 @@ a = 1103515245 (3^5 * 5 * 7 * 129749) c = 12345 (3 * 5 * 823) m = 18446744073709551616 (2^64) -@return number between 0 and 2^64-1 */ +@return number between 0 and 2^64-1 */ static ib_uint64_t page_cur_lcg_prng(void) @@ -76,41 +80,30 @@ page_cur_lcg_prng(void) return(lcg_current); } -/****************************************************************//** -Tries a search shortcut based on the last insert. -@return TRUE on success */ +/** Try a search shortcut based on the last insert. +@param[in] block index page +@param[in] index index tree +@param[in] tuple search key +@param[in,out] iup_matched_fields already matched fields in the +upper limit record +@param[in,out] ilow_matched_fields already matched fields in the +lower limit record +@param[out] cursor page cursor +@return true on success */ UNIV_INLINE -ibool +bool page_cur_try_search_shortcut( -/*=========================*/ - const buf_block_t* block, /*!< in: index page */ - const dict_index_t* index, /*!< in: record descriptor */ - const dtuple_t* tuple, /*!< in: data tuple */ + const buf_block_t* block, + const dict_index_t* index, + const dtuple_t* tuple, ulint* iup_matched_fields, - /*!< in/out: already matched - fields in upper limit record */ - ulint* iup_matched_bytes, - /*!< in/out: already matched - bytes in a field not yet - completely matched */ ulint* ilow_matched_fields, - /*!< in/out: already matched - fields in lower limit record */ - ulint* ilow_matched_bytes, - /*!< in/out: already matched - bytes in a field not yet - completely matched */ - page_cur_t* cursor) /*!< out: page cursor */ + page_cur_t* cursor) { const rec_t* rec; const rec_t* next_rec; ulint low_match; - ulint low_bytes; ulint up_match; - ulint up_bytes; -#ifdef UNIV_SEARCH_DEBUG - page_cur_t cursor2; -#endif ibool success = FALSE; const page_t* page = buf_block_get_frame(block); mem_heap_t* heap = NULL; @@ -127,53 +120,120 @@ page_cur_try_search_shortcut( ut_ad(rec); ut_ad(page_rec_is_user_rec(rec)); - ut_pair_min(&low_match, &low_bytes, - *ilow_matched_fields, *ilow_matched_bytes, - *iup_matched_fields, *iup_matched_bytes); + low_match = up_match = std::min(*ilow_matched_fields, + *iup_matched_fields); - up_match = low_match; - up_bytes = low_bytes; - - if (page_cmp_dtuple_rec_with_match(tuple, rec, offsets, - &low_match, &low_bytes) < 0) { + if (cmp_dtuple_rec_with_match(tuple, rec, offsets, &low_match) < 0) { goto exit_func; } next_rec = page_rec_get_next_const(rec); - offsets = rec_get_offsets(next_rec, index, offsets, - dtuple_get_n_fields(tuple), &heap); + if (!page_rec_is_supremum(next_rec)) { + offsets = rec_get_offsets(next_rec, index, offsets, + dtuple_get_n_fields(tuple), &heap); - if (page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets, - &up_match, &up_bytes) >= 0) { - goto exit_func; + if (cmp_dtuple_rec_with_match(tuple, next_rec, offsets, + &up_match) >= 0) { + goto exit_func; + } + + *iup_matched_fields = up_match; } page_cur_position(rec, block, cursor); -#ifdef UNIV_SEARCH_DEBUG - page_cur_search_with_match(block, index, tuple, PAGE_CUR_DBG, - iup_matched_fields, - iup_matched_bytes, - ilow_matched_fields, - ilow_matched_bytes, - &cursor2); - ut_a(cursor2.rec == cursor->rec); + *ilow_matched_fields = low_match; - if (!page_rec_is_supremum(next_rec)) { +#ifdef UNIV_SEARCH_PERF_STAT + page_cur_short_succ++; +#endif + success = TRUE; +exit_func: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + return(success); +} - ut_a(*iup_matched_fields == up_match); - ut_a(*iup_matched_bytes == up_bytes); +/** Try a search shortcut based on the last insert. +@param[in] block index page +@param[in] index index tree +@param[in] tuple search key +@param[in,out] iup_matched_fields already matched fields in the +upper limit record +@param[in,out] iup_matched_bytes already matched bytes in the +first partially matched field in the upper limit record +@param[in,out] ilow_matched_fields already matched fields in the +lower limit record +@param[in,out] ilow_matched_bytes already matched bytes in the +first partially matched field in the lower limit record +@param[out] cursor page cursor +@return true on success */ +UNIV_INLINE +bool +page_cur_try_search_shortcut_bytes( + const buf_block_t* block, + const dict_index_t* index, + const dtuple_t* tuple, + ulint* iup_matched_fields, + ulint* iup_matched_bytes, + ulint* ilow_matched_fields, + ulint* ilow_matched_bytes, + page_cur_t* cursor) +{ + const rec_t* rec; + const rec_t* next_rec; + ulint low_match; + ulint low_bytes; + ulint up_match; + ulint up_bytes; + ibool success = FALSE; + const page_t* page = buf_block_get_frame(block); + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + rec_offs_init(offsets_); + + ut_ad(dtuple_check_typed(tuple)); + + rec = page_header_get_ptr(page, PAGE_LAST_INSERT); + offsets = rec_get_offsets(rec, index, offsets, + dtuple_get_n_fields(tuple), &heap); + + ut_ad(rec); + ut_ad(page_rec_is_user_rec(rec)); + if (ut_pair_cmp(*ilow_matched_fields, *ilow_matched_bytes, + *iup_matched_fields, *iup_matched_bytes) < 0) { + up_match = low_match = *ilow_matched_fields; + up_bytes = low_bytes = *ilow_matched_bytes; + } else { + up_match = low_match = *iup_matched_fields; + up_bytes = low_bytes = *iup_matched_bytes; } - ut_a(*ilow_matched_fields == low_match); - ut_a(*ilow_matched_bytes == low_bytes); -#endif + if (cmp_dtuple_rec_with_match_bytes( + tuple, rec, index, offsets, &low_match, &low_bytes) < 0) { + goto exit_func; + } + + next_rec = page_rec_get_next_const(rec); if (!page_rec_is_supremum(next_rec)) { + offsets = rec_get_offsets(next_rec, index, offsets, + dtuple_get_n_fields(tuple), &heap); + + if (cmp_dtuple_rec_with_match_bytes( + tuple, next_rec, index, offsets, + &up_match, &up_bytes) + >= 0) { + goto exit_func; + } *iup_matched_fields = up_match; *iup_matched_bytes = up_bytes; } + page_cur_position(rec, block, cursor); + *ilow_matched_fields = low_match; *ilow_matched_bytes = low_bytes; @@ -187,7 +247,6 @@ exit_func: } return(success); } - #endif #ifdef PAGE_CUR_LE_OR_EXTENDS @@ -195,7 +254,7 @@ exit_func: Checks if the nth field in a record is a character type field which extends the nth field in tuple, i.e., the field is longer or equal in length and has common first characters. -@return TRUE if rec field extends tuple field */ +@return TRUE if rec field extends tuple field */ static ibool page_cur_rec_field_extends( @@ -222,16 +281,17 @@ page_cur_rec_field_extends( || type->mtype == DATA_FIXBINARY || type->mtype == DATA_BINARY || type->mtype == DATA_BLOB + || DATA_GEOMETRY_MTYPE(type->mtype) || type->mtype == DATA_VARMYSQL || type->mtype == DATA_MYSQL) { if (dfield_get_len(dfield) != UNIV_SQL_NULL && rec_f_len != UNIV_SQL_NULL && rec_f_len >= dfield_get_len(dfield) - && !cmp_data_data_slow(type->mtype, type->prtype, - dfield_get_data(dfield), - dfield_get_len(dfield), - rec_f, dfield_get_len(dfield))) { + && !cmp_data_data(type->mtype, type->prtype, + dfield_get_data(dfield), + dfield_get_len(dfield), + rec_f, dfield_get_len(dfield))) { return(TRUE); } @@ -241,33 +301,389 @@ page_cur_rec_field_extends( } #endif /* PAGE_CUR_LE_OR_EXTENDS */ +/** If key is fixed length then populate offset directly from +cached version. +@param[in] rec B-Tree record for which offset needs to be + populated. +@param[in,out] index index handler +@param[in] tuple data tuple +@param[in,out] offsets default offsets array +@param[in,out] heap heap +@return reference to populate offsets. */ +static +ulint* +populate_offsets( + const rec_t* rec, + const dtuple_t* tuple, + dict_index_t* index, + ulint* offsets, + mem_heap_t** heap) +{ + ut_ad(dict_table_is_intrinsic(index->table)); + + bool rec_has_null_values = false; + + if (index->rec_cache.key_has_null_cols) { + /* Check if record has null value. */ + const byte* nulls = rec - (1 + REC_N_NEW_EXTRA_BYTES); + ulint n_bytes_to_scan + = UT_BITS_IN_BYTES(index->n_nullable); + byte null_mask = 0xff; + ulint bits_examined = 0; + + for (ulint i = 0; i < n_bytes_to_scan - 1; i++) { + if (*nulls & null_mask) { + rec_has_null_values = true; + break; + } + --nulls; + bits_examined += 8; + } + + if (!rec_has_null_values) { + null_mask >>= (8 - (index->n_nullable - bits_examined)); + rec_has_null_values = *nulls & null_mask; + } + + if (rec_has_null_values) { + + offsets = rec_get_offsets( + rec, index, offsets, + dtuple_get_n_fields_cmp(tuple), heap); + + return(offsets); + } + } + + /* Check if offsets are cached else cache them first. + There are queries that will first verify if key is present using index + search and then initiate insert. If offsets are cached during index + search it would be based on key part only but during insert that looks + out for exact location to insert key + db_row_id both columns would + be used and so re-compute offsets in such case. */ + if (!index->rec_cache.offsets_cached + || (rec_offs_n_fields(index->rec_cache.offsets) + < dtuple_get_n_fields_cmp(tuple))) { + + offsets = rec_get_offsets( + rec, index, offsets, + dtuple_get_n_fields_cmp(tuple), heap); + + /* Reallocate if our offset array is not big + enough to hold the needed size. */ + ulint sz1 = index->rec_cache.sz_of_offsets; + ulint sz2 = offsets[0]; + if (sz1 < sz2) { + index->rec_cache.offsets = static_cast<ulint*>( + mem_heap_alloc( + index->heap, sizeof(ulint) * sz2)); + index->rec_cache.sz_of_offsets = + static_cast<uint32_t>(sz2); + } + + memcpy(index->rec_cache.offsets, + offsets, (sizeof(ulint) * sz2)); + index->rec_cache.offsets_cached = true; + } + + ut_ad(index->rec_cache.offsets[2] = (ulint) rec); + + return(index->rec_cache.offsets); +} + /****************************************************************//** Searches the right position for a page cursor. */ -UNIV_INTERN void page_cur_search_with_match( /*=======================*/ const buf_block_t* block, /*!< in: buffer block */ - const dict_index_t* index, /*!< in: record descriptor */ + const dict_index_t* index, /*!< in/out: record descriptor */ const dtuple_t* tuple, /*!< in: data tuple */ - ulint mode, /*!< in: PAGE_CUR_L, + page_cur_mode_t mode, /*!< in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE */ ulint* iup_matched_fields, /*!< in/out: already matched fields in upper limit record */ - ulint* iup_matched_bytes, - /*!< in/out: already matched - bytes in a field not yet - completely matched */ ulint* ilow_matched_fields, /*!< in/out: already matched fields in lower limit record */ + page_cur_t* cursor, /*!< out: page cursor */ + rtr_info_t* rtr_info)/*!< in/out: rtree search stack */ +{ + ulint up; + ulint low; + ulint mid; + const page_t* page; + const page_dir_slot_t* slot; + const rec_t* up_rec; + const rec_t* low_rec; + const rec_t* mid_rec; + ulint up_matched_fields; + ulint low_matched_fields; + ulint cur_matched_fields; + int cmp; +#ifdef UNIV_ZIP_DEBUG + const page_zip_des_t* page_zip = buf_block_get_page_zip(block); +#endif /* UNIV_ZIP_DEBUG */ + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + rec_offs_init(offsets_); + + ut_ad(dtuple_validate(tuple)); +#ifdef UNIV_DEBUG +# ifdef PAGE_CUR_DBG + if (mode != PAGE_CUR_DBG) +# endif /* PAGE_CUR_DBG */ +# ifdef PAGE_CUR_LE_OR_EXTENDS + if (mode != PAGE_CUR_LE_OR_EXTENDS) +# endif /* PAGE_CUR_LE_OR_EXTENDS */ + ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE + || mode == PAGE_CUR_G || mode == PAGE_CUR_GE + || dict_index_is_spatial(index)); +#endif /* UNIV_DEBUG */ + page = buf_block_get_frame(block); +#ifdef UNIV_ZIP_DEBUG + ut_a(!page_zip || page_zip_validate(page_zip, page, index)); +#endif /* UNIV_ZIP_DEBUG */ + + ut_d(page_check_dir(page)); + +#ifdef PAGE_CUR_ADAPT + if (page_is_leaf(page) + && (mode == PAGE_CUR_LE) + && !dict_index_is_spatial(index) + && (page_header_get_field(page, PAGE_N_DIRECTION) > 3) + && (page_header_get_ptr(page, PAGE_LAST_INSERT)) + && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) { + + if (page_cur_try_search_shortcut( + block, index, tuple, + iup_matched_fields, + ilow_matched_fields, + cursor)) { + return; + } + } +# ifdef PAGE_CUR_DBG + if (mode == PAGE_CUR_DBG) { + mode = PAGE_CUR_LE; + } +# endif +#endif + + /* If the mode is for R-tree indexes, use the special MBR + related compare functions */ + if (dict_index_is_spatial(index) && mode > PAGE_CUR_LE) { + /* For leaf level insert, we still use the traditional + compare function for now */ + if (mode == PAGE_CUR_RTREE_INSERT && page_is_leaf(page)){ + mode = PAGE_CUR_LE; + } else { + rtr_cur_search_with_match( + block, (dict_index_t*)index, tuple, mode, + cursor, rtr_info); + return; + } + } + + /* The following flag does not work for non-latin1 char sets because + cmp_full_field does not tell how many bytes matched */ +#ifdef PAGE_CUR_LE_OR_EXTENDS + ut_a(mode != PAGE_CUR_LE_OR_EXTENDS); +#endif /* PAGE_CUR_LE_OR_EXTENDS */ + + /* If mode PAGE_CUR_G is specified, we are trying to position the + cursor to answer a query of the form "tuple < X", where tuple is + the input parameter, and X denotes an arbitrary physical record on + the page. We want to position the cursor on the first X which + satisfies the condition. */ + + up_matched_fields = *iup_matched_fields; + low_matched_fields = *ilow_matched_fields; + + /* Perform binary search. First the search is done through the page + directory, after that as a linear search in the list of records + owned by the upper limit directory slot. */ + + low = 0; + up = page_dir_get_n_slots(page) - 1; + + /* Perform binary search until the lower and upper limit directory + slots come to the distance 1 of each other */ + + while (up - low > 1) { + mid = (low + up) / 2; + slot = page_dir_get_nth_slot(page, mid); + mid_rec = page_dir_slot_get_rec(slot); + + cur_matched_fields = std::min(low_matched_fields, + up_matched_fields); + + offsets = offsets_; + if (index->rec_cache.fixed_len_key) { + offsets = populate_offsets( + mid_rec, tuple, + const_cast<dict_index_t*>(index), + offsets, &heap); + } else { + offsets = rec_get_offsets( + mid_rec, index, offsets, + dtuple_get_n_fields_cmp(tuple), &heap); + + } + + cmp = cmp_dtuple_rec_with_match( + tuple, mid_rec, offsets, &cur_matched_fields); + + if (cmp > 0) { +low_slot_match: + low = mid; + low_matched_fields = cur_matched_fields; + + } else if (cmp) { +#ifdef PAGE_CUR_LE_OR_EXTENDS + if (mode == PAGE_CUR_LE_OR_EXTENDS + && page_cur_rec_field_extends( + tuple, mid_rec, offsets, + cur_matched_fields)) { + + goto low_slot_match; + } +#endif /* PAGE_CUR_LE_OR_EXTENDS */ +up_slot_match: + up = mid; + up_matched_fields = cur_matched_fields; + + } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE +#ifdef PAGE_CUR_LE_OR_EXTENDS + || mode == PAGE_CUR_LE_OR_EXTENDS +#endif /* PAGE_CUR_LE_OR_EXTENDS */ + ) { + goto low_slot_match; + } else { + + goto up_slot_match; + } + } + + slot = page_dir_get_nth_slot(page, low); + low_rec = page_dir_slot_get_rec(slot); + slot = page_dir_get_nth_slot(page, up); + up_rec = page_dir_slot_get_rec(slot); + + /* Perform linear search until the upper and lower records come to + distance 1 of each other. */ + + while (page_rec_get_next_const(low_rec) != up_rec) { + + mid_rec = page_rec_get_next_const(low_rec); + + cur_matched_fields = std::min(low_matched_fields, + up_matched_fields); + + offsets = offsets_; + if (index->rec_cache.fixed_len_key) { + offsets = populate_offsets( + mid_rec, tuple, + const_cast<dict_index_t*>(index), + offsets, &heap); + } else { + offsets = rec_get_offsets( + mid_rec, index, offsets, + dtuple_get_n_fields_cmp(tuple), &heap); + + } + + cmp = cmp_dtuple_rec_with_match( + tuple, mid_rec, offsets, &cur_matched_fields); + + if (cmp > 0) { +low_rec_match: + low_rec = mid_rec; + low_matched_fields = cur_matched_fields; + + } else if (cmp) { +#ifdef PAGE_CUR_LE_OR_EXTENDS + if (mode == PAGE_CUR_LE_OR_EXTENDS + && page_cur_rec_field_extends( + tuple, mid_rec, offsets, + cur_matched_fields)) { + + goto low_rec_match; + } +#endif /* PAGE_CUR_LE_OR_EXTENDS */ +up_rec_match: + up_rec = mid_rec; + up_matched_fields = cur_matched_fields; + } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE +#ifdef PAGE_CUR_LE_OR_EXTENDS + || mode == PAGE_CUR_LE_OR_EXTENDS +#endif /* PAGE_CUR_LE_OR_EXTENDS */ + ) { + if (!cmp && !cur_matched_fields) { +#ifdef UNIV_DEBUG + mtr_t mtr; + mtr_start(&mtr); + + /* We got a match, but cur_matched_fields is + 0, it must have REC_INFO_MIN_REC_FLAG */ + ulint rec_info = rec_get_info_bits(mid_rec, + rec_offs_comp(offsets)); + ut_ad(rec_info & REC_INFO_MIN_REC_FLAG); + ut_ad(btr_page_get_prev(page, &mtr) == FIL_NULL); + mtr_commit(&mtr); +#endif + + cur_matched_fields = dtuple_get_n_fields_cmp(tuple); + } + + goto low_rec_match; + } else { + + goto up_rec_match; + } + } + + if (mode <= PAGE_CUR_GE) { + page_cur_position(up_rec, block, cursor); + } else { + page_cur_position(low_rec, block, cursor); + } + + *iup_matched_fields = up_matched_fields; + *ilow_matched_fields = low_matched_fields; + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } +} + +/** Search the right position for a page cursor. +@param[in] block buffer block +@param[in] index index tree +@param[in] tuple key to be searched for +@param[in] mode search mode +@param[in,out] iup_matched_fields already matched fields in the +upper limit record +@param[in,out] iup_matched_bytes already matched bytes in the +first partially matched field in the upper limit record +@param[in,out] ilow_matched_fields already matched fields in the +lower limit record +@param[in,out] ilow_matched_bytes already matched bytes in the +first partially matched field in the lower limit record +@param[out] cursor page cursor */ +void +page_cur_search_with_match_bytes( + const buf_block_t* block, + const dict_index_t* index, + const dtuple_t* tuple, + page_cur_mode_t mode, + ulint* iup_matched_fields, + ulint* iup_matched_bytes, + ulint* ilow_matched_fields, ulint* ilow_matched_bytes, - /*!< in/out: already matched - bytes in a field not yet - completely matched */ - page_cur_t* cursor) /*!< out: page cursor */ + page_cur_t* cursor) { ulint up; ulint low; @@ -284,11 +700,6 @@ page_cur_search_with_match( ulint cur_matched_fields; ulint cur_matched_bytes; int cmp; -#ifdef UNIV_SEARCH_DEBUG - int dbg_cmp; - ulint dbg_matched_fields; - ulint dbg_matched_bytes; -#endif #ifdef UNIV_ZIP_DEBUG const page_zip_des_t* page_zip = buf_block_get_page_zip(block); #endif /* UNIV_ZIP_DEBUG */ @@ -297,8 +708,6 @@ page_cur_search_with_match( ulint* offsets = offsets_; rec_offs_init(offsets_); - ut_ad(block && tuple && iup_matched_fields && iup_matched_bytes - && ilow_matched_fields && ilow_matched_bytes && cursor); ut_ad(dtuple_validate(tuple)); #ifdef UNIV_DEBUG # ifdef PAGE_CUR_DBG @@ -315,7 +724,7 @@ page_cur_search_with_match( ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ - page_check_dir(page); + ut_d(page_check_dir(page)); #ifdef PAGE_CUR_ADAPT if (page_is_leaf(page) @@ -324,7 +733,7 @@ page_cur_search_with_match( && (page_header_get_ptr(page, PAGE_LAST_INSERT)) && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) { - if (page_cur_try_search_shortcut( + if (page_cur_try_search_shortcut_bytes( block, index, tuple, iup_matched_fields, iup_matched_bytes, ilow_matched_fields, ilow_matched_bytes, @@ -352,7 +761,7 @@ page_cur_search_with_match( satisfies the condition. */ up_matched_fields = *iup_matched_fields; - up_matched_bytes = *iup_matched_bytes; + up_matched_bytes = *iup_matched_bytes; low_matched_fields = *ilow_matched_fields; low_matched_bytes = *ilow_matched_bytes; @@ -375,20 +784,21 @@ page_cur_search_with_match( low_matched_fields, low_matched_bytes, up_matched_fields, up_matched_bytes); - offsets = rec_get_offsets(mid_rec, index, offsets, - dtuple_get_n_fields_cmp(tuple), - &heap); + offsets = rec_get_offsets( + mid_rec, index, offsets_, + dtuple_get_n_fields_cmp(tuple), &heap); - cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets, - &cur_matched_fields, - &cur_matched_bytes); - if (UNIV_LIKELY(cmp > 0)) { + cmp = cmp_dtuple_rec_with_match_bytes( + tuple, mid_rec, index, offsets, + &cur_matched_fields, &cur_matched_bytes); + + if (cmp > 0) { low_slot_match: low = mid; low_matched_fields = cur_matched_fields; low_matched_bytes = cur_matched_bytes; - } else if (UNIV_EXPECT(cmp, -1)) { + } else if (cmp) { #ifdef PAGE_CUR_LE_OR_EXTENDS if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends( @@ -408,7 +818,6 @@ up_slot_match: || mode == PAGE_CUR_LE_OR_EXTENDS #endif /* PAGE_CUR_LE_OR_EXTENDS */ ) { - goto low_slot_match; } else { @@ -432,20 +841,21 @@ up_slot_match: low_matched_fields, low_matched_bytes, up_matched_fields, up_matched_bytes); - offsets = rec_get_offsets(mid_rec, index, offsets, - dtuple_get_n_fields_cmp(tuple), - &heap); + offsets = rec_get_offsets( + mid_rec, index, offsets_, + dtuple_get_n_fields_cmp(tuple), &heap); - cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets, - &cur_matched_fields, - &cur_matched_bytes); - if (UNIV_LIKELY(cmp > 0)) { + cmp = cmp_dtuple_rec_with_match_bytes( + tuple, mid_rec, index, offsets, + &cur_matched_fields, &cur_matched_bytes); + + if (cmp > 0) { low_rec_match: low_rec = mid_rec; low_matched_fields = cur_matched_fields; low_matched_bytes = cur_matched_bytes; - } else if (UNIV_EXPECT(cmp, -1)) { + } else if (cmp) { #ifdef PAGE_CUR_LE_OR_EXTENDS if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends( @@ -464,6 +874,22 @@ up_rec_match: || mode == PAGE_CUR_LE_OR_EXTENDS #endif /* PAGE_CUR_LE_OR_EXTENDS */ ) { + if (!cmp && !cur_matched_fields) { +#ifdef UNIV_DEBUG + mtr_t mtr; + mtr_start(&mtr); + + /* We got a match, but cur_matched_fields is + 0, it must have REC_INFO_MIN_REC_FLAG */ + ulint rec_info = rec_get_info_bits(mid_rec, + rec_offs_comp(offsets)); + ut_ad(rec_info & REC_INFO_MIN_REC_FLAG); + ut_ad(btr_page_get_prev(page, &mtr) == FIL_NULL); + mtr_commit(&mtr); +#endif + + cur_matched_fields = dtuple_get_n_fields_cmp(tuple); + } goto low_rec_match; } else { @@ -472,58 +898,6 @@ up_rec_match: } } -#ifdef UNIV_SEARCH_DEBUG - - /* Check that the lower and upper limit records have the - right alphabetical order compared to tuple. */ - dbg_matched_fields = 0; - dbg_matched_bytes = 0; - - offsets = rec_get_offsets(low_rec, index, offsets, - ULINT_UNDEFINED, &heap); - dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec, offsets, - &dbg_matched_fields, - &dbg_matched_bytes); - if (mode == PAGE_CUR_G) { - ut_a(dbg_cmp >= 0); - } else if (mode == PAGE_CUR_GE) { - ut_a(dbg_cmp == 1); - } else if (mode == PAGE_CUR_L) { - ut_a(dbg_cmp == 1); - } else if (mode == PAGE_CUR_LE) { - ut_a(dbg_cmp >= 0); - } - - if (!page_rec_is_infimum(low_rec)) { - - ut_a(low_matched_fields == dbg_matched_fields); - ut_a(low_matched_bytes == dbg_matched_bytes); - } - - dbg_matched_fields = 0; - dbg_matched_bytes = 0; - - offsets = rec_get_offsets(up_rec, index, offsets, - ULINT_UNDEFINED, &heap); - dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec, offsets, - &dbg_matched_fields, - &dbg_matched_bytes); - if (mode == PAGE_CUR_G) { - ut_a(dbg_cmp == -1); - } else if (mode == PAGE_CUR_GE) { - ut_a(dbg_cmp <= 0); - } else if (mode == PAGE_CUR_L) { - ut_a(dbg_cmp <= 0); - } else if (mode == PAGE_CUR_LE) { - ut_a(dbg_cmp == -1); - } - - if (!page_rec_is_supremum(up_rec)) { - - ut_a(up_matched_fields == dbg_matched_fields); - ut_a(up_matched_bytes == dbg_matched_bytes); - } -#endif if (mode <= PAGE_CUR_GE) { page_cur_position(up_rec, block, cursor); } else { @@ -542,7 +916,6 @@ up_rec_match: /***********************************************************//** Positions a page cursor on a randomly chosen user record on a page. If there are no user records, sets the cursor on the infimum record. */ -UNIV_INTERN void page_cur_open_on_rnd_user_rec( /*==========================*/ @@ -583,11 +956,22 @@ page_cur_insert_rec_write_log( ulint extra_size; ulint cur_extra_size; const byte* ins_ptr; - byte* log_ptr; const byte* log_end; ulint i; + /* Avoid REDO logging to save on costly IO because + temporary tables are not recovered during crash recovery. */ + if (dict_table_is_temporary(index->table)) { + byte* log_ptr = mlog_open(mtr, 0); + if (log_ptr == NULL) { + return; + } + mlog_close(mtr, log_ptr); + log_ptr = NULL; + } + ut_a(rec_size < UNIV_PAGE_SIZE); + ut_ad(mtr->is_named_space(index->space)); ut_ad(page_align(insert_rec) == page_align(cursor_rec)); ut_ad(!page_rec_is_comp(insert_rec) == !dict_table_is_comp(index->table)); @@ -648,6 +1032,8 @@ page_cur_insert_rec_write_log( } while (i < min_rec_size); } + byte* log_ptr; + if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) { if (page_rec_is_comp(insert_rec)) { @@ -753,27 +1139,26 @@ need_extra_info: /***********************************************************//** Parses a log record of a record insert on a page. -@return end of log record or NULL */ -UNIV_INTERN +@return end of log record or NULL */ byte* page_cur_parse_insert_rec( /*======================*/ ibool is_short,/*!< in: TRUE if short inserts */ - byte* ptr, /*!< in: buffer */ - byte* end_ptr,/*!< in: buffer end */ + const byte* ptr, /*!< in: buffer */ + const byte* end_ptr,/*!< in: buffer end */ buf_block_t* block, /*!< in: page or NULL */ dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr or NULL */ { - ulint origin_offset; + ulint origin_offset = 0; /* remove warning */ ulint end_seg_len; - ulint mismatch_index; + ulint mismatch_index = 0; /* remove warning */ page_t* page; rec_t* cursor_rec; byte buf1[1024]; byte* buf; - byte* ptr2 = ptr; - ulint info_and_status_bits = 0; /* remove warning */ + const byte* ptr2 = ptr; + ulint info_and_status_bits = 0; /* remove warning */ page_cur_t cursor; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -799,7 +1184,7 @@ page_cur_parse_insert_rec( cursor_rec = page + offset; - if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)) { + if (offset >= UNIV_PAGE_SIZE) { recv_sys->found_corrupt_log = TRUE; @@ -807,14 +1192,14 @@ page_cur_parse_insert_rec( } } - ptr = mach_parse_compressed(ptr, end_ptr, &end_seg_len); + end_seg_len = mach_parse_compressed(&ptr, end_ptr); if (ptr == NULL) { return(NULL); } - if (UNIV_UNLIKELY(end_seg_len >= UNIV_PAGE_SIZE << 1)) { + if (end_seg_len >= UNIV_PAGE_SIZE << 1) { recv_sys->found_corrupt_log = TRUE; return(NULL); @@ -831,7 +1216,7 @@ page_cur_parse_insert_rec( info_and_status_bits = mach_read_from_1(ptr); ptr++; - ptr = mach_parse_compressed(ptr, end_ptr, &origin_offset); + origin_offset = mach_parse_compressed(&ptr, end_ptr); if (ptr == NULL) { @@ -840,7 +1225,7 @@ page_cur_parse_insert_rec( ut_a(origin_offset < UNIV_PAGE_SIZE); - ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index); + mismatch_index = mach_parse_compressed(&ptr, end_ptr); if (ptr == NULL) { @@ -850,14 +1235,14 @@ page_cur_parse_insert_rec( ut_a(mismatch_index < UNIV_PAGE_SIZE); } - if (UNIV_UNLIKELY(end_ptr < ptr + (end_seg_len >> 1))) { + if (end_ptr < ptr + (end_seg_len >> 1)) { return(NULL); } if (!block) { - return(ptr + (end_seg_len >> 1)); + return(const_cast<byte*>(ptr + (end_seg_len >> 1))); } ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); @@ -882,30 +1267,19 @@ page_cur_parse_insert_rec( buf = buf1; } else { buf = static_cast<byte*>( - mem_alloc(mismatch_index + end_seg_len)); + ut_malloc_nokey(mismatch_index + end_seg_len)); } /* Build the inserted record to buf */ if (UNIV_UNLIKELY(mismatch_index >= UNIV_PAGE_SIZE)) { - fprintf(stderr, - "Is short %lu, info_and_status_bits %lu, offset %lu, " - "o_offset %lu\n" - "mismatch index %lu, end_seg_len %lu\n" - "parsed len %lu\n", - (ulong) is_short, (ulong) info_and_status_bits, - (ulong) page_offset(cursor_rec), - (ulong) origin_offset, - (ulong) mismatch_index, (ulong) end_seg_len, - (ulong) (ptr - ptr2)); - - fputs("Dump of 300 bytes of log:\n", stderr); - ut_print_buf(stderr, ptr2, 300); - putc('\n', stderr); - - buf_page_print(page, 0, 0); - ut_error; + ib::fatal() << "is_short " << is_short << ", " + << "info_and_status_bits " << info_and_status_bits + << ", offset " << page_offset(cursor_rec) << "," + " o_offset " << origin_offset << ", mismatch index " + << mismatch_index << ", end_seg_len " << end_seg_len + << " parsed len " << (ptr - ptr2); } ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index); @@ -913,10 +1287,10 @@ page_cur_parse_insert_rec( if (page_is_comp(page)) { rec_set_info_and_status_bits(buf + origin_offset, - info_and_status_bits); + info_and_status_bits); } else { rec_set_info_bits_old(buf + origin_offset, - info_and_status_bits); + info_and_status_bits); } page_cur_position(cursor_rec, block, &cursor); @@ -933,22 +1307,21 @@ page_cur_parse_insert_rec( if (buf != buf1) { - mem_free(buf); + ut_free(buf); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - return(ptr + end_seg_len); + return(const_cast<byte*>(ptr + end_seg_len)); } /***********************************************************//** Inserts a record next to page cursor on an uncompressed page. Returns pointer to inserted record if succeed, i.e., enough space available, NULL otherwise. The cursor stays at the same position. -@return pointer to record if succeed, NULL otherwise */ -UNIV_INTERN +@return pointer to record if succeed, NULL otherwise */ rec_t* page_cur_insert_rec_low( /*====================*/ @@ -975,10 +1348,10 @@ page_cur_insert_rec_low( page = page_align(current_rec); ut_ad(dict_table_is_comp(index->table) == (ibool) !!page_is_comp(page)); - ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); - ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || recv_recovery_is_on() - || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); + ut_ad(fil_page_index_page_check(page)); + ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) == index->id + || recv_recovery_is_on() + || (mtr ? mtr->is_inside_ibuf() : dict_index_is_ibuf(index))); ut_ad(!page_rec_is_supremum(current_rec)); @@ -1095,7 +1468,214 @@ use_heap: || rec_get_node_ptr_flag(last_insert) == rec_get_node_ptr_flag(insert_rec)); - if (UNIV_UNLIKELY(last_insert == NULL)) { + if (!dict_index_is_spatial(index)) { + if (UNIV_UNLIKELY(last_insert == NULL)) { + page_header_set_field(page, NULL, PAGE_DIRECTION, + PAGE_NO_DIRECTION); + page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0); + + } else if ((last_insert == current_rec) + && (page_header_get_field(page, PAGE_DIRECTION) + != PAGE_LEFT)) { + + page_header_set_field(page, NULL, PAGE_DIRECTION, + PAGE_RIGHT); + page_header_set_field(page, NULL, PAGE_N_DIRECTION, + page_header_get_field( + page, PAGE_N_DIRECTION) + 1); + + } else if ((page_rec_get_next(insert_rec) == last_insert) + && (page_header_get_field(page, PAGE_DIRECTION) + != PAGE_RIGHT)) { + + page_header_set_field(page, NULL, PAGE_DIRECTION, + PAGE_LEFT); + page_header_set_field(page, NULL, PAGE_N_DIRECTION, + page_header_get_field( + page, PAGE_N_DIRECTION) + 1); + } else { + page_header_set_field(page, NULL, PAGE_DIRECTION, + PAGE_NO_DIRECTION); + page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0); + } + } + + page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, insert_rec); + + /* 7. It remains to update the owner record. */ + { + rec_t* owner_rec = page_rec_find_owner_rec(insert_rec); + ulint n_owned; + if (page_is_comp(page)) { + n_owned = rec_get_n_owned_new(owner_rec); + rec_set_n_owned_new(owner_rec, NULL, n_owned + 1); + } else { + n_owned = rec_get_n_owned_old(owner_rec); + rec_set_n_owned_old(owner_rec, n_owned + 1); + } + + /* 8. Now we have incremented the n_owned field of the owner + record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED, + we have to split the corresponding directory slot in two. */ + + if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) { + page_dir_split_slot( + page, NULL, + page_dir_find_owner_slot(owner_rec)); + } + } + + /* 9. Write log record of the insert */ + if (UNIV_LIKELY(mtr != NULL)) { + page_cur_insert_rec_write_log(insert_rec, rec_size, + current_rec, index, mtr); + } + + return(insert_rec); +} + +/** Inserts a record next to page cursor on an uncompressed page. +@param[in] current_rec pointer to current record after which + the new record is inserted. +@param[in] index record descriptor +@param[in] tuple pointer to a data tuple +@param[in] n_ext number of externally stored columns +@param[in] mtr mini-transaction handle, or NULL + +@return pointer to record if succeed, NULL otherwise */ +rec_t* +page_cur_direct_insert_rec_low( + rec_t* current_rec, + dict_index_t* index, + const dtuple_t* tuple, + ulint n_ext, + mtr_t* mtr) +{ + byte* insert_buf; + ulint rec_size; + page_t* page; /*!< the relevant page */ + rec_t* last_insert; /*!< cursor position at previous + insert */ + rec_t* free_rec; /*!< a free record that was reused, + or NULL */ + rec_t* insert_rec; /*!< inserted record */ + ulint heap_no; /*!< heap number of the inserted + record */ + + page = page_align(current_rec); + + ut_ad(dict_table_is_comp(index->table) + == (ibool) !!page_is_comp(page)); + + ut_ad(fil_page_index_page_check(page)); + + ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) + == index->id); + + ut_ad(!page_rec_is_supremum(current_rec)); + + /* 1. Get the size of the physical record in the page */ + rec_size = index->rec_cache.rec_size; + + /* 2. Try to find suitable space from page memory management */ + free_rec = page_header_get_ptr(page, PAGE_FREE); + if (free_rec) { + /* Try to allocate from the head of the free list. */ + ulint foffsets_[REC_OFFS_NORMAL_SIZE]; + ulint* foffsets = foffsets_; + mem_heap_t* heap = NULL; + + rec_offs_init(foffsets_); + + foffsets = rec_get_offsets( + free_rec, index, foffsets, ULINT_UNDEFINED, &heap); + if (rec_offs_size(foffsets) < rec_size) { + if (heap != NULL) { + mem_heap_free(heap); + heap = NULL; + } + + free_rec = NULL; + insert_buf = page_mem_alloc_heap( + page, NULL, rec_size, &heap_no); + + if (insert_buf == NULL) { + return(NULL); + } + } else { + insert_buf = free_rec - rec_offs_extra_size(foffsets); + + if (page_is_comp(page)) { + heap_no = rec_get_heap_no_new(free_rec); + page_mem_alloc_free( + page, NULL, + rec_get_next_ptr(free_rec, TRUE), + rec_size); + } else { + heap_no = rec_get_heap_no_old(free_rec); + page_mem_alloc_free( + page, NULL, + rec_get_next_ptr(free_rec, FALSE), + rec_size); + } + + if (heap != NULL) { + mem_heap_free(heap); + heap = NULL; + } + } + } else { + free_rec = NULL; + insert_buf = page_mem_alloc_heap(page, NULL, + rec_size, &heap_no); + + if (insert_buf == NULL) { + return(NULL); + } + } + + /* 3. Create the record */ + insert_rec = rec_convert_dtuple_to_rec(insert_buf, index, tuple, n_ext); + + /* 4. Insert the record in the linked list of records */ + ut_ad(current_rec != insert_rec); + + { + /* next record after current before the insertion */ + rec_t* next_rec = page_rec_get_next(current_rec); +#ifdef UNIV_DEBUG + if (page_is_comp(page)) { + ut_ad(rec_get_status(current_rec) + <= REC_STATUS_INFIMUM); + ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM); + ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM); + } +#endif + page_rec_set_next(insert_rec, next_rec); + page_rec_set_next(current_rec, insert_rec); + } + + page_header_set_field(page, NULL, PAGE_N_RECS, + 1 + page_get_n_recs(page)); + + /* 5. Set the n_owned field in the inserted record to zero, + and set the heap_no field */ + if (page_is_comp(page)) { + rec_set_n_owned_new(insert_rec, NULL, 0); + rec_set_heap_no_new(insert_rec, heap_no); + } else { + rec_set_n_owned_old(insert_rec, 0); + rec_set_heap_no_old(insert_rec, heap_no); + } + + /* 6. Update the last insertion info in page header */ + + last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT); + ut_ad(!last_insert || !page_is_comp(page) + || rec_get_node_ptr_flag(last_insert) + == rec_get_node_ptr_flag(insert_rec)); + + if (last_insert == NULL) { page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION); page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0); @@ -1143,21 +1723,22 @@ use_heap: record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED, we have to split the corresponding directory slot in two. */ - if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) { + if (n_owned == PAGE_DIR_SLOT_MAX_N_OWNED) { page_dir_split_slot( page, NULL, page_dir_find_owner_slot(owner_rec)); } } - /* 9. Write log record of the insert */ - if (UNIV_LIKELY(mtr != NULL)) { - page_cur_insert_rec_write_log(insert_rec, rec_size, - current_rec, index, mtr); + /* 8. Open the mtr for name sake to set the modification flag + to true failing which no flush would be done. */ + byte* log_ptr = mlog_open(mtr, 0); + ut_ad(log_ptr == NULL); + if (log_ptr != NULL) { + /* To keep complier happy. */ + mlog_close(mtr, log_ptr); } - btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert"); - return(insert_rec); } @@ -1172,8 +1753,7 @@ if this is a compressed leaf page in a secondary index. This has to be done either within the same mini-transaction, or by invoking ibuf_reset_free_bits() before mtr_commit(). -@return pointer to record if succeed, NULL otherwise */ -UNIV_INTERN +@return pointer to record if succeed, NULL otherwise */ rec_t* page_cur_insert_rec_zip( /*====================*/ @@ -1203,10 +1783,10 @@ page_cur_insert_rec_zip( page = page_cur_get_page(cursor); ut_ad(dict_table_is_comp(index->table)); ut_ad(page_is_comp(page)); - ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); - ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || recv_recovery_is_on() - || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); + ut_ad(fil_page_index_page_check(page)); + ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) == index->id + || (mtr ? mtr->is_inside_ibuf() : dict_index_is_ibuf(index)) + || recv_recovery_is_on()); ut_ad(!page_cur_is_after_last(cursor)); #ifdef UNIV_ZIP_DEBUG @@ -1264,7 +1844,7 @@ page_cur_insert_rec_zip( get rid of the modification log. */ page_create_zip(page_cur_get_block(cursor), index, page_header_get_field(page, PAGE_LEVEL), - 0, mtr); + 0, NULL, mtr); ut_ad(!page_header_get_ptr(page, PAGE_FREE)); if (page_zip_available( @@ -1337,7 +1917,7 @@ page_cur_insert_rec_zip( if (!log_compressed) { if (page_zip_compress( page_zip, page, index, - level, NULL)) { + level, NULL, NULL)) { page_cur_insert_rec_write_log( insert_rec, rec_size, cursor->rec, index, mtr); @@ -1403,12 +1983,10 @@ page_cur_insert_rec_zip( } /* Out of space: restore the page */ - btr_blob_dbg_remove(page, index, "insert_zip_fail"); if (!page_zip_decompress(page_zip, page, FALSE)) { ut_error; /* Memory corrupted? */ } ut_ad(page_validate(page, index)); - btr_blob_dbg_add(page, index, "insert_zip_fail"); insert_rec = NULL; } @@ -1569,34 +2147,38 @@ use_heap: || rec_get_node_ptr_flag(last_insert) == rec_get_node_ptr_flag(insert_rec)); - if (UNIV_UNLIKELY(last_insert == NULL)) { - page_header_set_field(page, page_zip, PAGE_DIRECTION, - PAGE_NO_DIRECTION); - page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0); - - } else if ((last_insert == cursor->rec) - && (page_header_get_field(page, PAGE_DIRECTION) - != PAGE_LEFT)) { - - page_header_set_field(page, page_zip, PAGE_DIRECTION, - PAGE_RIGHT); - page_header_set_field(page, page_zip, PAGE_N_DIRECTION, - page_header_get_field( - page, PAGE_N_DIRECTION) + 1); - - } else if ((page_rec_get_next(insert_rec) == last_insert) - && (page_header_get_field(page, PAGE_DIRECTION) - != PAGE_RIGHT)) { - - page_header_set_field(page, page_zip, PAGE_DIRECTION, - PAGE_LEFT); - page_header_set_field(page, page_zip, PAGE_N_DIRECTION, - page_header_get_field( - page, PAGE_N_DIRECTION) + 1); - } else { - page_header_set_field(page, page_zip, PAGE_DIRECTION, - PAGE_NO_DIRECTION); - page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0); + if (!dict_index_is_spatial(index)) { + if (UNIV_UNLIKELY(last_insert == NULL)) { + page_header_set_field(page, page_zip, PAGE_DIRECTION, + PAGE_NO_DIRECTION); + page_header_set_field(page, page_zip, + PAGE_N_DIRECTION, 0); + + } else if ((last_insert == cursor->rec) + && (page_header_get_field(page, PAGE_DIRECTION) + != PAGE_LEFT)) { + + page_header_set_field(page, page_zip, PAGE_DIRECTION, + PAGE_RIGHT); + page_header_set_field(page, page_zip, PAGE_N_DIRECTION, + page_header_get_field( + page, PAGE_N_DIRECTION) + 1); + + } else if ((page_rec_get_next(insert_rec) == last_insert) + && (page_header_get_field(page, PAGE_DIRECTION) + != PAGE_RIGHT)) { + + page_header_set_field(page, page_zip, PAGE_DIRECTION, + PAGE_LEFT); + page_header_set_field(page, page_zip, PAGE_N_DIRECTION, + page_header_get_field( + page, PAGE_N_DIRECTION) + 1); + } else { + page_header_set_field(page, page_zip, PAGE_DIRECTION, + PAGE_NO_DIRECTION); + page_header_set_field(page, page_zip, + PAGE_N_DIRECTION, 0); + } } page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, insert_rec); @@ -1622,8 +2204,6 @@ use_heap: page_zip_write_rec(page_zip, insert_rec, index, offsets, 1); - btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert_zip_ok"); - /* 9. Write log record of the insert */ if (UNIV_LIKELY(mtr != NULL)) { page_cur_insert_rec_write_log(insert_rec, rec_size, @@ -1649,6 +2229,7 @@ page_copy_rec_list_to_created_page_write_log( byte* log_ptr; ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); + ut_ad(mtr->is_named_space(index->space)); log_ptr = mlog_open_and_write_index(mtr, page, index, page_is_comp(page) @@ -1664,8 +2245,7 @@ page_copy_rec_list_to_created_page_write_log( /**********************************************************//** Parses a log record of copying a record list end to a new created page. -@return end of log record or NULL */ -UNIV_INTERN +@return end of log record or NULL */ byte* page_parse_copy_rec_list_to_created_page( /*=====================================*/ @@ -1711,9 +2291,12 @@ page_parse_copy_rec_list_to_created_page( page_zip = buf_block_get_page_zip(block); page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL); - page_header_set_field(page, page_zip, PAGE_DIRECTION, - PAGE_NO_DIRECTION); - page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0); + + if (!dict_index_is_spatial(index)) { + page_header_set_field(page, page_zip, PAGE_DIRECTION, + PAGE_NO_DIRECTION); + page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0); + } return(rec_end); } @@ -1727,7 +2310,6 @@ IMPORTANT: The caller will have to update IBUF_BITMAP_FREE if this is a compressed leaf page in a secondary index. This has to be done either within the same mini-transaction, or by invoking ibuf_reset_free_bits() before mtr_commit(). */ -UNIV_INTERN void page_copy_rec_list_end_to_created_page( /*===================================*/ @@ -1744,7 +2326,6 @@ page_copy_rec_list_end_to_created_page( ulint n_recs; ulint slot_index; ulint rec_size; - ulint log_mode; byte* log_ptr; ulint log_data_len; mem_heap_t* heap = NULL; @@ -1777,11 +2358,18 @@ page_copy_rec_list_end_to_created_page( log_ptr = page_copy_rec_list_to_created_page_write_log(new_page, index, mtr); - log_data_len = dyn_array_get_data_size(&(mtr->log)); + log_data_len = mtr->get_log()->size(); /* Individual inserts are logged in a shorter form */ - log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS); + mtr_log_t log_mode; + + if (dict_table_is_temporary(index->table) + || index->table->ibd_file_missing /* IMPORT TABLESPACE */) { + log_mode = mtr_get_log_mode(mtr); + } else { + log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS); + } prev_rec = page_get_infimum_rec(new_page); if (page_is_comp(new_page)) { @@ -1837,8 +2425,6 @@ page_copy_rec_list_end_to_created_page( heap_top += rec_size; rec_offs_make_valid(insert_rec, index, offsets); - btr_blob_dbg_add_rec(insert_rec, index, offsets, "copy_end"); - page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec, index, mtr); prev_rec = insert_rec; @@ -1866,11 +2452,11 @@ page_copy_rec_list_end_to_created_page( mem_heap_free(heap); } - log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len; + log_data_len = mtr->get_log()->size() - log_data_len; ut_a(log_data_len < 100 * UNIV_PAGE_SIZE); - if (UNIV_LIKELY(log_ptr != NULL)) { + if (log_ptr != NULL) { mach_write_to_4(log_ptr, log_data_len); } @@ -1891,8 +2477,9 @@ page_copy_rec_list_end_to_created_page( page_header_set_field(new_page, NULL, PAGE_N_RECS, n_recs); page_header_set_ptr(new_page, NULL, PAGE_LAST_INSERT, NULL); + page_header_set_field(new_page, NULL, PAGE_DIRECTION, - PAGE_NO_DIRECTION); + PAGE_NO_DIRECTION); page_header_set_field(new_page, NULL, PAGE_N_DIRECTION, 0); /* Restore the log mode */ @@ -1913,6 +2500,7 @@ page_cur_delete_rec_write_log( byte* log_ptr; ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); + ut_ad(mtr->is_named_space(index->space)); log_ptr = mlog_open_and_write_index(mtr, rec, index, page_rec_is_comp(rec) @@ -1936,8 +2524,7 @@ page_cur_delete_rec_write_log( /***********************************************************//** Parses log record of a record delete on a page. -@return pointer to record end or NULL */ -UNIV_INTERN +@return pointer to record end or NULL */ byte* page_cur_parse_delete_rec( /*======================*/ @@ -1986,7 +2573,6 @@ page_cur_parse_delete_rec( /***********************************************************//** Deletes a record at the page cursor. The cursor is moved to the next record after the deleted one. */ -UNIV_INTERN void page_cur_delete_rec( /*================*/ @@ -2022,10 +2608,11 @@ page_cur_delete_rec( current_rec = cursor->rec; ut_ad(rec_offs_validate(current_rec, index, offsets)); ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); - ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); - ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) - == index->id || recv_recovery_is_on() - || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index))); + ut_ad(fil_page_index_page_check(page)); + ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) == index->id + || (mtr ? mtr->is_inside_ibuf() : dict_index_is_ibuf(index)) + || recv_recovery_is_on()); + ut_ad(mtr == NULL || mtr->is_named_space(index->space)); /* The record must not be the supremum or infimum record. */ ut_ad(page_rec_is_user_rec(current_rec)); @@ -2084,7 +2671,7 @@ page_cur_delete_rec( /* rec now points to the record of the previous directory slot. Look for the immediate predecessor of current_rec in a loop. */ - while(current_rec != rec) { + while (current_rec != rec) { prev_rec = rec; rec = page_rec_get_next(rec); } @@ -2115,8 +2702,6 @@ page_cur_delete_rec( page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1); /* 6. Free the memory occupied by the record */ - btr_blob_dbg_remove_rec(current_rec, const_cast<dict_index_t*>(index), - offsets, "delete"); page_mem_free(page, page_zip, current_rec, index, offsets); /* 7. Now we have decremented the number of owned records of the slot. |