Line data Source code
1 : #include "fd_store.h"
2 :
3 : static inline fd_store_map_t *
4 330 : map_laddr( fd_store_t * store ) {
5 330 : return fd_wksp_laddr_fast( fd_store_wksp( store ), store->map_gaddr );
6 330 : }
7 :
8 : static inline fd_store_pool_t
9 516 : pool_ljoin( fd_store_t const * store ) {
10 516 : return (fd_store_pool_t){
11 516 : .pool = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_mem_gaddr ),
12 516 : .ele = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_ele_gaddr ),
13 516 : .ele_max = store->fec_max };
14 516 : }
15 :
16 : static inline fd_store_fec_t *
17 324 : pool_laddr( fd_store_t * store ) {
18 324 : fd_store_pool_t pool = pool_ljoin( store );
19 324 : return pool.ele;
20 324 : }
21 :
22 : void *
23 : fd_store_new( void * shmem,
24 : ulong part_cnt,
25 : ulong fec_max,
26 18 : ulong fec_data_max ) {
27 :
28 18 : if( FD_UNLIKELY( part_cnt==0UL ) ) {
29 0 : FD_LOG_WARNING(( "part_cnt must be non-zero" ));
30 0 : return NULL;
31 0 : }
32 :
33 18 : if( FD_UNLIKELY( !shmem ) ) {
34 0 : FD_LOG_WARNING(( "NULL mem" ));
35 0 : return NULL;
36 0 : }
37 :
38 18 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_store_align() ) ) ) {
39 0 : FD_LOG_WARNING(( "misaligned mem" ));
40 0 : return NULL;
41 0 : }
42 :
43 18 : ulong footprint = fd_store_footprint( fec_max, fec_data_max );
44 :
45 18 : fd_wksp_t * wksp = fd_wksp_containing( shmem );
46 18 : if( FD_UNLIKELY( !wksp ) ) {
47 0 : FD_LOG_WARNING(( "shmem must be part of a workspace" ));
48 0 : return NULL;
49 0 : }
50 :
51 : /* The seed is derived from the number of chains in the map. The
52 : number of chains is estimated from fec_max (via chain_cnt_est) and
53 : is always a power of two. The size of each partition is chain_cnt
54 : / part_cnt. We use the per partition slot count as the seed so
55 : that the modified hash function can hash the key into the correct
56 : partition. */
57 :
58 18 : ulong chain_cnt = fd_store_map_chain_cnt_est( fec_max );
59 18 : ulong part_slot_cnt = chain_cnt / part_cnt;
60 18 : ulong seed = part_slot_cnt;
61 :
62 18 : FD_SCRATCH_ALLOC_INIT( l, shmem );
63 18 : fd_store_t * store = FD_SCRATCH_ALLOC_APPEND( l, fd_store_align(), sizeof(fd_store_t) );
64 18 : void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_store_map_align(), fd_store_map_footprint( chain_cnt ) );
65 18 : void * shpool = FD_SCRATCH_ALLOC_APPEND( l, fd_store_pool_align(), fd_store_pool_footprint() );
66 18 : void * shele = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_store_fec_t), sizeof(fd_store_fec_t)*fec_max );
67 18 : uchar * data = FD_SCRATCH_ALLOC_APPEND( l, FD_STORE_ALIGN, fec_data_max*fec_max );
68 18 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_store_align() )==(ulong)shmem + footprint );
69 :
70 18 : fd_memset( store, 0, sizeof(fd_store_t) );
71 18 : store->part_cnt = part_cnt;
72 18 : store->fec_max = fec_max;
73 18 : store->fec_data_max = fec_data_max;
74 18 : store->store_gaddr = fd_wksp_gaddr_fast( wksp, store );
75 18 : store->map_gaddr = fd_wksp_gaddr_fast( wksp, fd_store_map_join( fd_store_map_new( map, chain_cnt, seed ) ) );
76 18 : store->pool_mem_gaddr = fd_wksp_gaddr_fast( wksp, shpool );
77 18 : store->pool_ele_gaddr = fd_wksp_gaddr_fast( wksp, shele );
78 18 : store->data_gaddr = fd_wksp_gaddr_fast( wksp, data );
79 :
80 18 : if( FD_UNLIKELY( !fd_store_pool_new( shpool ) ) ) {
81 0 : FD_LOG_WARNING(( "fd_store_pool_new failed" ));
82 0 : return NULL;
83 0 : }
84 18 : fd_store_pool_t pool_ljoin;
85 18 : fd_store_pool_reset( fd_store_pool_join( &pool_ljoin, shpool, shele, fec_max ) );
86 :
87 : /* Set each element's data_gaddr to point to its slice of the
88 : contiguous data buffer region. */
89 :
90 18 : fd_store_fec_t * fec0 = (fd_store_fec_t *)shele;
91 378 : for( ulong i=0UL; i<fec_max; i++ ) {
92 360 : fec0[ i ].data_gaddr = fd_wksp_gaddr_fast( wksp, data + i*fec_data_max );
93 360 : }
94 :
95 18 : FD_COMPILER_MFENCE();
96 18 : FD_VOLATILE( store->magic ) = FD_STORE_MAGIC;
97 18 : FD_COMPILER_MFENCE();
98 :
99 18 : return shmem;
100 18 : }
101 :
102 : fd_store_t *
103 18 : fd_store_join( void * shstore ) {
104 :
105 18 : if( FD_UNLIKELY( !shstore ) ) {
106 0 : FD_LOG_WARNING(( "NULL store" ));
107 0 : return NULL;
108 0 : }
109 :
110 18 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
111 0 : FD_LOG_WARNING(( "misaligned store" ));
112 0 : return NULL;
113 0 : }
114 :
115 18 : fd_wksp_t * wksp = fd_wksp_containing( shstore );
116 18 : if( FD_UNLIKELY( !wksp ) ) {
117 0 : FD_LOG_WARNING(( "store must be part of a workspace" ));
118 0 : return NULL;
119 0 : }
120 :
121 18 : fd_store_t * store = (fd_store_t *)shstore;
122 18 : if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
123 0 : FD_LOG_WARNING(( "bad magic" ));
124 0 : return NULL;
125 0 : }
126 :
127 18 : return store;
128 18 : }
129 :
130 : void *
131 12 : fd_store_leave( fd_store_t const * store ) {
132 :
133 12 : if( FD_UNLIKELY( !store ) ) {
134 0 : FD_LOG_WARNING(( "NULL store" ));
135 0 : return NULL;
136 0 : }
137 :
138 12 : return (void *)store;
139 12 : }
140 :
141 : void *
142 12 : fd_store_delete( void * shstore ) {
143 :
144 12 : if( FD_UNLIKELY( !shstore ) ) {
145 0 : FD_LOG_WARNING(( "NULL store" ));
146 0 : return NULL;
147 0 : }
148 :
149 12 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
150 0 : FD_LOG_WARNING(( "misaligned store" ));
151 0 : return NULL;
152 0 : }
153 :
154 12 : fd_store_t * store = (fd_store_t *)shstore;
155 12 : if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
156 0 : FD_LOG_WARNING(( "bad magic" ));
157 0 : return NULL;
158 0 : }
159 :
160 12 : FD_COMPILER_MFENCE();
161 12 : FD_VOLATILE( store->magic ) = 0UL;
162 12 : FD_COMPILER_MFENCE();
163 :
164 12 : return shstore;
165 12 : }
166 :
167 : fd_store_fec_t *
168 : fd_store_query( fd_store_t * store,
169 78 : fd_hash_t const * merkle_root ) {
170 :
171 78 : fd_store_pool_t pool = pool_ljoin( store );
172 78 : ulong null = fd_store_pool_idx_null();
173 84 : for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
174 81 : fd_store_key_t key = { *merkle_root, part_idx };
175 81 : ulong idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
176 81 : fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
177 81 : if( FD_LIKELY( fec ) ) return fec;
178 81 : }
179 3 : return NULL;
180 78 : }
181 :
182 : fd_store_fec_t *
183 : fd_store_insert( fd_store_t * store,
184 : ulong part_idx,
185 90 : fd_hash_t * merkle_root ) {
186 :
187 90 : fd_store_pool_t pool = pool_ljoin( store );
188 90 : ulong null = fd_store_pool_idx_null();
189 :
190 225 : for( ulong part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
191 141 : fd_store_key_t key = { *merkle_root, part_idx };
192 141 : ulong idx = null;
193 :
194 141 : FD_STORE_SLOCK_BEGIN( store ) {
195 141 : idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
196 141 : } FD_STORE_SLOCK_END;
197 :
198 141 : fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
199 141 : if( FD_UNLIKELY( fec ) ) return fec;
200 141 : }
201 :
202 84 : fd_store_fec_t * fec = fd_store_pool_acquire( &pool );
203 84 : if( FD_UNLIKELY( !fec ) ) FD_LOG_CRIT(( "fd_store_pool_acquire failed" ));
204 84 : fec->key.merkle_root = *merkle_root;
205 84 : fec->key.part_idx = part_idx;
206 84 : fec->cmr = (fd_hash_t){ 0 };
207 84 : fec->next = null;
208 84 : fec->data_sz = 0UL;
209 :
210 84 : FD_STORE_SLOCK_BEGIN( store ) {
211 84 : fd_store_map_ele_insert( map_laddr( store ), fec, pool_laddr( store ) );
212 84 : } FD_STORE_SLOCK_END;
213 :
214 84 : return fec;
215 84 : }
216 :
217 : void
218 : fd_store_remove( fd_store_t * store,
219 6 : fd_hash_t const * merkle_root ) {
220 :
221 6 : fd_store_pool_t pool = pool_ljoin( store );
222 9 : for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
223 6 : fd_store_key_t key = { *merkle_root, part_idx };
224 6 : fd_store_fec_t * fec = NULL;
225 :
226 6 : FD_STORE_XLOCK_BEGIN( store ) {
227 6 : fec = fd_store_map_ele_remove( map_laddr( store ), &key, NULL, pool_laddr( store ) );
228 6 : } FD_STORE_XLOCK_END;
229 6 : if( FD_UNLIKELY( !fec ) ) continue;
230 :
231 3 : fd_store_pool_release( &pool, fec );
232 3 : return;
233 6 : }
234 :
235 3 : FD_BASE58_ENCODE_32_BYTES( merkle_root->uc, _merkle_root );
236 3 : FD_LOG_WARNING(( "key not found %s", _merkle_root ));
237 3 : }
238 :
239 : int
240 9 : fd_store_verify( fd_store_t * store ) {
241 :
242 9 : fd_store_map_t * map = map_laddr( store );
243 9 : fd_store_fec_t * fec0 = pool_laddr( store );
244 :
245 9 : ulong part_sz = map->chain_cnt / store->part_cnt;
246 9 : if( part_sz != map->seed ) {
247 0 : FD_LOG_WARNING(( "part_sz (%lu) != map->seed (%lu)", part_sz, map->seed ));
248 0 : return -1;
249 0 : }
250 :
251 : /* Iterate the map and check slots are partitioned correctly. */
252 :
253 9 : for( fd_store_map_iter_t iter = fd_store_map_iter_init( map, fec0 );
254 21 : !fd_store_map_iter_done( iter, map, fec0 );
255 12 : iter = fd_store_map_iter_next( iter, map, fec0 ) ) {
256 12 : fd_store_fec_t const * fec = fd_store_map_iter_ele_const( iter, map, fec0 );
257 12 : if( FD_UNLIKELY( !fec ) ) {
258 0 : FD_LOG_WARNING(( "NULL ele" ));
259 0 : return -1;
260 0 : }
261 12 : ulong chain_idx = fd_store_map_private_chain_idx( &fec->key, map->seed, map->chain_cnt );
262 12 : ulong k = fec->key.part_idx;
263 12 : ulong n = part_sz;
264 12 : if( FD_UNLIKELY( chain_idx < k * n || chain_idx >= (k + 1) * n ) ) { /* chain_idx in [k*n, (k+1)*n) */
265 0 : FD_LOG_WARNING(( "chain_idx %lu not in range [%lu, %lu)", chain_idx, k * n, (k + 1) * n ) );
266 0 : return -1;
267 0 : }
268 12 : }
269 9 : fd_store_pool_t pool = pool_ljoin( store );
270 9 : if( FD_UNLIKELY( fd_store_pool_verify( &pool )==-1 ) ) return -1;
271 9 : return fd_store_map_verify( map, store->fec_max, fec0 );
272 9 : }
|