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:
@@ -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:
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user