Fix subcompaction bug to allow running two subcompactions (#11501)

Summary:
as reported in https://github.com/facebook/rocksdb/issues/11476, RocksDB currently does not execute compactions in two subcompactions even when they qualify. This PR fixes this issue.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11501

Test Plan:
* Add a new unit test.
* Run crash test with max_subcompactions=2: `python3 tools/db_crashtest.py blackbox --simple  --subcompactions=2 --target_file_size_base=1048576 --compaction_style=0`
  * saw logs showing compactions being executed as 2 subcompactions
```
2023/06/01-17:28:44.028470 3147486 (Original Log Time 2023/06/01-17:28:44.025972) EVENT_LOG_v1 {"time_micros": 1685665724025939, "job": 6, "event": "compaction_finished", "compaction_time_micros": 34539, "compaction_time_cpu_micros": 26404, "output_level": 6, "num_output_files": 2, "total_output_size": 1109796, "num_input_records": 13188, "num_output_records": 13021, "num_subcompactions": 2, "output_compression": "NoCompression", "num_single_delete_mismatches": 0, "num_single_delete_fallthrough": 0, "lsm_state": [0, 0, 0, 0, 0, 0, 13]}
```

Reviewed By: ajkr

Differential Revision: D46411497

Pulled By: cbi42

fbshipit-source-id: 3ebfc02e19f78f782e114a9546dc3d481d496258
oxigraph-main
Changyu Bi 1 year ago committed by Facebook GitHub Bot
parent ddfcbea3e1
commit 2e8cc98ab2
  1. 2
      db/compaction/compaction_job.cc
  2. 53
      db/db_compaction_test.cc
  3. 1
      unreleased_history/bug_fixes/subcompaction_2.md

@ -260,7 +260,7 @@ void CompactionJob::Prepare() {
StopWatch sw(db_options_.clock, stats_, SUBCOMPACTION_SETUP_TIME); StopWatch sw(db_options_.clock, stats_, SUBCOMPACTION_SETUP_TIME);
GenSubcompactionBoundaries(); GenSubcompactionBoundaries();
} }
if (boundaries_.size() > 1) { if (boundaries_.size() >= 1) {
for (size_t i = 0; i <= boundaries_.size(); i++) { for (size_t i = 0; i <= boundaries_.size(); i++) {
compact_->sub_compact_states.emplace_back( compact_->sub_compact_states.emplace_back(
c, (i != 0) ? std::optional<Slice>(boundaries_[i - 1]) : std::nullopt, c, (i != 0) ? std::optional<Slice>(boundaries_[i - 1]) : std::nullopt,

@ -9753,6 +9753,59 @@ TEST_F(DBCompactionTest,
ASSERT_EQ(0, NumTableFilesAtLevel(5)); ASSERT_EQ(0, NumTableFilesAtLevel(5));
} }
TEST_F(DBCompactionTest, NumberOfSubcompactions) {
// Tests that expected number of subcompactions are created.
class SubCompactionEventListener : public EventListener {
public:
void OnSubcompactionCompleted(const SubcompactionJobInfo&) override {
sub_compaction_finished_++;
}
void OnCompactionCompleted(DB*, const CompactionJobInfo&) override {
compaction_finished_++;
}
std::atomic<int> sub_compaction_finished_{0};
std::atomic<int> compaction_finished_{0};
};
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleLevel;
options.compression = kNoCompression;
const int kFileSize = 100 << 10; // 100KB
options.target_file_size_base = kFileSize;
const int kLevel0CompactTrigger = 2;
options.level0_file_num_compaction_trigger = kLevel0CompactTrigger;
Destroy(options);
Random rnd(301);
// Exposing internal implementation detail here where the
// number of subcompactions depends on the size of data
// being compacted. In particular, to enable x subcompactions,
// we need to compact at least x * target file size amount
// of data.
//
// Will write two files below to avoid trivial move.
// Size written in total: 500 * 1000 * 2 ~ 10MB ~ 100 * target file size.
const int kValueSize = 500;
const int kNumKeyPerFile = 1000;
for (int i = 1; i <= 8; ++i) {
options.max_subcompactions = i;
SubCompactionEventListener* listener = new SubCompactionEventListener();
options.listeners.clear();
options.listeners.emplace_back(listener);
TryReopen(options);
for (int file = 0; file < kLevel0CompactTrigger; ++file) {
for (int key = file; key < 2 * kNumKeyPerFile; key += 2) {
ASSERT_OK(Put(Key(key), rnd.RandomString(kValueSize)));
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
ASSERT_EQ(listener->compaction_finished_, 1);
EXPECT_EQ(listener->sub_compaction_finished_, i);
Destroy(options);
}
}
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) { int main(int argc, char** argv) {

@ -0,0 +1 @@
Fix a bug where compactions that are qualified to be run as 2 subcompactions were only run as one subcompaction.
Loading…
Cancel
Save