Skip to content

Commit

Permalink
Cancel manual compactions waiting on automatic compactions to drain (f…
Browse files Browse the repository at this point in the history
…acebook#8991)

Summary: Pull Request resolved: facebook#8991

Test Plan: the new test hangs forever without this fix and passes with this fix.

Reviewed By: hx235

Differential Revision: D31456419

Pulled By: ajkr

fbshipit-source-id: a82c0e5560b6e6153089dccd8e46163c61b07bff
  • Loading branch information
ajkr committed Oct 11, 2021
1 parent 307a655 commit ab2aceb
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
4 changes: 4 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Rocksdb Change Log
## Unreleased
### Bug Fixes
* Fix `DisableManualCompaction()` to cancel compactions even when they are waiting on automatic compactions to drain due to `CompactRangeOptions::exclusive_manual_compactions == true`.

## 6.25.1 (2021-09-28)
### Bug Fixes
* Fixes a bug in directed IO mode when calling MultiGet() for blobs in the same blob file. The bug is caused by not sorting the blob read requests by file offsets.
Expand Down
43 changes: 43 additions & 0 deletions db/db_compaction_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6817,6 +6817,49 @@ TEST_F(DBCompactionTest, FIFOWarm) {
Destroy(options);
}

TEST_F(DBCompactionTest,
DisableManualCompactionDoesNotWaitForDrainingAutomaticCompaction) {
// When `CompactRangeOptions::exclusive_manual_compaction == true`, we wait
// for automatic compactions to drain before starting the manual compaction.
// This test verifies `DisableManualCompaction()` can cancel such a compaction
// without waiting for the drain to complete.
const int kNumL0Files = 4;

// Enforces manual compaction enters wait loop due to pending automatic
// compaction.
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
{{"DBImpl::BGWorkCompaction", "DBImpl::RunManualCompaction:NotScheduled"},
{"DBImpl::RunManualCompaction:WaitScheduled",
"BackgroundCallCompaction:0"}});
// The automatic compaction will cancel the waiting manual compaction.
// Completing this implies the cancellation did not wait on automatic
// compactions to finish.
bool callback_completed = false;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"BackgroundCallCompaction:0", [&](void* /*arg*/) {
db_->DisableManualCompaction();
callback_completed = true;
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();

Options options = CurrentOptions();
options.level0_file_num_compaction_trigger = kNumL0Files;
Reopen(options);

for (int i = 0; i < kNumL0Files; ++i) {
ASSERT_OK(Put(Key(1), "value1"));
ASSERT_OK(Put(Key(2), "value2"));
ASSERT_OK(Flush());
}

CompactRangeOptions cro;
cro.exclusive_manual_compaction = true;
ASSERT_TRUE(db_->CompactRange(cro, nullptr, nullptr).IsIncomplete());

ASSERT_OK(dbfull()->TEST_WaitForCompact());
ASSERT_TRUE(callback_completed);
}

#endif // !defined(ROCKSDB_LITE)

} // namespace ROCKSDB_NAMESPACE
Expand Down
23 changes: 21 additions & 2 deletions db/db_impl/db_impl_compaction_flush.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1714,8 +1714,11 @@ Status DBImpl::RunManualCompaction(

// When a manual compaction arrives, temporarily disable scheduling of
// non-manual compactions and wait until the number of scheduled compaction
// jobs drops to zero. This is needed to ensure that this manual compaction
// can compact any range of keys/files.
// jobs drops to zero. This used to be needed to ensure that this manual
// compaction can compact any range of keys/files. Now it is optional
// (see `CompactRangeOptions::exclusive_manual_compaction`). The use case for
// `exclusive_manual_compaction=true` (the default) is unclear beyond not
// trusting the new code.
//
// HasPendingManualCompaction() is true when at least one thread is inside
// RunManualCompaction(), i.e. during that time no other compaction will
Expand All @@ -1729,8 +1732,20 @@ Status DBImpl::RunManualCompaction(
AddManualCompaction(&manual);
TEST_SYNC_POINT_CALLBACK("DBImpl::RunManualCompaction:NotScheduled", &mutex_);
if (exclusive) {
// Limitation: there's no way to wake up the below loop when user sets
// `*manual.canceled`. So `CompactRangeOptions::exclusive_manual_compaction`
// and `CompactRangeOptions::canceled` might not work well together.
while (bg_bottom_compaction_scheduled_ > 0 ||
bg_compaction_scheduled_ > 0) {
if (manual_compaction_paused_ > 0 ||
(manual.canceled != nullptr && *manual.canceled == true)) {
// Pretend the error came from compaction so the below cleanup/error
// handling code can process it.
manual.done = true;
manual.status =
Status::Incomplete(Status::SubCode::kManualCompactionPaused);
break;
}
TEST_SYNC_POINT("DBImpl::RunManualCompaction:WaitScheduled");
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
Expand Down Expand Up @@ -2223,6 +2238,10 @@ Status DBImpl::EnableAutoCompaction(
void DBImpl::DisableManualCompaction() {
InstrumentedMutexLock l(&mutex_);
manual_compaction_paused_.fetch_add(1, std::memory_order_release);

// Wake up manual compactions waiting to start.
bg_cv_.SignalAll();

// Wait for any pending manual compactions to finish (typically through
// failing with `Status::Incomplete`) prior to returning. This way we are
// guaranteed no pending manual compaction will commit while manual
Expand Down
3 changes: 3 additions & 0 deletions include/rocksdb/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,9 @@ struct CompactRangeOptions {
Slice* full_history_ts_low = nullptr;

// Allows cancellation of an in-progress manual compaction.
//
// Cancellation can be delayed waiting on automatic compactions when used
// together with `exclusive_manual_compaction == true`.
std::atomic<bool>* canceled = nullptr;
};

Expand Down

0 comments on commit ab2aceb

Please sign in to comment.