Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / common / test_bloom_filter.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2013 Inktank <info@inktank.com>
7  *
8  * LGPL2.1 (see COPYING-LGPL2.1) or later
9  */
10
11 #include <iostream>
12 #include <gtest/gtest.h>
13
14 #include "include/stringify.h"
15 #include "common/bloom_filter.hpp"
16
17 TEST(BloomFilter, Basic) {
18   bloom_filter bf(10, .1, 1);
19   bf.insert("foo");
20   bf.insert("bar");
21
22   ASSERT_TRUE(bf.contains("foo"));
23   ASSERT_TRUE(bf.contains("bar"));
24
25   ASSERT_EQ(2U, bf.element_count());
26 }
27
28 TEST(BloomFilter, Empty) {
29   bloom_filter bf;
30   for (int i=0; i<100; ++i) {
31     ASSERT_FALSE(bf.contains(i));
32     ASSERT_FALSE(bf.contains(stringify(i)));
33   }
34 }
35
36 TEST(BloomFilter, Sweep) {
37   std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
38   std::cout.precision(5);
39   std::cout << "# max\tfpp\tactual\tsize\tB/insert" << std::endl;
40   for (int ex = 3; ex < 12; ex += 2) {
41     for (float fpp = .001; fpp < .5; fpp *= 4.0) {
42       int max = 2 << ex;
43       bloom_filter bf(max, fpp, 1);
44       bf.insert("foo");
45       bf.insert("bar");
46
47       ASSERT_TRUE(bf.contains("foo"));
48       ASSERT_TRUE(bf.contains("bar"));
49
50       for (int n = 0; n < max; n++)
51         bf.insert("ok" + stringify(n));
52
53       int test = max * 100;
54       int hit = 0;
55       for (int n = 0; n < test; n++)
56         if (bf.contains("asdf" + stringify(n)))
57           hit++;
58
59       ASSERT_TRUE(bf.contains("foo"));
60       ASSERT_TRUE(bf.contains("bar"));
61
62       double actual = (double)hit / (double)test;
63
64       bufferlist bl;
65       ::encode(bf, bl);
66
67       double byte_per_insert = (double)bl.length() / (double)max;
68
69       std::cout << max << "\t" << fpp << "\t" << actual << "\t" << bl.length() << "\t" << byte_per_insert << std::endl;
70       ASSERT_TRUE(actual < fpp * 10);
71
72     }
73   }
74 }
75
76 TEST(BloomFilter, SweepInt) {
77   std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
78   std::cout.precision(5);
79   std::cout << "# max\tfpp\tactual\tsize\tB/insert\tdensity\tapprox_element_count" << std::endl;
80   for (int ex = 3; ex < 12; ex += 2) {
81     for (float fpp = .001; fpp < .5; fpp *= 4.0) {
82       int max = 2 << ex;
83       bloom_filter bf(max, fpp, 1);
84       bf.insert("foo");
85       bf.insert("bar");
86
87       ASSERT_TRUE(123);
88       ASSERT_TRUE(456);
89
90       for (int n = 0; n < max; n++)
91         bf.insert(n);
92
93       int test = max * 100;
94       int hit = 0;
95       for (int n = 0; n < test; n++)
96         if (bf.contains(100000 + n))
97           hit++;
98
99       ASSERT_TRUE(123);
100       ASSERT_TRUE(456);
101
102       double actual = (double)hit / (double)test;
103
104       bufferlist bl;
105       ::encode(bf, bl);
106
107       double byte_per_insert = (double)bl.length() / (double)max;
108
109       std::cout << max << "\t" << fpp << "\t" << actual << "\t" << bl.length() << "\t" << byte_per_insert
110                 << "\t" << bf.density() << "\t" << bf.approx_unique_element_count() << std::endl;
111       ASSERT_TRUE(actual < fpp * 10);
112       ASSERT_TRUE(actual > fpp / 10);
113       ASSERT_TRUE(bf.density() > 0.40);
114       ASSERT_TRUE(bf.density() < 0.60);
115     }
116   }
117 }
118
119
120 TEST(BloomFilter, CompressibleSweep) {
121   std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
122   std::cout.precision(5);
123   std::cout << "# max\tins\test ins\tafter\ttgtfpp\tactual\tsize\tb/elem\n";
124   float fpp = .01;
125   int max = 1024;
126   for (int div = 1; div < 10; div++) {
127     compressible_bloom_filter bf(max, fpp, 1);
128     int t = max/div;
129     for (int n = 0; n < t; n++)
130       bf.insert(n);
131
132     unsigned est = bf.approx_unique_element_count();
133     if (div > 1)
134       bf.compress(1.0 / div);
135
136     for (int n = 0; n < t; n++)
137       ASSERT_TRUE(bf.contains(n));
138
139     int test = max * 100;
140     int hit = 0;
141     for (int n = 0; n < test; n++)
142       if (bf.contains(100000 + n))
143         hit++;
144
145     double actual = (double)hit / (double)test;
146
147     bufferlist bl;
148     ::encode(bf, bl);
149
150     double byte_per_insert = (double)bl.length() / (double)max;
151     unsigned est_after = bf.approx_unique_element_count();
152     std::cout << max
153               << "\t" << t
154               << "\t" << est
155               << "\t" << est_after
156               << "\t" << fpp
157               << "\t" << actual
158               << "\t" << bl.length() << "\t" << byte_per_insert
159               << std::endl;
160
161     ASSERT_TRUE(actual < fpp * 2.0);
162     ASSERT_TRUE(actual > fpp / 2.0);
163     ASSERT_TRUE(est_after < est * 2);
164     ASSERT_TRUE(est_after > est / 2);
165   }
166 }
167
168
169
170 TEST(BloomFilter, BinSweep) {
171   std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
172   std::cout.precision(5);
173   int total_max = 16384;
174   float total_fpp = .01;
175   std::cout << "total_inserts " << total_max << " target-fpp " << total_fpp << std::endl;
176   for (int bins = 1; bins < 16; ++bins) {
177     int max = total_max / bins;
178     float fpp = total_fpp / bins;//pow(total_fpp, bins);
179
180     std::vector<bloom_filter*> ls;
181     bufferlist bl;
182     for (int i=0; i<bins; i++) {
183       ls.push_back(new bloom_filter(max, fpp, i));
184       for (int j=0; j<max; j++) {
185         ls.back()->insert(10000 * (i+1) + j);
186       }
187       ::encode(*ls.front(), bl);
188     }
189
190     int hit = 0;
191     int test = max * 100;
192     for (int i=0; i<test; ++i) {
193       for (std::vector<bloom_filter*>::iterator j = ls.begin(); j != ls.end(); ++j) {
194         if ((*j)->contains(i * 732)) {  // note: sequential i does not work here; the intenral int hash is weak!!
195           hit++;
196           break;
197         }
198       }
199     }
200
201     double actual = (double)hit / (double)test;
202     std::cout << "bins " << bins << " bin-max " << max << " bin-fpp " << fpp
203               << " actual-fpp " << actual
204               << " total-size " << bl.length() << std::endl;
205   }
206 }
207
208 // disable these tests; doing dual insertions in consecutive filters
209 // appears to be equivalent to doing a single insertion in a bloom
210 // filter that is twice as big.
211 #if 0
212
213 // test the fpp over a sequence of bloom filters, each with unique
214 // items inserted into it.
215 //
216 // we expect:  actual_fpp = num_filters * per_filter_fpp
217 TEST(BloomFilter, Sequence) {
218
219   int max = 1024;
220   double fpp = .01;
221   for (int seq = 2; seq <= 128; seq *= 2) {
222     std::vector<bloom_filter*> ls;
223     for (int i=0; i<seq; i++) {
224       ls.push_back(new bloom_filter(max*2, fpp, i));
225       for (int j=0; j<max; j++) {
226         ls.back()->insert("ok" + stringify(j) + "_" + stringify(i));
227         if (ls.size() > 1)
228           ls[ls.size() - 2]->insert("ok" + stringify(j) + "_" + stringify(i));
229       }
230     }
231
232     int hit = 0;
233     int test = max * 100;
234     for (int i=0; i<test; ++i) {
235       for (std::vector<bloom_filter*>::iterator j = ls.begin(); j != ls.end(); ++j) {
236         if ((*j)->contains("bad" + stringify(i))) {
237           hit++;
238           break;
239         }
240       }
241     }
242
243     double actual = (double)hit / (double)test;
244     std::cout << "seq " << seq << " max " << max << " fpp " << fpp << " actual " << actual << std::endl;
245   }
246 }
247
248 // test the ffp over a sequence of bloom filters, where actual values
249 // are always inserted into a consecutive pair of filters.  in order
250 // to have a false positive, we need to falsely match two consecutive
251 // filters.
252 //
253 // we expect:  actual_fpp = num_filters * per_filter_fpp^2
254 TEST(BloomFilter, SequenceDouble) {
255   int max = 1024;
256   double fpp = .01;
257   for (int seq = 2; seq <= 128; seq *= 2) {
258     std::vector<bloom_filter*> ls;
259     for (int i=0; i<seq; i++) {
260       ls.push_back(new bloom_filter(max*2, fpp, i));
261       for (int j=0; j<max; j++) {
262         ls.back()->insert("ok" + stringify(j) + "_" + stringify(i));
263         if (ls.size() > 1)
264           ls[ls.size() - 2]->insert("ok" + stringify(j) + "_" + stringify(i));
265       }
266     }
267
268     int hit = 0;
269     int test = max * 100;
270     int run = 0;
271     for (int i=0; i<test; ++i) {
272       for (std::vector<bloom_filter*>::iterator j = ls.begin(); j != ls.end(); ++j) {
273         if ((*j)->contains("bad" + stringify(i))) {
274           run++;
275           if (run >= 2) {
276             hit++;
277             break;
278           }
279         } else {
280           run = 0;
281         }
282       }
283     }
284
285     double actual = (double)hit / (double)test;
286     std::cout << "seq " << seq << " max " << max << " fpp " << fpp << " actual " << actual
287               << " expected " << (fpp*fpp*(double)seq) << std::endl;
288   }
289 }
290
291 #endif
292
293 TEST(BloomFilter, Assignement) {
294   bloom_filter bf1(10, .1, 1), bf2;
295
296   bf1.insert("foo");
297   bf2 = bf1;
298   bf1.insert("bar");
299
300   ASSERT_TRUE(bf2.contains("foo"));
301   ASSERT_FALSE(bf2.contains("bar"));
302
303   ASSERT_EQ(2U, bf1.element_count());
304   ASSERT_EQ(1U, bf2.element_count());
305 }