From 4428c7618103a1edc8ade238ca226e6aa33f8ac6 Mon Sep 17 00:00:00 2001 From: sdong Date: Thu, 30 Jun 2022 18:04:23 -0700 Subject: [PATCH] Multi-File Trivial Move in L0->L1 (#10188) Summary: In leveled compaction, L0->L1 trivial move will allow more than one file to be moved in one compaction. This would allow L0 files to be moved down faster when data is loaded in sequential order, making slowdown or stop condition harder to hit. Also seek L0->L1 trivial move when only some files qualify. 1. We always try to find L0->L1 trivial move from the oldest files. Keep including newer files, until adding a new file won't trigger a trivial move 2. Modify the trivial move condition so that this compaction would be tagged as trivial move. Pull Request resolved: https://github.com/facebook/rocksdb/pull/10188 Test Plan: See throughput improvements with db_bench with fast fillseq benchmark and small L0 files: ./db_bench_l0_move --benchmarks=fillseq --compression_type=lz4 --write_buffer_size=5000000 --num=100000000 --value_size=1000 -level_compaction_dynamic_level_bytes The throughput improved by about 50%. Stalling still happens though. Reviewed By: jay-zhuang Differential Revision: D37224743 fbshipit-source-id: 8958d97f22e12bdfc14d2e85930f6fa0070e9659 --- HISTORY.md | 1 + db/compaction/compaction.cc | 11 +- db/compaction/compaction.h | 6 + db/compaction/compaction_picker.cc | 10 +- db/compaction/compaction_picker.h | 2 + db/compaction/compaction_picker_fifo.cc | 10 +- db/compaction/compaction_picker_level.cc | 134 +++++++++++++++---- db/compaction/compaction_picker_test.cc | 86 ++++++++++++ db/compaction/compaction_picker_universal.cc | 7 +- db/corruption_test.cc | 40 ++++-- db/db_compaction_test.cc | 16 ++- 11 files changed, 277 insertions(+), 46 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 78086c33a..5de41a20b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -75,6 +75,7 @@ ### Performance Improvements * Rather than doing total sort against all files in a level, SortFileByOverlappingRatio() to only find the top 50 files based on score. This can improve write throughput for the use cases where data is loaded in increasing key order and there are a lot of files in one LSM-tree, where applying compaction results is the bottleneck. +* In leveled compaction, L0->L1 trivial move will allow more than one file to be moved in one compaction. This would allow L0 files to be moved down faster when data is loaded in sequential order, making slowdown or stop condition harder to hit. Also seek L0->L1 trivial move when only some files qualify. ## 7.3.0 (05/20/2022) ### Bug Fixes diff --git a/db/compaction/compaction.cc b/db/compaction/compaction.cc index 9fab3057a..d5ef4273f 100644 --- a/db/compaction/compaction.cc +++ b/db/compaction/compaction.cc @@ -214,7 +214,8 @@ Compaction::Compaction( CompressionOptions _compression_opts, Temperature _output_temperature, uint32_t _max_subcompactions, std::vector _grandparents, bool _manual_compaction, const std::string& _trim_ts, double _score, - bool _deletion_compaction, CompactionReason _compaction_reason, + bool _deletion_compaction, bool l0_files_might_overlap, + CompactionReason _compaction_reason, BlobGarbageCollectionPolicy _blob_garbage_collection_policy, double _blob_garbage_collection_age_cutoff) : input_vstorage_(vstorage), @@ -233,6 +234,7 @@ Compaction::Compaction( output_compression_opts_(_compression_opts), output_temperature_(_output_temperature), deletion_compaction_(_deletion_compaction), + l0_files_might_overlap_(l0_files_might_overlap), inputs_(PopulateWithAtomicBoundaries(vstorage, std::move(_inputs))), grandparents_(std::move(_grandparents)), score_(_score), @@ -241,6 +243,7 @@ Compaction::Compaction( is_manual_compaction_(_manual_compaction), trim_ts_(_trim_ts), is_trivial_move_(false), + compaction_reason_(_compaction_reason), notify_on_compaction_completion_(false), enable_blob_garbage_collection_( @@ -333,8 +336,10 @@ bool Compaction::IsTrivialMove() const { // filter to be applied to that level, and thus cannot be a trivial move. // Check if start level have files with overlapping ranges - if (start_level_ == 0 && input_vstorage_->level0_non_overlapping() == false) { - // We cannot move files from L0 to L1 if the files are overlapping + if (start_level_ == 0 && input_vstorage_->level0_non_overlapping() == false && + l0_files_might_overlap_) { + // We cannot move files from L0 to L1 if the L0 files in the LSM-tree are + // overlapping, unless we are sure that files picked in L0 don't overlap. return false; } diff --git a/db/compaction/compaction.h b/db/compaction/compaction.h index 94168a70f..37204127a 100644 --- a/db/compaction/compaction.h +++ b/db/compaction/compaction.h @@ -81,6 +81,7 @@ class Compaction { std::vector grandparents, bool manual_compaction = false, const std::string& trim_ts = "", double score = -1, bool deletion_compaction = false, + bool l0_files_might_overlap = true, CompactionReason compaction_reason = CompactionReason::kUnknown, BlobGarbageCollectionPolicy blob_garbage_collection_policy = BlobGarbageCollectionPolicy::kUseDefault, @@ -388,6 +389,11 @@ class Compaction { // should it split the output file using the compact cursor? InternalKey output_split_key_; + // L0 files in LSM-tree might be overlapping. But the compaction picking + // logic might pick a subset of the files that aren't overlapping. if + // that is the case, set the value to false. Otherwise, set it true. + bool l0_files_might_overlap_; + // Compaction input files organized by level. Constant after construction const std::vector inputs_; diff --git a/db/compaction/compaction_picker.cc b/db/compaction/compaction_picker.cc index 07d241de9..6bef17238 100644 --- a/db/compaction/compaction_picker.cc +++ b/db/compaction/compaction_picker.cc @@ -543,6 +543,10 @@ bool CompactionPicker::SetupOtherInputs( output_level_inputs_size); inputs->files = expanded_inputs.files; } + } else { + // Likely to be trivial move. Expand files if they are still trivial moves, + // but limit to mutable_cf_options.max_compaction_bytes or 8 files so that + // we don't create too much compaction pressure for the next level. } return true; } @@ -641,7 +645,8 @@ Compaction* CompactionPicker::CompactRange( GetCompressionOptions(mutable_cf_options, vstorage, output_level), Temperature::kUnknown, compact_range_options.max_subcompactions, /* grandparents */ {}, /* is manual */ true, trim_ts, /* score */ -1, - /* deletion_compaction */ false, CompactionReason::kUnknown, + /* deletion_compaction */ false, /* l0_files_might_overlap */ true, + CompactionReason::kUnknown, compact_range_options.blob_garbage_collection_policy, compact_range_options.blob_garbage_collection_age_cutoff); @@ -823,7 +828,8 @@ Compaction* CompactionPicker::CompactRange( GetCompressionOptions(mutable_cf_options, vstorage, output_level), Temperature::kUnknown, compact_range_options.max_subcompactions, std::move(grandparents), /* is manual */ true, trim_ts, /* score */ -1, - /* deletion_compaction */ false, CompactionReason::kUnknown, + /* deletion_compaction */ false, /* l0_files_might_overlap */ true, + CompactionReason::kUnknown, compact_range_options.blob_garbage_collection_policy, compact_range_options.blob_garbage_collection_age_cutoff); diff --git a/db/compaction/compaction_picker.h b/db/compaction/compaction_picker.h index 5b0b1b7fb..7afbf437d 100644 --- a/db/compaction/compaction_picker.h +++ b/db/compaction/compaction_picker.h @@ -217,6 +217,8 @@ class CompactionPicker { return &compactions_in_progress_; } + const InternalKeyComparator* icmp() const { return icmp_; } + protected: const ImmutableOptions& ioptions_; diff --git a/db/compaction/compaction_picker_fifo.cc b/db/compaction/compaction_picker_fifo.cc index 6ebdf674c..6034dd0ef 100644 --- a/db/compaction/compaction_picker_fifo.cc +++ b/db/compaction/compaction_picker_fifo.cc @@ -116,7 +116,8 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction( mutable_cf_options.compression_opts, Temperature::kUnknown, /* max_subcompactions */ 0, {}, /* is manual */ false, /* trim_ts */ "", vstorage->CompactionScore(0), - /* is deletion compaction */ true, CompactionReason::kFIFOTtl); + /* is deletion compaction */ true, /* l0_files_might_overlap */ true, + CompactionReason::kFIFOTtl); return c; } @@ -160,6 +161,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction( 0 /* max_subcompactions */, {}, /* is manual */ false, /* trim_ts */ "", vstorage->CompactionScore(0), /* is deletion compaction */ false, + /* l0_files_might_overlap */ true, CompactionReason::kFIFOReduceNumFiles); return c; } @@ -209,7 +211,8 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction( mutable_cf_options.compression_opts, Temperature::kUnknown, /* max_subcompactions */ 0, {}, /* is manual */ false, /* trim_ts */ "", vstorage->CompactionScore(0), - /* is deletion compaction */ true, CompactionReason::kFIFOMaxSize); + /* is deletion compaction */ true, + /* l0_files_might_overlap */ true, CompactionReason::kFIFOMaxSize); return c; } @@ -315,7 +318,8 @@ Compaction* FIFOCompactionPicker::PickCompactionToWarm( Temperature::kWarm, /* max_subcompactions */ 0, {}, /* is manual */ false, /* trim_ts */ "", vstorage->CompactionScore(0), - /* is deletion compaction */ false, CompactionReason::kChangeTemperature); + /* is deletion compaction */ false, /* l0_files_might_overlap */ true, + CompactionReason::kChangeTemperature); return c; } diff --git a/db/compaction/compaction_picker_level.cc b/db/compaction/compaction_picker_level.cc index b3e4cb310..1d19ae84f 100644 --- a/db/compaction/compaction_picker_level.cc +++ b/db/compaction/compaction_picker_level.cc @@ -7,11 +7,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. +#include "db/compaction/compaction_picker_level.h" + #include #include #include -#include "db/compaction/compaction_picker_level.h" +#include "db/version_edit.h" #include "logging/log_buffer.h" #include "test_util/sync_point.h" @@ -87,6 +89,9 @@ class LevelCompactionBuilder { // function will return false. bool PickFileToCompact(); + // Return true if a L0 trivial move is picked up. + bool TryPickL0TrivialMove(); + // For L0->L0, picks the longest span of files that aren't currently // undergoing compaction for which work-per-deleted-file decreases. The span // always starts from the newest L0 file. @@ -117,6 +122,7 @@ class LevelCompactionBuilder { int base_index_ = -1; double start_level_score_ = 0; bool is_manual_ = false; + bool is_l0_trivial_move_ = false; CompactionInputFiles start_level_inputs_; std::vector compaction_inputs_; CompactionInputFiles output_level_inputs_; @@ -261,7 +267,7 @@ void LevelCompactionBuilder::SetupInitialFiles() { } bool LevelCompactionBuilder::SetupOtherL0FilesIfNeeded() { - if (start_level_ == 0 && output_level_ != 0) { + if (start_level_ == 0 && output_level_ != 0 && !is_l0_trivial_move_) { return compaction_picker_->GetOverlappingL0Files( vstorage_, &start_level_inputs_, output_level_, &parent_index_); } @@ -274,7 +280,8 @@ bool LevelCompactionBuilder::SetupOtherInputsIfNeeded() { // need to consider other levels. if (output_level_ != 0) { output_level_inputs_.level = output_level_; - if (!compaction_picker_->SetupOtherInputs( + if (!is_l0_trivial_move_ && + !compaction_picker_->SetupOtherInputs( cf_name_, mutable_cf_options_, vstorage_, &start_level_inputs_, &output_level_inputs_, &parent_index_, base_index_)) { return false; @@ -285,20 +292,22 @@ bool LevelCompactionBuilder::SetupOtherInputsIfNeeded() { compaction_inputs_.push_back(output_level_inputs_); } - // In some edge cases we could pick a compaction that will be compacting - // a key range that overlap with another running compaction, and both - // of them have the same output level. This could happen if - // (1) we are running a non-exclusive manual compaction - // (2) AddFile ingest a new file into the LSM tree - // We need to disallow this from happening. - if (compaction_picker_->FilesRangeOverlapWithCompaction(compaction_inputs_, - output_level_)) { - // This compaction output could potentially conflict with the output - // of a currently running compaction, we cannot run it. - return false; + if (!is_l0_trivial_move_) { + // In some edge cases we could pick a compaction that will be compacting + // a key range that overlap with another running compaction, and both + // of them have the same output level. This could happen if + // (1) we are running a non-exclusive manual compaction + // (2) AddFile ingest a new file into the LSM tree + // We need to disallow this from happening. + if (compaction_picker_->FilesRangeOverlapWithCompaction( + compaction_inputs_, output_level_)) { + // This compaction output could potentially conflict with the output + // of a currently running compaction, we cannot run it. + return false; + } + compaction_picker_->GetGrandparents(vstorage_, start_level_inputs_, + output_level_inputs_, &grandparents_); } - compaction_picker_->GetGrandparents(vstorage_, start_level_inputs_, - output_level_inputs_, &grandparents_); } else { compaction_inputs_.push_back(start_level_inputs_); } @@ -349,6 +358,7 @@ Compaction* LevelCompactionBuilder::GetCompaction() { Temperature::kUnknown, /* max_subcompactions */ 0, std::move(grandparents_), is_manual_, /* trim_ts */ "", start_level_score_, false /* deletion_compaction */, + /* l0_files_might_overlap */ start_level_ == 0 && !is_l0_trivial_move_, compaction_reason_); // If it's level 0 compaction, make sure we don't execute any other level 0 @@ -417,6 +427,75 @@ uint32_t LevelCompactionBuilder::GetPathId( return p; } +bool LevelCompactionBuilder::TryPickL0TrivialMove() { + if (vstorage_->base_level() <= 0) { + return false; + } + if (start_level_ == 0 && mutable_cf_options_.compression_per_level.empty() && + !vstorage_->LevelFiles(output_level_).empty() && + ioptions_.db_paths.size() <= 1) { + // Try to pick trivial move from L0 to L1. We start from the oldest + // file. We keep expanding to newer files if it would form a + // trivial move. + // For now we don't support it with + // mutable_cf_options_.compression_per_level to prevent the logic + // of determining whether L0 can be trivial moved to the next level. + // We skip the case where output level is empty, since in this case, at + // least the oldest file would qualify for trivial move, and this would + // be a surprising behavior with few benefits. + + // We search from the oldest file from the newest. In theory, there are + // files in the middle can form trivial move too, but it is probably + // uncommon and we ignore these cases for simplicity. + const std::vector& level_files = + vstorage_->LevelFiles(start_level_); + + InternalKey my_smallest, my_largest; + for (auto it = level_files.rbegin(); it != level_files.rend(); ++it) { + CompactionInputFiles output_level_inputs; + output_level_inputs.level = output_level_; + FileMetaData* file = *it; + if (it == level_files.rbegin()) { + my_smallest = file->smallest; + my_largest = file->largest; + } else { + if (compaction_picker_->icmp()->Compare(file->largest, my_smallest) < + 0) { + my_smallest = file->smallest; + } else if (compaction_picker_->icmp()->Compare(file->smallest, + my_largest) > 0) { + my_largest = file->largest; + } else { + break; + } + } + vstorage_->GetOverlappingInputs(output_level_, &my_smallest, &my_largest, + &output_level_inputs.files); + if (output_level_inputs.empty()) { + assert(!file->being_compacted); + start_level_inputs_.files.push_back(file); + } else { + break; + } + } + } + + if (!start_level_inputs_.empty()) { + // Sort files by key range. Not sure it's 100% necessary but it's cleaner + // to always keep files sorted by key the key ranges don't overlap. + std::sort(start_level_inputs_.files.begin(), + start_level_inputs_.files.end(), + [icmp = compaction_picker_->icmp()](FileMetaData* f1, + FileMetaData* f2) -> bool { + return (icmp->Compare(f1->smallest, f2->smallest) < 0); + }); + + is_l0_trivial_move_ = true; + return true; + } + return false; +} + bool LevelCompactionBuilder::PickFileToCompact() { // level 0 files are overlapping. So we cannot pick more // than one concurrent compactions at this level. This @@ -429,20 +508,26 @@ bool LevelCompactionBuilder::PickFileToCompact() { } start_level_inputs_.clear(); + start_level_inputs_.level = start_level_; assert(start_level_ >= 0); - // Pick the largest file in this level that is not already - // being compacted - const std::vector& file_size = - vstorage_->FilesByCompactionPri(start_level_); + if (TryPickL0TrivialMove()) { + return true; + } + const std::vector& level_files = vstorage_->LevelFiles(start_level_); + // Pick the file with the highest score in this level that is not already + // being compacted. + const std::vector& file_scores = + vstorage_->FilesByCompactionPri(start_level_); + unsigned int cmp_idx; for (cmp_idx = vstorage_->NextCompactionIndex(start_level_); - cmp_idx < file_size.size(); cmp_idx++) { - int index = file_size[cmp_idx]; + cmp_idx < file_scores.size(); cmp_idx++) { + int index = file_scores[cmp_idx]; auto* f = level_files[index]; // do not pick a file to compact if it is being compacted @@ -460,7 +545,6 @@ bool LevelCompactionBuilder::PickFileToCompact() { } start_level_inputs_.files.push_back(f); - start_level_inputs_.level = start_level_; if (!compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_, &start_level_inputs_) || compaction_picker_->FilesRangeOverlapWithCompaction( @@ -478,8 +562,8 @@ bool LevelCompactionBuilder::PickFileToCompact() { continue; } - // Now that input level is fully expanded, we check whether any output files - // are locked due to pending compaction. + // Now that input level is fully expanded, we check whether any output + // files are locked due to pending compaction. // // Note we rely on ExpandInputsToCleanCut() to tell us whether any output- // level files are locked, not just the extra ones pulled in for user-key diff --git a/db/compaction/compaction_picker_test.cc b/db/compaction/compaction_picker_test.cc index c65ec1eec..5accd231a 100644 --- a/db/compaction/compaction_picker_test.cc +++ b/db/compaction/compaction_picker_test.cc @@ -2249,6 +2249,92 @@ TEST_F(CompactionPickerTest, IsTrivialMoveOn) { ASSERT_TRUE(compaction->IsTrivialMove()); } +TEST_F(CompactionPickerTest, L0TrivialMove1) { + mutable_cf_options_.max_bytes_for_level_base = 10000000u; + mutable_cf_options_.level0_file_num_compaction_trigger = 4; + mutable_cf_options_.max_compaction_bytes = 10000000u; + ioptions_.level_compaction_dynamic_level_bytes = false; + NewVersionStorage(6, kCompactionStyleLevel); + + Add(0, 1U, "100", "150", 3000U, 0, 710, 800); + Add(0, 2U, "151", "200", 3001U, 0, 610, 700); + Add(0, 3U, "301", "350", 3000U, 0, 510, 600); + Add(0, 4U, "451", "400", 3000U, 0, 410, 500); + + Add(1, 5U, "120", "130", 7000U); + Add(1, 6U, "170", "180", 7000U); + Add(1, 7U, "220", "230", 7000U); + Add(1, 8U, "270", "280", 7000U); + UpdateVersionStorageInfo(); + + std::unique_ptr compaction(level_compaction_picker.PickCompaction( + cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), + &log_buffer_)); + ASSERT_TRUE(compaction.get() != nullptr); + ASSERT_EQ(1, compaction->num_input_levels()); + ASSERT_EQ(2, compaction->num_input_files(0)); + ASSERT_EQ(3, compaction->input(0, 0)->fd.GetNumber()); + ASSERT_EQ(4, compaction->input(0, 1)->fd.GetNumber()); + ASSERT_TRUE(compaction->IsTrivialMove()); +} + +TEST_F(CompactionPickerTest, L0TrivialMoveOneFile) { + mutable_cf_options_.max_bytes_for_level_base = 10000000u; + mutable_cf_options_.level0_file_num_compaction_trigger = 4; + mutable_cf_options_.max_compaction_bytes = 10000000u; + ioptions_.level_compaction_dynamic_level_bytes = false; + NewVersionStorage(6, kCompactionStyleLevel); + + Add(0, 1U, "100", "150", 3000U, 0, 710, 800); + Add(0, 2U, "551", "600", 3001U, 0, 610, 700); + Add(0, 3U, "101", "150", 3000U, 0, 510, 600); + Add(0, 4U, "451", "400", 3000U, 0, 410, 500); + + Add(1, 5U, "120", "130", 7000U); + Add(1, 6U, "170", "180", 7000U); + Add(1, 7U, "220", "230", 7000U); + Add(1, 8U, "270", "280", 7000U); + UpdateVersionStorageInfo(); + + std::unique_ptr compaction(level_compaction_picker.PickCompaction( + cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), + &log_buffer_)); + ASSERT_TRUE(compaction.get() != nullptr); + ASSERT_EQ(1, compaction->num_input_levels()); + ASSERT_EQ(1, compaction->num_input_files(0)); + ASSERT_EQ(4, compaction->input(0, 0)->fd.GetNumber()); + ASSERT_TRUE(compaction->IsTrivialMove()); +} + +TEST_F(CompactionPickerTest, L0TrivialMoveWholeL0) { + mutable_cf_options_.max_bytes_for_level_base = 10000000u; + mutable_cf_options_.level0_file_num_compaction_trigger = 4; + mutable_cf_options_.max_compaction_bytes = 10000000u; + ioptions_.level_compaction_dynamic_level_bytes = false; + NewVersionStorage(6, kCompactionStyleLevel); + + Add(0, 1U, "300", "350", 3000U, 0, 710, 800); + Add(0, 2U, "651", "600", 3001U, 0, 610, 700); + Add(0, 3U, "501", "550", 3000U, 0, 510, 600); + Add(0, 4U, "451", "400", 3000U, 0, 410, 500); + + Add(1, 5U, "120", "130", 7000U); + Add(1, 6U, "970", "980", 7000U); + UpdateVersionStorageInfo(); + + std::unique_ptr compaction(level_compaction_picker.PickCompaction( + cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(), + &log_buffer_)); + ASSERT_TRUE(compaction.get() != nullptr); + ASSERT_EQ(1, compaction->num_input_levels()); + ASSERT_EQ(4, compaction->num_input_files(0)); + ASSERT_EQ(1, compaction->input(0, 0)->fd.GetNumber()); + ASSERT_EQ(4, compaction->input(0, 1)->fd.GetNumber()); + ASSERT_EQ(3, compaction->input(0, 2)->fd.GetNumber()); + ASSERT_EQ(2, compaction->input(0, 3)->fd.GetNumber()); + ASSERT_TRUE(compaction->IsTrivialMove()); +} + TEST_F(CompactionPickerTest, IsTrivialMoveOffSstPartitioned) { mutable_cf_options_.max_bytes_for_level_base = 10000u; mutable_cf_options_.max_compaction_bytes = 10001u; diff --git a/db/compaction/compaction_picker_universal.cc b/db/compaction/compaction_picker_universal.cc index c5c043c0f..686b40bd0 100644 --- a/db/compaction/compaction_picker_universal.cc +++ b/db/compaction/compaction_picker_universal.cc @@ -758,7 +758,8 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns( Temperature::kUnknown, /* max_subcompactions */ 0, grandparents, /* is manual */ false, /* trim_ts */ "", score_, - false /* deletion_compaction */, compaction_reason); + false /* deletion_compaction */, + /* l0_files_might_overlap */ true, compaction_reason); } // Look at overall size amplification. If size amplification @@ -1083,6 +1084,7 @@ Compaction* UniversalCompactionBuilder::PickIncrementalForReduceSizeAmp( Temperature::kUnknown, /* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false, /* trim_ts */ "", score_, false /* deletion_compaction */, + /* l0_files_might_overlap */ true, CompactionReason::kUniversalSizeAmplification); } @@ -1225,6 +1227,7 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() { Temperature::kUnknown, /* max_subcompactions */ 0, grandparents, /* is manual */ false, /* trim_ts */ "", score_, false /* deletion_compaction */, + /* l0_files_might_overlap */ true, CompactionReason::kFilesMarkedForCompaction); } @@ -1300,7 +1303,7 @@ Compaction* UniversalCompactionBuilder::PickCompactionToOldest( Temperature::kUnknown, /* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false, /* trim_ts */ "", score_, false /* deletion_compaction */, - compaction_reason); + /* l0_files_might_overlap */ true, compaction_reason); } Compaction* UniversalCompactionBuilder::PickPeriodicCompaction() { diff --git a/db/corruption_test.cc b/db/corruption_test.cc index 4d90cfaed..5d6ef2332 100644 --- a/db/corruption_test.cc +++ b/db/corruption_test.cc @@ -7,6 +7,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. +#include "rocksdb/options.h" #ifndef ROCKSDB_LITE #include @@ -553,7 +554,10 @@ TEST_F(CorruptionTest, CorruptedDescriptor) { ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); - ASSERT_OK(dbi->TEST_CompactRange(0, nullptr, nullptr)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_OK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); Corrupt(kDescriptorFile, 0, 1000); Status s = TryReopen(); @@ -770,7 +774,9 @@ TEST_F(CorruptionTest, ParanoidFileChecksOnCompact) { DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); mock->SetCorruptionMode(mode); - s = dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + s = dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr); if (mode == mock::MockTableFactory::kCorruptNone) { ASSERT_OK(s); } else { @@ -806,7 +812,10 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRangeFirst) { } else { DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); - ASSERT_OK(dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_OK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); } db_->ReleaseSnapshot(snap); } @@ -842,7 +851,10 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRange) { } else { DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); - ASSERT_OK(dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_OK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); } db_->ReleaseSnapshot(snap); } @@ -875,7 +887,10 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRangeLast) { } else { DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); - ASSERT_OK(dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_OK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); } db_->ReleaseSnapshot(snap); } @@ -902,7 +917,10 @@ TEST_F(CorruptionTest, LogCorruptionErrorsInCompactionIterator) { DBImpl* dbi = static_cast_with_check(db_); ASSERT_OK(dbi->TEST_FlushMemTable()); - Status s = dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + Status s = + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr); ASSERT_NOK(s); ASSERT_TRUE(s.IsCorruption()); } @@ -928,7 +946,10 @@ TEST_F(CorruptionTest, CompactionKeyOrderCheck) { mock->SetCorruptionMode(mock::MockTableFactory::kCorruptNone); ASSERT_OK(db_->SetOptions({{"check_flush_compaction_key_order", "true"}})); - ASSERT_NOK(dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_NOK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); } TEST_F(CorruptionTest, FlushKeyOrderCheck) { @@ -975,7 +996,10 @@ TEST_F(CorruptionTest, DisableKeyOrderCheck) { ASSERT_OK(db_->Put(WriteOptions(), "foo2", "v1")); ASSERT_OK(db_->Put(WriteOptions(), "foo4", "v1")); ASSERT_OK(dbi->TEST_FlushMemTable()); - ASSERT_OK(dbi->TEST_CompactRange(0, nullptr, nullptr, nullptr, true)); + CompactRangeOptions cro; + cro.bottommost_level_compaction = BottommostLevelCompaction::kForce; + ASSERT_OK( + dbi->CompactRange(cro, dbi->DefaultColumnFamily(), nullptr, nullptr)); ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing(); ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks(); } diff --git a/db/db_compaction_test.cc b/db/db_compaction_test.cc index 541405d45..e48e8f2d5 100644 --- a/db/db_compaction_test.cc +++ b/db/db_compaction_test.cc @@ -1093,16 +1093,20 @@ TEST_F(DBCompactionTest, ManualCompactionUnknownOutputSize) { // create two files in l1 that we can compact for (int i = 0; i < 2; ++i) { for (int j = 0; j < options.level0_file_num_compaction_trigger; j++) { - // make l0 files' ranges overlap to avoid trivial move ASSERT_OK(Put(std::to_string(2 * i), std::string(1, 'A'))); ASSERT_OK(Put(std::to_string(2 * i + 1), std::string(1, 'A'))); ASSERT_OK(Flush()); ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable()); } ASSERT_OK(dbfull()->TEST_WaitForCompact()); - ASSERT_EQ(NumTableFilesAtLevel(0, 0), 0); - ASSERT_EQ(NumTableFilesAtLevel(1, 0), i + 1); } + ASSERT_OK( + dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "2"}})); + ASSERT_OK(dbfull()->TEST_WaitForCompact()); + ASSERT_EQ(NumTableFilesAtLevel(0, 0), 0); + ASSERT_EQ(NumTableFilesAtLevel(1, 0), 2); + ASSERT_OK( + dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "3"}})); ColumnFamilyMetaData cf_meta; dbfull()->GetColumnFamilyMetaData(dbfull()->DefaultColumnFamily(), &cf_meta); @@ -4366,7 +4370,13 @@ TEST_F(DBCompactionTest, LevelTtlBooster) { ASSERT_OK(Flush()); ASSERT_OK(dbfull()->TEST_WaitForCompact()); } + // Force files to be compacted to L1 + ASSERT_OK( + dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "1"}})); + ASSERT_OK(dbfull()->TEST_WaitForCompact()); ASSERT_EQ("0,1,2", FilesPerLevel()); + ASSERT_OK( + dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "2"}})); ASSERT_GT(SizeAtLevel(1), kNumKeysPerFile * 4 * kValueSize); }