Skip to content

Commit 6a4e5bf

Browse files
committed
MDEV-25852: Orphan #sql*.ibd files are left behind
The implementation of MDEV-24626 was not entirely correct. We could occasionally fail to remove some *.ibd files on recovery. deferred_spaces: Keep track of FILE_DELETE records. deferred_spaces.add(): Do not allow duplicate file names. recv_rename_files(): Preserve some of renamed_spaces entries for deferred_spaces.reinit_all(). Thanks to Thirunarayanan Balathandayuthapani for noticing that deferred_spaces.add() must filter out duplicate file names, as well as some debugging help.
1 parent 65f1a42 commit 6a4e5bf

File tree

1 file changed

+87
-19
lines changed

1 file changed

+87
-19
lines changed

storage/innobase/log/log0recv.cc

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ static struct
597597
lsn_t lsn;
598598
/** File name from the FILE_ record */
599599
std::string file_name;
600+
/** whether a FILE_DELETE record was encountered */
601+
mutable bool deleted;
600602
};
601603

602604
using map= std::map<const uint32_t, item, std::less<const uint32_t>,
@@ -638,11 +640,39 @@ static struct
638640

639641
char *fil_path= fil_make_filepath(nullptr, {filename, strlen(filename)},
640642
IBD, false);
641-
const item defer= {lsn, fil_path};
642-
auto p= defers.emplace(space, defer);
643-
if (!p.second && p.first->second.lsn <= defer.lsn)
644-
p.first->second= defer;
643+
const item defer{lsn, fil_path, false};
645644
ut_free(fil_path);
645+
646+
/* The file name must be unique. Keep the one with the latest LSN. */
647+
auto d= defers.begin();
648+
649+
while (d != defers.end())
650+
{
651+
if (d->second.file_name != defer.file_name)
652+
++d;
653+
else if (d->first == space)
654+
{
655+
/* Neither the file name nor the tablespace ID changed.
656+
Update the LSN if needed. */
657+
if (d->second.lsn < lsn)
658+
d->second.lsn= lsn;
659+
return;
660+
}
661+
else if (d->second.lsn < lsn)
662+
defers.erase(d++);
663+
else
664+
{
665+
ut_ad(d->second.lsn != lsn);
666+
return; /* A later tablespace already has this name. */
667+
}
668+
}
669+
670+
auto p= defers.emplace(space, defer);
671+
if (!p.second && p.first->second.lsn <= lsn)
672+
{
673+
p.first->second.lsn= lsn;
674+
p.first->second.file_name= defer.file_name;
675+
}
646676
}
647677

648678
void remove(uint32_t space)
@@ -684,20 +714,42 @@ static struct
684714
const uint32_t space_id{d->first};
685715
recv_sys_t::map::iterator p{recv_sys.pages.lower_bound({space_id,0})};
686716

687-
if (p == recv_sys.pages.end() || p->first.space() != space_id)
717+
if (d->second.deleted ||
718+
p == recv_sys.pages.end() || p->first.space() != space_id)
688719
{
689-
/* No pages were recovered. We create a dummy tablespace,
690-
and let dict_drop_index_tree() delete the file. */
720+
/* We found a FILE_DELETE record for the tablespace, or
721+
there were no buffered records. Either way, we must create a
722+
dummy tablespace with the latest known name,
723+
for dict_drop_index_tree(). */
724+
while (p != recv_sys.pages.end() && p->first.space() == space_id)
725+
{
726+
recv_sys_t::map::iterator r= p++;
727+
r->second.log.clear();
728+
recv_sys.pages.erase(r);
729+
}
691730
recv_spaces_t::iterator it{recv_spaces.find(space_id)};
692731
if (it != recv_spaces.end())
693-
create(it, d->second.file_name, static_cast<uint32_t>
732+
{
733+
const std::string *name= &d->second.file_name;
734+
if (d->second.deleted)
735+
{
736+
const auto r= renamed_spaces.find(space_id);
737+
if (r != renamed_spaces.end())
738+
name= &r->second;
739+
bool exists;
740+
os_file_type_t ftype;
741+
if (!os_file_status(name->c_str(), &exists, &ftype) || !exists)
742+
goto processed;
743+
}
744+
create(it, *name, static_cast<uint32_t>
694745
(1U << FSP_FLAGS_FCRC32_POS_MARKER |
695-
FSP_FLAGS_FCRC32_PAGE_SSIZE()), nullptr, 0);
746+
FSP_FLAGS_FCRC32_PAGE_SSIZE()), nullptr, 0);
747+
}
696748
}
697749
else
698750
fail= recv_sys.recover_deferred(p, d->second.file_name, free_block);
699-
auto e= d++;
700-
defers.erase(e);
751+
processed:
752+
defers.erase(d++);
701753
if (fail)
702754
break;
703755
if (free_block)
@@ -791,11 +843,13 @@ bool recv_sys_t::recover_deferred(recv_sys_t::map::iterator &p,
791843
space->release();
792844
return false;
793845
}
846+
goto fail;
794847
}
795848

