Skip to content

Commit 43ca605

Browse files
MDEV-24720 AHI removal during rollback of bulk insert
InnoDB fails to remove the ahi entries during rollback of bulk insert operation. InnoDB throws the error when validates the ahi hash tables. InnoDB should remove the ahi entries while freeing the segment only during bulk index rollback operation. Reviewed-by: Marko Mäkelä
1 parent 1110bec commit 43ca605

File tree

5 files changed

+158
-44
lines changed

5 files changed

+158
-44
lines changed

mysql-test/suite/innodb/r/insert_into_empty.result

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,17 @@ SELECT * FROM t;
1313
a b
1414
1 3
1515
DROP TEMPORARY TABLE t;
16+
#
17+
# MDEV-24720 AHI removal during bulk index rollback
18+
#
19+
SET @save_ahi = @@global.innodb_adaptive_hash_index;
20+
SET GLOBAL innodb_adaptive_hash_index = 1;
21+
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
22+
BEGIN;
23+
INSERT INTO t1 SELECT * FROM seq_1_to_65536;
24+
ROLLBACK;
25+
CHECK TABLE t1;
26+
Table Op Msg_type Msg_text
27+
test.t1 check status OK
28+
DROP TABLE t1;
29+
SET GLOBAL innodb_adaptive_hash_index = @save_ahi;

mysql-test/suite/innodb/t/insert_into_empty.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
--source include/have_innodb.inc
2+
--source include/have_sequence.inc
23

34
--echo #
45
--echo # MDEV-24715 Assertion !node->table->skip_alter_undo
@@ -12,3 +13,16 @@ CREATE TEMPORARY TABLE t (a INT UNIQUE) ENGINE=InnoDB
1213
REPLACE SELECT 1 AS a, 2 AS b UNION SELECT 1 AS a, 3 AS c;
1314
SELECT * FROM t;
1415
DROP TEMPORARY TABLE t;
16+
17+
--echo #
18+
--echo # MDEV-24720 AHI removal during bulk index rollback
19+
--echo #
20+
SET @save_ahi = @@global.innodb_adaptive_hash_index;
21+
SET GLOBAL innodb_adaptive_hash_index = 1;
22+
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
23+
BEGIN;
24+
INSERT INTO t1 SELECT * FROM seq_1_to_65536;
25+
ROLLBACK;
26+
CHECK TABLE t1;
27+
DROP TABLE t1;
28+
SET GLOBAL innodb_adaptive_hash_index = @save_ahi;

storage/innobase/btr/btr0btr.cc

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,11 @@ static
11181118
void
11191119
btr_free_but_not_root(
11201120
buf_block_t* block,
1121-
mtr_log_t log_mode)
1121+
mtr_log_t log_mode
1122+
#ifdef BTR_CUR_HASH_ADAPT
1123+
,bool ahi=false
1124+
#endif
1125+
)
11221126
{
11231127
mtr_t mtr;
11241128

@@ -1147,7 +1151,11 @@ btr_free_but_not_root(
11471151
fsp0fsp. */
11481152

11491153
bool finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
1150-
&mtr);
1154+
&mtr
1155+
#ifdef BTR_CUR_HASH_ADAPT
1156+
, ahi
1157+
#endif /* BTR_CUR_HASH_ADAPT */
1158+
);
11511159
mtr_commit(&mtr);
11521160

11531161
if (!finished) {
@@ -1167,7 +1175,11 @@ btr_free_but_not_root(
11671175
#endif /* UNIV_BTR_DEBUG */
11681176

11691177
finished = fseg_free_step_not_header(
1170-
root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
1178+
root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr
1179+
#ifdef BTR_CUR_HASH_ADAPT
1180+
,ahi
1181+
#endif /* BTR_CUR_HASH_ADAPT */
1182+
);
11711183
mtr_commit(&mtr);
11721184

11731185
if (!finished) {
@@ -1191,12 +1203,22 @@ void dict_index_t::clear(que_thr_t *thr)
11911203
table->space->zip_size(),
11921204
RW_X_LATCH, &mtr))
11931205
{
1194-
btr_free_but_not_root(root_block, mtr.get_log_mode());
1206+
btr_free_but_not_root(root_block, mtr.get_log_mode()
1207+
#ifdef BTR_CUR_HASH_ADAPT
1208+
,n_ahi_pages() != 0
1209+
#endif
1210+
);
1211+
11951212
mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
11961213
FSEG_HEADER_SIZE, 0);
11971214
if (fseg_create(table->space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr, false,
11981215
root_block))
11991216
btr_root_page_init(root_block, id, this, &mtr);
1217+
#ifdef BTR_CUR_HASH_ADAPT
1218+
if (root_block->index)
1219+
btr_search_drop_page_hash_index(root_block);
1220+
ut_ad(n_ahi_pages() == 0);
1221+
#endif
12001222
}
12011223

12021224
mtr.commit();

