xref: /aosp_15_r20/external/leveldb/util/bloom_test.cc (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2012 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker 
5*9507f98cSAndroid Build Coastguard Worker #include "gtest/gtest.h"
6*9507f98cSAndroid Build Coastguard Worker #include "leveldb/filter_policy.h"
7*9507f98cSAndroid Build Coastguard Worker #include "util/coding.h"
8*9507f98cSAndroid Build Coastguard Worker #include "util/logging.h"
9*9507f98cSAndroid Build Coastguard Worker #include "util/testutil.h"
10*9507f98cSAndroid Build Coastguard Worker 
11*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
12*9507f98cSAndroid Build Coastguard Worker 
13*9507f98cSAndroid Build Coastguard Worker static const int kVerbose = 1;
14*9507f98cSAndroid Build Coastguard Worker 
Key(int i,char * buffer)15*9507f98cSAndroid Build Coastguard Worker static Slice Key(int i, char* buffer) {
16*9507f98cSAndroid Build Coastguard Worker   EncodeFixed32(buffer, i);
17*9507f98cSAndroid Build Coastguard Worker   return Slice(buffer, sizeof(uint32_t));
18*9507f98cSAndroid Build Coastguard Worker }
19*9507f98cSAndroid Build Coastguard Worker 
20*9507f98cSAndroid Build Coastguard Worker class BloomTest : public testing::Test {
21*9507f98cSAndroid Build Coastguard Worker  public:
BloomTest()22*9507f98cSAndroid Build Coastguard Worker   BloomTest() : policy_(NewBloomFilterPolicy(10)) {}
23*9507f98cSAndroid Build Coastguard Worker 
~BloomTest()24*9507f98cSAndroid Build Coastguard Worker   ~BloomTest() { delete policy_; }
25*9507f98cSAndroid Build Coastguard Worker 
Reset()26*9507f98cSAndroid Build Coastguard Worker   void Reset() {
27*9507f98cSAndroid Build Coastguard Worker     keys_.clear();
28*9507f98cSAndroid Build Coastguard Worker     filter_.clear();
29*9507f98cSAndroid Build Coastguard Worker   }
30*9507f98cSAndroid Build Coastguard Worker 
Add(const Slice & s)31*9507f98cSAndroid Build Coastguard Worker   void Add(const Slice& s) { keys_.push_back(s.ToString()); }
32*9507f98cSAndroid Build Coastguard Worker 
Build()33*9507f98cSAndroid Build Coastguard Worker   void Build() {
34*9507f98cSAndroid Build Coastguard Worker     std::vector<Slice> key_slices;
35*9507f98cSAndroid Build Coastguard Worker     for (size_t i = 0; i < keys_.size(); i++) {
36*9507f98cSAndroid Build Coastguard Worker       key_slices.push_back(Slice(keys_[i]));
37*9507f98cSAndroid Build Coastguard Worker     }
38*9507f98cSAndroid Build Coastguard Worker     filter_.clear();
39*9507f98cSAndroid Build Coastguard Worker     policy_->CreateFilter(&key_slices[0], static_cast<int>(key_slices.size()),
40*9507f98cSAndroid Build Coastguard Worker                           &filter_);
41*9507f98cSAndroid Build Coastguard Worker     keys_.clear();
42*9507f98cSAndroid Build Coastguard Worker     if (kVerbose >= 2) DumpFilter();
43*9507f98cSAndroid Build Coastguard Worker   }
44*9507f98cSAndroid Build Coastguard Worker 
FilterSize() const45*9507f98cSAndroid Build Coastguard Worker   size_t FilterSize() const { return filter_.size(); }
46*9507f98cSAndroid Build Coastguard Worker 
DumpFilter()47*9507f98cSAndroid Build Coastguard Worker   void DumpFilter() {
48*9507f98cSAndroid Build Coastguard Worker     std::fprintf(stderr, "F(");
49*9507f98cSAndroid Build Coastguard Worker     for (size_t i = 0; i + 1 < filter_.size(); i++) {
50*9507f98cSAndroid Build Coastguard Worker       const unsigned int c = static_cast<unsigned int>(filter_[i]);
51*9507f98cSAndroid Build Coastguard Worker       for (int j = 0; j < 8; j++) {
52*9507f98cSAndroid Build Coastguard Worker         std::fprintf(stderr, "%c", (c & (1 << j)) ? '1' : '.');
53*9507f98cSAndroid Build Coastguard Worker       }
54*9507f98cSAndroid Build Coastguard Worker     }
55*9507f98cSAndroid Build Coastguard Worker     std::fprintf(stderr, ")\n");
56*9507f98cSAndroid Build Coastguard Worker   }
57*9507f98cSAndroid Build Coastguard Worker 
Matches(const Slice & s)58*9507f98cSAndroid Build Coastguard Worker   bool Matches(const Slice& s) {
59*9507f98cSAndroid Build Coastguard Worker     if (!keys_.empty()) {
60*9507f98cSAndroid Build Coastguard Worker       Build();
61*9507f98cSAndroid Build Coastguard Worker     }
62*9507f98cSAndroid Build Coastguard Worker     return policy_->KeyMayMatch(s, filter_);
63*9507f98cSAndroid Build Coastguard Worker   }
64*9507f98cSAndroid Build Coastguard Worker 
FalsePositiveRate()65*9507f98cSAndroid Build Coastguard Worker   double FalsePositiveRate() {
66*9507f98cSAndroid Build Coastguard Worker     char buffer[sizeof(int)];
67*9507f98cSAndroid Build Coastguard Worker     int result = 0;
68*9507f98cSAndroid Build Coastguard Worker     for (int i = 0; i < 10000; i++) {
69*9507f98cSAndroid Build Coastguard Worker       if (Matches(Key(i + 1000000000, buffer))) {
70*9507f98cSAndroid Build Coastguard Worker         result++;
71*9507f98cSAndroid Build Coastguard Worker       }
72*9507f98cSAndroid Build Coastguard Worker     }
73*9507f98cSAndroid Build Coastguard Worker     return result / 10000.0;
74*9507f98cSAndroid Build Coastguard Worker   }
75*9507f98cSAndroid Build Coastguard Worker 
76*9507f98cSAndroid Build Coastguard Worker  private:
77*9507f98cSAndroid Build Coastguard Worker   const FilterPolicy* policy_;
78*9507f98cSAndroid Build Coastguard Worker   std::string filter_;
79*9507f98cSAndroid Build Coastguard Worker   std::vector<std::string> keys_;
80*9507f98cSAndroid Build Coastguard Worker };
81*9507f98cSAndroid Build Coastguard Worker 
TEST_F(BloomTest,EmptyFilter)82*9507f98cSAndroid Build Coastguard Worker TEST_F(BloomTest, EmptyFilter) {
83*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!Matches("hello"));
84*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!Matches("world"));
85*9507f98cSAndroid Build Coastguard Worker }
86*9507f98cSAndroid Build Coastguard Worker 
TEST_F(BloomTest,Small)87*9507f98cSAndroid Build Coastguard Worker TEST_F(BloomTest, Small) {
88*9507f98cSAndroid Build Coastguard Worker   Add("hello");
89*9507f98cSAndroid Build Coastguard Worker   Add("world");
90*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(Matches("hello"));
91*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(Matches("world"));
92*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!Matches("x"));
93*9507f98cSAndroid Build Coastguard Worker   ASSERT_TRUE(!Matches("foo"));
94*9507f98cSAndroid Build Coastguard Worker }
95*9507f98cSAndroid Build Coastguard Worker 
NextLength(int length)96*9507f98cSAndroid Build Coastguard Worker static int NextLength(int length) {
97*9507f98cSAndroid Build Coastguard Worker   if (length < 10) {
98*9507f98cSAndroid Build Coastguard Worker     length += 1;
99*9507f98cSAndroid Build Coastguard Worker   } else if (length < 100) {
100*9507f98cSAndroid Build Coastguard Worker     length += 10;
101*9507f98cSAndroid Build Coastguard Worker   } else if (length < 1000) {
102*9507f98cSAndroid Build Coastguard Worker     length += 100;
103*9507f98cSAndroid Build Coastguard Worker   } else {
104*9507f98cSAndroid Build Coastguard Worker     length += 1000;
105*9507f98cSAndroid Build Coastguard Worker   }
106*9507f98cSAndroid Build Coastguard Worker   return length;
107*9507f98cSAndroid Build Coastguard Worker }
108*9507f98cSAndroid Build Coastguard Worker 
TEST_F(BloomTest,VaryingLengths)109*9507f98cSAndroid Build Coastguard Worker TEST_F(BloomTest, VaryingLengths) {
110*9507f98cSAndroid Build Coastguard Worker   char buffer[sizeof(int)];
111*9507f98cSAndroid Build Coastguard Worker 
112*9507f98cSAndroid Build Coastguard Worker   // Count number of filters that significantly exceed the false positive rate
113*9507f98cSAndroid Build Coastguard Worker   int mediocre_filters = 0;
114*9507f98cSAndroid Build Coastguard Worker   int good_filters = 0;
115*9507f98cSAndroid Build Coastguard Worker 
116*9507f98cSAndroid Build Coastguard Worker   for (int length = 1; length <= 10000; length = NextLength(length)) {
117*9507f98cSAndroid Build Coastguard Worker     Reset();
118*9507f98cSAndroid Build Coastguard Worker     for (int i = 0; i < length; i++) {
119*9507f98cSAndroid Build Coastguard Worker       Add(Key(i, buffer));
120*9507f98cSAndroid Build Coastguard Worker     }
121*9507f98cSAndroid Build Coastguard Worker     Build();
122*9507f98cSAndroid Build Coastguard Worker 
123*9507f98cSAndroid Build Coastguard Worker     ASSERT_LE(FilterSize(), static_cast<size_t>((length * 10 / 8) + 40))
124*9507f98cSAndroid Build Coastguard Worker         << length;
125*9507f98cSAndroid Build Coastguard Worker 
126*9507f98cSAndroid Build Coastguard Worker     // All added keys must match
127*9507f98cSAndroid Build Coastguard Worker     for (int i = 0; i < length; i++) {
128*9507f98cSAndroid Build Coastguard Worker       ASSERT_TRUE(Matches(Key(i, buffer)))
129*9507f98cSAndroid Build Coastguard Worker           << "Length " << length << "; key " << i;
130*9507f98cSAndroid Build Coastguard Worker     }
131*9507f98cSAndroid Build Coastguard Worker 
132*9507f98cSAndroid Build Coastguard Worker     // Check false positive rate
133*9507f98cSAndroid Build Coastguard Worker     double rate = FalsePositiveRate();
134*9507f98cSAndroid Build Coastguard Worker     if (kVerbose >= 1) {
135*9507f98cSAndroid Build Coastguard Worker       std::fprintf(stderr,
136*9507f98cSAndroid Build Coastguard Worker                    "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n",
137*9507f98cSAndroid Build Coastguard Worker                    rate * 100.0, length, static_cast<int>(FilterSize()));
138*9507f98cSAndroid Build Coastguard Worker     }
139*9507f98cSAndroid Build Coastguard Worker     ASSERT_LE(rate, 0.02);  // Must not be over 2%
140*9507f98cSAndroid Build Coastguard Worker     if (rate > 0.0125)
141*9507f98cSAndroid Build Coastguard Worker       mediocre_filters++;  // Allowed, but not too often
142*9507f98cSAndroid Build Coastguard Worker     else
143*9507f98cSAndroid Build Coastguard Worker       good_filters++;
144*9507f98cSAndroid Build Coastguard Worker   }
145*9507f98cSAndroid Build Coastguard Worker   if (kVerbose >= 1) {
146*9507f98cSAndroid Build Coastguard Worker     std::fprintf(stderr, "Filters: %d good, %d mediocre\n", good_filters,
147*9507f98cSAndroid Build Coastguard Worker                  mediocre_filters);
148*9507f98cSAndroid Build Coastguard Worker   }
149*9507f98cSAndroid Build Coastguard Worker   ASSERT_LE(mediocre_filters, good_filters / 5);
150*9507f98cSAndroid Build Coastguard Worker }
151*9507f98cSAndroid Build Coastguard Worker 
152*9507f98cSAndroid Build Coastguard Worker // Different bits-per-byte
153*9507f98cSAndroid Build Coastguard Worker 
154*9507f98cSAndroid Build Coastguard Worker }  // namespace leveldb
155*9507f98cSAndroid Build Coastguard Worker 
156