summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-01-20 15:49:48 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2020-01-20 15:49:48 +0200
commit87a61355e8e499baf7908862711c26aa0225bf32 (patch)
tree7122052c801b5f1ee4a93af2348fad916aa2f86b /storage
parent7ea413ac2d80c7f03d1dbad90ac30ecddd8b2835 (diff)
parentbc43bf3e430c20bc2178e584215bd443054709d6 (diff)
downloadmariadb-git-87a61355e8e499baf7908862711c26aa0225bf32.tar.gz
Merge 10.3 into 10.4
The MDEV-17062 fix in commit c4195305b2a8431f39a4c75cc1c66ba43685f7a0 was omitted.
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/btr/btr0cur.cc204
-rw-r--r--storage/innobase/buf/buf0dblwr.cc4
-rw-r--r--storage/innobase/dict/dict0stats.cc17
-rw-r--r--storage/innobase/gis/gis0rtree.cc17
-rw-r--r--storage/innobase/include/btr0cur.h16
-rw-r--r--storage/innobase/include/dyn0buf.h17
-rw-r--r--storage/innobase/include/page0page.h20
-rw-r--r--storage/innobase/include/page0page.ic24
-rw-r--r--storage/innobase/include/rem0cmp.h48
-rw-r--r--storage/innobase/include/rem0cmp.ic35
-rw-r--r--storage/innobase/include/rem0rec.ic5
-rw-r--r--storage/innobase/include/row0row.h8
-rw-r--r--storage/innobase/include/univ.i2
-rw-r--r--storage/innobase/os/os0file.cc10
-rw-r--r--storage/innobase/rem/rem0cmp.cc89
-rw-r--r--storage/innobase/row/row0ftsort.cc5
-rw-r--r--storage/innobase/row/row0import.cc137
-rw-r--r--storage/innobase/row/row0log.cc7
-rw-r--r--storage/innobase/row/row0merge.cc12
-rw-r--r--storage/innobase/row/row0mysql.cc3
-rw-r--r--storage/innobase/row/row0row.cc25
-rw-r--r--storage/innobase/row/row0umod.cc4
-rw-r--r--storage/innobase/row/row0upd.cc15
-rw-r--r--storage/innobase/row/row0vers.cc6
-rw-r--r--storage/innobase/trx/trx0rec.cc17
25 files changed, 350 insertions, 397 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 19fc659f76f..f58628c5113 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -1,9 +1,9 @@
/*****************************************************************************
-Copyright (c) 1994, 2018, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -940,46 +940,66 @@ btr_cur_will_modify_tree(
const ulint n_recs = page_get_n_recs(page);
if (lock_intention <= BTR_INTENTION_BOTH) {
- ulint margin;
+ compile_time_assert(BTR_INTENTION_DELETE < BTR_INTENTION_BOTH);
+ compile_time_assert(BTR_INTENTION_BOTH < BTR_INTENTION_INSERT);
- /* check delete will cause. (BTR_INTENTION_BOTH
- or BTR_INTENTION_DELETE) */
- /* first, 2nd, 2nd-last and last records are 4 records */
- if (n_recs < 5) {
- return(true);
+ if (!page_has_siblings(page)) {
+ return true;
}
- /* is first, 2nd or last record */
- if (page_rec_is_first(rec, page)
- || (page_has_next(page)
- && (page_rec_is_last(rec, page)
- || page_rec_is_second_last(rec, page)))
- || (page_has_prev(page)
- && page_rec_is_second(rec, page))) {
- return(true);
- }
+ ulint margin = rec_size;
if (lock_intention == BTR_INTENTION_BOTH) {
+ ulint level = btr_page_get_level(page);
+
+ /* This value is the worst expectation for the node_ptr
+ records to be deleted from this page. It is used to
+ expect whether the cursor position can be the left_most
+ record in this page or not. */
+ ulint max_nodes_deleted = 0;
+
+ /* By modifying tree operations from the under of this
+ level, logically (2 ^ (level - 1)) opportunities to
+ deleting records in maximum even unreally rare case. */
+ if (level > 7) {
+ /* TODO: adjust this practical limit. */
+ max_nodes_deleted = 64;
+ } else if (level > 0) {
+ max_nodes_deleted = (ulint)1 << (level - 1);
+ }
+ /* check delete will cause. (BTR_INTENTION_BOTH
+ or BTR_INTENTION_DELETE) */
+ if (n_recs <= max_nodes_deleted * 2
+ || page_rec_is_first(rec, page)) {
+ /* The cursor record can be the left most record
+ in this page. */
+ return true;
+ }
+
+ if (page_has_prev(page)
+ && page_rec_distance_is_at_most(
+ page_get_infimum_rec(page), rec,
+ max_nodes_deleted)) {
+ return true;
+ }
+
+ if (page_has_next(page)
+ && page_rec_distance_is_at_most(
+ rec, page_get_supremum_rec(page),
+ max_nodes_deleted)) {
+ return true;
+ }
+
/* Delete at leftmost record in a page causes delete
& insert at its parent page. After that, the delete
might cause btr_compress() and delete record at its
- parent page. Thus we should consider max 2 deletes. */
-
- margin = rec_size * 2;
- } else {
- ut_ad(lock_intention == BTR_INTENTION_DELETE);
-
- margin = rec_size;
+ parent page. Thus we should consider max deletes. */
+ margin *= max_nodes_deleted;
}
- /* NOTE: call mach_read_from_4() directly to avoid assertion
- failure. It is safe because we already have SX latch of the
- index tree */
+
+ /* Safe because we already have SX latch of the index tree */
if (page_get_data_size(page)
- < margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index)
- || (mach_read_from_4(page + FIL_PAGE_NEXT)
- == FIL_NULL
- && mach_read_from_4(page + FIL_PAGE_PREV)
- == FIL_NULL)) {
+ < margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index)) {
return(true);
}
}
@@ -2160,9 +2180,9 @@ need_opposite_intention:
offsets2 = rec_get_offsets(
first_rec, index, offsets2,
false, ULINT_UNDEFINED, &heap);
- cmp_rec_rec_with_match(node_ptr, first_rec,
- offsets, offsets2, index, FALSE,
- &matched_fields);
+ cmp_rec_rec(node_ptr, first_rec,
+ offsets, offsets2, index, false,
+ &matched_fields);
if (matched_fields
>= rec_offs_n_fields(offsets) - 1) {
@@ -2178,10 +2198,10 @@ need_opposite_intention:
offsets2 = rec_get_offsets(
last_rec, index, offsets2,
false, ULINT_UNDEFINED, &heap);
- cmp_rec_rec_with_match(
+ cmp_rec_rec(
node_ptr, last_rec,
offsets, offsets2, index,
- FALSE, &matched_fields);
+ false, &matched_fields);
if (matched_fields
>= rec_offs_n_fields(offsets) - 1) {
detected_same_key_root = true;
@@ -4506,7 +4526,6 @@ btr_cur_optimistic_update(
dtuple_t* new_entry;
roll_ptr_t roll_ptr;
ulint i;
- ulint n_ext;
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
@@ -4585,10 +4604,8 @@ any_extern:
+ DTUPLE_EST_ALLOC(rec_offs_n_fields(*offsets)));
}
- new_entry = row_rec_to_index_entry(rec, index, *offsets,
- &n_ext, *heap);
- /* We checked above that there are no externally stored fields. */
- ut_a(!n_ext);
+ new_entry = row_rec_to_index_entry(rec, index, *offsets, *heap);
+ ut_ad(!dtuple_get_n_ext(new_entry));
/* The page containing the clustered index record
corresponding to new_entry is latched in mtr.
@@ -4850,7 +4867,6 @@ btr_cur_pessimistic_update(
roll_ptr_t roll_ptr;
ibool was_first;
ulint n_reserved = 0;
- ulint n_ext;
ulint max_ins_size = 0;
*offsets = NULL;
@@ -4923,15 +4939,14 @@ btr_cur_pessimistic_update(
ut_ad(flags & BTR_NO_LOCKING_FLAG);
ut_ad(index->is_instant());
new_entry = row_metadata_to_tuple(
- rec, index, *offsets,
- &n_ext, entry_heap,
+ rec, index, *offsets, entry_heap,
update->info_bits, !thr_get_trx(thr)->in_rollback);
ut_ad(new_entry->n_fields
== ulint(index->n_fields)
+ update->is_alter_metadata());
} else {
new_entry = row_rec_to_index_entry(rec, index, *offsets,
- &n_ext, entry_heap);
+ entry_heap);
}
/* The page containing the clustered index record
@@ -4942,7 +4957,6 @@ btr_cur_pessimistic_update(
itself. Thus the following call is safe. */
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
entry_heap);
- const ulint n = new_entry->n_fields;
btr_cur_trim(new_entry, index, update, thr);
/* We have to set appropriate extern storage bits in the new
@@ -4950,10 +4964,6 @@ btr_cur_pessimistic_update(
ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
ut_ad(rec_offs_validate(rec, index, *offsets));
- if (index->is_primary()) {
- n_ext += btr_push_update_extern_fields(
- new_entry, n, update, entry_heap);
- }
if ((flags & BTR_NO_UNDO_LOG_FLAG)
&& rec_offs_any_extern(*offsets)) {
@@ -4974,6 +4984,8 @@ btr_cur_pessimistic_update(
index, rec, page_zip, *offsets, update, true, mtr);
}
+ ulint n_ext = index->is_primary() ? dtuple_get_n_ext(new_entry) : 0;
+
if (page_zip_rec_needs_ext(
rec_get_converted_size(index, new_entry, n_ext),
page_is_comp(page),
@@ -7007,10 +7019,10 @@ btr_estimate_number_of_different_key_vals(
ULINT_UNDEFINED,
&heap);
- cmp_rec_rec_with_match(rec, next_rec,
- offsets_rec, offsets_next_rec,
- index, stats_null_not_equal,
- &matched_fields);
+ cmp_rec_rec(rec, next_rec,
+ offsets_rec, offsets_next_rec,
+ index, stats_null_not_equal,
+ &matched_fields);
for (j = matched_fields; j < n_cols; j++) {
/* We add one if this index record has
@@ -7290,88 +7302,6 @@ btr_cur_unmark_extern_fields(
}
}
-/** Flag the data tuple fields that are marked as extern storage in the
-update vector. We use this function to remember which fields we must
-mark as extern storage in a record inserted for an update.
-@param[in,out] tuple clustered index record
-@param[in] n number of fields in tuple, before any btr_cur_trim()
-@param[in] update update vector
-@param[in,out] heap memory heap
-@return number of flagged external columns */
-ulint
-btr_push_update_extern_fields(dtuple_t* tuple, ulint n, const upd_t* update,
- mem_heap_t* heap)
-{
- ulint n_pushed = 0;
- const upd_field_t* uf = update->fields;
-
- ut_ad(n >= tuple->n_fields);
- /* The clustered index record must always contain a
- PRIMARY KEY and the system columns DB_TRX_ID,DB_ROLL_PTR. */
- ut_ad(tuple->n_fields > DATA_ROLL_PTR);
- compile_time_assert(DATA_ROLL_PTR == 2);
-
- for (ulint un = upd_get_n_fields(update); un--; uf++) {
- ut_ad(uf->field_no < n);
-
- if (dfield_is_ext(&uf->new_val)
- && uf->field_no < tuple->n_fields) {
- dfield_t* field = &tuple->fields[uf->field_no];
-
- if (!dfield_is_ext(field)) {
- dfield_set_ext(field);
- n_pushed++;
- }
-
- switch (uf->orig_len) {
- byte* data;
- ulint len;
- byte* buf;
- case 0:
- break;
- case BTR_EXTERN_FIELD_REF_SIZE:
- /* Restore the original locally stored
- part of the column. In the undo log,
- InnoDB writes a longer prefix of externally
- stored columns, so that column prefixes
- in secondary indexes can be reconstructed. */
- dfield_set_data(field,
- (byte*) dfield_get_data(field)
- + dfield_get_len(field)
- - BTR_EXTERN_FIELD_REF_SIZE,
- BTR_EXTERN_FIELD_REF_SIZE);
- dfield_set_ext(field);
- break;
- default:
- /* Reconstruct the original locally
- stored part of the column. The data
- will have to be copied. */
- ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
-
- data = (byte*) dfield_get_data(field);
- len = dfield_get_len(field);
-
- buf = (byte*) mem_heap_alloc(heap,
- uf->orig_len);
- /* Copy the locally stored prefix. */
- memcpy(buf, data,
- unsigned(uf->orig_len)
- - BTR_EXTERN_FIELD_REF_SIZE);
- /* Copy the BLOB pointer. */
- memcpy(buf + unsigned(uf->orig_len)
- - BTR_EXTERN_FIELD_REF_SIZE,
- data + len - BTR_EXTERN_FIELD_REF_SIZE,
- BTR_EXTERN_FIELD_REF_SIZE);
-
- dfield_set_data(field, buf, uf->orig_len);
- dfield_set_ext(field);
- }
- }
- }
-
- return(n_pushed);
-}
-
/*******************************************************************//**
Returns the length of a BLOB part stored on the header page.
@return part length */
diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc
index 791b5614fc2..00d6c1f9ded 100644
--- a/storage/innobase/buf/buf0dblwr.cc
+++ b/storage/innobase/buf/buf0dblwr.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 2013, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -998,6 +998,7 @@ try_again:
int64_t sig_count = os_event_reset(buf_dblwr->b_event);
mutex_exit(&buf_dblwr->mutex);
+ os_aio_simulated_wake_handler_threads();
os_event_wait_low(buf_dblwr->b_event, sig_count);
goto try_again;
}
@@ -1124,6 +1125,7 @@ try_again:
checkpoint. */
int64_t sig_count = os_event_reset(buf_dblwr->b_event);
mutex_exit(&buf_dblwr->mutex);
+ os_aio_simulated_wake_handler_threads();
os_event_wait_low(buf_dblwr->b_event, sig_count);
goto try_again;
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 990a36524cd..c420d7a3c14 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1165,13 +1165,9 @@ dict_stats_analyze_index_level(
prev_rec, index, prev_rec_offsets, !level,
n_uniq, &heap);
- cmp_rec_rec_with_match(rec,
- prev_rec,
- rec_offsets,
- prev_rec_offsets,
- index,
- FALSE,
- &matched_fields);
+ cmp_rec_rec(prev_rec, rec,
+ prev_rec_offsets, rec_offsets, index,
+ false, &matched_fields);
for (i = matched_fields; i < n_uniq; i++) {
@@ -1391,9 +1387,8 @@ dict_stats_scan_page(
/* check whether rec != next_rec when looking at
the first n_prefix fields */
- cmp_rec_rec_with_match(rec, next_rec,
- offsets_rec, offsets_next_rec,
- index, FALSE, &matched_fields);
+ cmp_rec_rec(rec, next_rec, offsets_rec, offsets_next_rec,
+ index, false, &matched_fields);
if (matched_fields < n_prefix) {
/* rec != next_rec, => rec is non-boring */
diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc
index f54cb66692f..ec6143d05d3 100644
--- a/storage/innobase/gis/gis0rtree.cc
+++ b/storage/innobase/gis/gis0rtree.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, 2019, MariaDB Corporation.
+Copyright (c) 2018, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1438,10 +1438,9 @@ rtr_page_copy_rec_list_end_no_locks(
offsets2 = rec_get_offsets(cur_rec, index, offsets2,
is_leaf,
ULINT_UNDEFINED, &heap);
- cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
- offsets1, offsets2,
- index, FALSE,
- &cur_matched_fields);
+ cmp = cmp_rec_rec(cur1_rec, cur_rec,
+ offsets1, offsets2, index, false,
+ &cur_matched_fields);
if (cmp < 0) {
page_cur_move_to_prev(&page_cur);
break;
@@ -1553,15 +1552,13 @@ rtr_page_copy_rec_list_start_no_locks(
while (!page_rec_is_supremum(cur_rec)) {
ulint cur_matched_fields = 0;
- int cmp;
offsets2 = rec_get_offsets(cur_rec, index, offsets2,
is_leaf,
ULINT_UNDEFINED, &heap);
- cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
- offsets1, offsets2,
- index, FALSE,
- &cur_matched_fields);
+ int cmp = cmp_rec_rec(cur1_rec, cur_rec,
+ offsets1, offsets2, index, false,
+ &cur_matched_fields);
if (cmp < 0) {
page_cur_move_to_prev(&page_cur);
cur_rec = page_cur_get_rec(&page_cur);
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 84286bd2680..5d10d26e025 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -785,18 +785,6 @@ btr_rec_copy_externally_stored_field(
ulint* len,
mem_heap_t* heap);
-/** Flag the data tuple fields that are marked as extern storage in the
-update vector. We use this function to remember which fields we must
-mark as extern storage in a record inserted for an update.
-@param[in,out] tuple clustered index record
-@param[in] n number of fields in tuple, before any btr_cur_trim()
-@param[in] update update vector
-@param[in,out] heap memory heap
-@return number of flagged external columns */
-ulint
-btr_push_update_extern_fields(dtuple_t* tuple, ulint n, const upd_t* update,
- mem_heap_t* heap)
- MY_ATTRIBUTE((nonnull));
/***********************************************************//**
Sets a secondary index record's delete mark to the given value. This
function is only used by the insert buffer merge mechanism. */
diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h
index b5da367bae1..f66c7e3d405 100644
--- a/storage/innobase/include/dyn0buf.h
+++ b/storage/innobase/include/dyn0buf.h
@@ -303,8 +303,7 @@ public:
#ifdef UNIV_DEBUG
ulint total_size = 0;
- for (typename list_t::iterator it = m_list.begin(),
- end = m_list.end();
+ for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
total_size += it->used();
}
@@ -320,8 +319,7 @@ public:
template <typename Functor>
bool for_each_block(Functor& functor) const
{
- for (typename list_t::iterator it = m_list.begin(),
- end = m_list.end();
+ for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
if (!functor(&*it)) {
@@ -338,8 +336,8 @@ public:
template <typename Functor>
bool for_each_block_in_reverse(Functor& functor) const
{
- for (typename list_t::reverse_iterator it = m_list.rbegin(),
- end = m_list.rend();
+ for (list_t::reverse_iterator it = m_list.rbegin(),
+ end = m_list.rend();
it != end; ++it) {
if (!functor(&*it)) {
@@ -356,8 +354,8 @@ public:
template <typename Functor>
bool for_each_block_in_reverse(const Functor& functor) const
{
- for (typename list_t::reverse_iterator it = m_list.rbegin(),
- end = m_list.rend();
+ for (list_t::reverse_iterator it = m_list.rbegin(),
+ end = m_list.rend();
it != end; ++it) {
if (!functor(&*it)) {
@@ -425,8 +423,7 @@ private:
{
ut_ad(!m_list.empty());
- for (typename list_t::iterator it = m_list.begin(),
- end = m_list.end();
+ for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
if (pos < it->used()) {
diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
index 54586b3ce3b..31a60bcb4e5 100644
--- a/storage/innobase/include/page0page.h
+++ b/storage/innobase/include/page0page.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -852,6 +852,22 @@ page_rec_is_last(
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
+true if distance between the records (measured in number of times we have to
+move to the next record) is at most the specified value
+@param[in] left_rec lefter record
+@param[in] right_rec righter record
+@param[in] val specified value to compare
+@return true if the distance is smaller than the value */
+UNIV_INLINE
+bool
+page_rec_distance_is_at_most(
+/*=========================*/
+ const rec_t* left_rec,
+ const rec_t* right_rec,
+ ulint val)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/************************************************************//**
true if the record is the second last user record on a page.
@return true if the second last user record */
UNIV_INLINE
diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic
index 21ab45427ff..28ee193c6e5 100644
--- a/storage/innobase/include/page0page.ic
+++ b/storage/innobase/include/page0page.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2019, MariaDB Corporation.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2016, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -351,6 +351,26 @@ page_rec_is_last(
}
/************************************************************//**
+true if distance between the records (measured in number of times we have to
+move to the next record) is at most the specified value */
+UNIV_INLINE
+bool
+page_rec_distance_is_at_most(
+/*=========================*/
+ const rec_t* left_rec,
+ const rec_t* right_rec,
+ ulint val)
+{
+ for (ulint i = 0; i <= val; i++) {
+ if (left_rec == right_rec) {
+ return (true);
+ }
+ left_rec = page_rec_get_next_const(left_rec);
+ }
+ return (false);
+}
+
+/************************************************************//**
true if the record is the second last user record on a page.
@return true if the second last user record */
UNIV_INLINE
diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
index 0877c7b5b6a..af1b145b0d9 100644
--- a/storage/innobase/include/rem0cmp.h
+++ b/storage/innobase/include/rem0cmp.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -80,7 +80,7 @@ cmp_dfield_dfield(
/** Compare a GIS data tuple to a physical record.
@param[in] dtuple data tuple
-@param[in] rec B-tree record
+@param[in] rec R-tree record
@param[in] offsets rec_get_offsets(rec)
@param[in] mode compare mode
@retval negative if dtuple is less than rec */
@@ -190,43 +190,23 @@ cmp_rec_rec_simple(
duplicate key value if applicable,
or NULL */
MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result));
-/** Compare two B-tree records.
-@param[in] rec1 B-tree record
-@param[in] rec2 B-tree record
-@param[in] offsets1 rec_get_offsets(rec1, index)
-@param[in] offsets2 rec_get_offsets(rec2, index)
-@param[in] index B-tree index
-@param[in] nulls_unequal true if this is for index cardinality
-statistics estimation, and innodb_stats_method=nulls_unequal
-or innodb_stats_method=nulls_ignored
-@param[out] matched_fields number of completely matched fields
-within the first field not completely matched
-@return the comparison result
-@retval 0 if rec1 is equal to rec2
-@retval negative if rec1 is less than rec2
-@retval positive if rec2 is greater than rec2 */
-int
-cmp_rec_rec_with_match(
- const rec_t* rec1,
- const rec_t* rec2,
- const offset_t* offsets1,
- const offset_t* offsets2,
- const dict_index_t* index,
- bool nulls_unequal,
- ulint* matched_fields);
-/** Compare two B-tree records.
+/** Compare two B-tree or R-tree records.
Only the common first fields are compared, and externally stored field
are treated as equal.
-@param[in] rec1 B-tree record
-@param[in] rec2 B-tree record
+@param[in] rec1 record (possibly not on an index page)
+@param[in] rec2 B-tree or R-tree record in an index page
@param[in] offsets1 rec_get_offsets(rec1, index)
@param[in] offsets2 rec_get_offsets(rec2, index)
+@param[in] nulls_unequal true if this is for index cardinality
+ statistics estimation with
+ innodb_stats_method=nulls_unequal
+ or innodb_stats_method=nulls_ignored
@param[out] matched_fields number of completely matched fields
within the first field not completely matched
-@return positive, 0, negative if rec1 is greater, equal, less, than rec2,
-respectively */
-UNIV_INLINE
+@retval 0 if rec1 is equal to rec2
+@retval negative if rec1 is less than rec2
+@retval positive if rec1 is greater than rec2 */
int
cmp_rec_rec(
const rec_t* rec1,
@@ -234,7 +214,9 @@ cmp_rec_rec(
const offset_t* offsets1,
const offset_t* offsets2,
const dict_index_t* index,
- ulint* matched_fields = NULL);
+ bool nulls_unequal = false,
+ ulint* matched_fields = NULL)
+ MY_ATTRIBUTE((nonnull(1,2,3,4,5)));
/** Compare two data fields.
@param[in] dfield1 data field
diff --git a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic
index 5ac3838f244..4230543615a 100644
--- a/storage/innobase/include/rem0cmp.ic
+++ b/storage/innobase/include/rem0cmp.ic
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -52,40 +53,6 @@ cmp_dfield_dfield(
dfield_get_len(dfield2)));
}
-/** Compare two B-tree records.
-Only the common first fields are compared, and externally stored field
-are treated as equal.
-@param[in] rec1 B-tree record
-@param[in] rec2 B-tree record
-@param[in] offsets1 rec_get_offsets(rec1, index)
-@param[in] offsets2 rec_get_offsets(rec2, index)
-@param[out] matched_fields number of completely matched fields
- within the first field not completely matched
-@return positive, 0, negative if rec1 is greater, equal, less, than rec2,
-respectively */
-UNIV_INLINE
-int
-cmp_rec_rec(
- const rec_t* rec1,
- const rec_t* rec2,
- const offset_t* offsets1,
- const offset_t* offsets2,
- const dict_index_t* index,
- ulint* matched_fields)
-{
- ulint match_f;
- int ret;
-
- ret = cmp_rec_rec_with_match(
- rec1, rec2, offsets1, offsets2, index, false, &match_f);
-
- if (matched_fields != NULL) {
- *matched_fields = match_f;
- }
-
- return(ret);
-}
-
/** Compare two data fields.
@param[in] dfield1 data field
@param[in] dfield2 data field
diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic
index 56727f40e23..c440850cf13 100644
--- a/storage/innobase/include/rem0rec.ic
+++ b/storage/innobase/include/rem0rec.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1390,6 +1390,7 @@ rec_get_converted_size(
data_size = dtuple_get_data_size(dtuple, 0);
+ ut_ad(n_ext == dtuple_get_n_ext(dtuple));
extra_size = rec_get_converted_extra_size(
data_size, dtuple_get_n_fields(dtuple), n_ext);
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
index 264cae52832..be451751f56 100644
--- a/storage/innobase/include/row0row.h
+++ b/storage/innobase/include/row0row.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2019, MariaDB Corporation.
+Copyright (c) 2016, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -208,8 +208,6 @@ row_rec_to_index_entry_low(
const rec_t* rec, /*!< in: record in the index */
const dict_index_t* index, /*!< in: index */
const offset_t* offsets,/*!< in: rec_get_offsets(rec, index) */
- ulint* n_ext, /*!< out: number of externally
- stored columns */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
MY_ATTRIBUTE((warn_unused_result));
@@ -223,8 +221,6 @@ row_rec_to_index_entry(
const rec_t* rec, /*!< in: record in the index */
const dict_index_t* index, /*!< in: index */
const offset_t* offsets,/*!< in/out: rec_get_offsets(rec) */
- ulint* n_ext, /*!< out: number of externally
- stored columns */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
MY_ATTRIBUTE((warn_unused_result));
@@ -233,7 +229,6 @@ row_rec_to_index_entry(
@param[in] rec metadata record
@param[in] index clustered index after instant ALTER TABLE
@param[in] offsets rec_get_offsets(rec)
-@param[out] n_ext number of externally stored fields
@param[in,out] heap memory heap for allocations
@param[in] info_bits the info_bits after an update
@param[in] pad whether to pad to index->n_fields */
@@ -242,7 +237,6 @@ row_metadata_to_tuple(
const rec_t* rec,
const dict_index_t* index,
const offset_t* offsets,
- ulint* n_ext,
mem_heap_t* heap,
ulint info_bits,
bool pad)
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 644a9484af4..e9d427e04c0 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index 95c31523325..b1c2a3925ee 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -1,8 +1,8 @@
/***********************************************************************
-Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2019, MariaDB Corporation.
+Copyright (c) 2013, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted
by Percona Inc.. Those modifications are
@@ -1357,6 +1357,12 @@ os_file_get_parent_dir(
return(NULL);
}
+ if (last_slash - path < 0) {
+ /* Sanity check, it prevents gcc from trying to handle this case which
+ * results in warnings for some optimized builds */
+ return (NULL);
+ }
+
/* Non-trivial directory component */
return(mem_strdupl(path, ulint(last_slash - path)));
diff --git a/storage/innobase/rem/rem0cmp.cc b/storage/innobase/rem/rem0cmp.cc
index b9be9c05073..34ae5b08bab 100644
--- a/storage/innobase/rem/rem0cmp.cc
+++ b/storage/innobase/rem/rem0cmp.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -534,7 +535,7 @@ cmp_data(
/** Compare a GIS data tuple to a physical record.
@param[in] dtuple data tuple
-@param[in] rec B-tree record
+@param[in] rec R-tree record
@param[in] offsets rec_get_offsets(rec)
@param[in] mode compare mode
@retval negative if dtuple is less than rec */
@@ -1096,23 +1097,24 @@ cmp_rec_rec_simple(
return(0);
}
-/** Compare two B-tree records.
-@param[in] rec1 B-tree record
-@param[in] rec2 B-tree record
-@param[in] offsets1 rec_get_offsets(rec1, index)
-@param[in] offsets2 rec_get_offsets(rec2, index)
-@param[in] index B-tree index
-@param[in] nulls_unequal true if this is for index cardinality
-statistics estimation, and innodb_stats_method=nulls_unequal
-or innodb_stats_method=nulls_ignored
-@param[out] matched_fields number of completely matched fields
-within the first field not completely matched
-@return the comparison result
+/** Compare two B-tree or R-tree records.
+Only the common first fields are compared, and externally stored field
+are treated as equal.
+@param[in] rec1 record (possibly not on an index page)
+@param[in] rec2 B-tree or R-tree record in an index page
+@param[in] offsets1 rec_get_offsets(rec1, index)
+@param[in] offsets2 rec_get_offsets(rec2, index)
+@param[in] nulls_unequal true if this is for index cardinality
+ statistics estimation with
+ innodb_stats_method=nulls_unequal
+ or innodb_stats_method=nulls_ignored
+@param[out] matched_fields number of completely matched fields
+ within the first field not completely matched
@retval 0 if rec1 is equal to rec2
@retval negative if rec1 is less than rec2
-@retval positive if rec2 is greater than rec2 */
+@retval positive if rec1 is greater than rec2 */
int
-cmp_rec_rec_with_match(
+cmp_rec_rec(
const rec_t* rec1,
const rec_t* rec2,
const offset_t* offsets1,
@@ -1121,17 +1123,14 @@ cmp_rec_rec_with_match(
bool nulls_unequal,
ulint* matched_fields)
{
- ulint rec1_n_fields; /* the number of fields in rec */
ulint rec1_f_len; /* length of current field in rec */
const byte* rec1_b_ptr; /* pointer to the current byte
in rec field */
- ulint rec2_n_fields; /* the number of fields in rec */
ulint rec2_f_len; /* length of current field in rec */
const byte* rec2_b_ptr; /* pointer to the current byte
in rec field */
ulint cur_field = 0; /* current field number */
int ret = 0; /* return value */
- ulint comp;
ut_ad(rec1 != NULL);
ut_ad(rec2 != NULL);
@@ -1139,10 +1138,12 @@ cmp_rec_rec_with_match(
ut_ad(rec_offs_validate(rec1, index, offsets1));
ut_ad(rec_offs_validate(rec2, index, offsets2));
ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
+ ut_ad(fil_page_index_page_check(page_align(rec2)));
+ ut_ad(!!dict_index_is_spatial(index)
+ == (fil_page_get_type(page_align(rec2)) == FIL_PAGE_RTREE));
- comp = rec_offs_comp(offsets1);
- rec1_n_fields = rec_offs_n_fields(offsets1);
- rec2_n_fields = rec_offs_n_fields(offsets2);
+ ulint comp = rec_offs_comp(offsets1);
+ ulint n_fields;
/* Test if rec is the predefined minimum record */
if (UNIV_UNLIKELY(rec_get_info_bits(rec1, comp)
@@ -1158,37 +1159,41 @@ cmp_rec_rec_with_match(
goto order_resolved;
}
- /* Match fields in a loop */
+ /* For non-leaf spatial index records, the
+ dict_index_get_n_unique_in_tree() does include the child page
+ number, because spatial index node pointers only contain
+ the MBR (minimum bounding rectangle) and the child page number.
- for (; cur_field < rec1_n_fields && cur_field < rec2_n_fields;
- cur_field++) {
+ For B-tree node pointers, the key alone (secondary index
+ columns and PRIMARY KEY columns) must be unique, and there is
+ no need to compare the child page number. */
+ n_fields = std::min(rec_offs_n_fields(offsets1),
+ rec_offs_n_fields(offsets2));
+ n_fields = std::min(n_fields, dict_index_get_n_unique_in_tree(index));
+ for (; cur_field < n_fields; cur_field++) {
ulint mtype;
ulint prtype;
- /* If this is node-ptr records then avoid comparing node-ptr
- field. Only key field needs to be compared. */
- if (cur_field == dict_index_get_n_unique_in_tree(index)) {
- break;
- }
-
- if (dict_index_is_ibuf(index)) {
+ if (UNIV_UNLIKELY(dict_index_is_ibuf(index))) {
/* This is for the insert buffer B-tree. */
mtype = DATA_BINARY;
prtype = 0;
} else {
- const dict_col_t* col;
-
- col = dict_index_get_nth_col(index, cur_field);
-
+ const dict_col_t* col = dict_index_get_nth_col(
+ index, cur_field);
mtype = col->mtype;
prtype = col->prtype;
- /* If the index is spatial index, we mark the
- prtype of the first field as MBR field. */
- if (cur_field == 0 && dict_index_is_spatial(index)) {
+ if (UNIV_LIKELY(!dict_index_is_spatial(index))) {
+ } else if (cur_field == 0) {
ut_ad(DATA_GEOMETRY_MTYPE(mtype));
prtype |= DATA_GIS_MBR;
+ } else if (!page_rec_is_leaf(rec2)) {
+ /* Compare the child page number. */
+ ut_ad(cur_field == 1);
+ mtype = DATA_SYS_CHILD;
+ prtype = 0;
}
}
@@ -1226,8 +1231,10 @@ cmp_rec_rec_with_match(
to the common fields */
ut_ad(ret == 0);
order_resolved:
- *matched_fields = cur_field;
- return(ret);
+ if (matched_fields) {
+ *matched_fields = cur_field;
+ }
+ return ret;
}
#ifdef UNIV_COMPILE_TEST_FUNCS
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 38ba39bea98..7e3b70bfadb 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1722,7 +1722,6 @@ row_fts_merge_insert(
corresponding FTS index auxiliary tables */
for (;;) {
dtuple_t* dtuple;
- ulint n_ext;
int min_rec = 0;
if (fts_sort_pll_degree <= 2) {
@@ -1765,7 +1764,7 @@ row_fts_merge_insert(
}
dtuple = row_rec_to_index_entry_low(
- mrec[min_rec], index, offsets[min_rec], &n_ext,
+ mrec[min_rec], index, offsets[min_rec],
tuple_heap);
row_fts_insert_tuple(
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 9adc5da2b8b..d161a8134aa 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1157,60 +1157,82 @@ row_import::match_table_columns(
if (cfg_col->prtype != col->prtype) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s precise type mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s precise type mismatch,"
+ " it's 0X%X in the table and 0X%X"
+ " in the tablespace meta file",
+ col_name, col->prtype, cfg_col->prtype);
err = DB_ERROR;
}
if (cfg_col->mtype != col->mtype) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s main type mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s main type mismatch,"
+ " it's 0X%X in the table and 0X%X"
+ " in the tablespace meta file",
+ col_name, col->mtype, cfg_col->mtype);
err = DB_ERROR;
}
if (cfg_col->len != col->len) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s length mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s length mismatch,"
+ " it's %u in the table and %u"
+ " in the tablespace meta file",
+ col_name, col->len, cfg_col->len);
err = DB_ERROR;
}
if (cfg_col->mbminlen != col->mbminlen
|| cfg_col->mbmaxlen != col->mbmaxlen) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s multi-byte len mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s multi-byte len mismatch,"
+ " it's %u-%u in the table and %u-%u"
+ " in the tablespace meta file",
+ col_name, col->mbminlen, col->mbmaxlen,
+ cfg_col->mbminlen, cfg_col->mbmaxlen);
err = DB_ERROR;
}
if (cfg_col->ind != col->ind) {
+ ib_errf(thd,
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s position mismatch,"
+ " it's %u in the table and %u"
+ " in the tablespace meta file",
+ col_name, col->ind, cfg_col->ind);
err = DB_ERROR;
}
if (cfg_col->ord_part != col->ord_part) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s ordering mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s ordering mismatch,"
+ " it's %u in the table and %u"
+ " in the tablespace meta file",
+ col_name, col->ord_part,
+ cfg_col->ord_part);
err = DB_ERROR;
}
if (cfg_col->max_prefix != col->max_prefix) {
ib_errf(thd,
- IB_LOG_LEVEL_ERROR,
- ER_TABLE_SCHEMA_MISMATCH,
- "Column %s max prefix mismatch.",
- col_name);
+ IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Column %s max prefix mismatch"
+ " it's %u in the table and %u"
+ " in the tablespace meta file",
+ col_name, col->max_prefix,
+ cfg_col->max_prefix);
err = DB_ERROR;
}
}
@@ -1509,13 +1531,70 @@ IndexPurge::next() UNIV_NOTHROW
mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO);
btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr);
+ /* The following is based on btr_pcur_move_to_next_user_rec(). */
+ m_pcur.old_stored = false;
+ ut_ad(m_pcur.latch_mode == BTR_MODIFY_LEAF);
+ do {
+ if (btr_pcur_is_after_last_on_page(&m_pcur)) {
+ if (btr_pcur_is_after_last_in_tree(&m_pcur)) {
+ return DB_END_OF_INDEX;
+ }
- if (!btr_pcur_move_to_next_user_rec(&m_pcur, &m_mtr)) {
+ buf_block_t* block = btr_pcur_get_block(&m_pcur);
+ uint32_t next_page = btr_page_get_next(block->frame);
- return(DB_END_OF_INDEX);
- }
+ /* MDEV-13542 FIXME: Make these checks part of
+ btr_pcur_move_to_next_page(), and introduce a
+ return status that will be checked in all callers! */
+ switch (next_page) {
+ default:
+ if (next_page != block->page.id.page_no()) {
+ break;
+ }
+ /* MDEV-20931 FIXME: Check that
+ next_page is within the tablespace
+ bounds! Also check that it is not a
+ change buffer bitmap page. */
+ /* fall through */
+ case 0:
+ case 1:
+ case FIL_NULL:
+ return DB_CORRUPTION;
+ }
- return(DB_SUCCESS);
+ dict_index_t* index = m_pcur.btr_cur.index;
+ buf_block_t* next_block = btr_block_get(
+ page_id_t(block->page.id.space(), next_page),
+ block->zip_size(), BTR_MODIFY_LEAF, index,
+ &m_mtr);
+
+ if (UNIV_UNLIKELY(!next_block
+ || !fil_page_index_page_check(
+ next_block->frame)
+ || !!dict_index_is_spatial(index)
+ != (fil_page_get_type(
+ next_block->frame)
+ == FIL_PAGE_RTREE)
+ || page_is_comp(next_block->frame)
+ != page_is_comp(block->frame)
+ || btr_page_get_prev(
+ next_block->frame)
+ != block->page.id.page_no())) {
+ return DB_CORRUPTION;
+ }
+
+ btr_leaf_page_release(block, BTR_MODIFY_LEAF, &m_mtr);
+
+ page_cur_set_before_first(next_block,
+ &m_pcur.btr_cur.page_cur);
+
+ ut_d(page_check_dir(next_block->frame));
+ } else {
+ btr_pcur_move_to_next_on_page(&m_pcur);
+ }
+ } while (!btr_pcur_is_on_user_rec(&m_pcur));
+
+ return DB_SUCCESS;
}
/**
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index 56328349e1e..fa50ff80e55 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -3562,7 +3562,6 @@ row_log_apply_op(
enum row_op op;
ulint extra_size;
ulint data_size;
- ulint n_ext;
dtuple_t* entry;
trx_id_t trx_id;
@@ -3640,10 +3639,10 @@ corrupted:
}
entry = row_rec_to_index_entry_low(
- mrec - data_size, index, offsets, &n_ext, heap);
+ mrec - data_size, index, offsets, heap);
/* Online index creation is only implemented for secondary
indexes, which never contain off-page columns. */
- ut_ad(n_ext == 0);
+ ut_ad(dtuple_get_n_ext(entry) == 0);
row_log_apply_op_low(index, dup, error, offsets_heap,
has_index_lock, op, trx_id, entry);
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 8b3831f08af..afa692fa139 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2019, MariaDB Corporation.
+Copyright (c) 2014, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -3535,7 +3535,6 @@ row_merge_insert_index_tuples(
double curr_progress = 0;
dict_index_t* old_index = NULL;
const mrec_t* mrec = NULL;
- ulint n_ext = 0;
mtr_t mtr;
@@ -3601,8 +3600,6 @@ row_merge_insert_index_tuples(
row buffer to data tuple record */
row_merge_mtuple_to_dtuple(
index, dtuple, &row_buf->tuples[n_rows]);
-
- n_ext = dtuple_get_n_ext(dtuple);
n_rows++;
/* BLOB pointers must be copied from dtuple */
mrec = NULL;
@@ -3621,7 +3618,7 @@ row_merge_insert_index_tuples(
}
dtuple = row_rec_to_index_entry_low(
- mrec, index, offsets, &n_ext, tuple_heap);
+ mrec, index, offsets, tuple_heap);
}
old_index = dict_table_get_first_index(old_table);
@@ -3634,10 +3631,7 @@ row_merge_insert_index_tuples(
}
}
- if (!n_ext) {
- /* There are no externally stored columns. */
- } else {
- ut_ad(dict_index_is_clust(index));
+ if (dict_index_is_clust(index) && dtuple_get_n_ext(dtuple)) {
/* Off-page columns can be fetched safely
when concurrent modifications to the table
are disabled. (Purge can process delete-marked
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 86ef45167a4..bcc877d3d1f 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -4675,7 +4675,6 @@ row_scan_index_for_mysql(
ulint i;
ulint cnt;
mem_heap_t* heap = NULL;
- ulint n_ext;
offset_t offsets_[REC_OFFS_NORMAL_SIZE];
offset_t* offsets;
rec_offs_init(offsets_);
@@ -4817,7 +4816,7 @@ not_ok:
mem_heap_empty(heap);
prev_entry = row_rec_to_index_entry(
- rec, index, offsets, &n_ext, heap);
+ rec, index, offsets, heap);
if (UNIV_LIKELY_NULL(tmp_heap)) {
mem_heap_free(tmp_heap);
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index 4e901346580..83add52dd88 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, 2019, MariaDB Corporation.
+Copyright (c) 2018, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -722,7 +722,6 @@ row_rec_to_index_entry_impl(
const rec_t* rec,
const dict_index_t* index,
const offset_t* offsets,
- ulint* n_ext,
mem_heap_t* heap,
ulint info_bits = 0,
bool pad = false)
@@ -738,8 +737,6 @@ row_rec_to_index_entry_impl(
/* Because this function may be invoked by row0merge.cc
on a record whose header is in different format, the check
rec_offs_validate(rec, index, offsets) must be avoided here. */
- ut_ad(n_ext);
- *n_ext = 0;
const bool got = mblob == 2 && rec_is_alter_metadata(rec, *index);
ulint rec_len = rec_offs_n_fields(offsets);
@@ -790,7 +787,6 @@ row_rec_to_index_entry_impl(
if (rec_offs_nth_extern(offsets, i)) {
dfield_set_ext(dfield);
- ++*n_ext;
}
}
@@ -833,7 +829,6 @@ init_metadata:
ut_ad(len == FIELD_REF_SIZE);
dfield_set_data(dfield, field, len);
dfield_set_ext(dfield++);
- ++*n_ext;
copy_user_fields:
for (; i < rec_len; i++, dfield++) {
dict_col_copy_type(dict_index_get_nth_col(index, j++),
@@ -851,7 +846,6 @@ copy_user_fields:
if (rec_offs_nth_extern(offsets, i)) {
dfield_set_ext(dfield);
- ++*n_ext;
}
}
}
@@ -870,18 +864,15 @@ copy_user_fields:
@param[in] rec index record
@param[in] index index
@param[in] offsets rec_get_offsets(rec, index)
-@param[out] n_ext number of externally stored columns
@param[in,out] heap memory heap for allocations */
dtuple_t*
row_rec_to_index_entry_low(
const rec_t* rec,
const dict_index_t* index,
const offset_t* offsets,
- ulint* n_ext,
mem_heap_t* heap)
{
- return row_rec_to_index_entry_impl<false>(
- rec, index, offsets, n_ext, heap);
+ return row_rec_to_index_entry_impl<false>(rec, index, offsets, heap);
}
/*******************************************************************//**
@@ -894,8 +885,6 @@ row_rec_to_index_entry(
const rec_t* rec, /*!< in: record in the index */
const dict_index_t* index, /*!< in: index */
const offset_t* offsets,/*!< in: rec_get_offsets(rec) */
- ulint* n_ext, /*!< out: number of externally
- stored columns */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
{
@@ -915,9 +904,9 @@ row_rec_to_index_entry(
dtuple_t* entry = rec_is_alter_metadata(copy_rec, *index)
? row_rec_to_index_entry_impl<true,1>(
- copy_rec, index, offsets, n_ext, heap)
+ copy_rec, index, offsets, heap)
: row_rec_to_index_entry_impl<true>(
- copy_rec, index, offsets, n_ext, heap);
+ copy_rec, index, offsets, heap);
rec_offs_make_valid(rec, index, true,
const_cast<offset_t*>(offsets));
@@ -932,7 +921,6 @@ row_rec_to_index_entry(
@param[in] rec metadata record
@param[in] index clustered index after instant ALTER TABLE
@param[in] offsets rec_get_offsets(rec)
-@param[out] n_ext number of externally stored fields
@param[in,out] heap memory heap for allocations
@param[in] info_bits the info_bits after an update
@param[in] pad whether to pad to index->n_fields */
@@ -941,7 +929,6 @@ row_metadata_to_tuple(
const rec_t* rec,
const dict_index_t* index,
const offset_t* offsets,
- ulint* n_ext,
mem_heap_t* heap,
ulint info_bits,
bool pad)
@@ -962,9 +949,9 @@ row_metadata_to_tuple(
dtuple_t* entry = info_bits == REC_INFO_METADATA_ALTER
|| rec_is_alter_metadata(copy_rec, *index)
? row_rec_to_index_entry_impl<true,2>(
- copy_rec, index, offsets, n_ext, heap, info_bits, pad)
+ copy_rec, index, offsets, heap, info_bits, pad)
: row_rec_to_index_entry_impl<true>(
- copy_rec, index, offsets, n_ext, heap);
+ copy_rec, index, offsets, heap);
rec_offs_make_valid(rec, index, true,
const_cast<offset_t*>(offsets));
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index 5c318f34245..e028e0ccb56 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -236,6 +236,7 @@ static bool row_undo_mod_must_purge(undo_node_t* node, mtr_t* mtr)
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&node->pcur);
ut_ad(btr_cur->index->is_primary());
+ DEBUG_SYNC_C("rollback_purge_clust");
mtr->s_lock(&purge_sys.latch, __FILE__, __LINE__);
@@ -369,6 +370,7 @@ row_undo_mod_clust(
== node->new_trx_id);
btr_pcur_commit_specify_mtr(pcur, &mtr);
+ DEBUG_SYNC_C("rollback_undo_pk");
if (err != DB_SUCCESS) {
goto func_exit;
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 88a9f60206f..6ddd4046f09 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2019, MariaDB Corporation.
+Copyright (c) 2015, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -223,7 +223,6 @@ row_upd_check_references_constraints(
dtuple_t* entry;
trx_t* trx;
const rec_t* rec;
- ulint n_ext;
dberr_t err;
ibool got_s_lock = FALSE;
@@ -240,7 +239,7 @@ row_upd_check_references_constraints(
heap = mem_heap_create(500);
- entry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap);
+ entry = row_rec_to_index_entry(rec, index, offsets, heap);
mtr_commit(mtr);
@@ -341,7 +340,6 @@ wsrep_row_upd_check_foreign_constraints(
dtuple_t* entry;
trx_t* trx;
const rec_t* rec;
- ulint n_ext;
dberr_t err;
ibool got_s_lock = FALSE;
ibool opened = FALSE;
@@ -359,8 +357,7 @@ wsrep_row_upd_check_foreign_constraints(
heap = mem_heap_create(500);
- entry = row_rec_to_index_entry(rec, index, offsets,
- &n_ext, heap);
+ entry = row_rec_to_index_entry(rec, index, offsets, heap);
mtr_commit(mtr);
@@ -2803,9 +2800,9 @@ check_fk:
mtr_commit(mtr);
- err = row_ins_clust_index_entry(
- index, entry, thr,
- node->upd_ext ? node->upd_ext->n_ext : 0);
+ err = row_ins_clust_index_entry(index, entry, thr, node->upd_ext
+ ? node->upd_ext->n_ext
+ : dtuple_get_n_ext(entry));
node->state = UPD_NODE_INSERT_CLUSTERED;
mem_heap_free(heap);
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index 9fe183ecb29..5935b0a11ca 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -153,15 +153,13 @@ row_vers_impl_x_locked_low(
const ulint rec_del = rec_get_deleted_flag(rec, comp);
if (dict_index_has_virtual(index)) {
- ulint n_ext;
ulint est_size = DTUPLE_EST_ALLOC(index->n_fields);
/* Allocate the dtuple for virtual columns extracted from undo
log with its own heap, so to avoid it being freed as we
iterating in the version loop below. */
v_heap = mem_heap_create(est_size);
- ientry = row_rec_to_index_entry(
- rec, index, offsets, &n_ext, v_heap);
+ ientry = row_rec_to_index_entry(rec, index, offsets, v_heap);
}
/* We look up if some earlier version, which was modified by
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index 008e508f076..1ff18a2a7eb 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2019, MariaDB Corporation.
+Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -2435,8 +2435,6 @@ trx_undo_prev_version_build(
ut_a(ptr);
if (row_upd_changes_field_size_or_external(index, offsets, update)) {
- ulint n_ext;
-
/* We should confirm the existence of disowned external data,
if the previous version record is delete marked. If the trx_id
of the previous record is seen by purge view, we should treat
@@ -2477,17 +2475,16 @@ trx_undo_prev_version_build(
those fields that update updates to become externally stored
fields. Store the info: */
- entry = row_rec_to_index_entry(
- rec, index, offsets, &n_ext, heap);
- if (index->is_primary()) {
- n_ext += btr_push_update_extern_fields(
- entry, entry->n_fields, update, heap);
- }
+ entry = row_rec_to_index_entry(rec, index, offsets, heap);
/* The page containing the clustered index record
corresponding to entry is latched in mtr. Thus the
following call is safe. */
row_upd_index_replace_new_col_vals(entry, index, update, heap);
+ /* Get number of externally stored columns in updated record */
+ const ulint n_ext = index->is_primary()
+ ? dtuple_get_n_ext(entry) : 0;
+
buf = static_cast<byte*>(mem_heap_alloc(
heap, rec_get_converted_size(index, entry, n_ext)));