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