1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
6 #include "table/full_filter_block.h"
8 #include "rocksdb/filter_policy.h"
9 #include "util/coding.h"
10 #include "util/hash.h"
11 #include "util/string_util.h"
12 #include "util/testharness.h"
13 #include "util/testutil.h"
17 class TestFilterBitsBuilder
: public FilterBitsBuilder
{
19 explicit TestFilterBitsBuilder() {}
22 virtual void AddKey(const Slice
& key
) override
{
23 hash_entries_
.push_back(Hash(key
.data(), key
.size(), 1));
26 // Generate the filter using the keys that are added
27 virtual Slice
Finish(std::unique_ptr
<const char[]>* buf
) override
{
28 uint32_t len
= static_cast<uint32_t>(hash_entries_
.size()) * 4;
29 char* data
= new char[len
];
30 for (size_t i
= 0; i
< hash_entries_
.size(); i
++) {
31 EncodeFixed32(data
+ i
* 4, hash_entries_
[i
]);
33 const char* const_data
= data
;
34 buf
->reset(const_data
);
35 return Slice(data
, len
);
39 std::vector
<uint32_t> hash_entries_
;
42 class TestFilterBitsReader
: public FilterBitsReader
{
44 explicit TestFilterBitsReader(const Slice
& contents
)
45 : data_(contents
.data()), len_(static_cast<uint32_t>(contents
.size())) {}
47 virtual bool MayMatch(const Slice
& entry
) override
{
48 uint32_t h
= Hash(entry
.data(), entry
.size(), 1);
49 for (size_t i
= 0; i
+ 4 <= len_
; i
+= 4) {
50 if (h
== DecodeFixed32(data_
+ i
)) {
63 class TestHashFilter
: public FilterPolicy
{
65 virtual const char* Name() const override
{ return "TestHashFilter"; }
67 virtual void CreateFilter(const Slice
* keys
, int n
,
68 std::string
* dst
) const override
{
69 for (int i
= 0; i
< n
; i
++) {
70 uint32_t h
= Hash(keys
[i
].data(), keys
[i
].size(), 1);
75 virtual bool KeyMayMatch(const Slice
& key
,
76 const Slice
& filter
) const override
{
77 uint32_t h
= Hash(key
.data(), key
.size(), 1);
78 for (unsigned int i
= 0; i
+ 4 <= filter
.size(); i
+= 4) {
79 if (h
== DecodeFixed32(filter
.data() + i
)) {
86 virtual FilterBitsBuilder
* GetFilterBitsBuilder() const override
{
87 return new TestFilterBitsBuilder();
90 virtual FilterBitsReader
* GetFilterBitsReader(const Slice
& contents
)
92 return new TestFilterBitsReader(contents
);
96 class PluginFullFilterBlockTest
: public testing::Test
{
98 BlockBasedTableOptions table_options_
;
100 PluginFullFilterBlockTest() {
101 table_options_
.filter_policy
.reset(new TestHashFilter());
105 TEST_F(PluginFullFilterBlockTest
, PluginEmptyBuilder
) {
106 FullFilterBlockBuilder
builder(
107 nullptr, true, table_options_
.filter_policy
->GetFilterBitsBuilder());
108 Slice block
= builder
.Finish();
109 ASSERT_EQ("", EscapeString(block
));
111 FullFilterBlockReader
reader(
112 nullptr, true, block
,
113 table_options_
.filter_policy
->GetFilterBitsReader(block
), nullptr);
114 // Remain same symantic with blockbased filter
115 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
118 TEST_F(PluginFullFilterBlockTest
, PluginSingleChunk
) {
119 FullFilterBlockBuilder
builder(
120 nullptr, true, table_options_
.filter_policy
->GetFilterBitsBuilder());
125 builder
.Add("hello");
126 Slice block
= builder
.Finish();
127 FullFilterBlockReader
reader(
128 nullptr, true, block
,
129 table_options_
.filter_policy
->GetFilterBitsReader(block
), nullptr);
130 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
131 ASSERT_TRUE(reader
.KeyMayMatch("bar"));
132 ASSERT_TRUE(reader
.KeyMayMatch("box"));
133 ASSERT_TRUE(reader
.KeyMayMatch("hello"));
134 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
135 ASSERT_TRUE(!reader
.KeyMayMatch("missing"));
136 ASSERT_TRUE(!reader
.KeyMayMatch("other"));
139 class FullFilterBlockTest
: public testing::Test
{
141 BlockBasedTableOptions table_options_
;
143 FullFilterBlockTest() {
144 table_options_
.filter_policy
.reset(NewBloomFilterPolicy(10, false));
147 ~FullFilterBlockTest() {}
150 TEST_F(FullFilterBlockTest
, EmptyBuilder
) {
151 FullFilterBlockBuilder
builder(
152 nullptr, true, table_options_
.filter_policy
->GetFilterBitsBuilder());
153 Slice block
= builder
.Finish();
154 ASSERT_EQ("", EscapeString(block
));
156 FullFilterBlockReader
reader(
157 nullptr, true, block
,
158 table_options_
.filter_policy
->GetFilterBitsReader(block
), nullptr);
159 // Remain same symantic with blockbased filter
160 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
163 TEST_F(FullFilterBlockTest
, SingleChunk
) {
164 FullFilterBlockBuilder
builder(
165 nullptr, true, table_options_
.filter_policy
->GetFilterBitsBuilder());
170 builder
.Add("hello");
171 Slice block
= builder
.Finish();
172 FullFilterBlockReader
reader(
173 nullptr, true, block
,
174 table_options_
.filter_policy
->GetFilterBitsReader(block
), nullptr);
175 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
176 ASSERT_TRUE(reader
.KeyMayMatch("bar"));
177 ASSERT_TRUE(reader
.KeyMayMatch("box"));
178 ASSERT_TRUE(reader
.KeyMayMatch("hello"));
179 ASSERT_TRUE(reader
.KeyMayMatch("foo"));
180 ASSERT_TRUE(!reader
.KeyMayMatch("missing"));
181 ASSERT_TRUE(!reader
.KeyMayMatch("other"));
184 } // namespace rocksdb
186 int main(int argc
, char** argv
) {
187 ::testing::InitGoogleTest(&argc
, argv
);
188 return RUN_ALL_TESTS();