Skip to content

Commit 2ceadb3

Browse files
committed
MDEV-25506 (2 of 3): Kill during DDL leaves orphan .ibd file
dict_drop_index_tree(): Even if SYS_INDEXES.PAGE contains the special value FIL_NULL, the tablespace identified by SYS_INDEXES.SPACE may exist and may need to be dropped. This would definitely be the case if the server had been killed right after a FILE_CREATE record was persistently written during CREATE TABLE, but before the transaction was committed. btr_free_if_exists(): Simplify the interface, to avoid repeated tablespace lookup. One more scenario is known to be broken: If the server is killed during DROP TABLE (or table-rebuilding ALTER TABLE) right after a FILE_DELETE record has been persistently written but before the file was deleted, then we could end up recovering no tablespace at all, and failing to delete the file, in either of fil_name_process() or dict_drop_index_tree(). Thanks to Elena Stepanova for providing "rr replay" and data directories of these scenarios.
1 parent cc2ddde commit 2ceadb3

File tree

3 files changed

+24
-33
lines changed

3 files changed

+24
-33
lines changed

storage/innobase/btr/btr0btr.cc

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,23 +1225,20 @@ void dict_index_t::clear(que_thr_t *thr)
12251225
}
12261226

12271227
/** Free a persistent index tree if it exists.
1228-
@param[in] page_id root page id
1229-
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
1228+
@param[in,out] space tablespce
1229+
@param[in] page root page number
12301230
@param[in] index_id PAGE_INDEX_ID contents
12311231
@param[in,out] mtr mini-transaction */
1232-
void btr_free_if_exists(const page_id_t page_id, ulint zip_size,
1232+
void btr_free_if_exists(fil_space_t *space, uint32_t page,
12331233
index_id_t index_id, mtr_t *mtr)
12341234
{
1235-
if (fil_space_t *space= fil_space_t::get(page_id.space()))
1235+
if (buf_block_t *root= btr_free_root_check(page_id_t(space->id, page),
1236+
space->zip_size(),
1237+
index_id, mtr))
12361238
{
1237-
if (buf_block_t *root= btr_free_root_check(page_id, zip_size, index_id,
1238-
mtr))
1239-
{
1240-
btr_free_but_not_root(root, mtr->get_log_mode());
1241-
mtr->set_named_space(space);
1242-
btr_free_root(root, mtr);
1243-
}
1244-
space->release();
1239+
btr_free_but_not_root(root, mtr->get_log_mode());
1240+
mtr->set_named_space(space);
1241+
btr_free_root(root, mtr);
12451242
}
12461243
}
12471244

storage/innobase/dict/dict0crea.cc

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -871,17 +871,8 @@ void dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, dict_table_t *table,
871871
if (len != 4)
872872
goto rec_corrupted;
873873

874-
if (root_page_no == FIL_NULL)
875-
/* The tree has already been freed */
876-
return;
877-
878-
static_assert(FIL_NULL == 0xffffffff, "compatibility");
879-
static_assert(DICT_FLD__SYS_INDEXES__PAGE_NO ==
880-
DICT_FLD__SYS_INDEXES__SPACE + 1, "compatibility");
881-
mtr->memset(btr_pcur_get_block(pcur), page_offset(p + 4), 4, 0xff);
882-
883874
const uint32_t space_id= mach_read_from_4(p);
884-
ut_ad(space_id < SRV_TMP_SPACE_ID);
875+
ut_ad(root_page_no == FIL_NULL || space_id <= SRV_SPACE_ID_UPPER_BOUND);
885876

886877
if (space_id && (type & DICT_CLUSTERED))
887878
{
@@ -891,13 +882,20 @@ void dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, dict_table_t *table,
891882
ut_ad(!table);
892883
fil_delete_tablespace(space_id, true);
893884
}
885+
else if (root_page_no == FIL_NULL)
886+
/* The tree has already been freed */;
894887
else if (fil_space_t*s= fil_space_t::get(space_id))
895888
{
896889
/* Ensure that the tablespace file exists
897890
in order to avoid a crash in buf_page_get_gen(). */
898891
if (root_page_no < s->get_size())
899-
btr_free_if_exists(page_id_t(space_id, root_page_no), s->zip_size(),
900-
mach_read_from_8(rec + 8), mtr);
892+
{
893+
static_assert(FIL_NULL == 0xffffffff, "compatibility");
894+
static_assert(DICT_FLD__SYS_INDEXES__PAGE_NO ==
895+
DICT_FLD__SYS_INDEXES__SPACE + 1, "compatibility");
896+
mtr->memset(btr_pcur_get_block(pcur), page_offset(p + 4), 4, 0xff);
897+
btr_free_if_exists(s, root_page_no, mach_read_from_8(rec + 8), mtr);
898+
}
901899
s->release();
902900
}
903901
}

storage/innobase/include/btr0btr.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2012, Facebook Inc.
5-
Copyright (c) 2014, 2020, MariaDB Corporation.
5+
Copyright (c) 2014, 2021, MariaDB Corporation.
66
77
This program is free software; you can redistribute it and/or modify it under
88
the terms of the GNU General Public License as published by the Free Software
@@ -330,16 +330,12 @@ btr_create(
330330
mtr_t* mtr);
331331

332332
/** Free a persistent index tree if it exists.
333-
@param[in] page_id root page id
334-
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
333+
@param[in,out] space tablespce
334+
@param[in] page root page number
335335
@param[in] index_id PAGE_INDEX_ID contents
336336
@param[in,out] mtr mini-transaction */
337-
void
338-
btr_free_if_exists(
339-
const page_id_t page_id,
340-
ulint zip_size,
341-
index_id_t index_id,
342-
mtr_t* mtr);
337+
void btr_free_if_exists(fil_space_t *space, uint32_t page,
338+
index_id_t index_id, mtr_t *mtr);
343339

344340
/** Free an index tree in a temporary tablespace.
345341
@param[in] page_id root page id */

0 commit comments

Comments
 (0)