Fix an issue of manual / auto compaction data race
Summary: A data race between a manual and an auto compaction can cause a scheduled automatic compaction to be cancelled and never rescheduled again. This may cause a condition of hanging forever. Fix this by always making sure the cancelled compaction is put back to the compaction queue. Closes https://github.com/facebook/rocksdb/pull/2238 Differential Revision: D4984591 Pulled By: siying fbshipit-source-id: 3ab153886403c7b991896dcb2158b96cac12f227
This commit is contained in:
parent
6798d1f3be
commit
af6fe69e4c
@ -1852,6 +1852,47 @@ TEST_F(DBCompactionTest, L0_CompactionBug_Issue44_b) {
|
|||||||
} while (ChangeCompactOptions());
|
} while (ChangeCompactOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DBCompactionTest, ManualAutoRace) {
|
||||||
|
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||||
|
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||||
|
{{"DBImpl::BGWorkCompaction", "DBCompactionTest::ManualAutoRace:1"},
|
||||||
|
{"DBImpl::RunManualCompaction:WaitScheduled",
|
||||||
|
"BackgroundCallCompaction:0"}});
|
||||||
|
|
||||||
|
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||||
|
|
||||||
|
Put(1, "foo", "");
|
||||||
|
Put(1, "bar", "");
|
||||||
|
Flush(1);
|
||||||
|
Put(1, "foo", "");
|
||||||
|
Put(1, "bar", "");
|
||||||
|
// Generate four files in CF 0, which should trigger an auto compaction
|
||||||
|
Put("foo", "");
|
||||||
|
Put("bar", "");
|
||||||
|
Flush();
|
||||||
|
Put("foo", "");
|
||||||
|
Put("bar", "");
|
||||||
|
Flush();
|
||||||
|
Put("foo", "");
|
||||||
|
Put("bar", "");
|
||||||
|
Flush();
|
||||||
|
Put("foo", "");
|
||||||
|
Put("bar", "");
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// The auto compaction is scheduled but waited until here
|
||||||
|
TEST_SYNC_POINT("DBCompactionTest::ManualAutoRace:1");
|
||||||
|
// The auto compaction will wait until the the manual compaction is registerd
|
||||||
|
// before processing so that it will be cancelled.
|
||||||
|
dbfull()->CompactRange(CompactRangeOptions(), handles_[1], nullptr, nullptr);
|
||||||
|
ASSERT_EQ("0,1", FilesPerLevel(1));
|
||||||
|
|
||||||
|
// Eventually the cancelled compaction will be rescheduled and executed.
|
||||||
|
dbfull()->TEST_WaitForCompact();
|
||||||
|
ASSERT_EQ("0,1", FilesPerLevel(0));
|
||||||
|
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(DBCompactionTestWithParam, ManualCompaction) {
|
TEST_P(DBCompactionTestWithParam, ManualCompaction) {
|
||||||
Options options = CurrentOptions();
|
Options options = CurrentOptions();
|
||||||
options.max_subcompactions = max_subcompactions_;
|
options.max_subcompactions = max_subcompactions_;
|
||||||
|
@ -828,6 +828,7 @@ Status DBImpl::RunManualCompaction(ColumnFamilyData* cfd, int input_level,
|
|||||||
TEST_SYNC_POINT_CALLBACK("DBImpl::RunManualCompaction:NotScheduled", &mutex_);
|
TEST_SYNC_POINT_CALLBACK("DBImpl::RunManualCompaction:NotScheduled", &mutex_);
|
||||||
if (exclusive) {
|
if (exclusive) {
|
||||||
while (bg_compaction_scheduled_ > 0) {
|
while (bg_compaction_scheduled_ > 0) {
|
||||||
|
TEST_SYNC_POINT("DBImpl::RunManualCompaction:WaitScheduled");
|
||||||
ROCKS_LOG_INFO(
|
ROCKS_LOG_INFO(
|
||||||
immutable_db_options_.info_log,
|
immutable_db_options_.info_log,
|
||||||
"[%s] Manual compaction waiting for all other scheduled background "
|
"[%s] Manual compaction waiting for all other scheduled background "
|
||||||
@ -1394,6 +1395,16 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
|||||||
: m->manual_end->DebugString().c_str()));
|
: m->manual_end->DebugString().c_str()));
|
||||||
}
|
}
|
||||||
} else if (!compaction_queue_.empty()) {
|
} else if (!compaction_queue_.empty()) {
|
||||||
|
if (HaveManualCompaction(compaction_queue_.front())) {
|
||||||
|
// Can't compact right now, but try again later
|
||||||
|
TEST_SYNC_POINT("DBImpl::BackgroundCompaction()::Conflict");
|
||||||
|
|
||||||
|
// Stay in the compaciton queue.
|
||||||
|
unscheduled_compactions_++;
|
||||||
|
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
// cfd is referenced here
|
// cfd is referenced here
|
||||||
auto cfd = PopFirstFromCompactionQueue();
|
auto cfd = PopFirstFromCompactionQueue();
|
||||||
// We unreference here because the following code will take a Ref() on
|
// We unreference here because the following code will take a Ref() on
|
||||||
@ -1408,12 +1419,6 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
|||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HaveManualCompaction(cfd)) {
|
|
||||||
// Can't compact right now, but try again later
|
|
||||||
TEST_SYNC_POINT("DBImpl::BackgroundCompaction()::Conflict");
|
|
||||||
return Status::OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick up latest mutable CF Options and use it throughout the
|
// Pick up latest mutable CF Options and use it throughout the
|
||||||
// compaction job
|
// compaction job
|
||||||
// Compaction makes a copy of the latest MutableCFOptions. It should be used
|
// Compaction makes a copy of the latest MutableCFOptions. It should be used
|
||||||
|
Loading…
Reference in New Issue
Block a user