LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_bloom.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 84 115 73.0 %
Date: 2025-10-13 04:42: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        3630 : fd_bloom_align( void ) {
      21        3630 :   return FD_BLOOM_ALIGN;
      22        3630 : }
      23             : 
      24             : FD_FN_CONST ulong
      25             : fd_bloom_footprint( double false_positive_rate,
      26        1842 :                     ulong  max_bits ) {
      27        1842 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return 0UL;
      28        1842 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return 0UL;
      29             : 
      30        1842 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return 0UL;
      31             : 
      32        1842 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      33             : 
      34        1842 :   ulong l;
      35        1842 :   l = FD_LAYOUT_INIT;
      36        1842 :   l = FD_LAYOUT_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      37        1842 :   l = FD_LAYOUT_APPEND( l, 8UL,            num_keys*sizeof(ulong) );
      38        1842 :   l = FD_LAYOUT_APPEND( l, 8UL,            (max_bits+7UL)/8UL );
      39        1842 :   return FD_LAYOUT_FINI( l, FD_BLOOM_ALIGN );
      40        1842 : }
      41             : 
      42             : void *
      43             : fd_bloom_new( void *     shmem,
      44             :               fd_rng_t * rng,
      45             :               double     false_positive_rate,
      46        1809 :               ulong      max_bits ) {
      47             : 
      48        1809 :   if( FD_UNLIKELY( !shmem ) ) {
      49           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      50           0 :     return NULL;
      51           0 :   }
      52             : 
      53        1809 :   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        1809 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return NULL;
      59        1809 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return NULL;
      60             : 
      61        1809 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return NULL;
      62             : 
      63        1809 :   if( FD_UNLIKELY( !rng ) ) return NULL;
      64             : 
      65        1809 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      66             : 
      67        1809 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      68        1809 :   fd_bloom_t * bloom = FD_SCRATCH_ALLOC_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      69        1809 :   void * _keys       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, num_keys*sizeof(ulong) );
      70        1809 :   void * _bits       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, (max_bits+7UL)/8UL );
      71        1809 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, FD_BLOOM_ALIGN ) == (ulong)shmem + fd_bloom_footprint( false_positive_rate, max_bits ) );
      72             : 
      73        1809 :   bloom->keys      = (ulong *)_keys;
      74        1809 :   bloom->keys_len  = 0UL;
      75        1809 :   bloom->bits      = (ulong *)_bits;
      76        1809 :   bloom->bits_len  = 0UL;
      77             : 
      78        1809 :   bloom->hash_seed = 0UL;
      79        1809 :   bloom->rng       = rng;
      80             : 
      81        1809 :   bloom->false_positive_rate = false_positive_rate;
      82        1809 :   bloom->max_bits = max_bits;
      83             : 
      84        1809 :   FD_COMPILER_MFENCE();
      85        1809 :   FD_VOLATILE( bloom->magic ) = FD_BLOOM_MAGIC;
      86        1809 :   FD_COMPILER_MFENCE();
      87             : 
      88        1809 :   return (void *)bloom;
      89        1809 : }
      90             : 
      91             : fd_bloom_t *
      92        1809 : fd_bloom_join( void * shbloom ) {
      93        1809 :   if( FD_UNLIKELY( !shbloom ) ) {
      94           0 :     FD_LOG_WARNING(( "NULL shbloom" ));
      95           0 :     return NULL;
      96           0 :   }
      97             : 
      98        1809 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shbloom, fd_bloom_align() ) ) ) {
      99           0 :     FD_LOG_WARNING(( "misaligned shbloom" ));
     100           0 :     return NULL;
     101           0 :   }
     102             : 
     103        1809 :   fd_bloom_t * bloom = (fd_bloom_t *)shbloom;
     104             : 
     105        1809 :   if( FD_UNLIKELY( bloom->magic!=FD_BLOOM_MAGIC ) ) {
     106           0 :     FD_LOG_WARNING(( "bad magic" ));
     107           0 :     return NULL;
     108           0 :   }
     109             : 
     110        1809 :   return bloom;
     111        1809 : }
     112             : 
     113             : void
     114             : fd_bloom_initialize( fd_bloom_t * bloom,
     115          18 :                      ulong        num_items ) {
     116          18 :   double num_bits = ceil( ((double)num_items * log( bloom->false_positive_rate )) / log( 1.0 / pow( 2.0, log( 2.0 ) ) ) );
     117          18 :   num_bits = fmax( 1.0, fmin( (double)bloom->max_bits, num_bits ) );
     118             : 
     119          18 :   ulong num_keys;
     120          18 :   if( FD_UNLIKELY( num_items == 0UL ) ) {
     121           3 :     num_keys = 0UL;
     122          15 :   } else {
     123          15 :     num_keys = fd_ulong_max( 1UL, (ulong)( round( ((double)num_bits/(double)num_items) * FD_BLOOM_LN_2 ) ) );
     124          15 :   }
     125          66 :   for( ulong i=0UL; i<num_keys; i++ ) bloom->keys[ i ] = fd_rng_ulong( bloom->rng );
     126             : 
     127          18 :   bloom->keys_len = num_keys;
     128          18 :   bloom->bits_len = (ulong)num_bits;
     129          18 :   fd_memset( bloom->bits, 0, (ulong)((num_bits+7UL)/8UL) );
     130          18 : }
     131             : 
     132             : void
     133             : fd_bloom_insert( fd_bloom_t *  bloom,
     134             :                  uchar const * key,
     135           9 :                  ulong         key_sz ) {
     136          36 :   for( ulong i=0UL; i<bloom->keys_len; i++ ) {
     137          27 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ i ] ) % bloom->bits_len;
     138          27 :     bloom->bits[ bit / 64UL ] |= (1UL << (bit % 64UL));
     139          27 :   }
     140           9 : }
     141             : 
     142             : int
     143             : fd_bloom_contains( fd_bloom_t *  bloom,
     144             :                    uchar const * key,
     145          15 :                    ulong         key_sz ) {
     146          42 :   for( ulong i=0UL; i<bloom->keys_len; i++ ) {
     147          33 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ i ]) % bloom->bits_len;
     148          33 :     if( !(bloom->bits[ bit / 64UL ] & (1UL << (bit % 64UL))) ) {
     149           6 :       return 0;
     150           6 :     }
     151          33 :   }
     152           9 :   return 1;
     153          15 : }
     154             : 
     155             : int
     156             : fd_bloom_init_inplace( ulong *      keys,
     157             :                        ulong *      bits,
     158             :                        ulong        keys_len,
     159             :                        ulong        bits_len,
     160             :                        ulong        hash_seed,
     161             :                        fd_rng_t *   rng,
     162             :                        double       false_positive_rate,
     163           0 :                        fd_bloom_t * out_bloom ) {
     164           0 :   if( FD_UNLIKELY( !keys || !bits || !out_bloom ) ) {
     165           0 :     FD_LOG_ERR(( "NULL keys, bits or out_bloom" ));
     166           0 :     return -1;
     167           0 :   }
     168           0 :   out_bloom->keys                = keys;
     169           0 :   for( ulong i=0UL; i<keys_len; i++ ) out_bloom->keys[ i ] = fd_rng_ulong( rng );
     170             : 
     171           0 :   out_bloom->keys_len            = keys_len;
     172           0 :   out_bloom->bits                = bits;
     173           0 :   out_bloom->bits_len            = bits_len;
     174           0 :   out_bloom->hash_seed           = hash_seed;
     175           0 :   out_bloom->rng                 = rng;
     176           0 :   out_bloom->false_positive_rate = false_positive_rate;
     177           0 :   out_bloom->max_bits            = bits_len;
     178             : 
     179           0 :   return 0;
     180           0 : }

Generated by: LCOV version 1.14