diff --git a/db/version_set.cc b/db/version_set.cc index 397e63fda..f7c2fc5cd 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -695,12 +695,14 @@ void Version::AddIterators(const ReadOptions& read_options, return; } + auto* arena = merge_iter_builder->GetArena(); + // Merge all level zero files together since they may overlap for (size_t i = 0; i < storage_info_.LevelFilesBrief(0).num_files; i++) { const auto& file = storage_info_.LevelFilesBrief(0).files[i]; merge_iter_builder->AddIterator(cfd_->table_cache()->NewIterator( read_options, soptions, cfd_->internal_comparator(), file.fd, nullptr, - false, merge_iter_builder->GetArena())); + false, arena)); } // For levels > 0, we can use a concatenating iterator that sequentially @@ -708,14 +710,16 @@ void Version::AddIterators(const ReadOptions& read_options, // lazily. for (int level = 1; level < storage_info_.num_non_empty_levels(); level++) { if (storage_info_.LevelFilesBrief(level).num_files != 0) { - merge_iter_builder->AddIterator(NewTwoLevelIterator( - new LevelFileIteratorState( - cfd_->table_cache(), read_options, soptions, - cfd_->internal_comparator(), false /* for_compaction */, - cfd_->ioptions()->prefix_extractor != nullptr), - new LevelFileNumIterator(cfd_->internal_comparator(), - &storage_info_.LevelFilesBrief(level)), - merge_iter_builder->GetArena())); + auto* mem = arena->AllocateAligned(sizeof(LevelFileIteratorState)); + auto* state = new (mem) LevelFileIteratorState( + cfd_->table_cache(), read_options, soptions, + cfd_->internal_comparator(), false /* for_compaction */, + cfd_->ioptions()->prefix_extractor != nullptr); + mem = arena->AllocateAligned(sizeof(LevelFileNumIterator)); + auto* first_level_iter = new (mem) LevelFileNumIterator( + cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level)); + merge_iter_builder->AddIterator( + NewTwoLevelIterator(state, first_level_iter, arena, false)); } } } diff --git a/table/two_level_iterator.cc b/table/two_level_iterator.cc index 5d3e372dd..f540d3b16 100644 --- a/table/two_level_iterator.cc +++ b/table/two_level_iterator.cc @@ -22,11 +22,17 @@ namespace { class TwoLevelIterator: public Iterator { public: explicit TwoLevelIterator(TwoLevelIteratorState* state, - Iterator* first_level_iter); + Iterator* first_level_iter, + bool need_free_iter_and_state); virtual ~TwoLevelIterator() { - first_level_iter_.DeleteIter(false); + first_level_iter_.DeleteIter(!need_free_iter_and_state_); second_level_iter_.DeleteIter(false); + if (need_free_iter_and_state_) { + delete state_; + } else { + state_->~TwoLevelIteratorState(); + } } virtual void Seek(const Slice& target) override; @@ -65,9 +71,10 @@ class TwoLevelIterator: public Iterator { void SetSecondLevelIterator(Iterator* iter); void InitDataBlock(); - std::unique_ptr state_; + TwoLevelIteratorState* state_; IteratorWrapper first_level_iter_; IteratorWrapper second_level_iter_; // May be nullptr + bool need_free_iter_and_state_; Status status_; // If second_level_iter is non-nullptr, then "data_block_handle_" holds the // "index_value" passed to block_function_ to create the second_level_iter. @@ -75,8 +82,11 @@ class TwoLevelIterator: public Iterator { }; TwoLevelIterator::TwoLevelIterator(TwoLevelIteratorState* state, - Iterator* first_level_iter) - : state_(state), first_level_iter_(first_level_iter) {} + Iterator* first_level_iter, + bool need_free_iter_and_state) + : state_(state), + first_level_iter_(first_level_iter), + need_free_iter_and_state_(need_free_iter_and_state) {} void TwoLevelIterator::Seek(const Slice& target) { if (state_->check_prefix_may_match && @@ -186,12 +196,15 @@ void TwoLevelIterator::InitDataBlock() { } // namespace Iterator* NewTwoLevelIterator(TwoLevelIteratorState* state, - Iterator* first_level_iter, Arena* arena) { + Iterator* first_level_iter, Arena* arena, + bool need_free_iter_and_state) { if (arena == nullptr) { - return new TwoLevelIterator(state, first_level_iter); + return new TwoLevelIterator(state, first_level_iter, + need_free_iter_and_state); } else { auto mem = arena->AllocateAligned(sizeof(TwoLevelIterator)); - return new (mem) TwoLevelIterator(state, first_level_iter); + return new (mem) + TwoLevelIterator(state, first_level_iter, need_free_iter_and_state); } } diff --git a/table/two_level_iterator.h b/table/two_level_iterator.h index 030193597..4c6b48c2c 100644 --- a/table/two_level_iterator.h +++ b/table/two_level_iterator.h @@ -43,8 +43,11 @@ struct TwoLevelIteratorState { // arena: If not null, the arena is used to allocate the Iterator. // When destroying the iterator, the destructor will destroy // all the states but those allocated in arena. +// need_free_iter_and_state: free `state` and `first_level_iter` if +// true. Otherwise, just call destructor. extern Iterator* NewTwoLevelIterator(TwoLevelIteratorState* state, Iterator* first_level_iter, - Arena* arena = nullptr); + Arena* arena = nullptr, + bool need_free_iter_and_state = true); } // namespace rocksdb