796849
block->unfix();
797850
}
798851

852+
fail:
799853
ib::error() << "Cannot apply log to " << first
800854
<< " of corrupted file '" << name << "'";
801855
return true;
@@ -1034,9 +1088,11 @@ fil_name_process(char* name, ulint len, ulint space_id,
10341088

10351089
if (deleted) {
10361090
/* Got FILE_DELETE */
1091+
if (auto d = deferred_spaces.find(static_cast<uint32_t>(
1092+
space_id))) {
1093+
d->deleted = true;
1094+
}
10371095

1038-
deferred_spaces.remove(
1039-
static_cast<uint32_t>(space_id));
10401096
if (!p.second && f.status != file_name_t::DELETED) {
10411097
f.status = file_name_t::DELETED;
10421098
if (f.space != NULL) {
@@ -2988,18 +3044,26 @@ void recv_sys_t::apply(bool last_batch)
29883044
auto d= deferred_spaces.defers.find(space_id);
29893045
if (d != deferred_spaces.defers.end())
29903046
{
2991-
if (recover_deferred(p, d->second.file_name, free_block))
3047+
if (d->second.deleted)
29923048
{
2993-
if (!srv_force_recovery)
2994-
set_corrupt_fs();
3049+
/* For deleted files we must preserve the entry in deferred_spaces */
3050+
erase_for_space:
29953051
while (p != pages.end() && p->first.space() == space_id)
29963052
{
29973053
map::iterator r= p++;
29983054
r->second.log.clear();
29993055
pages.erase(r);
30003056
}
30013057
}
3002-
deferred_spaces.defers.erase(d);
3058+
else if (recover_deferred(p, d->second.file_name, free_block))
3059+
{
3060+
if (!srv_force_recovery)
3061+
set_corrupt_fs();
3062+
deferred_spaces.defers.erase(d);
3063+
goto erase_for_space;
3064+
}
3065+
else
3066+
deferred_spaces.defers.erase(d);
30033067
if (!free_block)
30043068
goto next_free_block;
30053069
p= pages.lower_bound(page_id);
@@ -3685,12 +3749,16 @@ static dberr_t recv_rename_files()
36853749

36863750
dberr_t err= DB_SUCCESS;
36873751

3688-
for (const auto &r : renamed_spaces)
3752+
for (auto i= renamed_spaces.begin(); i != renamed_spaces.end(); )
36893753
{
3754+
const auto &r= *i;
36903755
const uint32_t id= r.first;
36913756
fil_space_t *space= fil_space_t::get(id);
36923757
if (!space)
3758+
{
3759+
i++;
36933760
continue;
3761+
}
36943762
ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
36953763
char *old= space->chain.start->name;
36963764
if (r.second != old)
@@ -3743,8 +3811,8 @@ static dberr_t recv_rename_files()
37433811
recv_sys.set_corrupt_fs();
37443812
break;
37453813
}
3814+
renamed_spaces.erase(i++);
37463815
}
3747-
renamed_spaces.clear();
37483816
return err;
37493817
}
37503818

0 commit comments

Comments
 (0)