]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/bloom_test.cc
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 // 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");
18 #include <gflags/gflags.h>
21 #include "rocksdb/filter_policy.h"
22 #include "util/logging.h"
23 #include "util/testharness.h"
24 #include "util/testutil.h"
25 #include "util/arena.h"
27 using GFLAGS::ParseCommandLineFlags
;
29 DEFINE_int32(bits_per_key
, 10, "");
33 static const int kVerbose
= 1;
35 static Slice
Key(int i
, char* buffer
) {
37 PutFixed32(&s
, static_cast<uint32_t>(i
));
38 memcpy(buffer
, s
.c_str(), sizeof(i
));
39 return Slice(buffer
, sizeof(i
));
42 static int NextLength(int length
) {
45 } else if (length
< 100) {
47 } else if (length
< 1000) {
55 class BloomTest
: public testing::Test
{
57 const FilterPolicy
* policy_
;
59 std::vector
<std::string
> keys_
;
62 BloomTest() : policy_(
63 NewBloomFilterPolicy(FLAGS_bits_per_key
)) {}
74 void Add(const Slice
& s
) {
75 keys_
.push_back(s
.ToString());
79 std::vector
<Slice
> key_slices
;
80 for (size_t i
= 0; i
< keys_
.size(); i
++) {
81 key_slices
.push_back(Slice(keys_
[i
]));
84 policy_
->CreateFilter(&key_slices
[0], static_cast<int>(key_slices
.size()),
87 if (kVerbose
>= 2) DumpFilter();
90 size_t FilterSize() const {
91 return filter_
.size();
95 fprintf(stderr
, "F(");
96 for (size_t i
= 0; i
+1 < filter_
.size(); i
++) {
97 const unsigned int c
= static_cast<unsigned int>(filter_
[i
]);
98 for (int j
= 0; j
< 8; j
++) {
99 fprintf(stderr
, "%c", (c
& (1 <<j
)) ? '1' : '.');
102 fprintf(stderr
, ")\n");
105 bool Matches(const Slice
& s
) {
106 if (!keys_
.empty()) {
109 return policy_
->KeyMayMatch(s
, filter_
);
112 double FalsePositiveRate() {
113 char buffer
[sizeof(int)];
115 for (int i
= 0; i
< 10000; i
++) {
116 if (Matches(Key(i
+ 1000000000, buffer
))) {
120 return result
/ 10000.0;
124 TEST_F(BloomTest
, EmptyFilter
) {
125 ASSERT_TRUE(! Matches("hello"));
126 ASSERT_TRUE(! Matches("world"));
129 TEST_F(BloomTest
, Small
) {
132 ASSERT_TRUE(Matches("hello"));
133 ASSERT_TRUE(Matches("world"));
134 ASSERT_TRUE(! Matches("x"));
135 ASSERT_TRUE(! Matches("foo"));
138 TEST_F(BloomTest
, VaryingLengths
) {
139 char buffer
[sizeof(int)];
141 // Count number of filters that significantly exceed the false positive rate
142 int mediocre_filters
= 0;
143 int good_filters
= 0;
145 for (int length
= 1; length
<= 10000; length
= NextLength(length
)) {
147 for (int i
= 0; i
< length
; i
++) {
152 ASSERT_LE(FilterSize(), (size_t)((length
* 10 / 8) + 40)) << length
;
154 // All added keys must match
155 for (int i
= 0; i
< length
; i
++) {
156 ASSERT_TRUE(Matches(Key(i
, buffer
)))
157 << "Length " << length
<< "; key " << i
;
160 // Check false positive rate
161 double rate
= FalsePositiveRate();
163 fprintf(stderr
, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
164 rate
*100.0, length
, static_cast<int>(FilterSize()));
166 ASSERT_LE(rate
, 0.02); // Must not be over 2%
167 if (rate
> 0.0125) mediocre_filters
++; // Allowed, but not too often
171 fprintf(stderr
, "Filters: %d good, %d mediocre\n",
172 good_filters
, mediocre_filters
);
174 ASSERT_LE(mediocre_filters
, good_filters
/5);
177 // Different bits-per-byte
179 class FullBloomTest
: public testing::Test
{
181 const FilterPolicy
* policy_
;
182 std::unique_ptr
<FilterBitsBuilder
> bits_builder_
;
183 std::unique_ptr
<FilterBitsReader
> bits_reader_
;
184 std::unique_ptr
<const char[]> buf_
;
189 policy_(NewBloomFilterPolicy(FLAGS_bits_per_key
, false)),
199 bits_builder_
.reset(policy_
->GetFilterBitsBuilder());
200 bits_reader_
.reset(nullptr);
205 void Add(const Slice
& s
) {
206 bits_builder_
->AddKey(s
);
210 Slice filter
= bits_builder_
->Finish(&buf_
);
211 bits_reader_
.reset(policy_
->GetFilterBitsReader(filter
));
212 filter_size_
= filter
.size();
215 size_t FilterSize() const {
219 bool Matches(const Slice
& s
) {
220 if (bits_reader_
== nullptr) {
223 return bits_reader_
->MayMatch(s
);
226 double FalsePositiveRate() {
227 char buffer
[sizeof(int)];
229 for (int i
= 0; i
< 10000; i
++) {
230 if (Matches(Key(i
+ 1000000000, buffer
))) {
234 return result
/ 10000.0;
238 TEST_F(FullBloomTest
, FullEmptyFilter
) {
239 // Empty filter is not match, at this level
240 ASSERT_TRUE(!Matches("hello"));
241 ASSERT_TRUE(!Matches("world"));
244 TEST_F(FullBloomTest
, FullSmall
) {
247 ASSERT_TRUE(Matches("hello"));
248 ASSERT_TRUE(Matches("world"));
249 ASSERT_TRUE(!Matches("x"));
250 ASSERT_TRUE(!Matches("foo"));
253 TEST_F(FullBloomTest
, FullVaryingLengths
) {
254 char buffer
[sizeof(int)];
256 // Count number of filters that significantly exceed the false positive rate
257 int mediocre_filters
= 0;
258 int good_filters
= 0;
260 for (int length
= 1; length
<= 10000; length
= NextLength(length
)) {
262 for (int i
= 0; i
< length
; i
++) {
267 ASSERT_LE(FilterSize(), (size_t)((length
* 10 / 8) + 128 + 5)) << length
;
269 // All added keys must match
270 for (int i
= 0; i
< length
; i
++) {
271 ASSERT_TRUE(Matches(Key(i
, buffer
)))
272 << "Length " << length
<< "; key " << i
;
275 // Check false positive rate
276 double rate
= FalsePositiveRate();
278 fprintf(stderr
, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
279 rate
*100.0, length
, static_cast<int>(FilterSize()));
281 ASSERT_LE(rate
, 0.02); // Must not be over 2%
283 mediocre_filters
++; // Allowed, but not too often
288 fprintf(stderr
, "Filters: %d good, %d mediocre\n",
289 good_filters
, mediocre_filters
);
291 ASSERT_LE(mediocre_filters
, good_filters
/5);
294 } // namespace rocksdb
296 int main(int argc
, char** argv
) {
297 ::testing::InitGoogleTest(&argc
, argv
);
298 ParseCommandLineFlags(&argc
, &argv
, true);
300 return RUN_ALL_TESTS();