summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/innodb/r/insert_into_empty.result14
-rw-r--r--mysql-test/suite/innodb/t/insert_into_empty.test14
-rw-r--r--storage/innobase/btr/btr0btr.cc30
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc103
-rw-r--r--storage/innobase/include/fsp0fsp.h45
5 files changed, 160 insertions, 46 deletions
diff --git a/mysql-test/suite/innodb/r/insert_into_empty.result b/mysql-test/suite/innodb/r/insert_into_empty.result
index 651cadd50b7..02d9549886d 100644
--- a/mysql-test/suite/innodb/r/insert_into_empty.result
+++ b/mysql-test/suite/innodb/r/insert_into_empty.result
@@ -13,3 +13,17 @@ SELECT * FROM t;
a b
1 3
DROP TEMPORARY TABLE t;
+#
+# MDEV-24720 AHI removal during bulk index rollback
+#
+SET @save_ahi = @@global.innodb_adaptive_hash_index;
+SET GLOBAL innodb_adaptive_hash_index = 1;
+CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
+BEGIN;
+INSERT INTO t1 SELECT * FROM seq_1_to_65536;
+ROLLBACK;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+SET GLOBAL innodb_adaptive_hash_index = @save_ahi;
diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test
index 945f0dbd627..af067cbd02d 100644
--- a/mysql-test/suite/innodb/t/insert_into_empty.test
+++ b/mysql-test/suite/innodb/t/insert_into_empty.test
@@ -1,4 +1,5 @@
--source include/have_innodb.inc
+--source include/have_sequence.inc
--echo #
--echo # MDEV-24715 Assertion !node->table->skip_alter_undo
@@ -12,3 +13,16 @@ CREATE TEMPORARY TABLE t (a INT UNIQUE) ENGINE=InnoDB
REPLACE SELECT 1 AS a, 2 AS b UNION SELECT 1 AS a, 3 AS c;
SELECT * FROM t;
DROP TEMPORARY TABLE t;
+
+--echo #
+--echo # MDEV-24720 AHI removal during bulk index rollback
+--echo #
+SET @save_ahi = @@global.innodb_adaptive_hash_index;
+SET GLOBAL innodb_adaptive_hash_index = 1;
+CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
+BEGIN;
+INSERT INTO t1 SELECT * FROM seq_1_to_65536;
+ROLLBACK;
+CHECK TABLE t1;
+DROP TABLE t1;
+SET GLOBAL innodb_adaptive_hash_index = @save_ahi;
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 4d85ce16df1..96fe35362d5 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -1118,7 +1118,11 @@ static
void
btr_free_but_not_root(
buf_block_t* block,
- mtr_log_t log_mode)
+ mtr_log_t log_mode
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi=false
+#endif
+ )
{
mtr_t mtr;
@@ -1147,7 +1151,11 @@ leaf_loop:
fsp0fsp. */
bool finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
- &mtr);
+ &mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ , ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
mtr_commit(&mtr);
if (!finished) {
@@ -1167,7 +1175,11 @@ top_loop:
#endif /* UNIV_BTR_DEBUG */
finished = fseg_free_step_not_header(
- root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
+ root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
mtr_commit(&mtr);
if (!finished) {
@@ -1191,12 +1203,22 @@ void dict_index_t::clear(que_thr_t *thr)
table->space->zip_size(),
RW_X_LATCH, &mtr))
{
- btr_free_but_not_root(root_block, mtr.get_log_mode());
+ btr_free_but_not_root(root_block, mtr.get_log_mode()
+#ifdef BTR_CUR_HASH_ADAPT
+ ,n_ahi_pages() != 0
+#endif
+ );
+
mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
FSEG_HEADER_SIZE, 0);
if (fseg_create(table->space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr, false,
root_block))
btr_root_page_init(root_block, id, this, &mtr);
+#ifdef BTR_CUR_HASH_ADAPT
+ if (root_block->index)
+ btr_search_drop_page_hash_index(root_block);
+ ut_ad(n_ahi_pages() == 0);
+#endif
}
mtr.commit();
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 24bcbdbb949..18aa1285f73 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -2402,7 +2402,8 @@ try_to_extend:
@param[in] seg_inode segment inode
@param[in,out] space tablespace
@param[in] offset page number
-@param[in,out] mtr mini-transaction */
+@param[in,out] mtr mini-transaction
+@param[in] ahi Drop adaptive hash index */
static
void
fseg_free_page_low(
@@ -2410,7 +2411,11 @@ fseg_free_page_low(
buf_block_t* iblock,
fil_space_t* space,
page_no_t offset,
- mtr_t* mtr)
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi=false
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
{
ib_id_t descr_id;
ib_id_t seg_id;
@@ -2423,6 +2428,13 @@ fseg_free_page_low(
ut_ad(iblock->frame == page_align(seg_inode));
ut_d(space->modify_check(*mtr));
+#ifdef BTR_CUR_HASH_ADAPT
+ if (ahi) {
+ btr_search_drop_page_hash_when_freed(
+ page_id_t(space->id, offset));
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+
const uint32_t extent_size = FSP_EXTENT_SIZE;
ut_ad(ut_is_2pow(extent_size));
buf_block_t* xdes;
@@ -2593,7 +2605,11 @@ fseg_free_extent(
buf_block_t* iblock,
fil_space_t* space,
uint32_t page,
- mtr_t* mtr)
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi=false
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
{
ut_ad(mtr != NULL);
@@ -2611,6 +2627,21 @@ fseg_free_extent(
const uint16_t xoffset= uint16_t(descr - xdes->frame + XDES_FLST_NODE);
const uint16_t ioffset= uint16_t(seg_inode - iblock->frame);
+#ifdef BTR_CUR_HASH_ADAPT
+ if (ahi) {
+ for (uint32_t i = 0; i < FSP_EXTENT_SIZE; i++) {
+ if (!xdes_is_free(descr, i)) {
+ /* Drop search system page hash index
+ if the page is found in the pool and
+ is hashed */
+ btr_search_drop_page_hash_when_freed(
+ page_id_t(space->id,
+ first_page_in_extent + i));
+ }
+ }
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+
if (xdes_is_full(descr)) {
flst_remove(iblock, static_cast<uint16_t>(FSEG_FULL + ioffset),
xdes, xoffset, mtr);
@@ -2631,26 +2662,31 @@ fseg_free_extent(
fsp_free_extent(space, page, mtr);
- for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) {
+ for (uint32_t i = 0; i < FSP_EXTENT_SIZE; i++) {
if (!xdes_is_free(descr, i)) {
- buf_page_free(space, first_page_in_extent + 1, mtr);
+ buf_page_free(space, first_page_in_extent + i, mtr);
}
}
}
-/**********************************************************************//**
-Frees part of a segment. This function can be used to free a segment by
-repeatedly calling this function in different mini-transactions. Doing
-the freeing in a single mini-transaction might result in too big a
-mini-transaction.
+/** Frees part of a segment. This function can be used to free
+a segment by repeatedly calling this function in different
+mini-transactions. Doing the freeing in a single mini-transaction
+might result in too big a mini-transaction.
+@param header segment header; NOTE: if the header resides on first
+ page of the frag list of the segment, this pointer
+ becomes obsolete after the last freeing step
+@param mtr mini-transaction
+@param ahi Drop the adaptive hash index
@return whether the freeing was completed */
bool
fseg_free_step(
- fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
- resides on the first page of the frag list
- of the segment, this pointer becomes obsolete
- after the last freeing step */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+ fseg_header_t* header,
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
{
ulint n;
fseg_inode_t* inode;
@@ -2686,7 +2722,11 @@ fseg_free_step(
if (descr != NULL) {
/* Free the extent held by the segment */
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
- mtr);
+ mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ , ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
DBUG_RETURN(false);
}
@@ -2703,7 +2743,11 @@ fseg_free_step(
fseg_free_page_low(
inode, iblock, space,
fseg_get_nth_frag_page_no(inode, n),
- mtr);
+ mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ , ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
n = fseg_find_last_used_frag_page_slot(inode);
@@ -2717,15 +2761,14 @@ fseg_free_step(
DBUG_RETURN(false);
}
-/**********************************************************************//**
-Frees part of a segment. Differs from fseg_free_step because this function
-leaves the header page unfreed.
-@return whether the freeing was completed, except for the header page */
bool
fseg_free_step_not_header(
- fseg_header_t* header, /*!< in: segment header which must reside on
- the first fragment page of the segment */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+ fseg_header_t* header,
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
{
ulint n;
xdes_t* descr;
@@ -2748,7 +2791,11 @@ fseg_free_step_not_header(
if (descr != NULL) {
/* Free the extent held by the segment */
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
- mtr);
+ mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ , ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
return false;
}
@@ -2764,7 +2811,11 @@ fseg_free_step_not_header(
return true;
}
- fseg_free_page_low(inode, iblock, space, page_no, mtr);
+ fseg_free_page_low(inode, iblock, space, page_no, mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ , ahi
+#endif /* BTR_CUR_HASH_ADAPT */
+ );
return false;
}
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 43c45dcee0c..10765852529 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -493,29 +493,42 @@ fseg_free_page(
bool
fseg_page_is_free(fil_space_t* space, unsigned page)
MY_ATTRIBUTE((nonnull, warn_unused_result));
-/**********************************************************************//**
-Frees part of a segment. This function can be used to free a segment
-by repeatedly calling this function in different mini-transactions.
-Doing the freeing in a single mini-transaction might result in
-too big a mini-transaction.
+
+/** Frees part of a segment. This function can be used to free
+a segment by repeatedly calling this function in different
+mini-transactions. Doing the freeing in a single mini-transaction
+might result in too big a mini-transaction.
+@param header segment header; NOTE: if the header resides on first
+ page of the frag list of the segment, this pointer
+ becomes obsolete after the last freeing step
+@param mtr mini-transaction
+@param ahi Drop the adaptive hash index
@return whether the freeing was completed */
bool
fseg_free_step(
- fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
- resides on the first page of the frag list
- of the segment, this pointer becomes obsolete
- after the last freeing step */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+ fseg_header_t* header,
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi=false
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
MY_ATTRIBUTE((warn_unused_result));
-/**********************************************************************//**
-Frees part of a segment. Differs from fseg_free_step because this function
-leaves the header page unfreed.
+
+/** Frees part of a segment. Differs from fseg_free_step because
+this function leaves the header page unfreed.
+@param header segment header which must reside on the first
+ fragment page of the segment
+@param mtr mini-transaction
+@param ahi drop the adaptive hash index
@return whether the freeing was completed, except for the header page */
bool
fseg_free_step_not_header(
- fseg_header_t* header, /*!< in: segment header which must reside on
- the first fragment page of the segment */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+ fseg_header_t* header,
+ mtr_t* mtr
+#ifdef BTR_CUR_HASH_ADAPT
+ ,bool ahi=false
+#endif /* BTR_CUR_HASH_ADAPT */
+ )
MY_ATTRIBUTE((warn_unused_result));
/** Reset the page type.