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