Line data Source code
1 : #ifndef HEADER_fd_src_util_wksp_fd_wksp_h
2 : #define HEADER_fd_src_util_wksp_fd_wksp_h
3 :
4 : #include "../scratch/fd_scratch.h"
5 :
6 : /* opaque; the tpool API is in tpool/fd_tpool.h */
7 : struct fd_tpool_private;
8 : typedef struct fd_tpool_private fd_tpool_t;
9 :
10 : /* API for creating NUMA-aware and TLB-efficient workspaces used for
11 : complex inter-thread and inter-process shared memory communication
12 : patterns. fd must be booted to use the APIs in this module.
13 :
14 : For example, startup scripts could reserve some memory on each NUMA
15 : node backed by huge and gigantic pages:
16 :
17 : sudo bin/fd_shmem_cfg alloc 8 gigantic 0 \
18 : alloc 8 gigantic 1 \
19 : alloc 256 huge 0 \
20 : alloc 256 huge 1
21 :
22 : and then some of this memory could be formatted into fd_wksp for each
23 : NUMA node:
24 :
25 : bin/fd_shmem_ctl new my-wksp-numa-0 1 gigantic 0 \
26 : new my-wksp-numa-1 1 gigantic 1
27 :
28 : Then, at application startup, processes can join these fd_wksp and
29 : concurrently allocate memory from the desired NUMA nodes as
30 : necessary. E.g.
31 :
32 : fd_wksp_t * wksp = fd_wksp_attach( "my-wksp-numa-0" ); // logs details on failure
33 : if( !fd_wksp ) ... handle attach failure ...;
34 :
35 : ulong gaddr = fd_wksp_alloc( wksp, align, sz ); // logs details on failure
36 : if( !gaddr ) ... handle alloc failure ...;
37 :
38 : The local address of a workspace global address can be found via:
39 :
40 : void * laddr = fd_wksp_laddr( wksp, gaddr ); // logs details on failure
41 : if( !laddr ) ... handle bad (wksp,gaddr) ...;
42 :
43 : and the global address of a workspace local address can be found via:
44 :
45 : ulong gaddr = fd_wksp_gaddr( wksp, laddr ); // logs details on failure
46 : if( !gaddr ) ... handle bad (wksp,laddr) ...;
47 :
48 : Allocations can be freed via:
49 :
50 : fd_wksp_free( wksp, gaddr );
51 :
52 : Any join can free any allocation regardless of who made it.
53 :
54 : When the application is done using a wksp, it should leave it. The
55 : workspace will continue to exist (it just is no longer safe to access
56 : in the caller's address space). E.g.
57 :
58 : fd_wksp_detach( wksp ); // logs details on failure
59 :
60 : Likewise, if the workspaces are no longer in use, they can be deleted
61 : via something like:
62 :
63 : bin/fd_wksp_ctl delete my-wksp-numa-0 \
64 : delete my-wksp-numa-1
65 :
66 : All allocations can be freed via something like:
67 :
68 : bin/fd_wksp_ctl reset my-wksp-numa-0 \
69 : reset my-wksp-numa-1
70 :
71 : or in code:
72 :
73 : fd_wksp_reset( wksp, seed ); // logs details on failure
74 :
75 : It is the caller's responsibility to ensure that previous allocations
76 : to the wksp are not in use.
77 :
78 : Note: while this presents "aligned_alloc" style API semantics, this
79 : is not designed to be algorithmically optimal, HPC implementation or
80 : efficient at doing lots of tiny allocations. Rather it is designed
81 : to be akin to an "mmap" / "sbrk" style allocator of last resort, done
82 : rarely and then ideally at application startup (e.g. setting up
83 : datastructures at box startup or used in an interprocess lockfree
84 : allocator as a mmap replacement).
85 :
86 : Instead, this tries to keep wksp fragmentation low with low overhead
87 : and tight packing of larger size allocations (normal page size and
88 : up). It further tries to proactively limit the risk of heap
89 : _metadata_ corruption (proactive intraworkspace heap application
90 : _data_ corruption prevention is not a goal though typical mechanisms
91 : for such are in _direct_ opposition to efficient use of TLB, low
92 : fragmentation and tight allocation packing). It is quasi-lockfree
93 : such that a process _killed_ in the middle of a workspace operation
94 : will not prevent other processes from using the workspace but a
95 : process _stalled_ in the middle of a workspace operations can stall
96 : other applications waiting to use the workspace indefinitely.
97 : Operators can track down an errant process stalled in the middle of
98 : workspace operations and blocking other processes). Likewise
99 : detailed usage and metadata integrity checking and repair can be done
100 : via something like fd_wksp_ctl check / verify / rebuild / etc.
101 : Practically speaking, none of this really matters if usage occurs
102 : predominantly during application startup / shutdown.
103 :
104 : See below for more details. */
105 :
106 : /* FD_WKSP_SUCCESS is used by various APIs to indicate an operation
107 : successfully completed. This will be 0. FD_WKSP_ERR_* gives a
108 : number of error codes used by fd_wksp APIs. These will be negative
109 : integers. */
110 :
111 253902579 : #define FD_WKSP_SUCCESS (0) /* Success */
112 63 : #define FD_WKSP_ERR_INVAL (-1) /* Failed due to obviously invalid inputs */
113 78 : #define FD_WKSP_ERR_FAIL (-2) /* Failed due to shared memory limitation */
114 86050617 : #define FD_WKSP_ERR_CORRUPT (-3) /* Workspace memory corruption detected (potentially recoverable by rebuilding) */
115 :
116 : /* FD_WKSP_{ALIGN,FOOTPRINT} describe the alignment and footprint of a
117 : fd_wksp_t. ALIGN is a positive integer power of 2. FOOTPRINT is a
118 : multiple of ALIGN. FOOTPRINT assumes part_max and data_max are
119 : non-zero and small enough that the footprint will not overflow at
120 : most ULONG_MAX bytes. These are provided to facilitate compile time
121 : declarations. */
122 :
123 2133 : #define FD_WKSP_ALIGN (128UL)
124 : #define FD_WKSP_FOOTPRINT( part_max, data_max ) \
125 : FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \
126 : FD_WKSP_ALIGN, 128UL ), /* header */ \
127 : 64UL, 64UL*(part_max) ), /* partition info */ \
128 : 1UL, (data_max)+1UL ), /* data region and footer */ \
129 : FD_WKSP_ALIGN ) /* tail padding */
130 :
131 : /* FD_WKSP_ALIGN_DEFAULT gives the default alignments of a wksp
132 : allocation. This is a positive integer power of two of at least 16
133 : (for malloc compatibility). Additional details described in
134 : fd_wksp_alloc. */
135 :
136 15396207 : #define FD_WKSP_ALIGN_DEFAULT (4096UL)
137 :
138 : /* FD_WKSP_CSTR_MAX is the number of bytes maximum that can be in a wksp
139 : global address cstr. */
140 :
141 : #define FD_WKSP_CSTR_MAX (FD_SHMEM_NAME_MAX + 21UL)
142 :
143 : /* FD_WKSP_CHECKPT_STYLE_* specifies the streaming format to use for
144 : a workspace checkpoint. These are non-zero.
145 :
146 : V1 - the stream will have extensive workspace metadata followed by
147 : the used workspace partitions. No compression or hashing is
148 : done of the workspace partitions.
149 :
150 : V2 - similar to V1 in functionality but will be written such that
151 : checkpt and restore are parallelizable.
152 :
153 : V3 - This is actually V2 but compressed frames will be enabled.
154 :
155 : DEFAULT - the style to use when not specified by user. 0 indicates
156 : to use V3 if the target supports it and V2 if not. */
157 :
158 63 : #define FD_WKSP_CHECKPT_STYLE_V1 (1)
159 189 : #define FD_WKSP_CHECKPT_STYLE_V2 (2)
160 0 : #define FD_WKSP_CHECKPT_STYLE_V3 (3)
161 :
162 : #define FD_WKSP_CHECKPT_STYLE_DEFAULT (0)
163 :
164 : #define FD_WKSP_CHECKPT_STYLE_RAW FD_WKSP_CHECKPT_STYLE_V1 /* backward compat */
165 :
166 : /* A fd_wksp_t * is an opaque handle of a workspace */
167 :
168 : struct fd_wksp_private;
169 : typedef struct fd_wksp_private fd_wksp_t;
170 :
171 : /* A fd_wksp_usage_t is used to return workspace usage stats. */
172 :
173 : struct fd_wksp_usage {
174 : ulong total_max;
175 : ulong total_cnt; ulong total_sz;
176 : ulong free_cnt; ulong free_sz;
177 : ulong used_cnt; ulong used_sz;
178 : };
179 :
180 : typedef struct fd_wksp_usage fd_wksp_usage_t;
181 :
182 : FD_PROTOTYPES_BEGIN
183 :
184 : /* Admin APIs *********************************************************/
185 :
186 : /* It is rare to need to use the admin APIs directly (especially on a
187 : hosted system). Recommend using the helper APIs below for most
188 : needs. */
189 :
190 : /* Constructors */
191 :
192 : /* fd_wksp_part_max_est computes an estimated maximum number of
193 : partitions for a workspace that needs to fit within footprint bytes
194 : and has sz_typical allocations typically. Returns a positive value
195 : on success and 0 on failure. Reasons for failure include footprint
196 : too small, sz_typical is 0 and sz_typical is so large that footprint
197 : has no room for metadata anyway. Useful for determining how to pack
198 : a workspace tightly into a known footprint region. */
199 :
200 : FD_FN_CONST ulong
201 : fd_wksp_part_max_est( ulong footprint,
202 : ulong sz_typical );
203 :
204 : /* fd_wksp_data_max_est computes an estimated maximum data region size
205 : for footprint sized workspace with part_max partitions. Returns a
206 : positive value on success and 0 on failure. Reasons for failure
207 : include footprint is too small, part_max is 0, part_max is too large
208 : for under the hood implementation limitations or part_max is too
209 : large to have a non-zero sized data region. Useful for determining
210 : how to pack a workspace into a known footprint region. */
211 :
212 : FD_FN_CONST ulong
213 : fd_wksp_data_max_est( ulong footprint,
214 : ulong part_max );
215 :
216 : /* fd_wksp_{align,footprint} give the required alignment and footprint
217 : for a workspace that can support up to part_max partitions and with a
218 : data region of data_max bytes. fd_wksp_align returns FD_WKSP_ALIGN.
219 : fd_wksp_footprint(part_max,data_max) returns
220 : FD_WKSP_FOOTPRINT(part_max,data_max) on success and 0 on failure.
221 : Reasons for failure include zero part_max, part_max too large for
222 : this implementation, zero data_max, part_max/data_max requires a
223 : footprint that overflows a ULONG_MAX. */
224 :
225 : FD_FN_CONST ulong
226 : fd_wksp_align( void );
227 :
228 : FD_FN_CONST ulong
229 : fd_wksp_footprint( ulong part_max,
230 : ulong data_max );
231 :
232 : /* fd_wksp_new formats an unused memory region with the appropriate
233 : footprint and alignment mapped into the caller's address space at
234 : shmem into a wksp with given name (should be a valid fd_shmem name
235 : and will match the underlying shared memory region name / anonymous
236 : join for a wksp created via the shmem helpers below). seed is the
237 : arbitrary value used to seed the heap priorities under the hood.
238 : Returns NULL on failure (logs details) or shmem on success. The
239 : caller is _not_ joined on return. */
240 :
241 : void *
242 : fd_wksp_new( void * shmem,
243 : char const * name,
244 : uint seed,
245 : ulong part_max,
246 : ulong data_max );
247 :
248 : /* fd_wksp_join joins a workspace. shwksp is the location of the where
249 : the wksp has been mapped into the caller's address space. Returns
250 : the local handle of the join on success or NULL on failure (logs
251 : details). The caller can read / write memory in the joined workspace
252 : on return (a caller can do a read only join by mapping the shwksp
253 : into the local address as read only). There is no practical
254 : limitation on the number of concurrent joins in a thread, process or
255 : system wide.*/
256 :
257 : fd_wksp_t *
258 : fd_wksp_join( void * shwksp );
259 :
260 : /* fd_wksp_leave leaves a workspace. Returns shwksp on success and NULL
261 : on failure (logs details). The caller should not continue to read or
262 : write any memory for the join on return but the workspace will
263 : continue to exist. */
264 :
265 : void *
266 : fd_wksp_leave( fd_wksp_t * wksp );
267 :
268 : /* fd_wksp_delete unformats a memory region used as a workspace.
269 : Returns the shmem on pointer on success and NULL on failure (logs
270 : details). There should not be anybody joined to the workspace when
271 : it is deleted. */
272 :
273 : void *
274 : fd_wksp_delete( void * shwksp );
275 :
276 : /* Accessors */
277 :
278 : /* fd_wksp_name a cstr pointer to the wksp name (will point to a valid
279 : region name, e.g. strlen( name ) in [1,FD_SHMEM_NAME_MAX)). Assumes
280 : wksp is a valid current join. Lifetime of the returned string is the
281 : lifetime of the join. The pointer value is const and the string
282 : pointed at is const for the lifetime of join.
283 :
284 : fd_wksp_seed returns the seed used at creation / most recent rebuild.
285 : Assumes wksp is a current local join.
286 :
287 : fd_wksp_{part_max,data_max} returns {part_max,data_max} used at
288 : creation. Assumes wksp is a current local join.
289 :
290 : [fd_wksp_gaddr_lo,fd_wksp_gaddr_hi) is the range of valid wksp gaddr.
291 : lo is guaranteed to be non-zero. hi = lo + data_max. */
292 :
293 : FD_FN_CONST char const * fd_wksp_name ( fd_wksp_t const * wksp );
294 : FD_FN_PURE uint fd_wksp_seed ( fd_wksp_t const * wksp );
295 : FD_FN_PURE ulong fd_wksp_part_max( fd_wksp_t const * wksp );
296 : FD_FN_PURE ulong fd_wksp_data_max( fd_wksp_t const * wksp );
297 : FD_FN_PURE ulong fd_wksp_gaddr_lo( fd_wksp_t const * wksp );
298 : FD_FN_PURE ulong fd_wksp_gaddr_hi( fd_wksp_t const * wksp );
299 :
300 : /* fd_wksp_owner returns the id of the thread group that was currently
301 : in a wksp operation (0 indicates the wksp was in the process of being
302 : constructed) or ULONG_MAX if there was no operation in progress on
303 : the workspace. Assumes wksp is a current local join. The value will
304 : correspond to some point of time between when the call was made and
305 : the call returned. */
306 :
307 : ulong fd_wksp_owner( fd_wksp_t const * wksp );
308 :
309 : /* Misc */
310 :
311 : /* fd_wksp_strerror converts an FD_WKSP_SUCCESS / FD_WKSP_ERR_* code
312 : into a human readable cstr. The lifetime of the returned pointer is
313 : infinite. The returned pointer is always to a non-NULL cstr. */
314 :
315 : FD_FN_CONST char const *
316 : fd_wksp_strerror( int err );
317 :
318 : /* fd_wksp_verify does extensive verification of wksp. Returns
319 : FD_WKSP_SUCCESS (0) if there are no issues detected with the wksp or
320 : FD_WKSP_ERR_CORRUPT (negative) otherwise (logs details). wksp is a
321 : current local join to a workspace. This is used internally for
322 : verifying the integrity of a workspace if a caller detects in an
323 : operation that another caller died in the middle of a wksp operation.
324 : Users typically do not need to call this but it can be useful in
325 : debugging and testing.
326 :
327 : IMPORTANT SAFETY TIP! This assumes there are no concurrent
328 : operations on wksp. */
329 :
330 : int
331 : fd_wksp_verify( fd_wksp_t * wksp );
332 :
333 : /* fd_wksp_rebuilds a wksp. This is used internally for rebuilding
334 : workspace when a caller detects that another caller died in the
335 : middle of an alloc or free and left the workspace in an inconsistent
336 : state. Returns FD_WKSP_SUCCESS (0) if wksp was rebuilt successfully
337 : or a FD_WKSP_ERR_CORRUPT (negative) if it could not (logs details).
338 :
339 : Rebuilding operates under the principle of "do no harm".
340 : Specifically, rebuilding does not impact any completed wksp
341 : allocations (even when it fails). It can either complete or rollback
342 : any partially complete alloc / free depends on far along the partial
343 : operation was.
344 :
345 : Rebuilding should be always possible outside of actual memory
346 : corruption or code bug. The main reason for failure is overlapping
347 : allocations were discovered during the rebuild (which would either be
348 : caused by memory corruption or a bug).
349 :
350 : Users typically do not need to call this but it can be useful as a
351 : weak form of ASLR by changing up the seed. This is not a fast
352 : operation.
353 :
354 : IMPORTANT SAFETY TIP! This assumes there are no concurrent
355 : operations on wksp. */
356 :
357 : int
358 : fd_wksp_rebuild( fd_wksp_t * wksp,
359 : uint seed );
360 :
361 : /* User APIs **********************************************************/
362 :
363 : /* fd_wksp_laddr map a wksp global address (an address all joiners
364 : agree upon) to the caller's local address space. Invalid global
365 : addresses and/or 0UL will map to NULL (logs details if invalid).
366 : Assumes wksp is a current local join (NULL returns NULL). */
367 :
368 : void *
369 : fd_wksp_laddr( fd_wksp_t const * wksp,
370 : ulong gaddr );
371 :
372 : /* fd_wksp_gaddr maps a wksp local address to the corresponding wksp
373 : global address (an address all joiners agree upon). Invalid local
374 : addresses and/or NULL will map to 0UL (logs details if invalid).
375 : Assumes wksp is a current local join (NULL returns NULL). */
376 :
377 : ulong
378 : fd_wksp_gaddr( fd_wksp_t const * wksp,
379 : void const * laddr );
380 :
381 : /* fd_wksp_gaddr_fast converts a laddr into a gaddr under the assumption
382 : wksp is a current local join and laddr is non-NULL local address in
383 : the wksp. */
384 :
385 : FD_FN_CONST static inline ulong
386 : fd_wksp_gaddr_fast( fd_wksp_t const * wksp,
387 259570 : void const * laddr ) {
388 259570 : return (ulong)laddr - (ulong)wksp;
389 259570 : }
390 :
391 : /* fd_wksp_laddr_fast converts a gaddr into a laddr under the assumption
392 : wksp is a current local join and gaddr is non-NULL. */
393 :
394 : FD_FN_CONST static inline void *
395 : fd_wksp_laddr_fast( fd_wksp_t const * wksp,
396 74406230 : ulong gaddr ) {
397 74406230 : return (void *)((ulong)wksp + gaddr);
398 74406230 : }
399 :
400 : /* fd_wksp_alloc_at_least allocates at least sz bytes from wksp with
401 : an alignment of at least align (align must be a non-negative integer
402 : power-of-two or 0, which indicates to use the default alignment
403 : FD_WKSP_ALIGN_DEFAULT). The allocation will be tagged with a
404 : positive value tag. Returns the fd_wksp global address of the join
405 : on success and "NULL" (0UL) on failure (logs details). A zero sz
406 : returns "NULL" (silent). On return, [*lo,*hi) will contain the
407 : actually gaddr range allocated. On success, [*lo,*hi) will overlap
408 : completely [ret,ret+sz) and ret will be aligned to requested
409 : alignment. Assumes lo and hi are non-NULL.
410 :
411 : fd_wksp_alloc is a simple wrapper around fd_wksp_alloc_at_least for
412 : use when applications do not care about details of the actual
413 : allocated region.
414 :
415 : Note that fd_wksp_alloc / fd_wksp_free are not HPC implementations.
416 : Instead, these are designed to be akin to a mmap / sbrk allocator of
417 : "last resort" under the hood in other allocators like fd_alloc. As
418 : such it prioritizes packing efficiency (best fit with arbitrary sizes
419 : and alignments allowed) over algorithmic efficiency (e.g.
420 : O(lg wksp_alloc_cnt) instead of O(1) like fd_alloc) and prioritize
421 : robustness against heap corruption (e.g. overrunning an allocation
422 : might corrupt the data in other allocations but will not corrupt the
423 : heap structure ... as the goal of this data structure is to encourage
424 : minimization of TLB usage, there is very little that can be done to
425 : proactively prevent intraworkspace interallocation data corruption).
426 :
427 : These operations are "quasi-lock-free". Specifically, while they can
428 : suffer priority inversion due to a slow thread stalling other threads
429 : from using these operations, a process that is terminated in the
430 : middle of these operations leaves the wksp in a recoverable state.
431 : The only risk is the same risk generally from any application that
432 : uses persistent resources: applications that are terminated abruptly
433 : might leave allocations in the wksp that would have been freed had
434 : the application terminated normally. As the allocator has no way to
435 : tell the difference between such allocations and allocations that are
436 : intended to outlive the application, it is the caller's
437 : responsibility to clean up such (allocation tagging can help greatly
438 : simplify this for users). It would be possible to widen this API for
439 : applications to explicitly signal this intent and automatically clean
440 : up allocations not meant to outlive their creator but the general use
441 : here is expected to be long lived allocations.
442 :
443 : Priority inversion is not expected to be an issue practically as the
444 : expected use case is at app startup (some non-latency critical
445 : processes will do a handful of wksp operations to setup workspaces
446 : for applications on that box going forward and then the allocations
447 : will not be used again until the wksp is tore down / reset / etc).
448 : The remaining cases (e.g. a fine grained allocator like fd_alloc
449 : needs to procure more memory from the workspace) are expected to be
450 : rare enough that the O(lg N) costs still will be more than adequate.
451 : Note further that fd_alloc allows very fast interprocess allocations
452 : to be done by using a wksp as an allocator of last resort (in such,
453 : all allocations would be strictly lock free unless they needed to
454 : invoke this allocator, as is typically the case in other lock free
455 : allocators).
456 :
457 : Likewise, operations do extensive allocation metadata integrity
458 : checks to facilitate robust persistent usage. If there is metadata
459 : data corruption detected (e.g. hardware fault, code corruption, etc),
460 : there are fsck-like APIs to rebuild wksp metadata. Data integrity
461 : protection is more defined by the application.
462 :
463 : Tags are application specific. They can allow manual and automated
464 : processes to do various debugging, diagnostics, analytics and garbage
465 : collection on a workspace (e.g. superblocks from a fd_alloc can be
466 : tagged specifically for that fd_alloc to allow memory leaks in
467 : general to be detected at program termination with no additional
468 : overheads and allow such leaks cleaned up via tagged frees).
469 : Notably, tags are wide enough to encode gaddrs. This opens up the
470 : possibly for filesystem-like complex metadata operations.
471 :
472 : IMPORTANT! align technically refers to the alignment in the wksp's
473 : global address space. As such, wksp must be mmaped into each local
474 : address space with an alignment of at least the largest alignment the
475 : overall application intends to use. Common practices automatically
476 : satisfy this (e.g. if wksp is backed by normal/huge/gigantic pages
477 : and only asks for alignments of at most a normal/huge/gigantic page
478 : sz, this constraint is automatically satisfied as fd_shmem_join needs
479 : to mmap wksp into the local address space with normal/huge/gigantic
480 : alignment anyway). If doing more exotic things (e.g. backing wksp by
481 : normal pages but requiring much larger alignments), explicitly
482 : specifying the wksp virtual address location (e.g. in the
483 : fd_shmem_join call) might be necessary to satisfy this constraint.
484 :
485 : This implementation support arbitrary sz and align efficiently but
486 : each allocation will use up 1-3 wksp partitions to achieve this. As
487 : these are a finite resources (and typically sized for a wksp that
488 : handles primarily larger allocations, like a fd_alloc huge
489 : superblock) and as there are allocators like fd_alloc that faster are
490 : algorithmically, lower overhead and lockfree O(1) for small sizes and
491 : alignment, it is strongly recommended to use this as an allocator of
492 : last resort and/or use this for larger chunkier allocations at
493 : application startup (e.g. sz + align >>> cache line). An allocator
494 : like fd_alloc can then manage most allocations, falling back on this
495 : only when necessary. */
496 :
497 : ulong
498 : fd_wksp_alloc_at_least( fd_wksp_t * wksp,
499 : ulong align,
500 : ulong sz,
501 : ulong tag,
502 : ulong * lo,
503 : ulong * hi );
504 :
505 : static inline ulong
506 : fd_wksp_alloc( fd_wksp_t * wksp,
507 : ulong align,
508 : ulong sz,
509 5496 : ulong tag ) {
510 5496 : ulong dummy[2];
511 5496 : return fd_wksp_alloc_at_least( wksp, align, sz, tag, dummy, dummy+1 );
512 5496 : }
513 :
514 : /* fd_wksp_free frees a wksp allocation. gaddr is a global address that
515 : points to any byte in the allocation to free (i.e. can point to
516 : anything in of the gaddr range [*lo,*hi) returned by
517 : fd_wksp_alloc_at_least). Logs details of any weirdness detected.
518 : Free of "NULL" (0UL) silently returns. There are no restrictions on
519 : which join might free an allocation. See note above other details. */
520 :
521 : void
522 : fd_wksp_free( fd_wksp_t * wksp,
523 : ulong gaddr );
524 :
525 : /* fd_wksp_tag returns the tag associated with an allocation. gaddr
526 : is a wksp global address that points to any byte in the allocation.
527 : This is a fast O(lg wksp_alloc_cnt). A return of 0 indicates that
528 : gaddr did not point into an allocation at some point in time between
529 : when this function was called until when it returned (this includes
530 : the cases when wksp is NULL and/or gaddr is 0). This function is
531 : silent to facilitate integration with various analysis tools. */
532 :
533 : ulong
534 : fd_wksp_tag( fd_wksp_t * wksp,
535 : ulong gaddr );
536 :
537 : /* fd_wksp_tag_query queries the workspace for all partitions that match
538 : one of the given tags. The tag array is indexed [0,tag_cnt).
539 : Returns info_cnt, the number of matching partitions. Further, if
540 : info_max is non-zero, will return detailed information for the first
541 : (from low to high gaddr) min(info_cnt,info_max). Returns 0 if no
542 : partitions match any tags. If any wonkiness encountered (e.g. wksp
543 : is NULL, tag is not in positive, etc) returns 0 and logs details.
544 : This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
545 : O(wksp_alloc_cnt) with some additional work). */
546 :
547 : struct fd_wksp_tag_query_info {
548 : ulong gaddr_lo; /* Partition covers workspace global addresses [gaddr_lo,gaddr_hi) */
549 : ulong gaddr_hi; /* 0<gaddr_lo<gaddr_hi */
550 : ulong tag; /* Partition tag */
551 : };
552 :
553 : typedef struct fd_wksp_tag_query_info fd_wksp_tag_query_info_t;
554 :
555 : ulong
556 : fd_wksp_tag_query( fd_wksp_t * wksp,
557 : ulong const * tag,
558 : ulong tag_cnt,
559 : fd_wksp_tag_query_info_t * info,
560 : ulong info_max );
561 :
562 : /* fd_wksp_tag_free frees all allocations in wksp that match one of the
563 : given tags. The tag array is indexed [0,tag_cnt). Logs details if
564 : any wonkiness encountered (e.g. wksp is NULL, tag is not in positive.
565 : This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
566 : O(wksp_alloc_cnt) with some additional work). */
567 :
568 : void
569 : fd_wksp_tag_free( fd_wksp_t * wksp,
570 : ulong const * tag,
571 : ulong tag_cnt );
572 :
573 : /* fd_wksp_memset sets all bytes in a wksp allocation to character c.
574 : gaddr is a global address that points to any byte in the allocation
575 : (i.e. can point to anything in range returned by
576 : fd_wksp_alloc_at_least and will fill the whole range). Logs details
577 : of any weirdness detected. Clear of "NULL" (0UL) silently returns.
578 : Atomic with respect to other operations on this workspace. */
579 :
580 : void
581 : fd_wksp_memset( fd_wksp_t * wksp,
582 : ulong gaddr,
583 : int c );
584 :
585 : /* fd_wksp_reset frees all allocations from the wksp. Logs details on
586 : failure. */
587 :
588 : void
589 : fd_wksp_reset( fd_wksp_t * wksp,
590 : uint seed );
591 :
592 : /* fd_wksp_usage computes the wksp usage at some point in time between
593 : when the call was made and the call returned, populating the user
594 : provided usage structure with the result. Always returns usage.
595 :
596 : wksp is a current local join to the workspace to compute usage.
597 :
598 : tag[tag_idx] for tag_idx in [0,tag_cnt) is an array of tags to
599 : compute the usage. The order doesn't matter and, if a tag appears
600 : multiple times in the array, it will be counted once in the used
601 : stats. A zero tag_cnt (potentially with a NULL tag) is fine
602 : (used_cnt,used_set for such will be 0,0). A tag of 0 indicates to
603 : include free partitions in the used stats.
604 :
605 : total_max is the maximum partitions the wksp can have. This will be
606 : positive (==part_max).
607 :
608 : total_sz is the number of bytes the wksp has available for
609 : partitioning (==data_max). As the partitioning always covers the
610 : entire wksp, total_sz is constant for the lifetime of the wksp.
611 :
612 : total_cnt is the number of partitions the wksp currently has. This
613 : will be in [1,total_max].
614 :
615 : free_cnt/sz is the number of free partitions / free bytes the wksp
616 : currently has. A free partition has a tag of 0 and is currently
617 : available for splitting to satisfy the a future fd_wksp_alloc
618 : request.
619 :
620 : used_cnt/sz is the number of partitions / bytes used by wksp
621 : partitions whose tags match those in the provided tag set.
622 :
623 : This is O(wksp_alloc_cnt*tag_cnt) and will lock the wksp while
624 : running (and potentially block the caller if others are holding onto
625 : the lock). So use in testing, etc. Likewise, the precise meaning of
626 : the statistics computed by this API are dependent on the
627 : implementation details under the hood (that is do not be surprised if
628 : this API gets changed in the future). */
629 :
630 : fd_wksp_usage_t *
631 : fd_wksp_usage( fd_wksp_t * wksp,
632 : ulong const * tag,
633 : ulong tag_cnt,
634 : fd_wksp_usage_t * usage );
635 :
636 : /* shmem APIs *********************************************************/
637 :
638 : /* fd_wksp_new_named creates a shared memory region named name and
639 : formats as a workspace. Ignoring error trapping, this is a shorthand
640 : for:
641 :
642 : // Size the workspace to use all the memory
643 : ulong footprint = sum( sub_page_cnt[*] )*page_sz
644 : ulong part_max = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
645 : ulong data_max = fd_wksp_data_max_est( footprint, part_max );
646 :
647 : // Create the shared memory region and format as a workspace
648 : fd_shmem_create_multi( name, page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx, mode );
649 : void * shmem = fd_shmem_join( name, FD_SHMEM_JOIN_MODE_READ_WRITE, NULL, NULL, NULL ) );
650 : fd_wksp_new( shmem, name, seed, part_max, data_max );
651 : fd_shmem_leave( shmem, NULL, NULL );
652 :
653 : The 64 KiB above is where fd_alloc currently transitions to directly
654 : allocating from the wksp.
655 :
656 : Returns FD_WKSP_SUCCESS (0) on success and an FD_WKSP_ERR_*
657 : (negative) on failure (logs details). Reasons for failure include
658 : INVAL (user arguments obviously bad) and FAIL (could not procure or
659 : format the shared memory region). */
660 :
661 : int
662 : fd_wksp_new_named( char const * name,
663 : ulong page_sz,
664 : ulong sub_cnt,
665 : ulong const * sub_page_cnt,
666 : ulong const * sub_cpu_idx,
667 : ulong mode,
668 : uint seed,
669 : ulong opt_part_max );
670 :
671 : /* fd_wksp_delete_named deletes a workspace created with
672 : fd_wksp_new_named. There should not be any other joins / attachments
673 : to wksp when this is called. Returns FD_WKSP_SUCCESS (0) on success
674 : and FD_WKSP_ERR_* (negative) on failure (logs details). */
675 :
676 : int
677 : fd_wksp_delete_named( char const * name );
678 :
679 : /* fd_wksp_new_anon creates a workspace local to this thread group that
680 : otherwise looks and behaves _exactly_ like a workspace shared between
681 : multiple thread groups on this host of the same name, TLB and NUMA
682 : properties. Ignoring error trapping, this is a shorthand for:
683 :
684 : // Size the workspace to use all the memory
685 : ulong page_cnt = sum( sub_page_cnt[*] );
686 : ulong footprint = page_cnt*page_sz;
687 : ulong part_max = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
688 : ulong data_max = fd_wksp_data_max_est( footprint, part_max );
689 :
690 : // Create the anonymous memory region and format as a workspace
691 : void * mem = fd_shmem_acquire_multi( page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx );
692 : fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) );
693 : fd_shmem_join_anonymous( name, FD_SHMEM_JOIN_MODE_READ_WRITE, wksp, mem, page_sz, page_cnt );
694 :
695 : There should be must no current shmem joins to name and the anonymous
696 : join will shadow any preexisting fd_shmem region with the same name
697 : in the calling thread group). Returns the joined workspace on
698 : success and NULL on failure (logs details). The final leave and
699 : delete to this workspace should be through fd_wksp_delete_anon. */
700 :
701 : fd_wksp_t *
702 : fd_wksp_new_anon( char const * name,
703 : ulong page_sz,
704 : ulong sub_cnt,
705 : ulong const * sub_page_cnt,
706 : ulong const * sub_cpu_idx,
707 : uint seed,
708 : ulong opt_part_max );
709 :
710 : /* fd_wksp_delete_anon deletes a workspace created with fd_wksp_new_anon
711 : There should not be any other joins / attachments to wksp when this
712 : is called. This cannot fail from the caller's POV; logs details if
713 : any wonkiness is detected during the delete. */
714 :
715 : void
716 : fd_wksp_delete_anon( fd_wksp_t * wksp );
717 :
718 : /* TODO: eliminate these legacy versions of the in favor of the above. */
719 :
720 : static inline fd_wksp_t *
721 : fd_wksp_new_anonymous( ulong page_sz,
722 : ulong page_cnt,
723 : ulong cpu_idx,
724 : char const * name,
725 141 : ulong opt_part_max ) {
726 141 : return fd_wksp_new_anon( name, page_sz, 1UL, &page_cnt, &cpu_idx, 0U, opt_part_max );
727 141 : }
728 :
729 69 : static inline void fd_wksp_delete_anonymous( fd_wksp_t * wksp ) { fd_wksp_delete_anon( wksp ); }
730 :
731 : /* fd_wksp_attach attach to the workspace held by the shared memory
732 : region with the given name. If there are regions with the same name
733 : backed by different page sizes, defaults to the region backed by the
734 : largest page size. Returns wksp on success and NULL on failure
735 : (details are logged). Multiple attachments within are fine (all but
736 : the first attachment will be a reasonably fast O(1) call); all
737 : attachments in a process will use the same local fd_wksp_t handle.
738 : Every attach should be paired with a detach. TODO: CONST-VARIANTS? */
739 :
740 : fd_wksp_t *
741 : fd_wksp_attach( char const * name );
742 :
743 : /* fd_wksp_detach detaches from the given workspace. All but the last
744 : detach should be a reasonably fast O(1) call. Returns non-zero on
745 : failure. */
746 :
747 : int
748 : fd_wksp_detach( fd_wksp_t * wksp );
749 :
750 : /* fd_wksp_containing maps a fd_wksp local addr to the corresponding
751 : fd_wksp local join. Returns NULL if laddr does not appear to be from
752 : a locally joined fd_wksp. Always silent such that this can be used
753 : to detect if a pointer is from a fd_wksp or not. This is not a
754 : terribly fast call. This API can only be used on laddrs in wksp are
755 : either named or anonymous workspaces. */
756 :
757 : fd_wksp_t *
758 : fd_wksp_containing( void const * laddr );
759 :
760 : /* fd_wksp_alloc_laddr is the same as fd_wksp_alloc but returns a
761 : pointer in the caller's local address space if the allocation was
762 : successful (and NULL if not). Ignoring error trapping, this is a
763 : shorthand for:
764 :
765 : fd_wksp_laddr( wksp, fd_wksp_alloc( wksp, align, sz, tag ) ) */
766 :
767 : void *
768 : fd_wksp_alloc_laddr( fd_wksp_t * wksp,
769 : ulong align,
770 : ulong sz,
771 : ulong tag );
772 :
773 : /* fd_wksp_free_laddr is the same as fd_wksp_free but takes a pointer
774 : in the caller's local address space into a workspace allocation.
775 : Ignoring error trapping, this is a shorthand for:
776 :
777 : fd_wksp_t * wksp = fd_wksp_containing( laddr );
778 : fd_wksp_free( wksp, fd_wksp_gaddr( wksp, laddr ) );
779 :
780 : This API can only be used on laddrs in wksp are either named or
781 : anonymous workspaces. */
782 :
783 : void
784 : fd_wksp_free_laddr( void * laddr );
785 :
786 : /* cstr helper APIs ***************************************************/
787 :
788 : /* Overall, these are meant for use at application startup / shutdown
789 : and not in critical loops. */
790 :
791 : /* fd_wksp_cstr prints the wksp global address gaddr into cstr as a
792 : [fd_wksp_name(wksp)]:[gaddr]. Caller promises that cstr has room for
793 : FD_WKSP_CSTR_MAX bytes. Returns cstr on success and NULL on failure
794 : (logs details). Reasons for failure include NULL wksp, gaddr not in
795 : the data region (or one past), NULL cstr. */
796 :
797 : char *
798 : fd_wksp_cstr( fd_wksp_t const * wksp,
799 : ulong gaddr,
800 : char * cstr );
801 :
802 : /* fd_wksp_cstr_laddr is the same fd_wksp_cstr but takes a pointer in
803 : the caller's local address space to a wksp location. Ignoring error
804 : trapping, this is a shorthand for:
805 :
806 : fd_wksp_t * wksp = fd_wksp_containing( laddr );
807 : return fd_wksp_cstr( wksp, fd_wksp_gaddr( wksp, laddr ), cstr );
808 :
809 : Returns NULL if laddr does not point strictly inside a workspace
810 : (logs details). This API can only be used on laddrs in wksp are
811 : either named or anonymous workspaces. */
812 :
813 : char *
814 : fd_wksp_cstr_laddr( void const * laddr,
815 : char * cstr );
816 :
817 : /* fd_wksp_cstr_alloc allocates sz bytes with alignment align from name
818 : or anonymous wksp with name. align and sz have the exact same
819 : semantics as fd_wksp_alloc. cstr must be non-NULL with space for up
820 : to FD_WKSP_CSTR_MAX bytes.
821 :
822 : Returns cstr on success and NULL on failure (logs details). On
823 : success, cstr will contain a [name]:[gaddr] string suitable for use
824 : by fd_wksp_map and fd_wksp_cstr_free. cstr will be untouched
825 : otherwise. Ignoring error trapping, this is a shorthand for:
826 :
827 : fd_wksp_t * wksp = fd_wksp_attach( name );
828 : ulong gaddr = fd_wksp_alloc( wksp, align, sz );
829 : fd_wksp_detach( wksp );
830 : sprintf( cstr, "%s:%lu", name, gaddr );
831 : return cstr;
832 :
833 : As such, if doing many allocations from the same wksp, it is faster
834 : to do a fd_wksp_attach upfront, followed by the allocations and then
835 : a wksp detach (and faster still to use the advanced APIs to further
836 : amortize the fd_wksp_attach / fd_wksp_detach calls). */
837 :
838 : char *
839 : fd_wksp_cstr_alloc( char const * name,
840 : ulong align,
841 : ulong sz,
842 : ulong tag,
843 : char * cstr );
844 :
845 : /* fd_wksp_cstr_free frees a wksp allocation specified by a cstr
846 : containing [name]:[gaddr]. Ignoring parsing and error trapping, this
847 : is a shorthand for:
848 :
849 : fd_wksp_t * wksp = fd_wksp_attach( name );
850 : fd_wksp_free( wksp, gaddr );
851 : fd_wksp_detach( wksp );
852 :
853 : As such, if doing many frees from the same wksp, it is faster to do a
854 : fd_wksp_attach upfront, followed by the frees and then a
855 : fd_wksp_detach (and faster still to use the advanced APIs to further
856 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
857 :
858 : void
859 : fd_wksp_cstr_free( char const * cstr );
860 :
861 : /* fd_wksp_cstr_tag queries the tag of a wksp allocation specified by a
862 : cstr containing [name]:[gaddr]. Ignoring parsing and error trapping,
863 : this is a shorthand for:
864 :
865 : fd_wksp_t * wksp = fd_wksp_attach( name );
866 : ulong tag = fd_wksp_tag( wksp, gaddr );
867 : fd_wksp_detach( wksp );
868 :
869 : As such, if doing many queries on the same wksp, it is faster to do
870 : fd_wksp_attach upfront, followed by the queries and then a
871 : fd_wksp_detach (and faster still to use the advanced APIs to further
872 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
873 :
874 : ulong
875 : fd_wksp_cstr_tag( char const * cstr );
876 :
877 : /* fd_wksp_cstr_memset memsets a wksp allocation specified by a cstr
878 : containing [name]:[gaddr] to c. Ignoring parsing and error trapping,
879 : equivalent to:
880 :
881 : fd_wksp_t * wksp = fd_wksp_attach( name );
882 : fd_wksp_memset( wksp, gaddr, c );
883 : fd_wksp_detach( wksp );
884 :
885 : As such, if doing many memset in the same wksp, it is faster to do a
886 : fd_wksp_attach upfront, followed by the memsets and then a
887 : fd_wksp_detach (and faster still to use the advanced APIs to further
888 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
889 :
890 : void
891 : fd_wksp_cstr_memset( char const * cstr,
892 : int c );
893 :
894 : /* fd_wksp_map returns a pointer in the caller's address space to
895 : the wksp allocation specified by a cstr containing [name]:[gaddr].
896 : [name] is the name of the shared memory region holding the wksp.
897 : [gaddr] is converted to a number via fd_cstr_to_ulong that should
898 : correspond to a valid non-NULL global address in that wksp. Ignoring
899 : parsing, edge cases and error trapping, this is a shorthand for:
900 :
901 : fd_wksp_laddr( fd_wksp_attach( name ), gaddr )
902 :
903 : Returns non-NULL on successful (the lifetime of the returned pointer
904 : will be until fd_wksp_unmap is called on it). Returns NULL and logs
905 : details on failure.
906 :
907 : fd_wksp_map is algorithmically efficient and reasonably low overhead
908 : (especially if is this not the first attachment to the wksp).
909 :
910 : TODO: consider const-correct variant? */
911 :
912 : void *
913 : fd_wksp_map( char const * cstr );
914 :
915 : /* fd_wksp_unmap unmaps a pointer returned by fd_wksp_map, logs details
916 : if anything weird is detected. Ignoring error trapping, this is a
917 : shorthand for:
918 :
919 : fd_wksp_detach( fd_wksp_containing( laddr ) )
920 :
921 : Undefined behavior if laddr is not currently mapped by fd_wksp_map.
922 : fd_wksp_unmap is not algorithmically efficient but practically still
923 : quite fast (especially if this is not the last attachment to wksp).
924 : This API can only be used on laddrs in wksp are either named or
925 : anonymous workspaces. */
926 :
927 : void
928 : fd_wksp_unmap( void const * laddr );
929 :
930 : /* pod helper APIs ****************************************************/
931 :
932 : /* Ignoring error trapping, fd_wksp_pod_attach( cstr ) is shorthand
933 : for:
934 :
935 : fd_pod_join( fd_wksp_map( cstr ) )
936 :
937 : Cannot fail from the caller's point of view (will terminate the
938 : thread group of the caller with a detailed FD_LOG_ERR message on
939 : failure. Calls to fd_wksp_pod_attach should be paired with calls to
940 : fd_wksp_pod_detach when pod usage is done. */
941 :
942 : uchar const *
943 : fd_wksp_pod_attach( char const * cstr );
944 :
945 : /* Ignoring error trapping, fd_wksp_pod_detach( pod ) is shorthand for:
946 :
947 : fd_wksp_unmap( fd_pod_leave( pod ) )
948 :
949 : Provided for symmetry with fd_wksp_pod_attach. Cannot fail from the
950 : caller's point of view (will terminate the thread group of the caller
951 : with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
952 : if anything wonky occurs in the unmap under the hood). */
953 :
954 : void
955 : fd_wksp_pod_detach( uchar const * pod );
956 :
957 : /* Ignoring error trapping, fd_wksp_pod_map( pod, path ) is shorthand
958 : for:
959 :
960 : fd_wksp_map( fd_pod_query_cstr( pod, path, NULL ) )
961 :
962 : Cannot fail from the caller's point of view (will terminate the
963 : thread group of the caller with detailed FD_LOG_ERR message on
964 : failure). Calls to fd_wksp_pod_map should be paired with calls to
965 : fd_wksp_pod_unmap. */
966 :
967 : void *
968 : fd_wksp_pod_map( uchar const * pod,
969 : char const * path );
970 :
971 : /* Ignoring error trapping, fd_wksp_pod_unmap( obj ) is shorthand for:
972 :
973 : fd_wksp_unmap( obj )
974 :
975 : Provided for symmetry with fd_wksp_pod_map. Cannot fail from the
976 : caller's point of view (will terminate the thread group of the caller
977 : with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
978 : if anything wonky occurs in the unmap under the hood). */
979 :
980 : void
981 : fd_wksp_pod_unmap( void * obj );
982 :
983 : /* io APIs ************************************************************/
984 :
985 : /* fd_wksp_checkpt_tpool will write the wksp's state to a file using
986 : tpool threads [t0,t1). Assumes the caller is thread t0 and threads
987 : (t0,t1) are available. The file will be located at path with UNIX
988 : style permissions given by mode. style specifies the checkpt style
989 : and should be a FD_WKSP_CHECKPT_STYLE_* value or 0 (0 indicates to
990 : use FD_WKSP_CHECKPT_STYLE_DEFAULT). uinfo points to a cstr with
991 : optional additional user context (NULL will be treated as the empty
992 : string "" ... if the strlen is longer than 16384 bytes, the info will
993 : be truncated to a strlen of 16383).
994 :
995 : Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
996 : (logs details). Reasons for failure include INVAL (NULL wksp, NULL
997 : path, bad mode, unsupported style), CORRUPT (wksp memory corruption
998 : detected), FAIL (fail already exists, I/O error). On failure, this
999 : will make a best effort to clean up after any partially written
1000 : checkpt file.
1001 :
1002 : fd_wksp_checkpt is a convenience wrapper for serial checkpts. */
1003 :
1004 : int
1005 : fd_wksp_checkpt_tpool( fd_tpool_t * tpool,
1006 : ulong t0,
1007 : ulong t1,
1008 : fd_wksp_t * wksp,
1009 : char const * path,
1010 : ulong mode,
1011 : int style,
1012 : char const * uinfo );
1013 :
1014 : static inline int
1015 : fd_wksp_checkpt( fd_wksp_t * wksp,
1016 : char const * path,
1017 : ulong mode,
1018 : int style,
1019 54 : char const * uinfo ) {
1020 54 : return fd_wksp_checkpt_tpool( NULL, 0UL, 1UL, wksp, path, mode, style, uinfo );
1021 54 : }
1022 :
1023 : /* fd_wksp_restore_tpool will replace all allocations in the current
1024 : workspace with the allocations from the checkpt at path. The
1025 : restored workspace will use the given seed. Tpool threads [t0,t1)
1026 : will be used for the restore. Assumes the caller is thread t0 and
1027 : threads (t0,t1) are available.
1028 :
1029 : IMPORTANT! It is okay for wksp to have a different size, backing
1030 : page sz and/or numa affinity than the original wksp. The only
1031 : requirements are the wksp be able to support as many allocations as
1032 : are in the checkpt and that these partitions can be restored to their
1033 : original positions in wksp's global address space. If wksp has
1034 : part_max in checkpt's [alloc_cnt,part_max] and a data_max>=checkpt's
1035 : data_max, this is guaranteed. Likewise, the number and range of
1036 : threads used on restore does _not_ need to match the range used on
1037 : checkpt.
1038 :
1039 : Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
1040 : (logs details). Reasons for failure include INVAL (NULL wksp, NULL
1041 : path), FAIL or CORRUPT (couldn't open checkpt, I/O error, checkpt
1042 : format error, incompatible wksp for checkpt, etc ... logs details).
1043 : For the INVAL and FAIL cases, the original workspace allocations was
1044 : untouched. For the CORRUPT case, original workspace allocations were
1045 : removed because the checkpt issues were detected after the restore
1046 : process began (a best effort to reset wksp to the empty state was
1047 : done before return).
1048 :
1049 : fd_wksp_restore is a convenience wrapper for serial restores. */
1050 :
1051 : int
1052 : fd_wksp_restore_tpool( fd_tpool_t * tpool,
1053 : ulong t0,
1054 : ulong t1,
1055 : fd_wksp_t * wksp,
1056 : char const * path,
1057 : uint seed );
1058 :
1059 : static inline int
1060 : fd_wksp_restore( fd_wksp_t * wksp,
1061 : char const * path,
1062 63 : uint seed ) {
1063 : return fd_wksp_restore_tpool( NULL, 0UL, 1UL, wksp, path, seed );
1064 63 : }
1065 :
1066 : /* fd_wksp_preview previews the wksp checkpt at path. On success,
1067 : returns FD_WKSP_SUCCESS (0), path seems to contain a supported wksp
1068 : checkpt and, if opt_preview was non-NULL, *opt_preview will contain,
1069 : at a minimum, the info needed to create a new wksp with the same
1070 : parameters as the wksp at path. On failure, returns a FD_WKSP_ERR
1071 : (negative, silent) and *_opt_preview is unchanged. Returns for
1072 : failure include INVAL (NULL path), FAIL (unable to read checkpt
1073 : header at path), CORRUPT (the leading bytes at path don't appear to
1074 : be a wksp checkpt). */
1075 :
1076 : struct fd_wksp_preview {
1077 : int style;
1078 : uint seed;
1079 : ulong part_max;
1080 : ulong data_max;
1081 : char name[ FD_SHMEM_NAME_MAX ]; /* cstr holding the original wksp name */
1082 : };
1083 :
1084 : typedef struct fd_wksp_preview fd_wksp_preview_t;
1085 :
1086 : int
1087 : fd_wksp_preview( char const * path,
1088 : fd_wksp_preview_t * _opt_preview );
1089 :
1090 : /* fd_wksp_printf pretty prints to fd (e.g. fileno(stdout)) information
1091 : about the wksp checkpt at path. verbose specifies the verbosity
1092 : level. Typical verbose levels are:
1093 :
1094 : <0 - do not print
1095 : 0 - preview info
1096 : 1 - verbose 0 + metadata
1097 : 2 - verbose 1 + build and user info
1098 : 3 - verbose 2 + partition summary info
1099 : 4 - verbose 3 + individual allocated partition metdata
1100 : >4 - verbose 4 + hex dumps of allocated partition data
1101 :
1102 : but this can vary for different checkpt styles. The return value has
1103 : the same interpretation as printf. */
1104 :
1105 : int
1106 : fd_wksp_printf( int fd,
1107 : char const * path,
1108 : int verbose );
1109 :
1110 : FD_PROTOTYPES_END
1111 :
1112 : #endif /* HEADER_fd_src_util_wksp_fd_wksp_h */
|