Skip to content

Commit 0e860cb

Browse files
committed
Fix regression issue of too large score (#10518)
Summary: #10057 caused a regression bug: since the base level size is not adjusted based on L0 size anymore, L0 score might become very large. This makes compaction heavily favor L0->L1 compaction against L1->L2 compaction, and cause in some cases, data stuck in L1 without being moved down. We fix calculating a score of L0 by size(L0)/size(L1) in the case where L0 is large.. Pull Request resolved: #10518 Test Plan: run db_bench against data on tmpfs and watch the behavior of data stuck in L1 goes away. Reviewed By: ajkr Differential Revision: D38603145 fbshipit-source-id: 4949e52dc28b54aacfe08417c6e6cc7e40a27225
1 parent dcd4435 commit 0e860cb

File tree

1 file changed

+37
-18
lines changed

1 file changed

+37
-18
lines changed

db/version_set.cc

+37-18
Original file line numberDiff line numberDiff line change
@@ -2733,24 +2733,43 @@ void VersionStorageInfo::ComputeCompactionScore(
27332733
// Level-based involves L0->L0 compactions that can lead to oversized
27342734
// L0 files. Take into account size as well to avoid later giant
27352735
// compactions to the base level.
2736-
uint64_t l0_target_size = mutable_cf_options.max_bytes_for_level_base;
2737-
if (immutable_options.level_compaction_dynamic_level_bytes &&
2738-
level_multiplier_ != 0.0) {
2739-
// Prevent L0 to Lbase fanout from growing larger than
2740-
// `level_multiplier_`. This prevents us from getting stuck picking
2741-
// L0 forever even when it is hurting write-amp. That could happen
2742-
// in dynamic level compaction's write-burst mode where the base
2743-
// level's target size can grow to be enormous.
2744-
l0_target_size =
2745-
std::max(l0_target_size,
2746-
static_cast<uint64_t>(level_max_bytes_[base_level_] /
2747-
level_multiplier_));
2748-
}
2749-
score =
2750-
std::max(score, static_cast<double>(total_size) / l0_target_size);
2751-
if (immutable_options.level_compaction_dynamic_level_bytes &&
2752-
score > 1.0) {
2753-
score *= kScoreScale;
2736+
// If score in L0 is always too high, L0->L1 will always be
2737+
// prioritized over L1->L2 compaction and L1 will accumulate to
2738+
// too large. But if L0 score isn't high enough, L0 will accumulate
2739+
// and data is not moved to L1 fast enough. With potential L0->L0
2740+
// compaction, number of L0 files aren't always an indication of
2741+
// L0 oversizing, and we also need to consider total size of L0.
2742+
if (immutable_options.level_compaction_dynamic_level_bytes) {
2743+
if (total_size >= mutable_cf_options.max_bytes_for_level_base) {
2744+
// When calculating estimated_compaction_needed_bytes, we assume
2745+
// L0 is qualified as pending compactions. We will need to make
2746+
// sure that it qualifies for compaction.
2747+
// It might be guafanteed by logic below anyway, but we are
2748+
// explicit here to make sure we don't stop writes with no
2749+
// compaction scheduled.
2750+
score = std::max(score, 1.01);
2751+
}
2752+
if (total_size > level_max_bytes_[base_level_]) {
2753+
// In this case, we compare L0 size with actual L1 size and make
2754+
// sure score is more than 1.0 (10.0 after scaled) if L0 is larger
2755+
// than L1. Since in this case L1 score is lower than 10.0, L0->L1
2756+
// is prioritized over L1->L2.
2757+
uint64_t base_level_size = 0;
2758+
for (auto f : files_[base_level_]) {
2759+
base_level_size += f->compensated_file_size;
2760+
}
2761+
score = std::max(score, static_cast<double>(total_size) /
2762+
static_cast<double>(std::max(
2763+
base_level_size,
2764+
level_max_bytes_[base_level_])));
2765+
}
2766+
if (score > 1.0) {
2767+
score *= kScoreScale;
2768+
}
2769+
} else {
2770+
score = std::max(score,
2771+
static_cast<double>(total_size) /
2772+
mutable_cf_options.max_bytes_for_level_base);
27542773
}
27552774
}
27562775
}

0 commit comments

Comments
 (0)