LCS: try harder to move SSTables to highest levels.

Our current implementation of LCS can end up with situations in which
just a bit of data is in the highest levels, with the majority in the
lowest levels. That happens because we will only promote things to
highest levels if the amount of data in the current level is higher than
the maximum.

This is a pre-existing problem in itself, but became even clearer when
we started trying to define what is the backlog for LCS.

We have discussed ways to fix this it by redefining the criteria on when
to move data to the next levels. That would require us to change the way
things are today considerably, allowing parallel compactions, etc. There
is significant risk that we'll increase write amplication and we would
need to carefully validate that.

For now I will propose a simpler change, that essentially solves the
"inverted pyramid" problem of current LCS without major disruption:
keep selecting compaction candidates with the same criteria that we do
today, we should help make sure we are not compacting high levels for no
reason; but if there is nothing to do, use the idle time to push data to
higher levels. As an added benefit, old data that is in the higher level
can also be compacted away faster.

With this patch we see that in an idle, post-load system all data is
eventually pushed to the last level. Systems under constant writes keep
behaving the same way they did before.

Signed-off-by: Glauber Costa <glauber@scylladb.com>
This commit is contained in:
Glauber Costa
2018-05-18 17:14:07 -04:00
parent e64b471e3d
commit 28382cb25c

View File

@@ -160,6 +160,23 @@ public:
return max_bytes_for_level(level, _max_sstable_size_in_bytes);
}
sstables::compaction_descriptor get_descriptor_for_level(int level, const std::vector<stdx::optional<dht::decorated_key>>& last_compacted_keys,
std::vector<int>& compaction_counter) {
auto info = get_candidates_for(level, last_compacted_keys);
if (!info.candidates.empty()) {
int next_level = get_next_level(info.candidates, info.can_promote);
if (info.can_promote) {
info.candidates = get_overlapping_starved_sstables(next_level, std::move(info.candidates), compaction_counter);
}
return sstables::compaction_descriptor(std::move(info.candidates), next_level, _max_sstable_size_in_bytes);
} else {
logger.debug("No compaction candidates for L{}", level);
return sstables::compaction_descriptor();
}
}
/**
* @return highest-priority sstables to compact, and level to compact them to
* If no compactions are necessary, will return null
@@ -234,35 +251,36 @@ public:
return sstables::compaction_descriptor(std::move(most_interesting));
}
}
// L0 is fine, proceed with this level
auto info = get_candidates_for(i, last_compacted_keys);
if (!info.candidates.empty()) {
int next_level = get_next_level(info.candidates, info.can_promote);
if (info.can_promote) {
info.candidates = get_overlapping_starved_sstables(next_level, std::move(info.candidates), compaction_counter);
}
#if 0
if (logger.isDebugEnabled())
logger.debug("Compaction candidates for L{} are {}", i, toString(candidates));
#endif
return sstables::compaction_descriptor(std::move(info.candidates), next_level, _max_sstable_size_in_bytes);
} else {
logger.debug("No compaction candidates for L{}", i);
auto descriptor = get_descriptor_for_level(i, last_compacted_keys, compaction_counter);
if (descriptor.sstables.size() > 0) {
return descriptor;
}
}
// Higher levels are happy, time for a standard, non-STCS L0 compaction
if (get_level(0).empty()) {
return sstables::compaction_descriptor();
if (!get_level(0).empty()) {
auto info = get_candidates_for(0, last_compacted_keys);
if (!info.candidates.empty()) {
auto next_level = get_next_level(info.candidates, info.can_promote);
return sstables::compaction_descriptor(std::move(info.candidates), next_level, _max_sstable_size_in_bytes);
}
}
auto info = get_candidates_for(0, last_compacted_keys);
if (info.candidates.empty()) {
return sstables::compaction_descriptor();
for (size_t i = _generations.size() - 1; i > 0; --i) {
auto& sstables = get_level(i);
if (sstables.empty()) {
continue;
}
auto& sstables_prev_level = get_level(i-1);
if (sstables_prev_level.empty()) {
continue;
}
auto descriptor = get_descriptor_for_level(i-1, last_compacted_keys, compaction_counter);
if (descriptor.sstables.size() > 0) {
return descriptor;
}
}
auto next_level = get_next_level(info.candidates, info.can_promote);
return sstables::compaction_descriptor(std::move(info.candidates), next_level, _max_sstable_size_in_bytes);
return sstables::compaction_descriptor();
}
private:
/**