Trigger compaction to the next level if the data age exceeds periodic_compaction_seconds (#12175)

Summary:
Currently, the data are always compacted to the same level if exceed periodic_compaction_seconds which may confuse users, so we change it to allow trigger compaction to the next level here. It's a behavior change to users, and may affect users
who have disabled their ttl or ttl > periodic_compaction_seconds.

Relate issue: https://github.com/facebook/rocksdb/issues/12165

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

Reviewed By: ajkr

Differential Revision: D52446722

Pulled By: cbi42

fbshipit-source-id: ccd3d2c6434ed77055735a03408d4a62d119342f
This commit is contained in:
hulk 2023-12-28 12:50:08 -08:00 committed by Facebook GitHub Bot
parent 3d81f175b4
commit b7ecbe309d
4 changed files with 32 additions and 11 deletions

View File

@ -45,6 +45,13 @@ bool LevelCompactionPicker::NeedsCompaction(
}
namespace {
enum class CompactToNextLevel {
kNo, // compact to the same level as the input file
kYes, // compact to the next level except the last level to the same level
kSkipLastLevel, // compact to the next level but skip the last level
};
// A class to build a leveled compaction step-by-step.
class LevelCompactionBuilder {
public:
@ -115,9 +122,10 @@ class LevelCompactionBuilder {
// level_files is a vector of (level, file metadata) in ascending order of
// level. If compact_to_next_level is true, compact the file to the next
// level, otherwise, compact to the same level as the input file.
// If skip_last_level is true, skip the last level.
void PickFileToCompact(
const autovector<std::pair<int, FileMetaData*>>& level_files,
bool compact_to_next_level);
CompactToNextLevel compact_to_next_level);
const std::string& cf_name_;
VersionStorageInfo* vstorage_;
@ -149,20 +157,24 @@ class LevelCompactionBuilder {
void LevelCompactionBuilder::PickFileToCompact(
const autovector<std::pair<int, FileMetaData*>>& level_files,
bool compact_to_next_level) {
CompactToNextLevel compact_to_next_level) {
for (auto& level_file : level_files) {
// If it's being compacted it has nothing to do here.
// If this assert() fails that means that some function marked some
// files as being_compacted, but didn't call ComputeCompactionScore()
assert(!level_file.second->being_compacted);
start_level_ = level_file.first;
if ((compact_to_next_level &&
if ((compact_to_next_level == CompactToNextLevel::kSkipLastLevel &&
start_level_ == vstorage_->num_non_empty_levels() - 1) ||
(start_level_ == 0 &&
!compaction_picker_->level0_compactions_in_progress()->empty())) {
continue;
}
if (compact_to_next_level) {
// Compact to the next level only if the file is not in the last level and
// compact_to_next_level is kYes or kSkipLastLevel.
if (compact_to_next_level != CompactToNextLevel::kNo &&
(start_level_ < vstorage_->num_non_empty_levels() - 1)) {
output_level_ =
(start_level_ == 0) ? vstorage_->base_level() : start_level_ + 1;
} else {
@ -248,7 +260,8 @@ void LevelCompactionBuilder::SetupInitialFiles() {
}
// Bottommost Files Compaction on deleting tombstones
PickFileToCompact(vstorage_->BottommostFilesMarkedForCompaction(), false);
PickFileToCompact(vstorage_->BottommostFilesMarkedForCompaction(),
CompactToNextLevel::kNo);
if (!start_level_inputs_.empty()) {
compaction_reason_ = CompactionReason::kBottommostFiles;
return;
@ -274,21 +287,26 @@ void LevelCompactionBuilder::SetupInitialFiles() {
}
}
PickFileToCompact(vstorage_->ExpiredTtlFiles(), true);
PickFileToCompact(vstorage_->ExpiredTtlFiles(),
CompactToNextLevel::kSkipLastLevel);
if (!start_level_inputs_.empty()) {
compaction_reason_ = CompactionReason::kTtl;
return;
}
// Periodic Compaction
PickFileToCompact(vstorage_->FilesMarkedForPeriodicCompaction(), false);
PickFileToCompact(vstorage_->FilesMarkedForPeriodicCompaction(),
ioptions_.level_compaction_dynamic_level_bytes
? CompactToNextLevel::kYes
: CompactToNextLevel::kNo);
if (!start_level_inputs_.empty()) {
compaction_reason_ = CompactionReason::kPeriodicCompaction;
return;
}
// Forced blob garbage collection
PickFileToCompact(vstorage_->FilesMarkedForForcedBlobGC(), false);
PickFileToCompact(vstorage_->FilesMarkedForForcedBlobGC(),
CompactToNextLevel::kNo);
if (!start_level_inputs_.empty()) {
compaction_reason_ = CompactionReason::kForcedBlobGC;
return;

View File

@ -914,7 +914,9 @@ struct AdvancedColumnFamilyOptions {
//
// Leveled: files older than `periodic_compaction_seconds` will be picked up
// for compaction and will be re-written to the same level as they were
// before.
// before if level_compaction_dynamic_level_bytes is disabled. Otherwise,
// it will rewrite files to the next level except for the last level files
// to the same level.
//
// FIFO: not supported. Setting this option has no effect for FIFO compaction.
//

View File

@ -48,7 +48,7 @@ Updating HISTORY.md with release notes
--------------------------------------
The script unreleased_history/release.sh does this. Run the script before
updating version.h to the next develpment release, so that the script will pick
updating version.h to the next development release, so that the script will pick
up the version being released. You might want to start with
$ DRY_RUN=1 unreleased_history/release.sh | less
@ -68,6 +68,6 @@ First, it was common to hit unnecessary merge conflicts when adding entries to
HISTORY.md, which slowed development. Second, when a PR was opened before a
release cut and landed after the release cut, it was easy to add the HISTORY
entry to the wrong version's history. This new setup completely fixes both of
those issues, with perhaps slighly more initial work to create each entry.
those issues, with perhaps slightly more initial work to create each entry.
There is also now an extra step in using `git blame` to map a release note
to its source code implementation, but that is a relatively rare operation.

View File

@ -0,0 +1 @@
Files will be compacted to the next level if the data age exceeds periodic_compaction_seconds except for the last level.