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