storage/innobase/fsp/fsp0fsp.cc

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,15 +2402,20 @@ fsp_reserve_free_extents(
24022402
@param[in] seg_inode segment inode
24032403
@param[in,out] space tablespace
24042404
@param[in] offset page number
2405-
@param[in,out] mtr mini-transaction */
2405+
@param[in,out] mtr mini-transaction
2406+
@param[in] ahi Drop adaptive hash index */
24062407
static
24072408
void
24082409
fseg_free_page_low(
24092410
fseg_inode_t* seg_inode,
24102411
buf_block_t* iblock,
24112412
fil_space_t* space,
24122413
page_no_t offset,
2413-
mtr_t* mtr)
2414+
mtr_t* mtr
2415+
#ifdef BTR_CUR_HASH_ADAPT
2416+
,bool ahi=false
2417+
#endif /* BTR_CUR_HASH_ADAPT */
2418+
)
24142419
{
24152420
ib_id_t descr_id;
24162421
ib_id_t seg_id;
@@ -2423,6 +2428,13 @@ fseg_free_page_low(
24232428
ut_ad(iblock->frame == page_align(seg_inode));
24242429
ut_d(space->modify_check(*mtr));
24252430

2431+
#ifdef BTR_CUR_HASH_ADAPT
2432+
if (ahi) {
2433+
btr_search_drop_page_hash_when_freed(
2434+
page_id_t(space->id, offset));
2435+
}
2436+
#endif /* BTR_CUR_HASH_ADAPT */
2437+
24262438
const uint32_t extent_size = FSP_EXTENT_SIZE;
24272439
ut_ad(ut_is_2pow(extent_size));
24282440
buf_block_t* xdes;
@@ -2593,7 +2605,11 @@ fseg_free_extent(
25932605
buf_block_t* iblock,
25942606
fil_space_t* space,
25952607
uint32_t page,
2596-
mtr_t* mtr)
2608+
mtr_t* mtr
2609+
#ifdef BTR_CUR_HASH_ADAPT
2610+
,bool ahi=false
2611+
#endif /* BTR_CUR_HASH_ADAPT */
2612+
)
25972613
{
25982614

25992615
ut_ad(mtr != NULL);
@@ -2611,6 +2627,21 @@ fseg_free_extent(
26112627
const uint16_t xoffset= uint16_t(descr - xdes->frame + XDES_FLST_NODE);
26122628
const uint16_t ioffset= uint16_t(seg_inode - iblock->frame);
26132629

2630+
#ifdef BTR_CUR_HASH_ADAPT
2631+
if (ahi) {
2632+
for (uint32_t i = 0; i < FSP_EXTENT_SIZE; i++) {
2633+
if (!xdes_is_free(descr, i)) {
2634+
/* Drop search system page hash index
2635+
if the page is found in the pool and
2636+
is hashed */
2637+
btr_search_drop_page_hash_when_freed(
2638+
page_id_t(space->id,
2639+
first_page_in_extent + i));
2640+
}
2641+
}
2642+
}
2643+
#endif /* BTR_CUR_HASH_ADAPT */
2644+
26142645
if (xdes_is_full(descr)) {
26152646
flst_remove(iblock, static_cast<uint16_t>(FSEG_FULL + ioffset),
26162647
xdes, xoffset, mtr);
@@ -2638,19 +2669,24 @@ fseg_free_extent(
26382669
}
26392670
}
26402671

2641-
/**********************************************************************//**
2642-
Frees part of a segment. This function can be used to free a segment by
2643-
repeatedly calling this function in different mini-transactions. Doing
2644-
the freeing in a single mini-transaction might result in too big a
2645-
mini-transaction.
2672+
/** Frees part of a segment. This function can be used to free
2673+
a segment by repeatedly calling this function in different
2674+
mini-transactions. Doing the freeing in a single mini-transaction
2675+
might result in too big a mini-transaction.
2676+
@param header segment header; NOTE: if the header resides on first
2677+
page of the frag list of the segment, this pointer
2678+
becomes obsolete after the last freeing step
2679+
@param mtr mini-transaction
2680+
@param ahi Drop the adaptive hash index
26462681
@return whether the freeing was completed */
26472682
bool
26482683
fseg_free_step(
2649-
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
2650-
resides on the first page of the frag list
2651-
of the segment, this pointer becomes obsolete
2652-
after the last freeing step */
2653-
mtr_t* mtr) /*!< in/out: mini-transaction */
2684+
fseg_header_t* header,
2685+
mtr_t* mtr
2686+
#ifdef BTR_CUR_HASH_ADAPT
2687+
,bool ahi
2688+
#endif /* BTR_CUR_HASH_ADAPT */
2689+
)
26542690
{
26552691
ulint n;
26562692
fseg_inode_t* inode;
@@ -2686,7 +2722,11 @@ fseg_free_step(
26862722
if (descr != NULL) {
26872723
/* Free the extent held by the segment */
26882724
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
2689-
mtr);
2725+
mtr
2726+
#ifdef BTR_CUR_HASH_ADAPT
2727+
, ahi
2728+
#endif /* BTR_CUR_HASH_ADAPT */
2729+
);
26902730
DBUG_RETURN(false);
26912731
}
26922732

@@ -2702,7 +2742,11 @@ fseg_free_step(
27022742

27032743
page_no_t page_no = fseg_get_nth_frag_page_no(inode, n);
27042744

2705-
fseg_free_page_low(inode, iblock, space, page_no, mtr);
2745+
fseg_free_page_low(inode, iblock, space, page_no, mtr
2746+
#ifdef BTR_CUR_HASH_ADAPT
2747+
, ahi
2748+
#endif /* BTR_CUR_HASH_ADAPT */
2749+
);
27062750

27072751
buf_page_free(space, page_no, mtr);
27082752

@@ -2718,15 +2762,14 @@ fseg_free_step(
27182762
DBUG_RETURN(false);
27192763
}
27202764

2721-
/**********************************************************************//**
2722-
Frees part of a segment. Differs from fseg_free_step because this function
2723-
leaves the header page unfreed.
2724-
@return whether the freeing was completed, except for the header page */
27252765
bool
27262766
fseg_free_step_not_header(
2727-
fseg_header_t* header, /*!< in: segment header which must reside on
2728-
the first fragment page of the segment */
2729-
mtr_t* mtr) /*!< in/out: mini-transaction */
2767+
fseg_header_t* header,
2768+
mtr_t* mtr
2769+
#ifdef BTR_CUR_HASH_ADAPT
2770+
,bool ahi
2771+
#endif /* BTR_CUR_HASH_ADAPT */
2772+
)
27302773
{
27312774
ulint n;
27322775
xdes_t* descr;
@@ -2749,7 +2792,11 @@ fseg_free_step_not_header(
27492792
if (descr != NULL) {
27502793
/* Free the extent held by the segment */
27512794
fseg_free_extent(inode, iblock, space, xdes_get_offset(descr),
2752-
mtr);
2795+
mtr
2796+
#ifdef BTR_CUR_HASH_ADAPT
2797+
, ahi
2798+
#endif /* BTR_CUR_HASH_ADAPT */
2799+
);
27532800
return false;
27542801
}
27552802

@@ -2765,7 +2812,11 @@ fseg_free_step_not_header(
27652812
return true;
27662813
}
27672814

2768-
fseg_free_page_low(inode, iblock, space, page_no, mtr);
2815+
fseg_free_page_low(inode, iblock, space, page_no, mtr
2816+
#ifdef BTR_CUR_HASH_ADAPT
2817+
, ahi
2818+
#endif /* BTR_CUR_HASH_ADAPT */
2819+
);
27692820
buf_page_free(space, page_no, mtr);
27702821
return false;
27712822
}

storage/innobase/include/fsp0fsp.h

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -493,29 +493,42 @@ fseg_free_page(
493493
bool
494494
fseg_page_is_free(fil_space_t* space, unsigned page)
495495
MY_ATTRIBUTE((nonnull, warn_unused_result));
496-
/**********************************************************************//**
497-
Frees part of a segment. This function can be used to free a segment
498-
by repeatedly calling this function in different mini-transactions.
499-
Doing the freeing in a single mini-transaction might result in
500-
too big a mini-transaction.
496+
497+
/** Frees part of a segment. This function can be used to free
498+
a segment by repeatedly calling this function in different
499+
mini-transactions. Doing the freeing in a single mini-transaction
500+
might result in too big a mini-transaction.
501+
@param header segment header; NOTE: if the header resides on first
502+
page of the frag list of the segment, this pointer
503+
becomes obsolete after the last freeing step
504+
@param mtr mini-transaction
505+
@param ahi Drop the adaptive hash index
501506
@return whether the freeing was completed */
502507
bool
503508
fseg_free_step(
504-
fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
505-
resides on the first page of the frag list
506-
of the segment, this pointer becomes obsolete
507-
after the last freeing step */
508-
mtr_t* mtr) /*!< in/out: mini-transaction */
509+
fseg_header_t* header,
510+
mtr_t* mtr
511+
#ifdef BTR_CUR_HASH_ADAPT
512+
,bool ahi=false
513+
#endif /* BTR_CUR_HASH_ADAPT */
514+
)
509515
MY_ATTRIBUTE((warn_unused_result));
510-
/**********************************************************************//**
511-
Frees part of a segment. Differs from fseg_free_step because this function
512-
leaves the header page unfreed.
516+
517+
/** Frees part of a segment. Differs from fseg_free_step because
518+
this function leaves the header page unfreed.
519+
@param header segment header which must reside on the first
520+
fragment page of the segment
521+
@param mtr mini-transaction
522+
@param ahi drop the adaptive hash index
513523
@return whether the freeing was completed, except for the header page */
514524
bool
515525
fseg_free_step_not_header(
516-
fseg_header_t* header, /*!< in: segment header which must reside on
517-
the first fragment page of the segment */
518-
mtr_t* mtr) /*!< in/out: mini-transaction */
526+
fseg_header_t* header,
527+
mtr_t* mtr
528+
#ifdef BTR_CUR_HASH_ADAPT
529+
,bool ahi=false
530+
#endif /* BTR_CUR_HASH_ADAPT */
531+
)
519532
MY_ATTRIBUTE((warn_unused_result));
520533

521534
/** Reset the page type.

0 commit comments

Comments
 (0)