mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 14:47:40 +08:00
Fix a missing CV signal in FindObsoleteFiles() (#14069)
Summary: Fixed a missing CV signal when `FindObsoleteFiles()` decides there is nothing to purge and then decrements `pending_purge_obsolete_files_` to zero. This bug could cause `DB::GetSortedWalFiles()` to hang, at least. Pull Request resolved: https://github.com/facebook/rocksdb/pull/14069 Test Plan: unit test repro Reviewed By: hx235 Differential Revision: D85453534 Pulled By: cbi42 fbshipit-source-id: cf5cfe7f5087459ca1f1f28ce81ea6afc84178f0
This commit is contained in:
committed by
meta-codesync[bot]
parent
2edc660e28
commit
e687ca79b4
@@ -109,6 +109,7 @@ Status DBImpl::GetSortedWalFilesImpl(VectorWalPtr& files, bool need_seqnos) {
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
while (pending_purge_obsolete_files_ > 0 || bg_purge_scheduled_ > 0) {
|
||||
TEST_SYNC_POINT("DBImpl::GetSortedWalFilesImpl:WaitPurge");
|
||||
bg_cv_.Wait();
|
||||
}
|
||||
|
||||
|
||||
@@ -267,6 +267,9 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
if (!job_context->HaveSomethingToDelete()) {
|
||||
mutex_.AssertHeld();
|
||||
--pending_purge_obsolete_files_;
|
||||
if (pending_purge_obsolete_files_ == 0) {
|
||||
bg_cv_.SignalAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -303,6 +303,47 @@ TEST_F(ObsoleteFilesTest, BlobFiles) {
|
||||
ASSERT_EQ(deleted_files, expected_deleted_files);
|
||||
}
|
||||
|
||||
TEST_F(ObsoleteFilesTest, GetSortedWalFilesHangsAfterNoopPurge) {
|
||||
// This test used to trigger a hang in `DB::GetSortedWalFiles()`, where it
|
||||
// would wait for a no-op purge that did not signal the CV upon completion.
|
||||
|
||||
// Grab an iterator and flush to switch the super version. That way, when the
|
||||
// iterator is destroyed, it will go through the purge path.
|
||||
DB* db = db_; // Only using `db` makes it clear we only use DB-level APIs.
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key", "value"));
|
||||
std::unique_ptr<Iterator> iter(db->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Sync points ensure `GetSortedWalFiles()` waits for a purge after
|
||||
// `FindObsoleteFiles()` releases the mutex but before its corresponding purge
|
||||
// completes.
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"FindObsoleteFiles::PostMutexUnlock", [&](void* /* arg */) {
|
||||
TEST_SYNC_POINT(
|
||||
"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:"
|
||||
"InCallback:1");
|
||||
TEST_SYNC_POINT(
|
||||
"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:"
|
||||
"InCallback:2");
|
||||
});
|
||||
SyncPoint::GetInstance()->LoadDependency({
|
||||
{"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:InCallback:1",
|
||||
"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:Thread:Begin"},
|
||||
{"DBImpl::GetSortedWalFilesImpl:WaitPurge",
|
||||
"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:InCallback:2"},
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
port::Thread get_sorted_wal_files_thread([db]() {
|
||||
TEST_SYNC_POINT(
|
||||
"ObsoleteFilesTest::GetSortedWalFilesHangsAfterNoopPurge:Thread:Begin");
|
||||
VectorWalPtr files;
|
||||
ASSERT_OK(db->GetSortedWalFiles(files));
|
||||
});
|
||||
iter.reset();
|
||||
get_sorted_wal_files_thread.join();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Fixed a bug where `DB::GetSortedWalFiles()` could hang when waiting for a purge operation that found nothing to do (potentially triggered by iterator release, flush, compaction, etc.).
|
||||
Reference in New Issue
Block a user