Line data Source code
1 : #include "fd_store.h"
2 :
3 75 : #define BLOCKING 1
4 :
5 : static inline fd_store_map_t *
6 300 : map_laddr( fd_store_t * store ) {
7 300 : return fd_wksp_laddr_fast( fd_store_wksp( store ), store->map_gaddr );
8 300 : }
9 :
10 : static inline fd_store_pool_t
11 480 : pool_ljoin( fd_store_t const * store ) {
12 480 : return (fd_store_pool_t){
13 480 : .pool = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_mem_gaddr ),
14 480 : .ele = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_ele_gaddr ),
15 480 : .ele_max = store->fec_max };
16 480 : }
17 :
18 : static inline fd_store_fec_t *
19 294 : pool_laddr( fd_store_t * store ) {
20 294 : fd_store_pool_t pool = pool_ljoin( store );
21 294 : return pool.ele;
22 294 : }
23 :
24 : void *
25 12 : fd_store_new( void * shmem, ulong fec_max, ulong part_cnt ) {
26 :
27 12 : 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 12 : if( FD_UNLIKELY( !shmem ) ) {
33 0 : FD_LOG_WARNING(( "NULL mem" ));
34 0 : return NULL;
35 0 : }
36 :
37 12 : 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 12 : ulong footprint = fd_store_footprint( fec_max );
43 12 : if( FD_UNLIKELY( !footprint ) ) {
44 0 : FD_LOG_WARNING(( "bad fec_max (%lu)", fec_max ));
45 0 : return NULL;
46 0 : }
47 :
48 12 : fd_wksp_t * wksp = fd_wksp_containing( shmem );
49 12 : 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 12 : ulong part_slot_cnt = fec_max / part_cnt;
62 12 : ulong seed = part_slot_cnt;
63 :
64 12 : FD_SCRATCH_ALLOC_INIT( l, shmem );
65 12 : fd_store_t * store = FD_SCRATCH_ALLOC_APPEND( l, fd_store_align(), sizeof(fd_store_t) );
66 12 : void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_store_map_align(), fd_store_map_footprint ( fec_max ) );
67 12 : void * shpool = FD_SCRATCH_ALLOC_APPEND( l, fd_store_pool_align(), fd_store_pool_footprint() );
68 12 : void * shele = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_store_fec_t), sizeof(fd_store_fec_t)*fec_max );
69 12 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_store_align() )==(ulong)shmem + footprint );
70 :
71 12 : fd_memset( store, 0, sizeof(fd_store_t) );
72 12 : store->store_gaddr = fd_wksp_gaddr_fast( wksp, store );
73 12 : store->pool_mem_gaddr = fd_wksp_gaddr_fast( wksp, shpool );
74 12 : store->pool_ele_gaddr = fd_wksp_gaddr_fast( wksp, shele );
75 12 : store->map_gaddr = fd_wksp_gaddr_fast( wksp, fd_store_map_join( fd_store_map_new ( map, fec_max, seed ) ) );
76 :
77 12 : store->part_cnt = part_cnt;
78 12 : store->fec_max = fec_max;
79 :
80 12 : fd_store_pool_t pool = pool_ljoin( store );
81 12 : 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 12 : fd_store_pool_reset( &pool, 0 );
86 :
87 12 : FD_COMPILER_MFENCE();
88 12 : FD_VOLATILE( store->magic ) = FD_STORE_MAGIC;
89 12 : FD_COMPILER_MFENCE();
90 :
91 12 : return shmem;
92 12 : }
93 :
94 : fd_store_t *
95 12 : fd_store_join( void * shstore ) {
96 :
97 12 : if( FD_UNLIKELY( !shstore ) ) {
98 0 : FD_LOG_WARNING(( "NULL store" ));
99 0 : return NULL;
100 0 : }
101 :
102 12 : 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 12 : fd_wksp_t * wksp = fd_wksp_containing( shstore );
108 12 : if( FD_UNLIKELY( !wksp ) ) {
109 0 : FD_LOG_WARNING(( "store must be part of a workspace" ));
110 0 : return NULL;
111 0 : }
112 :
113 12 : fd_store_t * store = (fd_store_t *)shstore;
114 12 : if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
115 0 : FD_LOG_WARNING(( "bad magic" ));
116 0 : return NULL;
117 0 : }
118 :
119 12 : return store;
120 12 : }
121 :
122 : void *
123 6 : fd_store_leave( fd_store_t const * store ) {
124 :
125 6 : if( FD_UNLIKELY( !store ) ) {
126 0 : FD_LOG_WARNING(( "NULL store" ));
127 0 : return NULL;
128 0 : }
129 :
130 6 : return (void *)store;
131 6 : }
132 :
133 : void *
134 6 : fd_store_delete( void * shstore ) {
135 :
136 6 : if( FD_UNLIKELY( !shstore ) ) {
137 0 : FD_LOG_WARNING(( "NULL store" ));
138 0 : return NULL;
139 0 : }
140 :
141 6 : 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 6 : fd_store_t * store = (fd_store_t *)shstore;
147 6 : if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
148 0 : FD_LOG_WARNING(( "bad magic" ));
149 0 : return NULL;
150 0 : }
151 :
152 6 : FD_COMPILER_MFENCE();
153 6 : FD_VOLATILE( store->magic ) = 0UL;
154 6 : FD_COMPILER_MFENCE();
155 :
156 6 : return shstore;
157 6 : }
158 :
159 : fd_store_fec_t *
160 : fd_store_query( fd_store_t * store,
161 78 : fd_hash_t const * merkle_root ) {
162 :
163 78 : fd_store_pool_t pool = pool_ljoin( store );
164 78 : ulong null = fd_store_pool_idx_null();
165 84 : for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
166 81 : fd_store_key_t key = { *merkle_root, part_idx };
167 81 : ulong idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
168 81 : fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
169 81 : if( FD_LIKELY( fec ) ) return fec;
170 81 : }
171 3 : return NULL;
172 78 : }
173 :
174 : fd_store_fec_t *
175 : fd_store_insert( fd_store_t * store,
176 : ulong part_idx,
177 78 : fd_hash_t * merkle_root ) {
178 :
179 78 : fd_store_pool_t pool = pool_ljoin( store );
180 78 : ulong null = fd_store_pool_idx_null();
181 :
182 201 : for( ulong part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
183 129 : fd_store_key_t key = { *merkle_root, part_idx };
184 129 : ulong idx = null;
185 :
186 129 : FD_STORE_SLOCK_BEGIN( store ) {
187 129 : idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
188 129 : } FD_STORE_SLOCK_END;
189 :
190 129 : fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
191 129 : if( FD_UNLIKELY( fec ) ) return fec;
192 129 : }
193 :
194 72 : int err; fd_store_fec_t * fec = fd_store_pool_acquire( &pool, NULL, BLOCKING, &err );
195 72 : if( FD_UNLIKELY( err!=FD_POOL_SUCCESS ) ) FD_LOG_CRIT(( "store pool: %s", fd_store_pool_strerror( err ) ));
196 72 : fec->key.merkle_root = *merkle_root;
197 72 : fec->key.part_idx = part_idx;
198 72 : fec->cmr = (fd_hash_t){ 0 };
199 72 : fec->next = null;
200 72 : fec->data_sz = 0UL;
201 :
202 72 : FD_STORE_SLOCK_BEGIN( store ) {
203 72 : fd_store_map_ele_insert( map_laddr( store ), fec, pool_laddr( store ) );
204 72 : } FD_STORE_SLOCK_END;
205 :
206 72 : return fec;
207 72 : }
208 :
209 : void
210 : fd_store_remove( fd_store_t * store,
211 6 : fd_hash_t const * merkle_root ) {
212 :
213 6 : fd_store_pool_t pool = pool_ljoin( store );
214 9 : for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
215 6 : fd_store_key_t key = { *merkle_root, part_idx };
216 6 : fd_store_fec_t * fec = NULL;
217 :
218 6 : FD_STORE_XLOCK_BEGIN( store ) {
219 6 : fec = fd_store_map_ele_remove( map_laddr( store ), &key, NULL, pool_laddr( store ) );
220 6 : } FD_STORE_XLOCK_END;
221 6 : if( FD_UNLIKELY( !fec ) ) continue;
222 :
223 3 : int err = fd_store_pool_release( &pool, fec, BLOCKING );
224 3 : if( FD_UNLIKELY( err!=FD_POOL_SUCCESS ) ) FD_LOG_CRIT(( "store pool: %s", fd_store_pool_strerror( err ) ));
225 3 : return;
226 3 : }
227 :
228 3 : FD_BASE58_ENCODE_32_BYTES( merkle_root->uc, _merkle_root );
229 3 : FD_LOG_WARNING(( "key not found %s", _merkle_root ));
230 3 : }
231 :
232 : int
233 3 : fd_store_verify( fd_store_t * store ) {
234 :
235 3 : fd_store_map_t * map = map_laddr( store );
236 3 : fd_store_fec_t * fec0 = pool_laddr( store );
237 :
238 3 : ulong part_sz = store->fec_max / store->part_cnt;
239 3 : 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 3 : for( fd_store_map_iter_t iter = fd_store_map_iter_init( map, fec0 );
247 3 : !fd_store_map_iter_done( iter, map, fec0 );
248 3 : 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 3 : fd_store_pool_t pool = pool_ljoin( store );
263 3 : if( FD_UNLIKELY( fd_store_pool_verify( &pool )==-1 ) ) return -1;
264 3 : return fd_store_map_verify( map, store->fec_max, fec0 );
265 3 : }
|