From: Andrew Kryczka Date: Mon, 15 Oct 2018 23:18:55 +0000 (-0700) Subject: Avoid per-key linear scan over snapshots in compaction (#4495) X-Git-Tag: v5.16.6~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ab21dc6323cc7b41e3c495ae61e69752e9b233de;p=rocksdb.git Avoid per-key linear scan over snapshots in compaction (#4495) Summary: `CompactionIterator::snapshots_` is ordered by ascending seqnum, just like `DBImpl`'s linked list of snapshots from which it was copied. This PR exploits this ordering to make `findEarliestVisibleSnapshot` do binary search rather than linear scan. This can make flush/compaction significantly faster when many snapshots exist since that function is called on every single key. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4495 Differential Revision: D10386470 Pulled By: ajkr fbshipit-source-id: 29734991631227b6b7b677e156ac567690118a8b --- diff --git a/HISTORY.md b/HISTORY.md index ca6afaef..cf23380b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,4 +1,8 @@ # Rocksdb Change Log +## Unreleased +### Bug Fixes +* Fix slow flush/compaction when DB contains many snapshots. The problem became noticeable to us in DBs with 100,000+ snapshots, though it will affect others at different thresholds. + ## 5.16.4 (10/10/2018) ### Bug Fixes * Fix corner case where a write group leader blocked due to write stall blocks other writers in queue with WriteOptions::no_slowdown set. diff --git a/db/compaction_iterator.cc b/db/compaction_iterator.cc index 7b096ca0..7ac00ba9 100644 --- a/db/compaction_iterator.cc +++ b/db/compaction_iterator.cc @@ -77,6 +77,12 @@ CompactionIterator::CompactionIterator( earliest_snapshot_ = snapshots_->at(0); latest_snapshot_ = snapshots_->back(); } +#ifndef NDEBUG + // findEarliestVisibleSnapshot assumes this ordering. + for (size_t i = 1; i < snapshots_->size(); ++i) { + assert(snapshots_->at(i - 1) <= snapshots_->at(i)); + } +#endif if (compaction_filter_ != nullptr) { if (compaction_filter_->IgnoreSnapshots()) { ignore_snapshots_ = true; @@ -603,18 +609,23 @@ void CompactionIterator::PrepareOutput() { inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot( SequenceNumber in, SequenceNumber* prev_snapshot) { assert(snapshots_->size()); - SequenceNumber prev = kMaxSequenceNumber; - for (const auto cur : *snapshots_) { - assert(prev == kMaxSequenceNumber || prev <= cur); - if (cur >= in && (snapshot_checker_ == nullptr || - snapshot_checker_->IsInSnapshot(in, cur))) { - *prev_snapshot = prev == kMaxSequenceNumber ? 0 : prev; + auto snapshots_iter = std::lower_bound( + snapshots_->begin(), snapshots_->end(), in); + if (snapshots_iter == snapshots_->begin()) { + *prev_snapshot = 0; + } else { + *prev_snapshot = *std::prev(snapshots_iter); + assert(*prev_snapshot < in); + } + for (; snapshots_iter != snapshots_->end(); ++snapshots_iter) { + auto cur = *snapshots_iter; + assert(in <= cur); + if (snapshot_checker_ == nullptr || + snapshot_checker_->IsInSnapshot(in, cur)) { return cur; } - prev = cur; - assert(prev < kMaxSequenceNumber); + *prev_snapshot = cur; } - *prev_snapshot = prev; return kMaxSequenceNumber; }