LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_bloom.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 82 114 71.9 %
Date: 2025-09-19 04:41:14 Functions: 8 9 88.9 %

          Line data    Source code
       1             : #include "fd_bloom.h"
       2             : 
       3             : #include "../../util/log/fd_log.h"
       4             : 
       5             : #include <math.h>
       6             : 
       7             : static const double FD_BLOOM_LN_2 = 0.69314718055994530941723212145818;
       8             : static ulong
       9             : fnv_hasher( uchar const * ele,
      10             :             ulong         ele_sz,
      11          60 :             ulong         key ) {
      12         846 :   for( ulong i=0UL; i<ele_sz; i++ ) {
      13         786 :     key ^= (ulong)ele[i];
      14         786 :     key *= 1099511628211UL; /* FNV prime */
      15         786 :   }
      16          60 :   return key;
      17          60 : }
      18             : 
      19             : FD_FN_CONST ulong
      20        1830 : fd_bloom_align( void ) {
      21        1830 :   return FD_BLOOM_ALIGN;
      22        1830 : }
      23             : 
      24             : FD_FN_CONST ulong
      25             : fd_bloom_footprint( double false_positive_rate,
      26          15 :                     ulong  max_bits ) {
      27          15 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return 0UL;
      28          15 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return 0UL;
      29             : 
      30          15 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return 0UL;
      31             : 
      32          15 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      33             : 
      34          15 :   ulong l;
      35          15 :   l = FD_LAYOUT_INIT;
      36          15 :   l = FD_LAYOUT_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      37          15 :   l = FD_LAYOUT_APPEND( l, 8UL,            num_keys*sizeof(ulong) );
      38          15 :   l = FD_LAYOUT_APPEND( l, 8UL,            (max_bits+7UL)/8UL );
      39          15 :   return FD_LAYOUT_FINI( l, FD_BLOOM_ALIGN );
      40          15 : }
      41             : 
      42             : void *
      43             : fd_bloom_new( void *     shmem,
      44             :               fd_rng_t * rng,
      45             :               double     false_positive_rate,
      46         909 :               ulong      max_bits ) {
      47             : 
      48         909 :   if( FD_UNLIKELY( !shmem ) ) {
      49           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      50           0 :     return NULL;
      51           0 :   }
      52             : 
      53         909 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_bloom_align() ) ) ) {
      54           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
      55           0 :     return NULL;
      56           0 :   }
      57             : 
      58         909 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return NULL;
      59         909 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return NULL;
      60             : 
      61         909 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return NULL;
      62             : 
      63         909 :   if( FD_UNLIKELY( !rng ) ) return NULL;
      64             : 
      65         909 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      66             : 
      67         909 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      68         909 :   fd_bloom_t * bloom = FD_SCRATCH_ALLOC_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      69         909 :   void * _keys       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, num_keys*sizeof(ulong) );
      70         909 :   void * _bits       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, (max_bits+7UL)/8UL );
      71             : 
      72           0 :   bloom->keys      = (ulong *)_keys;
      73         909 :   bloom->keys_len  = 0UL;
      74         909 :   bloom->bits      = (ulong *)_bits;
      75         909 :   bloom->bits_len  = 0UL;
      76             : 
      77         909 :   bloom->hash_seed = 0UL;
      78         909 :   bloom->rng       = rng;
      79             : 
      80         909 :   bloom->false_positive_rate = false_positive_rate;
      81         909 :   bloom->max_bits = max_bits;
      82             : 
      83         909 :   FD_COMPILER_MFENCE();
      84         909 :   FD_VOLATILE( bloom->magic ) = FD_BLOOM_MAGIC;
      85         909 :   FD_COMPILER_MFENCE();
      86             : 
      87         909 :   return (void *)bloom;
      88         909 : }
      89             : 
      90             : fd_bloom_t *
      91         909 : fd_bloom_join( void * shbloom ) {
      92         909 :   if( FD_UNLIKELY( !shbloom ) ) {
      93           0 :     FD_LOG_WARNING(( "NULL shbloom" ));
      94           0 :     return NULL;
      95           0 :   }
      96             : 
      97         909 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shbloom, fd_bloom_align() ) ) ) {
      98           0 :     FD_LOG_WARNING(( "misaligned shbloom" ));
      99           0 :     return NULL;
     100           0 :   }
     101             : 
     102         909 :   fd_bloom_t * bloom = (fd_bloom_t *)shbloom;
     103             : 
     104         909 :   if( FD_UNLIKELY( bloom->magic!=FD_BLOOM_MAGIC ) ) {
     105           0 :     FD_LOG_WARNING(( "bad magic" ));
     106           0 :     return NULL;
     107           0 :   }
     108             : 
     109         909 :   return bloom;
     110         909 : }
     111             : 
     112             : void
     113             : fd_bloom_initialize( fd_bloom_t * bloom,
     114          18 :                      ulong        num_items ) {
     115          18 :   double num_bits = ceil( ((double)num_items * log( bloom->false_positive_rate )) / log( 1.0 / pow( 2.0, log( 2.0 ) ) ) );
     116          18 :   num_bits = fmax( 1.0, fmin( (double)bloom->max_bits, num_bits ) );
     117             : 
     118          18 :   ulong num_keys;
     119          18 :   if( FD_UNLIKELY( num_items == 0UL ) ) {
     120           3 :     num_keys = 0UL;
     121          15 :   } else {
     122          15 :     num_keys = fd_ulong_max( 1UL, (ulong)( round( ((double)num_bits/(double)num_items) * FD_BLOOM_LN_2 ) ) );
     123          15 :   }
     124          66 :   for( ulong i=0UL; i<num_keys; i++ ) bloom->keys[ i ] = fd_rng_ulong( bloom->rng );
     125             : 
     126          18 :   bloom->keys_len = num_keys;
     127          18 :   bloom->bits_len = (ulong)num_bits;
     128          18 :   fd_memset( bloom->bits, 0, (ulong)((num_bits+7UL)/8UL) );
     129          18 : }
     130             : 
     131             : void
     132             : fd_bloom_insert( fd_bloom_t *  bloom,
     133             :                  uchar const * key,
     134           9 :                  ulong         key_sz ) {
     135          36 :   for( ulong i=0UL; i<bloom->keys_len; i++ ) {
     136          27 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ i ] ) % bloom->bits_len;
     137          27 :     bloom->bits[ bit / 64UL ] |= (1UL << (bit % 64UL));
     138          27 :   }
     139           9 : }
     140             : 
     141             : int
     142             : fd_bloom_contains( fd_bloom_t *  bloom,
     143             :                    uchar const * key,
     144          15 :                    ulong         key_sz ) {
     145          42 :   for( ulong i=0UL; i<bloom->keys_len; i++ ) {
     146          33 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ i ]) % bloom->bits_len;
     147          33 :     if( !(bloom->bits[ bit / 64UL ] & (1UL << (bit % 64UL))) ) {
     148           6 :       return 0;
     149           6 :     }
     150          33 :   }
     151           9 :   return 1;
     152          15 : }
     153             : 
     154             : int
     155             : fd_bloom_init_inplace( ulong *      keys,
     156             :                        ulong *      bits,
     157             :                        ulong        keys_len,
     158             :                        ulong        bits_len,
     159             :                        ulong        hash_seed,
     160             :                        fd_rng_t *   rng,
     161             :                        double       false_positive_rate,
     162           0 :                        fd_bloom_t * out_bloom ) {
     163           0 :   if( FD_UNLIKELY( !keys || !bits || !out_bloom ) ) {
     164           0 :     FD_LOG_ERR(( "NULL keys, bits or out_bloom" ));
     165           0 :     return -1;
     166           0 :   }
     167           0 :   out_bloom->keys                = keys;
     168           0 :   for( ulong i=0UL; i<keys_len; i++ ) out_bloom->keys[ i ] = fd_rng_ulong( rng );
     169             : 
     170           0 :   out_bloom->keys_len            = keys_len;
     171           0 :   out_bloom->bits                = bits;
     172           0 :   out_bloom->bits_len            = bits_len;
     173           0 :   out_bloom->hash_seed           = hash_seed;
     174           0 :   out_bloom->rng                 = rng;
     175           0 :   out_bloom->false_positive_rate = false_positive_rate;
     176           0 :   out_bloom->max_bits            = bits_len;
     177             : 
     178           0 :   return 0;
     179           0 : }

Generated by: LCOV version 1.14