@@ -216,30 +216,54 @@ void CBloomFilter::UpdateEmptyFull()
216
216
isEmpty = empty;
217
217
}
218
218
219
- CRollingBloomFilter::CRollingBloomFilter (unsigned int nElements, double fpRate) :
220
- b1(nElements * 2 , fpRate, 0 ), b2(nElements * 2 , fpRate, 0 )
219
+ CRollingBloomFilter::CRollingBloomFilter (unsigned int nElements, double fpRate)
221
220
{
222
- // Implemented using two bloom filters of 2 * nElements each.
223
- // We fill them up, and clear them, staggered, every nElements
224
- // inserted, so at least one always contains the last nElements
225
- // inserted.
226
- nInsertions = 0 ;
227
- nBloomSize = nElements * 2 ;
228
-
221
+ double logFpRate = log (fpRate);
222
+ /* The optimal number of hash functions is log(fpRate) / log(0.5), but
223
+ * restrict it to the range 1-50. */
224
+ nHashFuncs = std::max (1 , std::min ((int )round (logFpRate / log (0.5 )), 50 ));
225
+ /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
226
+ nEntriesPerGeneration = (nElements + 1 ) / 2 ;
227
+ uint32_t nMaxElements = nEntriesPerGeneration * 3 ;
228
+ /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
229
+ * => pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
230
+ * => 1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
231
+ * => log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
232
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
233
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
234
+ */
235
+ uint32_t nFilterBits = (uint32_t )ceil (-1.0 * nHashFuncs * nMaxElements / log (1.0 - exp (logFpRate / nHashFuncs)));
236
+ data.clear ();
237
+ /* We store up to 16 'bits' per data element. */
238
+ data.resize ((nFilterBits + 15 ) / 16 );
229
239
reset ();
230
240
}
231
241
242
+ /* Similar to CBloomFilter::Hash */
243
+ inline unsigned int CRollingBloomFilter::Hash (unsigned int nHashNum, const std::vector<unsigned char >& vDataToHash) const {
244
+ return MurmurHash3 (nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size () * 16 );
245
+ }
246
+
232
247
void CRollingBloomFilter::insert (const std::vector<unsigned char >& vKey)
233
248
{
234
- if (nInsertions == 0 ) {
235
- b1.clear ();
236
- } else if (nInsertions == nBloomSize / 2 ) {
237
- b2.clear ();
249
+ if (nEntriesThisGeneration == nEntriesPerGeneration) {
250
+ nEntriesThisGeneration = 0 ;
251
+ nGeneration++;
252
+ if (nGeneration == 4 ) {
253
+ nGeneration = 1 ;
254
+ }
255
+ /* Wipe old entries that used this generation number. */
256
+ for (uint32_t p = 0 ; p < data.size () * 16 ; p++) {
257
+ if (get (p) == nGeneration) {
258
+ put (p, 0 );
259
+ }
260
+ }
238
261
}
239
- b1.insert (vKey);
240
- b2.insert (vKey);
241
- if (++nInsertions == nBloomSize) {
242
- nInsertions = 0 ;
262
+ nEntriesThisGeneration++;
263
+
264
+ for (int n = 0 ; n < nHashFuncs; n++) {
265
+ uint32_t h = Hash (n, vKey);
266
+ put (h, nGeneration);
243
267
}
244
268
}
245
269
@@ -251,10 +275,13 @@ void CRollingBloomFilter::insert(const uint256& hash)
251
275
252
276
bool CRollingBloomFilter::contains (const std::vector<unsigned char >& vKey) const
253
277
{
254
- if (nInsertions < nBloomSize / 2 ) {
255
- return b2.contains (vKey);
278
+ for (int n = 0 ; n < nHashFuncs; n++) {
279
+ uint32_t h = Hash (n, vKey);
280
+ if (get (h) == 0 ) {
281
+ return false ;
282
+ }
256
283
}
257
- return b1. contains (vKey) ;
284
+ return true ;
258
285
}
259
286
260
287
bool CRollingBloomFilter::contains (const uint256& hash) const
@@ -265,8 +292,10 @@ bool CRollingBloomFilter::contains(const uint256& hash) const
265
292
266
293
void CRollingBloomFilter::reset ()
267
294
{
268
- unsigned int nNewTweak = GetRand (std::numeric_limits<unsigned int >::max ());
269
- b1.reset (nNewTweak);
270
- b2.reset (nNewTweak);
271
- nInsertions = 0 ;
295
+ nTweak = GetRand (std::numeric_limits<unsigned int >::max ());
296
+ nEntriesThisGeneration = 0 ;
297
+ nGeneration = 1 ;
298
+ for (std::vector<uint32_t >::iterator it = data.begin (); it != data.end (); it++) {
299
+ *it = 0 ;
300
+ }
272
301
}
0 commit comments