]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/bloom_test.cc
bbf1d3ae9a84da1b335ea602c212f93ead6e6377
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 // Copyright (c) 2012 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
13 fprintf(stderr
, "Please install gflags to run this test... Skipping...\n");
20 #include "rocksdb/filter_policy.h"
21 #include "table/full_filter_bits_builder.h"
22 #include "util/arena.h"
23 #include "util/gflags_compat.h"
24 #include "util/logging.h"
25 #include "util/testharness.h"
26 #include "util/testutil.h"
28 using GFLAGS_NAMESPACE::ParseCommandLineFlags
;
30 DEFINE_int32(bits_per_key
, 10, "");
34 static const int kVerbose
= 1;
36 static Slice
Key(int i
, char* buffer
) {
38 PutFixed32(&s
, static_cast<uint32_t>(i
));
39 memcpy(buffer
, s
.c_str(), sizeof(i
));
40 return Slice(buffer
, sizeof(i
));
43 static int NextLength(int length
) {
46 } else if (length
< 100) {
48 } else if (length
< 1000) {
56 class BloomTest
: public testing::Test
{
58 const FilterPolicy
* policy_
;
60 std::vector
<std::string
> keys_
;
63 BloomTest() : policy_(
64 NewBloomFilterPolicy(FLAGS_bits_per_key
)) {}
75 void Add(const Slice
& s
) {
76 keys_
.push_back(s
.ToString());
80 std::vector
<Slice
> key_slices
;
81 for (size_t i
= 0; i
< keys_
.size(); i
++) {
82 key_slices
.push_back(Slice(keys_
[i
]));
85 policy_
->CreateFilter(&key_slices
[0], static_cast<int>(key_slices
.size()),
88 if (kVerbose
>= 2) DumpFilter();
91 size_t FilterSize() const {
92 return filter_
.size();
96 fprintf(stderr
, "F(");
97 for (size_t i
= 0; i
+1 < filter_
.size(); i
++) {
98 const unsigned int c
= static_cast<unsigned int>(filter_
[i
]);
99 for (int j
= 0; j
< 8; j
++) {
100 fprintf(stderr
, "%c", (c
& (1 <<j
)) ? '1' : '.');
103 fprintf(stderr
, ")\n");
106 bool Matches(const Slice
& s
) {
107 if (!keys_
.empty()) {
110 return policy_
->KeyMayMatch(s
, filter_
);
113 double FalsePositiveRate() {
114 char buffer
[sizeof(int)];
116 for (int i
= 0; i
< 10000; i
++) {
117 if (Matches(Key(i
+ 1000000000, buffer
))) {
121 return result
/ 10000.0;
125 TEST_F(BloomTest
, EmptyFilter
) {
126 ASSERT_TRUE(! Matches("hello"));
127 ASSERT_TRUE(! Matches("world"));
130 TEST_F(BloomTest
, Small
) {
133 ASSERT_TRUE(Matches("hello"));
134 ASSERT_TRUE(Matches("world"));
135 ASSERT_TRUE(! Matches("x"));
136 ASSERT_TRUE(! Matches("foo"));
139 TEST_F(BloomTest
, VaryingLengths
) {
140 char buffer
[sizeof(int)];
142 // Count number of filters that significantly exceed the false positive rate
143 int mediocre_filters
= 0;
144 int good_filters
= 0;
146 for (int length
= 1; length
<= 10000; length
= NextLength(length
)) {
148 for (int i
= 0; i
< length
; i
++) {
153 ASSERT_LE(FilterSize(), (size_t)((length
* 10 / 8) + 40)) << length
;
155 // All added keys must match
156 for (int i
= 0; i
< length
; i
++) {
157 ASSERT_TRUE(Matches(Key(i
, buffer
)))
158 << "Length " << length
<< "; key " << i
;
161 // Check false positive rate
162 double rate
= FalsePositiveRate();
164 fprintf(stderr
, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
165 rate
*100.0, length
, static_cast<int>(FilterSize()));
167 ASSERT_LE(rate
, 0.02); // Must not be over 2%
168 if (rate
> 0.0125) mediocre_filters
++; // Allowed, but not too often
172 fprintf(stderr
, "Filters: %d good, %d mediocre\n",
173 good_filters
, mediocre_filters
);
175 ASSERT_LE(mediocre_filters
, good_filters
/5);
178 // Different bits-per-byte
180 class FullBloomTest
: public testing::Test
{
182 const FilterPolicy
* policy_
;
183 std::unique_ptr
<FilterBitsBuilder
> bits_builder_
;
184 std::unique_ptr
<FilterBitsReader
> bits_reader_
;
185 std::unique_ptr
<const char[]> buf_
;
190 policy_(NewBloomFilterPolicy(FLAGS_bits_per_key
, false)),
199 FullFilterBitsBuilder
* GetFullFilterBitsBuilder() {
200 return dynamic_cast<FullFilterBitsBuilder
*>(bits_builder_
.get());
204 bits_builder_
.reset(policy_
->GetFilterBitsBuilder());
205 bits_reader_
.reset(nullptr);
210 void Add(const Slice
& s
) {
211 bits_builder_
->AddKey(s
);
215 Slice filter
= bits_builder_
->Finish(&buf_
);
216 bits_reader_
.reset(policy_
->GetFilterBitsReader(filter
));
217 filter_size_
= filter
.size();
220 size_t FilterSize() const {
224 bool Matches(const Slice
& s
) {
225 if (bits_reader_
== nullptr) {
228 return bits_reader_
->MayMatch(s
);
231 double FalsePositiveRate() {
232 char buffer
[sizeof(int)];
234 for (int i
= 0; i
< 10000; i
++) {
235 if (Matches(Key(i
+ 1000000000, buffer
))) {
239 return result
/ 10000.0;
243 TEST_F(FullBloomTest
, FilterSize
) {
244 uint32_t dont_care1
, dont_care2
;
245 auto full_bits_builder
= GetFullFilterBitsBuilder();
246 for (int n
= 1; n
< 100; n
++) {
247 auto space
= full_bits_builder
->CalculateSpace(n
, &dont_care1
, &dont_care2
);
248 auto n2
= full_bits_builder
->CalculateNumEntry(space
);
251 full_bits_builder
->CalculateSpace(n2
, &dont_care1
, &dont_care2
);
252 ASSERT_EQ(space
, space2
);
256 TEST_F(FullBloomTest
, FullEmptyFilter
) {
257 // Empty filter is not match, at this level
258 ASSERT_TRUE(!Matches("hello"));
259 ASSERT_TRUE(!Matches("world"));
262 TEST_F(FullBloomTest
, FullSmall
) {
265 ASSERT_TRUE(Matches("hello"));
266 ASSERT_TRUE(Matches("world"));
267 ASSERT_TRUE(!Matches("x"));
268 ASSERT_TRUE(!Matches("foo"));
271 TEST_F(FullBloomTest
, FullVaryingLengths
) {
272 char buffer
[sizeof(int)];
274 // Count number of filters that significantly exceed the false positive rate
275 int mediocre_filters
= 0;
276 int good_filters
= 0;
278 for (int length
= 1; length
<= 10000; length
= NextLength(length
)) {
280 for (int i
= 0; i
< length
; i
++) {
285 ASSERT_LE(FilterSize(), (size_t)((length
* 10 / 8) + 128 + 5)) << length
;
287 // All added keys must match
288 for (int i
= 0; i
< length
; i
++) {
289 ASSERT_TRUE(Matches(Key(i
, buffer
)))
290 << "Length " << length
<< "; key " << i
;
293 // Check false positive rate
294 double rate
= FalsePositiveRate();
296 fprintf(stderr
, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
297 rate
*100.0, length
, static_cast<int>(FilterSize()));
299 ASSERT_LE(rate
, 0.02); // Must not be over 2%
301 mediocre_filters
++; // Allowed, but not too often
306 fprintf(stderr
, "Filters: %d good, %d mediocre\n",
307 good_filters
, mediocre_filters
);
309 ASSERT_LE(mediocre_filters
, good_filters
/5);
312 } // namespace rocksdb
314 int main(int argc
, char** argv
) {
315 ::testing::InitGoogleTest(&argc
, argv
);
316 ParseCommandLineFlags(&argc
, &argv
, true);
318 return RUN_ALL_TESTS();