From 5eb48c8317ab5514dcada6de39158bf1008b23d2 Mon Sep 17 00:00:00 2001 From: LiuYangming Date: Sun, 28 Mar 2021 16:22:31 +0800 Subject: [PATCH 1/5] add dbiter value_meta() --- db/comparator_db_test.cc | 4 + db/db_iter.cc | 24 +++++ db/db_iter.h | 1 + db/db_test.cc | 97 +++++++++++++++++++ db/dbformat.h | 3 + include/rocksdb/iterator.h | 7 ++ include/rocksdb/utilities/juxtapose_db.h | 5 +- table/iterator.cc | 4 + utilities/ttl/db_ttl_impl.h | 5 +- .../write_batch_with_index.cc | 5 +- .../write_batch_with_index_test.cc | 4 + 11 files changed, 156 insertions(+), 3 deletions(-) diff --git a/db/comparator_db_test.cc b/db/comparator_db_test.cc index 22d9affe88..cda62565bd 100644 --- a/db/comparator_db_test.cc +++ b/db/comparator_db_test.cc @@ -53,6 +53,10 @@ class KVIter : public Iterator { virtual Slice key() const override { return iter_->first; } virtual Slice value() const override { return iter_->second; } + std::string value_meta() const override { + assert(false); + return ""; + } virtual Status status() const override { return Status::OK(); } private: diff --git a/db/db_iter.cc b/db/db_iter.cc index 586020968d..790a52b5ac 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -199,6 +199,27 @@ class DBIter final : public Iterator { } return value_.slice(); } + virtual std::string value_meta() const override { + if (cfd_ == nullptr) return ""; + + value_.fetch(); + assert(value_.valid()); + if (isValueHandleType(ikey_.type)) { + return separate_helper_->DecodeValueMeta(value_.slice()).ToString(); + } + + ValueExtractorContext context = {cfd_->GetID()}; + auto value_meta_extractor = + cfd_->ioptions()->value_meta_extractor_factory->CreateValueExtractor( + context); + std::string value_meta; + Status s = value_meta_extractor->Extract(ikey_.user_key, value_.slice(), + &value_meta); + if (!s.ok()) { + return ""; + } + return value_meta; + } virtual Status status() const override { if (status_.ok()) { return iter_->status(); @@ -1446,6 +1467,9 @@ inline void ArenaWrappedDBIter::Next() { db_iter_->Next(); } inline void ArenaWrappedDBIter::Prev() { db_iter_->Prev(); } inline Slice ArenaWrappedDBIter::key() const { return db_iter_->key(); } inline Slice ArenaWrappedDBIter::value() const { return db_iter_->value(); } +inline std::string ArenaWrappedDBIter::value_meta() const { + return db_iter_->value_meta(); +} inline Status ArenaWrappedDBIter::status() const { return db_iter_->status(); } inline Status ArenaWrappedDBIter::GetProperty(std::string prop_name, std::string* prop) { diff --git a/db/db_iter.h b/db/db_iter.h index b7cac2d82d..dace73613c 100644 --- a/db/db_iter.h +++ b/db/db_iter.h @@ -69,6 +69,7 @@ class ArenaWrappedDBIter : public Iterator { virtual void Prev() override; virtual Slice key() const override; virtual Slice value() const override; + virtual std::string value_meta() const override; virtual Status status() const override; virtual Status Refresh() override; diff --git a/db/db_test.cc b/db/db_test.cc index d1c1f9f762..d9708815b8 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -62,6 +62,29 @@ namespace TERARKDB_NAMESPACE { +class TestValueExtractor : public ValueExtractor { + public: + ~TestValueExtractor() override{}; + + // Extract a custom info from a specified key value pair. This method is + // called when a value will trans to separate. + virtual Status Extract(const Slice& /*key*/, const Slice& value, + std::string* output) const override { + output->assign(std::to_string(value.size())); + return Status::OK(); + }; +}; +class TestValueExtractorFactory : public ValueExtractorFactory { + public: + virtual std::unique_ptr CreateValueExtractor( + const Context& context) const override { + return std::make_unique(); + } + + // Returns a name that identifies this value extractor factory. + virtual const char* Name() const override { return "TestValueExtractor"; } +}; + class DBTest : public DBTestBase { public: DBTest() : DBTestBase("/db_test") {} @@ -225,6 +248,76 @@ TEST_F(DBTest, WriteEmptyBatch) { ASSERT_EQ("bar", Get(1, "foo")); } +TEST_F(DBTest, GetValueMeta) { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; + options.value_meta_extractor_factory = + std::make_shared(); + + CreateAndReopenWithCF({"pikachu"}, options); + + ASSERT_OK(Put(1, "k4", "123456")); + ASSERT_OK(Put(1, "k6", "12345678")); + ASSERT_OK(Put(1, "k3", "12345")); + ASSERT_OK(Put(1, "k1", "123")); + ASSERT_OK(Put(1, "k2", "1234")); + ASSERT_OK(Put(1, "k5", "1234567")); + ASSERT_OK(Put(1, "k7", "123456789")); + WriteBatch empty_batch; + ASSERT_OK(dbfull()->Write(WriteOptions(), &empty_batch)); + + std::unique_ptr db_iter( + dbfull()->NewIterator(ReadOptions(), dbfull()->GetColumnFamilyHandle(1))); + db_iter->SeekToFirst(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "3"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "4"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "5"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "6"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "7"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "8"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "9"); + db_iter.reset(); + + ASSERT_OK(TryReopenWithColumnFamilies({"default", "pikachu"}, options)); + db_iter.reset( + dbfull()->NewIterator(ReadOptions(), dbfull()->GetColumnFamilyHandle(1))); + db_iter->SeekToFirst(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "3"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "4"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "5"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "6"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "7"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "8"); + db_iter->Next(); + ASSERT_TRUE(db_iter->Valid()); + ASSERT_EQ(db_iter->value_meta(), "9"); +} + TEST_F(DBTest, SkipDelay) { Options options = CurrentOptions(); options.env = env_; @@ -2762,6 +2855,10 @@ class ModelDB : public DB { virtual Slice key() const override { return iter_->first; } virtual Slice value() const override { return iter_->second; } + virtual std::string value_meta() const override { + assert(false); + return ""; + } virtual Status status() const override { return Status::OK(); } private: diff --git a/db/dbformat.h b/db/dbformat.h index 808b54ae04..1fdf9a8cb3 100644 --- a/db/dbformat.h +++ b/db/dbformat.h @@ -77,6 +77,9 @@ inline bool IsValueType(ValueType t) { return t <= kTypeMerge || t == kTypeSingleDeletion || t == kTypeValueIndex || t == kTypeMergeIndex; } +inline bool isValueHandleType(ValueType t) { + return t == kTypeValueIndex || t == kTypeMergeIndex; +} // Checks whether a type is from user operation // kTypeRangeDeletion is in meta block so this API is separated from above diff --git a/include/rocksdb/iterator.h b/include/rocksdb/iterator.h index eabd8350fb..3e7dfcae92 100644 --- a/include/rocksdb/iterator.h +++ b/include/rocksdb/iterator.h @@ -80,6 +80,13 @@ class Iterator : public Cleanable { // REQUIRES: Valid() virtual Slice value() const = 0; + // Return the value meta for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // NOTE: value meta may generate on the fly, just return str value not Slice + // REQUIRES: Valid() + virtual std::string value_meta() const = 0; + // If an error has occurred, return it. Else return an ok status. // If non-blocking IO is requested and this operation cannot be // satisfied without doing some IO, then this returns Status::Incomplete(). diff --git a/include/rocksdb/utilities/juxtapose_db.h b/include/rocksdb/utilities/juxtapose_db.h index f97cdf0afd..d09d5e6cc8 100644 --- a/include/rocksdb/utilities/juxtapose_db.h +++ b/include/rocksdb/utilities/juxtapose_db.h @@ -302,7 +302,10 @@ class JuxtaposeDB : public StackableDB { assert(iter->value() == iter_ref->value()); return iter->value(); } - + std::string value_meta() const override { + assert(false); + return ""; + } Status status() const override { assert(iter->status() == iter_ref->status()); return iter->status(); diff --git a/table/iterator.cc b/table/iterator.cc index 9e7de3aba1..1912d2579d 100644 --- a/table/iterator.cc +++ b/table/iterator.cc @@ -167,6 +167,10 @@ class EmptyIterator : public Iterator { assert(false); return Slice(); } + std::string value_meta() const override { + assert(false); + return ""; + } virtual Status status() const override { return status_; } private: diff --git a/utilities/ttl/db_ttl_impl.h b/utilities/ttl/db_ttl_impl.h index 4a0919cf1e..35936d15de 100644 --- a/utilities/ttl/db_ttl_impl.h +++ b/utilities/ttl/db_ttl_impl.h @@ -134,7 +134,10 @@ class TtlIterator : public Iterator { trimmed_value.size_ -= DBWithTTLImpl::kTSLength; return trimmed_value; } - + std::string value_meta() const override { + assert(false); + return ""; + } Status status() const override { return iter_->status(); } private: diff --git a/utilities/write_batch_with_index/write_batch_with_index.cc b/utilities/write_batch_with_index/write_batch_with_index.cc index 610edb1a26..f8221ae750 100644 --- a/utilities/write_batch_with_index/write_batch_with_index.cc +++ b/utilities/write_batch_with_index/write_batch_with_index.cc @@ -160,7 +160,10 @@ class BaseDeltaIterator : public Iterator { return current_at_base_ ? base_iterator_->value() : delta_iterator_->Entry().value; } - + std::string value_meta() const override { + assert(false); + return ""; + } Status status() const override { if (!status_.ok()) { return status_; diff --git a/utilities/write_batch_with_index/write_batch_with_index_test.cc b/utilities/write_batch_with_index/write_batch_with_index_test.cc index 0fcaf99162..844de811db 100644 --- a/utilities/write_batch_with_index/write_batch_with_index_test.cc +++ b/utilities/write_batch_with_index/write_batch_with_index_test.cc @@ -539,6 +539,10 @@ class KVIter : public Iterator { virtual Slice key() const { return iter_->first; } virtual Slice value() const { return iter_->second; } + std::string value_meta() const override { + assert(false); + return ""; + } virtual Status status() const { return Status::OK(); } private: From 867144197cca08846ea50de1953dd36a0e75f1b1 Mon Sep 17 00:00:00 2001 From: ZhaoMing Date: Mon, 29 Mar 2021 20:28:39 +0800 Subject: [PATCH 2/5] WIP --- db/builder.cc | 15 +++--- db/builder.h | 3 +- db/column_family.cc | 18 +++++++ db/column_family.h | 8 +++ db/compaction_job.cc | 13 ++--- db/comparator_db_test.cc | 5 +- db/db_impl_open.cc | 2 +- db/db_iter.cc | 53 ++++++++++--------- db/db_iter.h | 2 +- db/db_test.cc | 33 ++++++------ db/dbformat.cc | 15 +++--- db/dbformat.h | 5 +- db/flush_job.cc | 7 +-- db/repair.cc | 12 ++--- db/write_batch_test.cc | 1 + include/rocksdb/db.h | 2 + include/rocksdb/iterator.h | 9 ++-- include/rocksdb/utilities/juxtapose_db.h | 10 ++-- table/iterator.cc | 10 ++-- utilities/ttl/db_ttl_impl.h | 7 ++- .../write_batch_with_index.cc | 40 ++++++++++---- .../write_batch_with_index_test.cc | 6 +-- 22 files changed, 157 insertions(+), 119 deletions(-) diff --git a/db/builder.cc b/db/builder.cc index 50cb88a7e4..bcab1afe21 100644 --- a/db/builder.cc +++ b/db/builder.cc @@ -80,7 +80,8 @@ Status BuildTable( int_tbl_prop_collector_factories, const std::vector>* int_tbl_prop_collector_factories_for_blob, - uint32_t column_family_id, const std::string& column_family_name, + const ValueExtractor* meta_extractor, uint32_t column_family_id, + const std::string& column_family_name, std::vector snapshots, SequenceNumber earliest_write_conflict_snapshot, SnapshotChecker* snapshot_checker, const CompressionType compression, @@ -165,7 +166,7 @@ Status BuildTable( std::unique_ptr builder; FileMetaData* current_output = nullptr; TableProperties* current_prop = nullptr; - std::unique_ptr value_meta_extractor; + const ValueExtractor* meta_extractor; Status (*trans_to_separate_callback)(void* args, const Slice& key, LazyBuffer& value) = nullptr; void* trans_to_separate_callback_args = nullptr; @@ -175,7 +176,7 @@ Status BuildTable( bool is_index) override { return SeparateHelper::TransToSeparate( internal_key, value, value.file_number(), meta, is_merge, is_index, - value_meta_extractor.get()); + meta_extractor); } Status TransToSeparate(const Slice& internal_key, @@ -194,11 +195,6 @@ Status BuildTable( return LazyBuffer(); } } separate_helper; - if (ioptions.value_meta_extractor_factory != nullptr) { - ValueExtractorContext context = {column_family_id}; - separate_helper.value_meta_extractor = - ioptions.value_meta_extractor_factory->CreateValueExtractor(context); - } auto finish_output_blob_sst = [&] { Status status; @@ -292,7 +288,7 @@ Status BuildTable( status = SeparateHelper::TransToSeparate( key, value, blob_meta->fd.GetNumber(), Slice(), GetInternalKeyType(key) == kTypeMerge, false, - separate_helper.value_meta_extractor.get()); + separate_helper.meta_extractor); } return status; }; @@ -307,6 +303,7 @@ Status BuildTable( c_style_callback(trans_to_separate); separate_helper.trans_to_separate_callback_args = &trans_to_separate; } + separate_helper.meta_extractor = meta_extractor; CompactionIterator c_iter( iter.get(), &separate_helper, nullptr, diff --git a/db/builder.h b/db/builder.h index 5cdd526705..350111ebe6 100644 --- a/db/builder.h +++ b/db/builder.h @@ -80,7 +80,8 @@ extern Status BuildTable( int_tbl_prop_collector_factories, const std::vector>* int_tbl_prop_collector_factories_for_blob, - uint32_t column_family_id, const std::string& column_family_name, + const ValueExtractor* meta_extractor, uint32_t column_family_id, + const std::string& column_family_name, std::vector snapshots, SequenceNumber earliest_write_conflict_snapshot, SnapshotChecker* snapshot_checker, const CompressionType compression, diff --git a/db/column_family.cc b/db/column_family.cc index 05e9de12de..7a6463fb9c 100644 --- a/db/column_family.cc +++ b/db/column_family.cc @@ -104,6 +104,10 @@ const Comparator* ColumnFamilyHandleImpl::GetComparator() const { return cfd()->user_comparator(); } +const ValueExtractor* ColumnFamilyHandleImpl::GetMetaExtractor() const { + return cfd()->meta_extractor(); +} + Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options) { if (!cf_options.compression_per_level.empty()) { for (size_t level = 0; level < cf_options.compression_per_level.size(); @@ -489,6 +493,12 @@ ColumnFamilyData::ColumnFamilyData( } } + if (ioptions_.value_meta_extractor_factory) { + ValueExtractorContext ctx{id_}; + meta_extractor_ = + ioptions_.value_meta_extractor_factory->CreateValueExtractor(ctx); + } + RecalculateWriteStallConditions(mutable_cf_options_); } @@ -1476,4 +1486,12 @@ const Comparator* GetColumnFamilyUserComparator( return nullptr; } +const ValueExtractor* GetColumnFamilyMetaExtractor( + ColumnFamilyHandle* column_family) { + if (column_family != nullptr) { + return column_family->GetMetaExtractor(); + } + return nullptr; +} + } // namespace TERARKDB_NAMESPACE diff --git a/db/column_family.h b/db/column_family.h index 0bc4b2e93b..5db9da6b7d 100644 --- a/db/column_family.h +++ b/db/column_family.h @@ -64,6 +64,7 @@ class ColumnFamilyHandleImpl : public ColumnFamilyHandle { virtual const std::string& GetName() const override; virtual Status GetDescriptor(ColumnFamilyDescriptor* desc) override; virtual const Comparator* GetComparator() const override; + virtual const ValueExtractor* GetMetaExtractor() const override; private: ColumnFamilyData* cfd_; @@ -318,6 +319,8 @@ class ColumnFamilyData { const InternalKeyComparator& internal_comparator() const { return internal_comparator_; } + // thread-safe + const ValueExtractor* meta_extractor() const { return meta_extractor_.get(); } const std::vector>* int_tbl_prop_collector_factories(const MutableCFOptions& moptions) const { @@ -436,6 +439,8 @@ class ColumnFamilyData { const ImmutableCFOptions ioptions_; MutableCFOptions mutable_cf_options_; + std::unique_ptr meta_extractor_; + const bool is_delete_range_supported_; std::unique_ptr table_cache_; @@ -655,4 +660,7 @@ extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family); extern const Comparator* GetColumnFamilyUserComparator( ColumnFamilyHandle* column_family); +extern const ValueExtractor* GetColumnFamilyMetaExtractor( + ColumnFamilyHandle* column_family); + } // namespace TERARKDB_NAMESPACE diff --git a/db/compaction_job.cc b/db/compaction_job.cc index bc582a7a44..0a9aaa9c17 100644 --- a/db/compaction_job.cc +++ b/db/compaction_job.cc @@ -1277,7 +1277,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) { struct BuilderSeparateHelper : public SeparateHelper { SeparateHelper* separate_helper = nullptr; - std::unique_ptr value_meta_extractor; + const ValueExtractor* meta_extractor; Status (*trans_to_separate_callback)(void* args, const Slice& key, LazyBuffer& value) = nullptr; void* trans_to_separate_callback_args = nullptr; @@ -1287,7 +1287,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) { bool is_index) override { return SeparateHelper::TransToSeparate( internal_key, value, value.file_number(), meta, is_merge, is_index, - value_meta_extractor.get()); + meta_extractor); } Status TransToSeparate(const Slice& key, LazyBuffer& value) override { @@ -1303,13 +1303,6 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) { return separate_helper->TransToCombined(user_key, sequence, value); } } separate_helper; - if (compact_->compaction->immutable_cf_options() - ->value_meta_extractor_factory != nullptr) { - ValueExtractorContext context = {cfd->GetID()}; - separate_helper.value_meta_extractor = - compact_->compaction->immutable_cf_options() - ->value_meta_extractor_factory->CreateValueExtractor(context); - } auto trans_to_separate = [&](const Slice& key, LazyBuffer& value) { assert(value.file_number() == uint64_t(-1)); @@ -1340,6 +1333,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) { }; separate_helper.separate_helper = sub_compact->compaction->input_version(); + separate_helper.meta_extractor = + compact_->compaction->column_family_data()->meta_extractor(); if (!sub_compact->compaction->immutable_cf_options() ->table_factory->IsBuilderNeedSecondPass()) { separate_helper.trans_to_separate_callback = diff --git a/db/comparator_db_test.cc b/db/comparator_db_test.cc index cda62565bd..3208ae9ff1 100644 --- a/db/comparator_db_test.cc +++ b/db/comparator_db_test.cc @@ -52,11 +52,8 @@ class KVIter : public Iterator { } virtual Slice key() const override { return iter_->first; } + virtual Slice meta() const override { return Slice::Invalid(); } virtual Slice value() const override { return iter_->second; } - std::string value_meta() const override { - assert(false); - return ""; - } virtual Status status() const override { return Status::OK(); } private: diff --git a/db/db_impl_open.cc b/db/db_impl_open.cc index e66722a9d3..f84dad3b86 100644 --- a/db/db_impl_open.cc +++ b/db/db_impl_open.cc @@ -1173,7 +1173,7 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd, &meta_vec, cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(mutable_cf_options), cfd->int_tbl_prop_collector_factories_for_blob(mutable_cf_options), - cfd->GetID(), cfd->GetName(), snapshot_seqs, + cfd->meta_extractor(), cfd->GetID(), cfd->GetName(), snapshot_seqs, earliest_write_conflict_snapshot, snapshot_checker, GetCompressionFlush(*cfd->ioptions(), mutable_cf_options), cfd->ioptions()->compression_opts, paranoid_file_checks, diff --git a/db/db_iter.cc b/db/db_iter.cc index 790a52b5ac..439b3e2bdb 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -189,6 +189,31 @@ class DBIter final : public Iterator { return saved_key_.GetUserKey(); } } + virtual Slice meta() const override { + if (cfd_ == nullptr) { + return Slice::Invalid(); + } + if (meta_.valid()) { + return meta_; + } + do { + auto v = value(); + if (!v.valid()) { + break; + } + auto s = cfd_->meta_extractor()->Extract(saved_key_.GetUserKey(), v, + &meta_buffer_); + if (!s.ok()) { + valid_ = false; + break; + } + meta_ = meta_buffer_; + return meta_; + } while (false); + + meta_ = Slice::Invalid(); + return meta_; + } virtual Slice value() const override { assert(valid_); auto s = value_.fetch(); @@ -199,27 +224,6 @@ class DBIter final : public Iterator { } return value_.slice(); } - virtual std::string value_meta() const override { - if (cfd_ == nullptr) return ""; - - value_.fetch(); - assert(value_.valid()); - if (isValueHandleType(ikey_.type)) { - return separate_helper_->DecodeValueMeta(value_.slice()).ToString(); - } - - ValueExtractorContext context = {cfd_->GetID()}; - auto value_meta_extractor = - cfd_->ioptions()->value_meta_extractor_factory->CreateValueExtractor( - context); - std::string value_meta; - Status s = value_meta_extractor->Extract(ikey_.user_key, value_.slice(), - &value_meta); - if (!s.ok()) { - return ""; - } - return value_meta; - } virtual Status status() const override { if (status_.ok()) { return iter_->status(); @@ -300,6 +304,7 @@ class DBIter final : public Iterator { local_stats_.skip_count_--; } num_internal_keys_skipped_ = 0; + meta_ = Slice::Invalid(); value_.reset(); if (value_buffer_.capacity() > 1048576) { std::string().swap(value_buffer_); @@ -324,6 +329,8 @@ class DBIter final : public Iterator { ParsedInternalKey ikey_; LazyBuffer value_; std::string value_buffer_; + mutable Slice meta_; + mutable std::string meta_buffer_; Direction direction_; mutable bool valid_; bool current_entry_is_merged_; @@ -1466,10 +1473,8 @@ inline void ArenaWrappedDBIter::SeekForPrev(const Slice& target) { inline void ArenaWrappedDBIter::Next() { db_iter_->Next(); } inline void ArenaWrappedDBIter::Prev() { db_iter_->Prev(); } inline Slice ArenaWrappedDBIter::key() const { return db_iter_->key(); } +inline Slice ArenaWrappedDBIter::meta() const { return db_iter_->meta(); } inline Slice ArenaWrappedDBIter::value() const { return db_iter_->value(); } -inline std::string ArenaWrappedDBIter::value_meta() const { - return db_iter_->value_meta(); -} inline Status ArenaWrappedDBIter::status() const { return db_iter_->status(); } inline Status ArenaWrappedDBIter::GetProperty(std::string prop_name, std::string* prop) { diff --git a/db/db_iter.h b/db/db_iter.h index dace73613c..63cbf8770c 100644 --- a/db/db_iter.h +++ b/db/db_iter.h @@ -68,8 +68,8 @@ class ArenaWrappedDBIter : public Iterator { virtual void Next() override; virtual void Prev() override; virtual Slice key() const override; + virtual Slice meta() const override; virtual Slice value() const override; - virtual std::string value_meta() const override; virtual Status status() const override; virtual Status Refresh() override; diff --git a/db/db_test.cc b/db/db_test.cc index d9708815b8..c01a259506 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -271,25 +271,25 @@ TEST_F(DBTest, GetValueMeta) { dbfull()->NewIterator(ReadOptions(), dbfull()->GetColumnFamilyHandle(1))); db_iter->SeekToFirst(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "3"); + ASSERT_EQ(db_iter->meta(), "3"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "4"); + ASSERT_EQ(db_iter->meta(), "4"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "5"); + ASSERT_EQ(db_iter->meta(), "5"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "6"); + ASSERT_EQ(db_iter->meta(), "6"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "7"); + ASSERT_EQ(db_iter->meta(), "7"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "8"); + ASSERT_EQ(db_iter->meta(), "8"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "9"); + ASSERT_EQ(db_iter->meta(), "9"); db_iter.reset(); ASSERT_OK(TryReopenWithColumnFamilies({"default", "pikachu"}, options)); @@ -297,25 +297,25 @@ TEST_F(DBTest, GetValueMeta) { dbfull()->NewIterator(ReadOptions(), dbfull()->GetColumnFamilyHandle(1))); db_iter->SeekToFirst(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "3"); + ASSERT_EQ(db_iter->meta(), "3"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "4"); + ASSERT_EQ(db_iter->meta(), "4"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "5"); + ASSERT_EQ(db_iter->meta(), "5"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "6"); + ASSERT_EQ(db_iter->meta(), "6"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "7"); + ASSERT_EQ(db_iter->meta(), "7"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "8"); + ASSERT_EQ(db_iter->meta(), "8"); db_iter->Next(); ASSERT_TRUE(db_iter->Valid()); - ASSERT_EQ(db_iter->value_meta(), "9"); + ASSERT_EQ(db_iter->meta(), "9"); } TEST_F(DBTest, SkipDelay) { @@ -2855,10 +2855,7 @@ class ModelDB : public DB { virtual Slice key() const override { return iter_->first; } virtual Slice value() const override { return iter_->second; } - virtual std::string value_meta() const override { - assert(false); - return ""; - } + virtual Slice meta() const override { return Slice::Invalid(); } virtual Status status() const override { return Status::OK(); } private: diff --git a/db/dbformat.cc b/db/dbformat.cc index 7ea4fa94a7..4ec81d3bfa 100644 --- a/db/dbformat.cc +++ b/db/dbformat.cc @@ -198,12 +198,13 @@ void IterKey::EnlargeBuffer(size_t key_size) { buf_size_ = key_size; } -Status SeparateHelper::TransToSeparate( - const Slice& internal_key, LazyBuffer& value, uint64_t file_number, - const Slice& meta, bool is_merge, bool is_index, - const ValueExtractor* value_meta_extractor) { +Status SeparateHelper::TransToSeparate(const Slice& internal_key, + LazyBuffer& value, uint64_t file_number, + const Slice& meta, bool is_merge, + bool is_index, + const ValueExtractor* meta_extractor) { assert(file_number != uint64_t(-1)); - if (value_meta_extractor == nullptr || is_merge) { + if (meta_extractor == nullptr || is_merge) { value.reset(EncodeFileNumber(file_number), true, file_number); return Status::OK(); } @@ -217,8 +218,8 @@ Status SeparateHelper::TransToSeparate( return s; } std::string value_meta; - s = value_meta_extractor->Extract(ExtractUserKey(internal_key), - value.slice(), &value_meta); + s = meta_extractor->Extract(ExtractUserKey(internal_key), value.slice(), + &value_meta); if (s.ok()) { Slice parts[] = {EncodeFileNumber(file_number), value_meta}; value.reset(SliceParts(parts, 2), file_number); diff --git a/db/dbformat.h b/db/dbformat.h index 1fdf9a8cb3..7b53ad28fd 100644 --- a/db/dbformat.h +++ b/db/dbformat.h @@ -77,9 +77,6 @@ inline bool IsValueType(ValueType t) { return t <= kTypeMerge || t == kTypeSingleDeletion || t == kTypeValueIndex || t == kTypeMergeIndex; } -inline bool isValueHandleType(ValueType t) { - return t == kTypeValueIndex || t == kTypeMergeIndex; -} // Checks whether a type is from user operation // kTypeRangeDeletion is in meta block so this API is separated from above @@ -813,7 +810,7 @@ class SeparateHelper { static Status TransToSeparate(const Slice& internal_key, LazyBuffer& value, uint64_t file_number, const Slice& meta, bool is_merge, bool is_index, - const ValueExtractor* value_meta_extractor); + const ValueExtractor* meta_extractor); virtual Status TransToSeparate(const Slice& internal_key, LazyBuffer& value, const Slice& meta, bool is_merge, diff --git a/db/flush_job.cc b/db/flush_job.cc index 4599c89c41..f6001e83ce 100644 --- a/db/flush_job.cc +++ b/db/flush_job.cc @@ -379,9 +379,10 @@ Status FlushJob::WriteLevel0Table() { cfd_->internal_comparator(), cfd_->int_tbl_prop_collector_factories(mutable_cf_options_), cfd_->int_tbl_prop_collector_factories_for_blob(mutable_cf_options_), - cfd_->GetID(), cfd_->GetName(), existing_snapshots_, - earliest_write_conflict_snapshot_, snapshot_checker_, - output_compression_, cfd_->ioptions()->compression_opts, + cfd_->meta_extractor(), cfd_->GetID(), cfd_->GetName(), + existing_snapshots_, earliest_write_conflict_snapshot_, + snapshot_checker_, output_compression_, + cfd_->ioptions()->compression_opts, mutable_cf_options_.paranoid_file_checks, cfd_->internal_stats(), TableFileCreationReason::kFlush, event_logger_, job_context_->job_id, Env::IO_HIGH, &table_properties_, 0 /* level */, flush_load_, diff --git a/db/repair.cc b/db/repair.cc index 9fbb6ff2ee..3a2d8f4fbd 100644 --- a/db/repair.cc +++ b/db/repair.cc @@ -442,12 +442,12 @@ class Repairer { &get_range_del_iters, &meta, cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(moptions), cfd->int_tbl_prop_collector_factories_for_blob(moptions), - cfd->GetID(), cfd->GetName(), {}, kMaxSequenceNumber, - snapshot_checker, kNoCompression, CompressionOptions(), false, - nullptr /* internal_stats */, TableFileCreationReason::kRecovery, - nullptr /* event_logger */, 0 /* job_id */, Env::IO_HIGH, - nullptr /* table_properties */, -1 /* level */, current_time, - write_hint); + cfd->meta_extractor(), cfd->GetID(), cfd->GetName(), {}, + kMaxSequenceNumber, snapshot_checker, kNoCompression, + CompressionOptions(), false, nullptr /* internal_stats */, + TableFileCreationReason::kRecovery, nullptr /* event_logger */, + 0 /* job_id */, Env::IO_HIGH, nullptr /* table_properties */, + -1 /* level */, current_time, write_hint); ROCKS_LOG_INFO(db_options_.info_log, "Log #%" PRIu64 ": %d ops saved to Table #%" PRIu64 " %s", log, counter, meta[0].fd.GetNumber(), diff --git a/db/write_batch_test.cc b/db/write_batch_test.cc index 6c23813496..d107aea87d 100644 --- a/db/write_batch_test.cc +++ b/db/write_batch_test.cc @@ -626,6 +626,7 @@ class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl { const Comparator* GetComparator() const override { return BytewiseComparator(); } + const ValueExtractor* GetMetaExtractor() const override { return nullptr; } private: uint32_t id_; diff --git a/include/rocksdb/db.h b/include/rocksdb/db.h index 33768b69ff..c9f0971929 100644 --- a/include/rocksdb/db.h +++ b/include/rocksdb/db.h @@ -27,6 +27,7 @@ #include "rocksdb/thread_status.h" #include "rocksdb/transaction_log.h" #include "rocksdb/types.h" +#include "rocksdb/value_extractor.h" #include "rocksdb/version.h" #ifdef _WIN32 @@ -99,6 +100,7 @@ class ColumnFamilyHandle { // Returns the comparator of the column family associated with the // current handle. virtual const Comparator* GetComparator() const = 0; + virtual const ValueExtractor* GetMetaExtractor() const = 0; }; static const int kMajorVersion = __ROCKSDB_MAJOR__; diff --git a/include/rocksdb/iterator.h b/include/rocksdb/iterator.h index 3e7dfcae92..c8b956f775 100644 --- a/include/rocksdb/iterator.h +++ b/include/rocksdb/iterator.h @@ -74,18 +74,17 @@ class Iterator : public Cleanable { // REQUIRES: Valid() virtual Slice key() const = 0; - // Return the value for the current entry. The underlying storage for + // Return the meta for the current entry. The underlying storage for // the returned slice is valid only until the next modification of // the iterator. // REQUIRES: Valid() - virtual Slice value() const = 0; + virtual Slice meta() const = 0; - // Return the value meta for the current entry. The underlying storage for + // Return the value for the current entry. The underlying storage for // the returned slice is valid only until the next modification of // the iterator. - // NOTE: value meta may generate on the fly, just return str value not Slice // REQUIRES: Valid() - virtual std::string value_meta() const = 0; + virtual Slice value() const = 0; // If an error has occurred, return it. Else return an ok status. // If non-blocking IO is requested and this operation cannot be diff --git a/include/rocksdb/utilities/juxtapose_db.h b/include/rocksdb/utilities/juxtapose_db.h index d09d5e6cc8..a70048bdac 100644 --- a/include/rocksdb/utilities/juxtapose_db.h +++ b/include/rocksdb/utilities/juxtapose_db.h @@ -298,14 +298,16 @@ class JuxtaposeDB : public StackableDB { return iter->key(); } + Slice meta() const override { + assert(iter->meta() == iter_ref->meta()); + return iter->meta(); + } + Slice value() const override { assert(iter->value() == iter_ref->value()); return iter->value(); } - std::string value_meta() const override { - assert(false); - return ""; - } + Status status() const override { assert(iter->status() == iter_ref->status()); return iter->status(); diff --git a/table/iterator.cc b/table/iterator.cc index 1912d2579d..42cc48131e 100644 --- a/table/iterator.cc +++ b/table/iterator.cc @@ -161,15 +161,15 @@ class EmptyIterator : public Iterator { virtual void Prev() override { assert(false); } Slice key() const override { assert(false); - return Slice(); + return Slice::Invalid(); } - Slice value() const override { + Slice meta() const override { assert(false); - return Slice(); + return Slice::Invalid(); } - std::string value_meta() const override { + Slice value() const override { assert(false); - return ""; + return Slice::Invalid(); } virtual Status status() const override { return status_; } diff --git a/utilities/ttl/db_ttl_impl.h b/utilities/ttl/db_ttl_impl.h index 35936d15de..ed26b90257 100644 --- a/utilities/ttl/db_ttl_impl.h +++ b/utilities/ttl/db_ttl_impl.h @@ -127,6 +127,8 @@ class TtlIterator : public Iterator { DBWithTTLImpl::kTSLength); } + Slice meta() const override { return iter_->meta(); } + Slice value() const override { // TODO: handle timestamp corruption like in general iterator semantics assert(DBWithTTLImpl::SanityCheckTimestamp(iter_->value()).ok()); @@ -134,10 +136,7 @@ class TtlIterator : public Iterator { trimmed_value.size_ -= DBWithTTLImpl::kTSLength; return trimmed_value; } - std::string value_meta() const override { - assert(false); - return ""; - } + Status status() const override { return iter_->status(); } private: diff --git a/utilities/write_batch_with_index/write_batch_with_index.cc b/utilities/write_batch_with_index/write_batch_with_index.cc index f8221ae750..6bfdfb173d 100644 --- a/utilities/write_batch_with_index/write_batch_with_index.cc +++ b/utilities/write_batch_with_index/write_batch_with_index.cc @@ -19,6 +19,7 @@ #include "rocksdb/comparator.h" #include "rocksdb/iterator.h" #include "rocksdb/terark_namespace.h" +#include "rocksdb/value_extractor.h" #include "util/arena.h" #include "util/cast_util.h" #include "util/string_util.h" @@ -35,19 +36,21 @@ namespace TERARKDB_NAMESPACE { class BaseDeltaIterator : public Iterator { public: BaseDeltaIterator(Iterator* base_iterator, WBWIIterator* delta_iterator, - const Comparator* comparator) + const Comparator* comparator, + const ValueExtractor* meta_extractor) : forward_(true), current_at_base_(true), equal_keys_(false), status_(Status::OK()), base_iterator_(base_iterator), delta_iterator_(delta_iterator), - comparator_(comparator) {} + comparator_(comparator), + meta_extractor_(meta_extractor) {} virtual ~BaseDeltaIterator() {} bool Valid() const override { - return current_at_base_ ? BaseValid() : DeltaValid(); + return status_.ok() && (current_at_base_ ? BaseValid() : DeltaValid()); } void SeekToFirst() override { @@ -155,15 +158,29 @@ class BaseDeltaIterator : public Iterator { return current_at_base_ ? base_iterator_->key() : delta_iterator_->Entry().key; } + virtual Slice meta() const override { + if (current_at_base_) { + return base_iterator_->meta(); + } + if (!meta_extractor_) { + return Slice::Invalid(); + } + auto s = meta_extractor_->Extract(delta_iterator_->Entry().key, + delta_iterator_->Entry().value, &meta_); + if (!s.ok()) { + if (status_.ok()) { + status_ = std::move(s); + } + return Slice::Invalid(); + } + return meta_; + } Slice value() const override { return current_at_base_ ? base_iterator_->value() : delta_iterator_->Entry().value; } - std::string value_meta() const override { - assert(false); - return ""; - } + Status status() const override { if (!status_.ok()) { return status_; @@ -327,10 +344,12 @@ class BaseDeltaIterator : public Iterator { bool forward_; bool current_at_base_; bool equal_keys_; - Status status_; + mutable Status status_; std::unique_ptr base_iterator_; std::unique_ptr delta_iterator_; const Comparator* comparator_; // not owned + mutable std::string meta_; + const ValueExtractor* meta_extractor_; }; class WBWIIteratorImpl : public WBWIIterator { @@ -687,7 +706,8 @@ Iterator* WriteBatchWithIndex::NewIteratorWithBase( return nullptr; } return new BaseDeltaIterator(base_iterator, NewIterator(column_family), - GetColumnFamilyUserComparator(column_family)); + GetColumnFamilyUserComparator(column_family), + GetColumnFamilyMetaExtractor(column_family)); } Iterator* WriteBatchWithIndex::NewIteratorWithBase(Iterator* base_iterator) { @@ -697,7 +717,7 @@ Iterator* WriteBatchWithIndex::NewIteratorWithBase(Iterator* base_iterator) { } // default column family's comparator return new BaseDeltaIterator(base_iterator, NewIterator(), - rep->default_comparator); + rep->default_comparator, nullptr); } Status WriteBatchWithIndex::Put(ColumnFamilyHandle* column_family, diff --git a/utilities/write_batch_with_index/write_batch_with_index_test.cc b/utilities/write_batch_with_index/write_batch_with_index_test.cc index 844de811db..12041ef0df 100644 --- a/utilities/write_batch_with_index/write_batch_with_index_test.cc +++ b/utilities/write_batch_with_index/write_batch_with_index_test.cc @@ -34,6 +34,7 @@ class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl { comparator_(comparator) {} uint32_t GetID() const override { return id_; } const Comparator* GetComparator() const override { return comparator_; } + const ValueExtractor* GetMetaExtractor() const override { return nullptr; } private: uint32_t id_; @@ -538,11 +539,8 @@ class KVIter : public Iterator { } virtual Slice key() const { return iter_->first; } + virtual Slice meta() const override { return Slice::Invalid(); } virtual Slice value() const { return iter_->second; } - std::string value_meta() const override { - assert(false); - return ""; - } virtual Status status() const { return Status::OK(); } private: From 65f859ba1109ac650b0179011c68b75347664279 Mon Sep 17 00:00:00 2001 From: LiuYangming Date: Tue, 30 Mar 2021 15:05:20 +0800 Subject: [PATCH 3/5] minor fix --- db/compaction_job.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/compaction_job.cc b/db/compaction_job.cc index 0a9aaa9c17..acda325c60 100644 --- a/db/compaction_job.cc +++ b/db/compaction_job.cc @@ -1327,7 +1327,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) { status = SeparateHelper::TransToSeparate( key, value, blob_meta->fd.GetNumber(), Slice(), GetInternalKeyType(key) == kTypeMerge, false, - separate_helper.value_meta_extractor.get()); + separate_helper.meta_extractor); } return status; }; From af45c67e309c7d5c32e8615c0445ced1f4e0bfab Mon Sep 17 00:00:00 2001 From: ZhaoMing Date: Wed, 31 Mar 2021 19:05:14 +0800 Subject: [PATCH 4/5] Make Address Sanitizer happy --- db/version_set.cc | 15 ++++--------- db/version_set.h | 56 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index 5566f18c50..53f0b75479 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -342,8 +342,6 @@ class FilePicker { }; } // anonymous namespace -VersionStorageInfo::~VersionStorageInfo() { delete[](files_ - 1); } - Version::~Version() { assert(refs_ == 0); @@ -1174,7 +1172,7 @@ VersionStorageInfo::VersionStorageInfo( num_non_empty_levels_(0), file_indexer_(user_comparator), compaction_style_(compaction_style), - files_(new std::vector[num_levels_ + 1]), + files_(num_levels_), base_level_(num_levels_ == 1 ? -1 : 1), level_multiplier_(0.0), files_by_compaction_pri_(num_levels_), @@ -1196,9 +1194,7 @@ VersionStorageInfo::VersionStorageInfo( is_pick_compaction_fail(false), is_pick_garbage_collection_fail(false), force_consistency_checks_(_force_consistency_checks), - blob_marked_for_compaction_(false) { - ++files_; // level -1 used for dependence files -} + blob_marked_for_compaction_(false) {} Version::Version(ColumnFamilyData* column_family_data, VersionSet* vset, const EnvOptions& env_opt, @@ -4046,9 +4042,7 @@ Status VersionSet::ReduceNumberOfLevels(const std::string& dbname, // we need to allocate an array with the old number of levels size to // avoid SIGSEGV in WriteSnapshot() // however, all levels bigger or equal to new_levels will be empty - std::vector* new_files_list = - new std::vector[current_levels + 1]; - ++new_files_list; + VersionStorageInfo::Files new_files_list(current_levels); for (int i = -1; i < new_levels - 1; i++) { new_files_list[i] = vstorage->LevelFiles(i); } @@ -4057,8 +4051,7 @@ Status VersionSet::ReduceNumberOfLevels(const std::string& dbname, new_files_list[new_levels - 1] = vstorage->LevelFiles(first_nonempty_level); } - delete[](vstorage->files_ - 1); - vstorage->files_ = new_files_list; + vstorage->files_ = std::move(new_files_list); vstorage->num_levels_ = new_levels; MutableCFOptions mutable_cf_options(*options); diff --git a/db/version_set.h b/db/version_set.h index d49511d4d5..6200cf9af5 100644 --- a/db/version_set.h +++ b/db/version_set.h @@ -97,7 +97,7 @@ class VersionStorageInfo { const Comparator* user_comparator, int num_levels, CompactionStyle compaction_style, bool _force_consistency_checks); - ~VersionStorageInfo(); + ~VersionStorageInfo() = default; void Reserve(int level, size_t size) { files_[level].reserve(size); } @@ -514,7 +514,59 @@ class VersionStorageInfo { // List of files per level, files in each level are arranged // in increasing order of keys - std::vector* files_; + struct Files { + Files(const Files&) = delete; + Files& operator=(const Files&) = delete; + +#if __SANITIZE_ADDRESS__ + std::vector> files; + + Files(size_t num_levels) { files.resize(num_levels + 1); } + Files(Files&&) = default; + Files& operator=(Files&&) = default; + + std::vector& operator[](int l) { return files[l + 1]; } + const std::vector& operator[](int l) const { + return files[l + 1]; + } + + operator std::vector*() { return files.data() + 1; } +#else + std::vector* files; + + Files(size_t num_levels) + : files(new std::vector[num_levels + 1]) { + ++files; + } + Files(Files&& other) { + files = other.files; + other.files = nullptr; + } + Files& operator=(Files&& other) { + if (this != &other) { + if (files != nullptr) { + delete[](files - 1); + } + files = other.files; + other.files = nullptr; + } + return *this; + } + ~Files() { + if (files != nullptr) { + delete[](files - 1); + } + } + + std::vector& operator[](int l) { return files[l]; } + const std::vector& operator[](int l) const { + return files[l]; + } + + operator std::vector*() { return files; } +#endif + }; + Files files_; // Dependence files both in files[-1] and dependence_map DependenceMap dependence_map_; From 9f6429e5c1a732bb2d9f1e6bb8b718357d477030 Mon Sep 17 00:00:00 2001 From: ZhaoMing Date: Fri, 2 Apr 2021 19:48:20 +0800 Subject: [PATCH 5/5] Make meta_buffer empty for user meta_extractor --- db/db_iter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/db/db_iter.cc b/db/db_iter.cc index 439b3e2bdb..2e93af5d70 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -305,6 +305,7 @@ class DBIter final : public Iterator { } num_internal_keys_skipped_ = 0; meta_ = Slice::Invalid(); + meta_buffer_.clear(); value_.reset(); if (value_buffer_.capacity() > 1048576) { std::string().swap(value_buffer_);