diff --git a/db/db_bloom_filter_test.cc b/db/db_bloom_filter_test.cc index 4a97f93d7..289b5ec62 100644 --- a/db/db_bloom_filter_test.cc +++ b/db/db_bloom_filter_test.cc @@ -39,6 +39,26 @@ class DBBloomFilterTestWithParam } }; +class SliceTransformLimitedDomainGeneric : public SliceTransform { + const char* Name() const override { + return "SliceTransformLimitedDomainGeneric"; + } + + Slice Transform(const Slice& src) const override { + return Slice(src.data(), 5); + } + + bool InDomain(const Slice& src) const override { + // prefix will be x???? + return src.size() >= 5; + } + + bool InRange(const Slice& dst) const override { + // prefix will be x???? + return dst.size() == 5; + } +}; + // KeyMayExist can lead to a few false positives, but not false negatives. // To make test deterministic, use a much larger number of bits per key-20 than // bits in the key, so that false positives are eliminated @@ -117,6 +137,53 @@ TEST_P(DBBloomFilterTestWithParam, KeyMayExist) { ChangeOptions(kSkipPlainTable | kSkipHashIndex | kSkipFIFOCompaction)); } +TEST_F(DBBloomFilterTest, GetFilterByPrefixBloomCustomPrefixExtractor) { + for (bool partition_filters : {true, false}) { + Options options = last_options_; + options.prefix_extractor = + std::make_shared(); + options.statistics = rocksdb::CreateDBStatistics(); + BlockBasedTableOptions bbto; + bbto.filter_policy.reset(NewBloomFilterPolicy(10, false)); + if (partition_filters) { + bbto.partition_filters = true; + bbto.index_type = BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch; + } + bbto.whole_key_filtering = false; + options.table_factory.reset(NewBlockBasedTableFactory(bbto)); + DestroyAndReopen(options); + + WriteOptions wo; + ReadOptions ro; + FlushOptions fo; + fo.wait = true; + std::string value; + + ASSERT_OK(dbfull()->Put(wo, "barbarbar", "foo")); + ASSERT_OK(dbfull()->Put(wo, "barbarbar2", "foo2")); + ASSERT_OK(dbfull()->Put(wo, "foofoofoo", "bar")); + + dbfull()->Flush(fo); + + ASSERT_EQ("foo", Get("barbarbar")); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 0); + ASSERT_EQ("foo2", Get("barbarbar2")); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 0); + ASSERT_EQ("NOT_FOUND", Get("barbarbar3")); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 0); + + ASSERT_EQ("NOT_FOUND", Get("barfoofoo")); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 1); + + ASSERT_EQ("NOT_FOUND", Get("foobarbar")); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 2); + + ro.total_order_seek = true; + ASSERT_TRUE(db_->Get(ro, "foobarbar", &value).IsNotFound()); + ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 2); + } +} + TEST_F(DBBloomFilterTest, GetFilterByPrefixBloom) { for (bool partition_filters : {true, false}) { Options options = last_options_; diff --git a/db/db_iterator_test.cc b/db/db_iterator_test.cc index b040a02b3..dfcd2a428 100644 --- a/db/db_iterator_test.cc +++ b/db/db_iterator_test.cc @@ -1537,6 +1537,26 @@ TEST_P(DBIteratorTest, PinnedDataIteratorReadAfterUpdate) { delete iter; } +class SliceTransformLimitedDomainGeneric : public SliceTransform { + const char* Name() const override { + return "SliceTransformLimitedDomainGeneric"; + } + + Slice Transform(const Slice& src) const override { + return Slice(src.data(), 1); + } + + bool InDomain(const Slice& src) const override { + // prefix will be x???? + return src.size() >= 1; + } + + bool InRange(const Slice& dst) const override { + // prefix will be x???? + return dst.size() == 1; + } +}; + TEST_P(DBIteratorTest, IterSeekForPrevCrossingFiles) { Options options = CurrentOptions(); options.prefix_extractor.reset(NewFixedPrefixTransform(1)); @@ -1591,6 +1611,61 @@ TEST_P(DBIteratorTest, IterSeekForPrevCrossingFiles) { } } +TEST_P(DBIteratorTest, IterSeekForPrevCrossingFilesCustomPrefixExtractor) { + Options options = CurrentOptions(); + options.prefix_extractor = + std::make_shared(); + options.disable_auto_compactions = true; + // Enable prefix bloom for SST files + BlockBasedTableOptions table_options; + table_options.filter_policy.reset(NewBloomFilterPolicy(10, true)); + options.table_factory.reset(NewBlockBasedTableFactory(table_options)); + DestroyAndReopen(options); + + ASSERT_OK(Put("a1", "va1")); + ASSERT_OK(Put("a2", "va2")); + ASSERT_OK(Put("a3", "va3")); + ASSERT_OK(Flush()); + + ASSERT_OK(Put("b1", "vb1")); + ASSERT_OK(Put("b2", "vb2")); + ASSERT_OK(Put("b3", "vb3")); + ASSERT_OK(Flush()); + + ASSERT_OK(Put("b4", "vb4")); + ASSERT_OK(Put("d1", "vd1")); + ASSERT_OK(Put("d2", "vd2")); + ASSERT_OK(Put("d4", "vd4")); + ASSERT_OK(Flush()); + + MoveFilesToLevel(1); + { + ReadOptions ro; + Iterator* iter = NewIterator(ro); + + iter->SeekForPrev("a4"); + ASSERT_EQ(iter->key().ToString(), "a3"); + ASSERT_EQ(iter->value().ToString(), "va3"); + + iter->SeekForPrev("c2"); + ASSERT_EQ(iter->key().ToString(), "b3"); + iter->SeekForPrev("d3"); + ASSERT_EQ(iter->key().ToString(), "d2"); + iter->SeekForPrev("b5"); + ASSERT_EQ(iter->key().ToString(), "b4"); + delete iter; + } + + { + ReadOptions ro; + ro.prefix_same_as_start = true; + Iterator* iter = NewIterator(ro); + iter->SeekForPrev("c2"); + ASSERT_TRUE(!iter->Valid()); + delete iter; + } +} + TEST_P(DBIteratorTest, IterPrevKeyCrossingBlocks) { Options options = CurrentOptions(); BlockBasedTableOptions table_options; diff --git a/table/block_based_filter_block.cc b/table/block_based_filter_block.cc index ffd37f01d..a4b406869 100644 --- a/table/block_based_filter_block.cc +++ b/table/block_based_filter_block.cc @@ -201,9 +201,6 @@ bool BlockBasedFilterBlockReader::PrefixMayMatch( uint64_t block_offset, const bool /*no_io*/, const Slice* const /*const_ikey_ptr*/) { assert(block_offset != kNotValid); - if (!prefix_extractor_) { - return true; - } return MayMatch(prefix, block_offset); } diff --git a/table/full_filter_block.cc b/table/full_filter_block.cc index fec42c407..da9b93ee6 100644 --- a/table/full_filter_block.cc +++ b/table/full_filter_block.cc @@ -135,9 +135,6 @@ bool FullFilterBlockReader::PrefixMayMatch( (void)block_offset; #endif assert(block_offset == kNotValid); - if (!prefix_extractor_) { - return true; - } return MayMatch(prefix); } diff --git a/table/partitioned_filter_block.cc b/table/partitioned_filter_block.cc index e9d02ea67..0ee738c4a 100644 --- a/table/partitioned_filter_block.cc +++ b/table/partitioned_filter_block.cc @@ -186,7 +186,7 @@ bool PartitionedFilterBlockReader::PrefixMayMatch( #endif assert(const_ikey_ptr != nullptr); assert(block_offset == kNotValid); - if (!prefix_extractor_) { + if (!prefix_extractor_ && !prefix_extractor) { return true; } if (UNLIKELY(idx_on_fltr_blk_->size() == 0)) {