Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_txncache_private_h 2 : #define HEADER_fd_src_flamenco_runtime_fd_txncache_private_h 3 : 4 : #include "fd_txncache_shmem.h" 5 : #include "../types/fd_types_custom.h" 6 : #include "../fd_rwlock.h" 7 : 8 : /* The number of transactions in each page. This needs to be high 9 : enough to amoritze the cost of caller code reserving pages from, 10 : and returning pages to the pool, but not so high that the memory 11 : wasted from blockhashes with only one transaction is significant. */ 12 : 13 0 : #define FD_TXNCACHE_TXNS_PER_PAGE (16384UL) 14 : 15 : /* The maximum distance a transaction blockhash reference can be 16 : (inclusive). For example, if no slots were skipped, and the value is 17 : 151, slot 300 is allowed to reference blockhashes from slots 18 : [149, 300). */ 19 0 : #define FD_TXNCACHE_MAX_BLOCKHASH_DISTANCE (151UL) 20 : 21 : struct fd_txncache_single_txn { 22 : uint blockcache_next; /* Pointer to the next element in the blockcache hash chain containing this entry from the pool. */ 23 : uint generation; /* The generation of the fork when this transaction was inserted. Used to 24 : determine if the transaction is still valid for a fork that might have 25 : advanced since insertion. */ 26 : 27 : fd_txncache_fork_id_t fork_id; /* Fork that the transaction was executed on. A transaction might be in the cache 28 : multiple times if it was executed on multiple forks. */ 29 : uchar txnhash[ 20UL ]; /* The transaction message hash, truncated to 20 bytes. The hash is not always the first 20 30 : bytes, but is 20 bytes starting at some arbitrary offset given by the txnhash_offset value 31 : of the containing blockcache entry. */ 32 : }; 33 : 34 : typedef struct fd_txncache_single_txn fd_txncache_single_txn_t; 35 : 36 : struct fd_txncache_txnpage { 37 : ushort free; /* The number of free txn entries in this page. */ 38 : fd_txncache_single_txn_t txns[ FD_TXNCACHE_TXNS_PER_PAGE][ 1 ]; /* The transactions in the page. */ 39 : }; 40 : 41 : typedef struct fd_txncache_txnpage fd_txncache_txnpage_t; 42 : 43 : struct fd_txncache_blockcache_shmem { 44 : fd_txncache_fork_id_t parent_id; 45 : fd_txncache_fork_id_t child_id; 46 : fd_txncache_fork_id_t sibling_id; 47 : 48 : int frozen; /* This is used to enforce invariants on the caller of the txncache. 49 : -1: invalid 50 : 0: active 51 : 1: semi frozen, only happens during snapshot load 52 : 2: frozen, should not be modified */ 53 : 54 : uint generation; 55 : 56 : fd_hash_t blockhash; /* The blockhash that this entry is for. */ 57 : ulong txnhash_offset; /* To save memory, the Agave validator decided to truncate the hash of transactions stored in 58 : this memory to 20 bytes rather than 32 bytes. The bytes used are not the first 20 as you 59 : might expect, but instead the first 20 starting at some random offset into the transaction 60 : hash (starting between 0 and len(hash)-20, a/k/a 44 for signatures, and 12 for hashes). 61 : 62 : In an unfortunate turn, the offset is also propogated to peers via. snapshot responses, 63 : which only communicate the offset and the respective 20 bytes. To make sure we are 64 : deduplicating incoming transactions correctly, we must replicate this system even though 65 : it would be easier to just always take the first 20 bytes. For transactions that we 66 : insert into the cache ourselves, we do just always use a key_offset of zero, so this is 67 : only nonzero when constructed form a peer snapshot. */ 68 : 69 : ushort pages_cnt; /* The number of txnpages currently in use to store the transactions in this blockcache. */ 70 : 71 : struct { 72 : ulong next; 73 : } pool; 74 : 75 : struct { 76 : ulong next; 77 : } slist; 78 : 79 : struct { 80 : ulong next; 81 : ulong prev; 82 : } blockhash_map; 83 : }; 84 : 85 : typedef struct fd_txncache_blockcache_shmem fd_txncache_blockcache_shmem_t; 86 : 87 : #define POOL_NAME blockcache_pool 88 : #define POOL_T fd_txncache_blockcache_shmem_t 89 : #define POOL_IDX_T ulong 90 0 : #define POOL_NEXT pool.next 91 : #define POOL_IMPL_STYLE 1 92 : #include "../../util/tmpl/fd_pool.c" 93 : 94 : #define MAP_NAME blockhash_map 95 : #define MAP_KEY blockhash 96 : #define MAP_ELE_T fd_txncache_blockcache_shmem_t 97 : #define MAP_KEY_T fd_hash_t 98 : #define MAP_PREV blockhash_map.prev 99 : #define MAP_NEXT blockhash_map.next 100 0 : #define MAP_KEY_EQ(k0,k1) fd_hash_eq( k0, k1 ) 101 0 : #define MAP_KEY_HASH(key,seed) (__extension__({ (void)(seed); fd_ulong_load_8_fast( (key)->uc ); })) 102 : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1 103 : #define MAP_MULTI 1 104 : #define MAP_IMPL_STYLE 1 105 : #include "../../util/tmpl/fd_map_chain.c" 106 : 107 : #define SLIST_NAME root_slist 108 : #define SLIST_ELE_T fd_txncache_blockcache_shmem_t 109 0 : #define SLIST_IDX_T ulong 110 0 : #define SLIST_NEXT slist.next 111 : #define SLIST_IMPL_STYLE 1 112 : #include "../../util/tmpl/fd_slist.c" 113 : 114 : #define SET_NAME descends_set 115 : #include "../../util/tmpl/fd_set_dynamic.c" 116 : 117 : struct __attribute__((aligned(FD_TXNCACHE_SHMEM_ALIGN))) fd_txncache_shmem_private { 118 : /* The txncache is a concurrent structure and will be accessed by multiple threads 119 : concurrently. Insertion and querying only take a read lock as they can be done 120 : lockless but all other operations will take a write lock internally. 121 : 122 : The lock needs to be aligned to 128 bytes to avoid false sharing with other 123 : data that might be on the same cache line. */ 124 : fd_rwlock_t lock[ 1 ] __attribute__((aligned(128UL))); 125 : 126 : ulong txn_per_slot_max; 127 : ulong active_slots_max; 128 : ushort txnpages_per_blockhash_max; 129 : ushort max_txnpages; 130 : 131 : uint blockcache_generation; /* Incremented for every blockcache. */ 132 : ushort txnpages_free_cnt; /* The number of pages in the txnpages that are not currently in use. */ 133 : 134 : ulong root_cnt; 135 : root_slist_t root_ll[1]; /* A singly linked list of the forks that are roots of fork chains. The tail is the 136 : most recently added root, the head is the oldest root. This is used to identify 137 : which forks can be pruned when a new root is added. */ 138 : 139 : ulong magic; /* ==FD_TXNCACHE_SHMEM_MAGIC */ 140 : }; 141 : 142 : FD_PROTOTYPES_BEGIN 143 : 144 : FD_FN_CONST ushort 145 : fd_txncache_max_txnpages_per_blockhash( ulong max_active_slots, 146 : ulong max_txn_per_slot ); 147 : 148 : FD_FN_CONST ushort 149 : fd_txncache_max_txnpages( ulong max_active_slots, 150 : ulong max_txn_per_slot ); 151 : 152 : FD_PROTOTYPES_END 153 : 154 : #endif /* HEADER_fd_src_flamenco_runtime_fd_txncache_private_h */