@@ -234,14 +234,18 @@ CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
234
234
*/
235
235
uint32_t nFilterBits = (uint32_t )ceil (-1.0 * nHashFuncs * nMaxElements / log (1.0 - exp (logFpRate / nHashFuncs)));
236
236
data.clear ();
237
- /* We store up to 16 'bits' per data element. */
238
- data.resize ((nFilterBits + 15 ) / 16 );
237
+ /* For each data element we need to store 2 bits. If both bits are 0, the
238
+ * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
239
+ * treated as set in generation 1, 2, or 3 respectively.
240
+ * These bits are stored in separate integers: position P corresponds to bit
241
+ * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
242
+ data.resize (((nFilterBits + 63 ) / 64 ) << 1 );
239
243
reset ();
240
244
}
241
245
242
246
/* 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 ) ;
247
+ static inline uint32_t RollingBloomHash (unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char >& vDataToHash) {
248
+ return MurmurHash3 (nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
245
249
}
246
250
247
251
void CRollingBloomFilter::insert (const std::vector<unsigned char >& vKey)
@@ -252,18 +256,25 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
252
256
if (nGeneration == 4 ) {
253
257
nGeneration = 1 ;
254
258
}
259
+ uint64_t nGenerationMask1 = -(uint64_t )(nGeneration & 1 );
260
+ uint64_t nGenerationMask2 = -(uint64_t )(nGeneration >> 1 );
255
261
/* 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
- }
262
+ for (uint32_t p = 0 ; p < data.size (); p += 2 ) {
263
+ uint64_t p1 = data[p], p2 = data[p + 1 ];
264
+ uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
265
+ data[p] = p1 & mask;
266
+ data[p + 1 ] = p2 & mask;
260
267
}
261
268
}
262
269
nEntriesThisGeneration++;
263
270
264
271
for (int n = 0 ; n < nHashFuncs; n++) {
265
- uint32_t h = Hash (n, vKey);
266
- put (h, nGeneration);
272
+ uint32_t h = RollingBloomHash (n, nTweak, vKey);
273
+ int bit = h & 0x3F ;
274
+ uint32_t pos = (h >> 6 ) % data.size ();
275
+ /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
276
+ data[pos & ~1 ] = (data[pos & ~1 ] & ~(((uint64_t )1 ) << bit)) | ((uint64_t )(nGeneration & 1 )) << bit;
277
+ data[pos | 1 ] = (data[pos | 1 ] & ~(((uint64_t )1 ) << bit)) | ((uint64_t )(nGeneration >> 1 )) << bit;
267
278
}
268
279
}
269
280
@@ -276,8 +287,11 @@ void CRollingBloomFilter::insert(const uint256& hash)
276
287
bool CRollingBloomFilter::contains (const std::vector<unsigned char >& vKey) const
277
288
{
278
289
for (int n = 0 ; n < nHashFuncs; n++) {
279
- uint32_t h = Hash (n, vKey);
280
- if (get (h) == 0 ) {
290
+ uint32_t h = RollingBloomHash (n, nTweak, vKey);
291
+ int bit = h & 0x3F ;
292
+ uint32_t pos = (h >> 6 ) % data.size ();
293
+ /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
294
+ if (!(((data[pos & ~1 ] | data[pos | 1 ]) >> bit) & 1 )) {
281
295
return false ;
282
296
}
283
297
}
@@ -295,7 +309,7 @@ void CRollingBloomFilter::reset()
295
309
nTweak = GetRand (std::numeric_limits<unsigned int >::max ());
296
310
nEntriesThisGeneration = 0 ;
297
311
nGeneration = 1 ;
298
- for (std::vector<uint32_t >::iterator it = data.begin (); it != data.end (); it++) {
312
+ for (std::vector<uint64_t >::iterator it = data.begin (); it != data.end (); it++) {
299
313
*it = 0 ;
300
314
}
301
315
}
0 commit comments