LCOV - code coverage report
Current view: top level - discof/repair - fd_policy.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 51 0.0 %
Date: 2025-10-27 04:40:00 Functions: 0 21 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_repair_fd_policy_h
       2             : #define HEADER_fd_src_discof_repair_fd_policy_h
       3             : 
       4             : /* fd_policy implements the policy of the Repair agent.  It determines
       5             :    what shreds the validator is expecting but has not yet received and
       6             :    needs to request via repair.  It also determines which peer(s) the
       7             :    validator should request the shred from.
       8             : 
       9             :    The default policy implementation is round-robin DFS with time-based
      10             :    dedup: round-robin through all the repair peers we know about, and
      11             :    depth-first search down the repair forest (see fd_forest.h).  This
      12             :    policy also dedups identical repair requests that occur within a
      13             :    specified amount of time window of each other (configurable on init
      14             :    as a hyperparameter).  With the DFS strategy, the smaller the tree,
      15             :    the sooner an element will be iterated again (when the DFS restarts
      16             :    from the root of the tree). */
      17             : 
      18             : #include "../../flamenco/types/fd_types_custom.h"
      19             : #include "../forest/fd_forest.h"
      20             : #include "../../util/net/fd_net_headers.h"
      21             : #include "fd_repair.h"
      22             : 
      23             : /* FD_POLICY_PEER_MAX specifies a hard bound for how many peers Policy
      24             :    needs to track.  4096 is derived from the BLS signature max, which
      25             :    is the maximum number of staked validators Solana can support. */
      26             : 
      27             : #define FD_POLICY_PEER_MAX (4096UL)
      28             : 
      29             : /* fd_policy_dedup implements a dedup cache for already sent Repair
      30             :    requests.  It is backed by a map and linked list, in which the least
      31             :    recently used (oldest Repair request) in the map is evicted when the
      32             :    map is full. */
      33             : 
      34             : typedef struct fd_policy_dedup fd_policy_dedup_t; /* forward decl */
      35             : 
      36             : /* fd_policy_dedup_ele describes an element in the dedup cache.  The key
      37             :    compactly encodes an fd_repair_req_t.
      38             : 
      39             :    | kind (2 bits)       | slot (32 bits)  | shred_idx (15 bits) |
      40             :    | 0x0 (SHRED)         | slot            | shred_idx           |
      41             :    | 0x1 (HIGHEST_SHRED) | slot            | >=shred_idx         |
      42             :    | 0x2 (ORPHAN)        | orphan slot     | N/A                 |
      43             : 
      44             :    Note the common header (sig, from, to, ts, nonce) is not included. */
      45             : 
      46             : struct fd_policy_dedup_ele {
      47             :   ulong key;      /* compact encoding of fd_repair_req_t detailed above */
      48             :   ulong prev;   /* reserved by lru */
      49             :   ulong next;
      50             :   ulong hash;     /* reserved by pool and map_chain */
      51             :   long  req_ts;   /* timestamp when the request was sent */
      52             : };
      53             : typedef struct fd_policy_dedup_ele fd_policy_dedup_ele_t;
      54             : 
      55             : FD_FN_CONST static inline ulong
      56           0 : fd_policy_dedup_key( uint kind, ulong slot, uint shred_idx ) {
      57           0 :   return (ulong)kind << 61 | slot << 30 | shred_idx << 15;
      58           0 : }
      59             : 
      60           0 : FD_FN_CONST static inline uint  fd_policy_dedup_key_kind     ( ulong key ) { return (uint)fd_ulong_extract( key, 62, 63 ); }
      61           0 : FD_FN_CONST static inline ulong fd_policy_dedup_key_slot     ( ulong key ) { return       fd_ulong_extract( key, 30, 61 ); }
      62           0 : FD_FN_CONST static inline uint  fd_policy_dedup_key_shred_idx( ulong key ) { return (uint)fd_ulong_extract( key, 15, 29  ); }
      63             : 
      64             : #define POOL_NAME fd_policy_dedup_pool
      65           0 : #define POOL_T    fd_policy_dedup_ele_t
      66           0 : #define POOL_NEXT hash
      67             : #include "../../util/tmpl/fd_pool.c"
      68             : 
      69             : #define MAP_NAME  fd_policy_dedup_map
      70             : #define MAP_ELE_T fd_policy_dedup_ele_t
      71           0 : #define MAP_NEXT  hash
      72             : #include "../../util/tmpl/fd_map_chain.c"
      73             : 
      74             : #define DLIST_NAME   fd_policy_dedup_lru
      75             : #define DLIST_ELE_T  fd_policy_dedup_ele_t
      76           0 : #define DLIST_NEXT   next
      77           0 : #define DLIST_PREV   prev
      78             : #include "../../util/tmpl/fd_dlist.c"
      79             : struct fd_policy_dedup {
      80             :   fd_policy_dedup_map_t * map;  /* map of dedup elements */
      81             :   fd_policy_dedup_ele_t * pool; /* memory pool of dedup elements */
      82             :   fd_policy_dedup_lru_t * lru;  /* singly-linked list of dedup elements by insertion order.  TODO: add eviction feature using linkedlist */
      83             : };
      84             : 
      85             : /* fd_policy_peer_t describes a peer validator that serves repairs.
      86             :    Peers are discovered through gossip, via a "ContactInfo" message that
      87             :    shares the validator's ip and repair server port. */
      88             : 
      89             : struct fd_policy_peer {
      90             :   fd_pubkey_t key;     /* map key, pubkey of the validator */
      91             :   uint        hash;    /* reserved for map */
      92             :   uint        ip4;     /* ip4 addr of the peer */
      93             :   ushort      port;    /* repair server port of the peer */
      94             :   ulong       req_cnt; /* count of requests we've sent to this peer */
      95             :   ulong       res_cnt; /* count of responses we've received from this peer */
      96             : 
      97             :   /* below are for measuring bandwidth usage */
      98             :   long  first_req_ts;
      99             :   long  last_req_ts;
     100             : 
     101             :   long  first_resp_ts;
     102             :   long  last_resp_ts;
     103             : 
     104             :   long  total_lat; /* total RTT over all responses in ns */
     105             :   ulong stake;
     106             : 
     107             :   ulong pool_idx;
     108             : };
     109             : typedef struct fd_policy_peer fd_policy_peer_t;
     110             : 
     111             : #define MAP_NAME              fd_policy_peer_map
     112           0 : #define MAP_T                 fd_policy_peer_t
     113           0 : #define MAP_KEY_T             fd_pubkey_t
     114           0 : #define MAP_KEY_NULL          null_pubkey
     115             : #define MAP_KEY_EQUAL_IS_SLOW 1
     116             : #define MAP_MEMOIZE           0
     117           0 : #define MAP_KEY_INVAL(k)      MAP_KEY_EQUAL((k),MAP_KEY_NULL)
     118           0 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp( (k0).key, (k1).key, 32UL ))
     119           0 : #define MAP_KEY_HASH(key)     ((MAP_HASH_T)( (key).ul[1] ))
     120             : #include "../../util/tmpl/fd_map_dynamic.c"
     121             : 
     122             : struct fd_peer {
     123             :   fd_pubkey_t identity;
     124             :   ulong       next;
     125             :   ulong       prev;
     126             : };
     127             : typedef struct fd_peer fd_peer_t;
     128             : 
     129             : #define POOL_NAME fd_peer_pool
     130           0 : #define POOL_T    fd_peer_t
     131             : #include "../../util/tmpl/fd_pool.c"
     132             : 
     133             : #define DLIST_NAME  fd_peer_dlist
     134             : #define DLIST_ELE_T fd_peer_t
     135           0 : #define DLIST_NEXT  next
     136           0 : #define DLIST_PREV  prev
     137             : #include "../../util/tmpl/fd_dlist.c"
     138             : 
     139             : /* fd_policy_peers implements the data structures and bookkeeping for
     140             :    selecting repair peers via round-robin. */
     141             : 
     142             : struct fd_policy_peers {
     143             :   fd_peer_t        * pool;  /* memory pool of repair peer pubkeys, contains entries of both dlist */
     144             :   fd_peer_dlist_t  * fast;  /* [0, FD_POLICY_LATENCY_THRESH]   ms latency group FD_POLICY_LATENCY_FAST */
     145             :   fd_peer_dlist_t  * slow;  /* (FD_POLICY_LATENCY_THRESH, inf) ms latency group FD_POLICY_LATENCY_SLOW */
     146             :   fd_policy_peer_t * map;   /* map dynamic of pubkey->peer data */
     147             :   struct {
     148             :      uint stage;                  /* < sizeof(bucket_stages)        */
     149             :      fd_peer_dlist_iter_t iter;   /* round-robin index of next peer */
     150             :   } select;
     151             : };
     152             : typedef struct fd_policy_peers fd_policy_peers_t;
     153             : 
     154           0 : #define FD_POLICY_LATENCY_FAST  1
     155             : #define FD_POLICY_LATENCY_SLOW 3
     156             : 
     157             : /* Policy parameters start */
     158           0 : #define FD_POLICY_LATENCY_THRESH 30e6L /* less than this is a BEST peer, otherwise a WORST peer */
     159             : #define FD_POLICY_DEDUP_TIMEOUT  50e6L /* how long wait to request the same shred */
     160             : 
     161             : /* Round robins through ALL the worst peers once, then round robins
     162             :    through ALL the best peers once, then round robins through ALL the
     163             :    best peers again, etc. All peers are initially added to the worst
     164             :    bucket, and moved once round trip times have been recorded. */
     165             : 
     166             : static const uint bucket_stages[7] = {
     167             :    FD_POLICY_LATENCY_SLOW, /* do a cycle through worst peers 1/7 times to see if any improvements are made */
     168             :    FD_POLICY_LATENCY_FAST,
     169             :    FD_POLICY_LATENCY_FAST,
     170             :    FD_POLICY_LATENCY_FAST,
     171             :    FD_POLICY_LATENCY_FAST,
     172             :    FD_POLICY_LATENCY_FAST,
     173             :    FD_POLICY_LATENCY_FAST,
     174             : };
     175             : /* Policy parameters end */
     176             : 
     177             : struct fd_policy {
     178             :   fd_policy_dedup_t dedup; /* dedup cache of already sent requests */
     179             :   fd_policy_peers_t peers; /* repair peers (strategy & data) */
     180             :   long              tsmax; /* maximum time for an iteration before resetting the DFS to root */
     181             :   long              tsref; /* reference timestamp for resetting DFS */
     182             : 
     183             :   fd_forest_iter_t  iterf; /* forest iterator */
     184             :   ulong             tsreset; /* ms timestamp of last reset of iterf */
     185             : 
     186             :   ulong turbine_slot0;
     187             :   uint nonce;
     188             : };
     189             : typedef struct fd_policy fd_policy_t;
     190             : 
     191             : /* Constructors */
     192             : 
     193             : /* fd_policy_{align,footprint} return the required alignment and
     194             :    footprint of a memory region suitable for use as policy with up to
     195             :    ele_max eles and vote_max votes. */
     196             : 
     197             : FD_FN_CONST static inline ulong
     198           0 : fd_policy_align( void ) {
     199           0 :   return alignof(fd_policy_t);
     200           0 : }
     201             : 
     202             : FD_FN_CONST static inline ulong
     203           0 : fd_policy_footprint( ulong dedup_max, ulong peer_max ) {
     204           0 :   int lg_peer_max = fd_ulong_find_msb( fd_ulong_pow2_up( peer_max ) );
     205           0 :   return FD_LAYOUT_FINI(
     206           0 :     FD_LAYOUT_APPEND(
     207           0 :     FD_LAYOUT_APPEND(
     208           0 :     FD_LAYOUT_APPEND(
     209           0 :     FD_LAYOUT_APPEND(
     210           0 :     FD_LAYOUT_APPEND(
     211           0 :     FD_LAYOUT_APPEND(
     212           0 :     FD_LAYOUT_APPEND(
     213           0 :     FD_LAYOUT_APPEND(
     214           0 :     FD_LAYOUT_INIT,
     215           0 :       alignof(fd_policy_t),         sizeof(fd_policy_t)                           ),
     216           0 :       fd_policy_dedup_map_align(),  fd_policy_dedup_map_footprint ( dedup_max   ) ),
     217           0 :       fd_policy_dedup_pool_align(), fd_policy_dedup_pool_footprint( dedup_max   ) ),
     218           0 :       fd_policy_dedup_lru_align(),  fd_policy_dedup_lru_footprint()               ),
     219           0 :       fd_policy_peer_map_align(),   fd_policy_peer_map_footprint  ( lg_peer_max ) ),
     220           0 :       fd_peer_pool_align(),         fd_peer_pool_footprint        ( peer_max    ) ),
     221           0 :       fd_peer_dlist_align(),        fd_peer_dlist_footprint()                     ),
     222           0 :       fd_peer_dlist_align(),        fd_peer_dlist_footprint()                     ),
     223           0 :     fd_policy_align() );
     224           0 : }
     225             : 
     226             : /* fd_policy_new formats an unused memory region for use as a policy.
     227             :    mem is a non-NULL pointer to this region in the local address space
     228             :    with the required footprint and alignment. */
     229             : 
     230             : void *
     231             : fd_policy_new( void * shmem, ulong dedup_max, ulong peer_max, ulong seed );
     232             : 
     233             : /* fd_policy_join joins the caller to the policy.  policy points to the
     234             :    first byte of the memory region backing the policy in the caller's
     235             :    address space.  Returns a pointer in the local address space to
     236             :    policy on success. */
     237             : 
     238             : fd_policy_t *
     239             : fd_policy_join( void * policy );
     240             : 
     241             : /* fd_policy_leave leaves a current local join.  Returns a pointer to
     242             :    the underlying shared memory region on success and NULL on failure
     243             :    (logs details).  Reasons for failure include policy is NULL. */
     244             : 
     245             : void *
     246             : fd_policy_leave( fd_policy_t const * policy );
     247             : 
     248             : /* fd_policy_delete unformats a memory region used as a policy.  Assumes
     249             :    only the nobody is joined to the region.  Returns a pointer to the
     250             :    underlying shared memory region or NULL if used obviously in error
     251             :    (e.g. policy is obviously not a policy ... logs details).  The
     252             :    ownership of the memory region is transferred to the caller. */
     253             : 
     254             : void *
     255             : fd_policy_delete( void * policy );
     256             : 
     257             : /* fd_policy_next returns the next repair request that should be made.
     258             :    Currently implements the default round-robin DFS strategy. */
     259             : 
     260             : fd_repair_msg_t const *
     261             : fd_policy_next( fd_policy_t * policy, fd_forest_t * forest, fd_repair_t * repair, long now, ulong highest_known_slot );
     262             : 
     263             : fd_policy_peer_t const *
     264             : fd_policy_peer_insert( fd_policy_t * policy, fd_pubkey_t const * key, fd_ip4_port_t const * addr );
     265             : 
     266             : fd_policy_peer_t *
     267             : fd_policy_peer_query( fd_policy_t * policy, fd_pubkey_t const * key );
     268             : 
     269             : int
     270             : fd_policy_peer_remove( fd_policy_t * policy, fd_pubkey_t const * key );
     271             : 
     272             : fd_pubkey_t const *
     273             : fd_policy_peer_select( fd_policy_t * policy );
     274             : 
     275             : void
     276             : fd_policy_peer_request_update( fd_policy_t * policy, fd_pubkey_t const * to );
     277             : 
     278             : static inline fd_peer_dlist_t *
     279           0 : fd_policy_peer_latency_bucket( fd_policy_t * policy, long total_rtt /* ns */, ulong res_cnt ) {
     280           0 :    if( res_cnt == 0 || (long)(total_rtt / (long)res_cnt) > FD_POLICY_LATENCY_THRESH ) return policy->peers.slow;
     281           0 :    return policy->peers.fast;
     282           0 : }
     283             : 
     284             : void
     285             : fd_policy_peer_response_update( fd_policy_t * policy, fd_pubkey_t const * to, long rtt );
     286             : 
     287             : void
     288             : fd_policy_set_turbine_slot0( fd_policy_t * policy, ulong slot );
     289             : 
     290             : void
     291             : fd_policy_reset( fd_policy_t * policy, fd_forest_t * forest );
     292             : 
     293             : #endif /* HEADER_fd_src_discof_repair_fd_policy_h */

Generated by: LCOV version 1.14