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