Line data Source code
1 : #include "fd_inflight.h"
2 :
3 : void *
4 : fd_inflights_new( void * shmem,
5 0 : ulong seed ) {
6 0 : if( FD_UNLIKELY( !shmem ) ) {
7 0 : FD_LOG_WARNING(( "NULL mem" ));
8 0 : return NULL;
9 0 : }
10 :
11 0 : ulong footprint = fd_inflights_footprint();
12 0 : ulong chain_cnt = fd_inflight_map_chain_cnt_est( FD_INFLIGHT_REQ_MAX );
13 :
14 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
15 0 : fd_inflights_t * table = FD_SCRATCH_ALLOC_APPEND( l, fd_inflights_align(), sizeof(fd_inflights_t) );
16 0 : void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_inflight_pool_align(), fd_inflight_pool_footprint( FD_INFLIGHT_REQ_MAX ) );
17 0 : void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_inflight_map_align(), fd_inflight_map_footprint ( chain_cnt ) );
18 0 : void * pmap = FD_SCRATCH_ALLOC_APPEND( l, fd_inflight_map_align(), fd_inflight_map_footprint ( chain_cnt ) );
19 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_inflights_align() ) == (ulong)shmem + footprint );
20 :
21 0 : table->pool = fd_inflight_pool_join ( fd_inflight_pool_new ( pool, FD_INFLIGHT_REQ_MAX ) );
22 0 : table->map = fd_inflight_map_join ( fd_inflight_map_new ( map, chain_cnt, seed ) );
23 0 : table->popped_map = fd_inflight_map_join ( fd_inflight_map_new ( pmap, chain_cnt, seed ) );
24 0 : table->popped_cnt = 0UL;
25 0 : FD_TEST( table->outstanding_dl==fd_inflight_dlist_join( fd_inflight_dlist_new( table->outstanding_dl ) ) );
26 0 : FD_TEST( table->popped_dl ==fd_inflight_dlist_join( fd_inflight_dlist_new( table->popped_dl ) ) );
27 :
28 0 : FD_TEST( table->pool );
29 0 : FD_TEST( table->map );
30 0 : FD_TEST( table->popped_map );
31 :
32 0 : return shmem;
33 0 : }
34 :
35 : fd_inflights_t *
36 0 : fd_inflights_join( void * shmem ) {
37 0 : fd_inflights_t * table = (fd_inflights_t *)shmem;
38 :
39 0 : if( FD_UNLIKELY( !table ) ) {
40 0 : FD_LOG_WARNING(( "NULL inflight table" ));
41 0 : return NULL;
42 0 : }
43 :
44 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)table, fd_inflights_align() ) ) ) {
45 0 : FD_LOG_WARNING(( "misaligned inflight table" ));
46 0 : return NULL;
47 0 : }
48 :
49 0 : return (fd_inflights_t *)shmem;
50 0 : }
51 :
52 : void
53 : fd_inflights_request_insert( fd_inflights_t * table,
54 : ulong nonce,
55 : fd_pubkey_t const * pubkey,
56 : ulong slot,
57 0 : ulong shred_idx ) {
58 0 : if( FD_UNLIKELY( !fd_inflight_pool_free( table->pool ) ) ) {
59 0 : if( FD_LIKELY( !fd_inflight_dlist_is_empty( table->popped_dl, table->pool ) ) ) {
60 0 : fd_inflight_t * evict = fd_inflight_dlist_ele_pop_head( table->popped_dl, table->pool );
61 0 : table->popped_cnt--;
62 0 : fd_inflight_map_ele_remove_fast( table->popped_map, evict, table->pool );
63 0 : fd_inflight_pool_ele_release ( table->pool, evict );
64 0 : } else {
65 : /* (pool free cnt) + (popped_dl cnt) + (outstanding_dl cnt) ==
66 : INFLIGHT_REQ_MAX, so they can't all be 0. */
67 0 : fd_inflight_t * evict = fd_inflight_dlist_ele_pop_head( table->outstanding_dl, table->pool );
68 0 : FD_LOG_WARNING(( "Evicting outstanding request for slot %lu, shred_idx %lu, nonce %lu", evict->key.slot, evict->key.shred_idx, evict->key.nonce ));
69 : /* The above should be impossible. We could LOG_CRIT, but it's
70 : possible we could still make progress if this request comes
71 : back to us. */
72 0 : fd_inflight_map_ele_remove_fast( table->map, evict, table->pool );
73 0 : fd_inflight_pool_ele_release ( table->pool, evict );
74 0 : }
75 0 : }
76 :
77 0 : fd_inflight_t * inflight_req = fd_inflight_pool_ele_acquire( table->pool );
78 0 : inflight_req->key.nonce = nonce;
79 0 : inflight_req->key.slot = slot;
80 0 : inflight_req->key.shred_idx = shred_idx;
81 0 : inflight_req->timestamp_ns = fd_log_wallclock();
82 0 : inflight_req->pubkey = *pubkey;
83 :
84 0 : fd_inflight_map_ele_insert ( table->map, inflight_req, table->pool );
85 0 : fd_inflight_dlist_ele_push_tail( table->outstanding_dl, inflight_req, table->pool );
86 0 : }
87 :
88 : long
89 : fd_inflights_request_remove( fd_inflights_t * table,
90 : ulong nonce,
91 : ulong slot,
92 : ulong shred_idx,
93 0 : fd_pubkey_t * peer_out ) {
94 0 : fd_inflight_key_t query[1] = {{ .slot = slot, .shred_idx = shred_idx, .nonce = nonce }};
95 : /* In the unlikely case that there are multiple requests (outstanding
96 : or popped) with the same (slot, shred_idx, nonce) tuple, we'll
97 : remove them all and credit the response to the oldest one. */
98 0 : long now = fd_log_wallclock();
99 0 : long req_ts = now;
100 :
101 0 : int query_idx = 0;
102 0 : while( query_idx<2 ) {
103 : /* Look in the outstanding map first */
104 0 : fd_inflight_map_t * query_map = fd_ptr_if( !query_idx, table->map, table->popped_map );
105 0 : fd_inflight_dlist_t * query_list = fd_ptr_if( !query_idx, (fd_inflight_dlist_t *)table->outstanding_dl, table->popped_dl );
106 :
107 0 : fd_inflight_t * inflight_req = fd_inflight_map_ele_remove( query_map, query, NULL, table->pool );
108 0 : if( FD_LIKELY( inflight_req ) ) {
109 :
110 : /* Take oldest one (probably only one, but req_ts initialized to
111 : now, so all are older than it. */
112 0 : if( FD_LIKELY( inflight_req->timestamp_ns<req_ts ) ) {
113 0 : req_ts = inflight_req->timestamp_ns;
114 0 : *peer_out = inflight_req->pubkey;
115 0 : }
116 :
117 : /* Remove the element from the inflight table */
118 0 : fd_inflight_dlist_ele_remove( query_list, inflight_req, table->pool );
119 0 : fd_inflight_pool_ele_release( table->pool, inflight_req );
120 0 : if( FD_UNLIKELY( query_idx == 1 ) ) table->popped_cnt--;
121 0 : } else {
122 0 : query_idx++;
123 0 : }
124 0 : }
125 0 : return now-req_ts; /* 0 if nothing found */
126 0 : }
127 :
128 : void
129 : fd_inflights_request_pop( fd_inflights_t * table,
130 : ulong * nonce_out,
131 : ulong * slot_out,
132 0 : ulong * shred_idx_out ) {
133 0 : fd_inflight_t * inflight_req = fd_inflight_dlist_ele_pop_head( table->outstanding_dl, table->pool );
134 0 : fd_inflight_map_ele_remove_fast( table->map, inflight_req, table->pool );
135 0 : *nonce_out = inflight_req->key.nonce;
136 0 : *slot_out = inflight_req->key.slot;
137 0 : *shred_idx_out = inflight_req->key.shred_idx;
138 0 : fd_inflight_map_ele_insert ( table->popped_map, inflight_req, table->pool );
139 0 : fd_inflight_dlist_ele_push_tail( table->popped_dl, inflight_req, table->pool );
140 0 : table->popped_cnt++;
141 0 : }
142 :
143 :
144 : #include <stdio.h>
145 :
146 : void
147 0 : fd_inflights_print( fd_inflight_dlist_t * dlist, fd_inflight_t * pool ) {
148 :
149 0 : printf("%-15s %-8s %-15s %-44s\n", "Slot", "Idx", "Timestamp", "Peer");
150 0 : printf("%-15s %-8s %-15s %-44s\n",
151 0 : "---------------", "--------", "------------",
152 0 : "--------------------------------------------");
153 0 : for( fd_inflight_dlist_iter_t iter = fd_inflight_dlist_iter_fwd_init( dlist, pool );
154 0 : !fd_inflight_dlist_iter_done( iter, dlist, pool );
155 0 : iter = fd_inflight_dlist_iter_fwd_next( iter, dlist, pool ) ) {
156 0 : fd_inflight_t * inflight_req = fd_inflight_dlist_iter_ele( iter, dlist, pool );
157 0 : FD_BASE58_ENCODE_32_BYTES( inflight_req->pubkey.uc, peer );
158 :
159 0 : printf("%-15lu %-8lu %-15lu %-44.44s\n",
160 0 : inflight_req->key.slot,
161 0 : inflight_req->key.shred_idx,
162 0 : (ulong)inflight_req->timestamp_ns / (ulong)1e6,
163 0 : peer);
164 0 : }
165 0 : printf("\n");
166 0 : }
|