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 997338804 : #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 130251573 : #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 1770 : #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 81666168 : #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_FN_CONST char const * fd_wksp_name ( fd_wksp_t const * wksp );
288 : FD_FN_PURE uint fd_wksp_seed ( fd_wksp_t const * wksp );
289 : FD_FN_PURE ulong fd_wksp_part_max( fd_wksp_t const * wksp );
290 : FD_FN_PURE ulong fd_wksp_data_max( fd_wksp_t const * wksp );
291 :
292 : /* fd_wksp_owner returns the id of the thread group that was currently
293 : in a wksp operation (0 indicates the wksp was in the process of being
294 : constructed) or ULONG_MAX if there was no operation in progress on
295 : the workspace. Assumes wksp is a current local join. The value will
296 : correspond to some point of time between when the call was made and
297 : the call returned. */
298 :
299 : ulong fd_wksp_owner( fd_wksp_t const * wksp );
300 :
301 : /* Misc */
302 :
303 : /* fd_wksp_strerror converts an FD_WKSP_SUCCESS / FD_WKSP_ERR_* code
304 : into a human readable cstr. The lifetime of the returned pointer is
305 : infinite. The returned pointer is always to a non-NULL cstr. */
306 :
307 : FD_FN_CONST char const *
308 : fd_wksp_strerror( int err );
309 :
310 : /* fd_wksp_verify does extensive verification of wksp. Returns
311 : FD_WKSP_SUCCESS (0) if there are no issues detected with the wksp or
312 : FD_WKSP_ERR_CORRUPT (negative) otherwise (logs details). wksp is a
313 : current local join to a workspace. This is used internally for
314 : verifying the integrity of a workspace if a caller detects in an
315 : operation that another caller died in the middle of a wksp operation.
316 : Users typically do not need to call this but it can be useful in
317 : debugging and testing.
318 :
319 : IMPORTANT SAFETY TIP! This assumes there are no concurrent
320 : operations on wksp. */
321 :
322 : int
323 : fd_wksp_verify( fd_wksp_t * wksp );
324 :
325 : /* fd_wksp_rebuilds a wksp. This is used internally for rebuilding
326 : workspace when a caller detects that another caller died in the
327 : middle of an alloc or free and left the workspace in an inconsistent
328 : state. Returns FD_WKSP_SUCCESS (0) if wksp was rebuilt successfully
329 : or a FD_WKSP_ERR_CORRUPT (negative) if it could not (logs details).
330 :
331 : Rebuilding operates under the principle of "do no harm".
332 : Specifically, rebuilding does not impact any completed wksp
333 : allocations (even when it fails). It can either complete or rollback
334 : any partially complete alloc / free depends on far along the partial
335 : operation was.
336 :
337 : Rebuilding should be always possible outside of actual memory
338 : corruption or code bug. The main reason for failure is overlapping
339 : allocations were discovered during the rebuild (which would either be
340 : caused by memory corruption or a bug).
341 :
342 : Users typically do not need to call this but it can be useful as a
343 : weak form of ASLR by changing up the seed. This is not a fast
344 : operation.
345 :
346 : IMPORTANT SAFETY TIP! This assumes there are no concurrent
347 : operations on wksp. */
348 :
349 : int
350 : fd_wksp_rebuild( fd_wksp_t * wksp,
351 : uint seed );
352 :
353 : /* User APIs **********************************************************/
354 :
355 : /* fd_wksp_laddr map a wksp global address (an address all joiners
356 : agree upon) to the caller's local address space. Invalid global
357 : addresses and/or 0UL will map to NULL (logs details if invalid).
358 : Assumes wksp is a current local join (NULL returns NULL). */
359 :
360 : void *
361 : fd_wksp_laddr( fd_wksp_t const * wksp,
362 : ulong gaddr );
363 :
364 : /* fd_wksp_gaddr maps a wksp local address to the corresponding wksp
365 : global address (an address all joiners agree upon). Invalid local
366 : addresses and/or NULL will map to 0UL (logs details if invalid).
367 : Assumes wksp is a current local join (NULL returns NULL). */
368 :
369 : ulong
370 : fd_wksp_gaddr( fd_wksp_t const * wksp,
371 : void const * laddr );
372 :
373 : /* fd_wksp_gaddr_fast converts a laddr into a gaddr under the assumption
374 : wksp is a current local join and laddr is non-NULL local address in
375 : the wksp. */
376 :
377 : FD_FN_CONST static inline ulong
378 : fd_wksp_gaddr_fast( fd_wksp_t const * wksp,
379 28015000 : void const * laddr ) {
380 28015000 : return (ulong)laddr - (ulong)wksp;
381 28015000 : }
382 :
383 : /* fd_wksp_laddr_fast converts a gaddr into a laddr under the assumption
384 : wksp is a current local join and gaddr is non-NULL. */
385 :
386 : FD_FN_CONST static inline void *
387 : fd_wksp_laddr_fast( fd_wksp_t const * wksp,
388 410470759 : ulong gaddr ) {
389 410470759 : return (void *)((ulong)wksp + gaddr);
390 410470759 : }
391 :
392 : /* fd_wksp_alloc_at_least allocates at least sz bytes from wksp with
393 : an alignment of at least align (align must be a non-negative integer
394 : power-of-two or 0, which indicates to use the default alignment
395 : FD_WKSP_ALIGN_DEFAULT). The allocation will be tagged with a
396 : positive value tag. Returns the fd_wksp global address of the join
397 : on success and "NULL" (0UL) on failure (logs details). A zero sz
398 : returns "NULL" (silent). On return, [*lo,*hi) will contain the
399 : actually gaddr range allocated. On success, [*lo,*hi) will overlap
400 : completely [ret,ret+sz) and ret will be aligned to requested
401 : alignment. Assumes lo and hi are non-NULL.
402 :
403 : fd_wksp_alloc is a simple wrapper around fd_wksp_alloc_at_least for
404 : use when applications do not care about details of the actual
405 : allocated region.
406 :
407 : Note that fd_wksp_alloc / fd_wksp_free are not HPC implementations.
408 : Instead, these are designed to be akin to a mmap / sbrk allocator of
409 : "last resort" under the hood in other allocators like fd_alloc. As
410 : such it prioritizes packing efficiency (best fit with arbitrary sizes
411 : and alignments allowed) over algorithmic efficiency (e.g.
412 : O(lg wksp_alloc_cnt) instead of O(1) like fd_alloc) and prioritize
413 : robustness against heap corruption (e.g. overrunning an allocation
414 : might corrupt the data in other allocations but will not corrupt the
415 : heap structure ... as the goal of this data structure is to encourage
416 : minimization of TLB usage, there is very little that can be done to
417 : proactively prevent intraworkspace interallocation data corruption).
418 :
419 : These operations are "quasi-lock-free". Specifically, while they can
420 : suffer priority inversion due to a slow thread stalling other threads
421 : from using these operations, a process that is terminated in the
422 : middle of these operations leaves the wksp in a recoverable state.
423 : The only risk is the same risk generally from any application that
424 : uses persistent resources: applications that are terminated abruptly
425 : might leave allocations in the wksp that would have been freed had
426 : the application terminated normally. As the allocator has no way to
427 : tell the difference between such allocations and allocations that are
428 : intended to outlive the application, it is the caller's
429 : responsibility to clean up such (allocation tagging can help greatly
430 : simplify this for users). It would be possible to widen this API for
431 : applications to explicitly signal this intent and automatically clean
432 : up allocations not meant to outlive their creator but the general use
433 : here is expected to be long lived allocations.
434 :
435 : Priority inversion is not expected to be an issue practically as the
436 : expected use case is at app startup (some non-latency critical
437 : processes will do a handful of wksp operations to setup workspaces
438 : for applications on that box going forward and then the allocations
439 : will not be used again until the wksp is tore down / reset / etc).
440 : The remaining cases (e.g. a fine grained allocator like fd_alloc
441 : needs to procure more memory from the workspace) are expected to be
442 : rare enough that the O(lg N) costs still will be more than adequate.
443 : Note further that fd_alloc allows very fast interprocess allocations
444 : to be done by using a wksp as an allocator of last resort (in such,
445 : all allocations would be strictly lock free unless they needed to
446 : invoke this allocator, as is typically the case in other lock free
447 : allocators).
448 :
449 : Likewise, operations do extensive allocation metadata integrity
450 : checks to facilitate robust persistent usage. If there is metadata
451 : data corruption detected (e.g. hardware fault, code corruption, etc),
452 : there are fsck-like APIs to rebuild wksp metadata. Data integrity
453 : protection is more defined by the application.
454 :
455 : Tags are application specific. They can allow manual and automated
456 : processes to do various debugging, diagnostics, analytics and garbage
457 : collection on a workspace (e.g. superblocks from a fd_alloc can be
458 : tagged specifically for that fd_alloc to allow memory leaks in
459 : general to be detected at program termination with no additional
460 : overheads and allow such leaks cleaned up via tagged frees).
461 : Notably, tags are wide enough to encode gaddrs. This opens up the
462 : possibly for filesystem-like complex metadata operations.
463 :
464 : IMPORTANT! align technically refers to the alignment in the wksp's
465 : global address space. As such, wksp must be mmaped into each local
466 : address space with an alignment of at least the largest alignment the
467 : overall application intends to use. Common practices automatically
468 : satisfy this (e.g. if wksp is backed by normal/huge/gigantic pages
469 : and only asks for alignments of at most a normal/huge/gigantic page
470 : sz, this constraint is automatically satisfied as fd_shmem_join needs
471 : to mmap wksp into the local address space with normal/huge/gigantic
472 : alignment anyway). If doing more exotic things (e.g. backing wksp by
473 : normal pages but requiring much larger alignments), explicitly
474 : specifying the wksp virtual address location (e.g. in the
475 : fd_shmem_join call) might be necessary to satisfy this constraint.
476 :
477 : This implementation support arbitrary sz and align efficiently but
478 : each allocation will use up 1-3 wksp partitions to achieve this. As
479 : these are a finite resources (and typically sized for a wksp that
480 : handles primarily larger allocations, like a fd_alloc huge
481 : superblock) and as there are allocators like fd_alloc that faster are
482 : algorithmically, lower overhead and lockfree O(1) for small sizes and
483 : alignment, it is strongly recommended to use this as an allocator of
484 : last resort and/or use this for larger chunkier allocations at
485 : application startup (e.g. sz + align >>> cache line). An allocator
486 : like fd_alloc can then manage most allocations, falling back on this
487 : only when necessary. */
488 :
489 : ulong
490 : fd_wksp_alloc_at_least( fd_wksp_t * wksp,
491 : ulong align,
492 : ulong sz,
493 : ulong tag,
494 : ulong * lo,
495 : ulong * hi );
496 :
497 : static inline ulong
498 : fd_wksp_alloc( fd_wksp_t * wksp,
499 : ulong align,
500 : ulong sz,
501 10320 : ulong tag ) {
502 10320 : ulong dummy[2];
503 10320 : return fd_wksp_alloc_at_least( wksp, align, sz, tag, dummy, dummy+1 );
504 10320 : }
505 :
506 : /* fd_wksp_free frees a wksp allocation. gaddr is a global address that
507 : points to any byte in the allocation to free (i.e. can point to
508 : anything in of the gaddr range [*lo,*hi) returned by
509 : fd_wksp_alloc_at_least). Logs details of any weirdness detected.
510 : Free of "NULL" (0UL) silently returns. There are no restrictions on
511 : which join might free an allocation. See note above other details. */
512 :
513 : void
514 : fd_wksp_free( fd_wksp_t * wksp,
515 : ulong gaddr );
516 :
517 : /* fd_wksp_tag returns the tag associated with an allocation. gaddr
518 : is a wksp global address that points to any byte in the allocation.
519 : This is a fast O(lg wksp_alloc_cnt). A return of 0 indicates that
520 : gaddr did not point into an allocation at some point in time between
521 : when this function was called until when it returned (this includes
522 : the cases when wksp is NULL and/or gaddr is 0). This function is
523 : silent to facilitate integration with various analysis tools. */
524 :
525 : ulong
526 : fd_wksp_tag( fd_wksp_t * wksp,
527 : ulong gaddr );
528 :
529 : /* fd_wksp_tag_query queries the workspace for all partitions that match
530 : one of the given tags. The tag array is indexed [0,tag_cnt).
531 : Returns info_cnt, the number of matching partitions. Further, if
532 : info_max is non-zero, will return detailed information for the first
533 : (from low to high gaddr) min(info_cnt,info_max). Returns 0 if no
534 : partitions match any tags. If any wonkiness encountered (e.g. wksp
535 : is NULL, tag is not in positive, etc) returns 0 and logs details.
536 : This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
537 : O(wksp_alloc_cnt) with some additional work). */
538 :
539 : struct fd_wksp_tag_query_info {
540 : ulong gaddr_lo; /* Partition covers workspace global addresses [gaddr_lo,gaddr_hi) */
541 : ulong gaddr_hi; /* 0<gaddr_lo<gaddr_hi */
542 : ulong tag; /* Partition tag */
543 : };
544 :
545 : typedef struct fd_wksp_tag_query_info fd_wksp_tag_query_info_t;
546 :
547 : ulong
548 : fd_wksp_tag_query( fd_wksp_t * wksp,
549 : ulong const * tag,
550 : ulong tag_cnt,
551 : fd_wksp_tag_query_info_t * info,
552 : ulong info_max );
553 :
554 : /* fd_wksp_tag_free frees all allocations in wksp that match one of the
555 : given tags. The tag array is indexed [0,tag_cnt). Logs details if
556 : any wonkiness encountered (e.g. wksp is NULL, tag is not in positive.
557 : This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
558 : O(wksp_alloc_cnt) with some additional work). */
559 :
560 : void
561 : fd_wksp_tag_free( fd_wksp_t * wksp,
562 : ulong const * tag,
563 : ulong tag_cnt );
564 :
565 : /* fd_wksp_memset sets all bytes in a wksp allocation to character c.
566 : gaddr is a global address that points to any byte in the allocation
567 : (i.e. can point to anything in range returned by
568 : fd_wksp_alloc_at_least and will fill the whole range). Logs details
569 : of any weirdness detected. Clear of "NULL" (0UL) silently returns.
570 : Atomic with respect to other operations on this workspace. */
571 :
572 : void
573 : fd_wksp_memset( fd_wksp_t * wksp,
574 : ulong gaddr,
575 : int c );
576 :
577 : /* fd_wksp_reset frees all allocations from the wksp. Logs details on
578 : failure. */
579 :
580 : void
581 : fd_wksp_reset( fd_wksp_t * wksp,
582 : uint seed );
583 :
584 : /* fd_wksp_usage computes the wksp usage at some point in time between
585 : when the call was made and the call returned, populating the user
586 : provided usage structure with the result. Always returns usage.
587 :
588 : wksp is a current local join to the workspace to compute usage.
589 :
590 : tag[tag_idx] for tag_idx in [0,tag_cnt) is an array of tags to
591 : compute the usage. The order doesn't matter and, if a tag appears
592 : multiple times in the array, it will be counted once in the used
593 : stats. A zero tag_cnt (potentially with a NULL tag) is fine
594 : (used_cnt,used_set for such will be 0,0). A tag of 0 indicates to
595 : include free partitions in the used stats.
596 :
597 : total_max is the maximum partitions the wksp can have. This will be
598 : positive (==part_max).
599 :
600 : total_sz is the number of bytes the wksp has available for
601 : partitioning (==data_max). As the partitioning always covers the
602 : entire wksp, total_sz is constant for the lifetime of the wksp.
603 :
604 : total_cnt is the number of partitions the wksp currently has. This
605 : will be in [1,total_max].
606 :
607 : free_cnt/sz is the number of free partitions / free bytes the wksp
608 : currently has. A free partition has a tag of 0 and is currently
609 : available for splitting to satisfy the a future fd_wksp_alloc
610 : request.
611 :
612 : used_cnt/sz is the number of partitions / bytes used by wksp
613 : partitions whose tags match those in the provided tag set.
614 :
615 : This is O(wksp_alloc_cnt*tag_cnt) and will lock the wksp while
616 : running (and potentially block the caller if others are holding onto
617 : the lock). So use in testing, etc. Likewise, the precise meaning of
618 : the statistics computed by this API are dependent on the
619 : implementation details under the hood (that is do not be surprised if
620 : this API gets changed in the future). */
621 :
622 : fd_wksp_usage_t *
623 : fd_wksp_usage( fd_wksp_t * wksp,
624 : ulong const * tag,
625 : ulong tag_cnt,
626 : fd_wksp_usage_t * usage );
627 :
628 : /* shmem APIs *********************************************************/
629 :
630 : /* fd_wksp_new_named creates a shared memory region named name and
631 : formats as a workspace. Ignoring error trapping, this is a shorthand
632 : for:
633 :
634 : // Size the workspace to use all the memory
635 : ulong footprint = sum( sub_page_cnt[*] )*page_sz
636 : ulong part_max = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
637 : ulong data_max = fd_wksp_data_max_est( footprint, part_max );
638 :
639 : // Create the shared memory region and format as a workspace
640 : fd_shmem_create_multi( name, page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx, mode );
641 : void * shmem = fd_shmem_join( name, FD_SHMEM_JOIN_MODE_READ_WRITE, NULL, NULL, NULL ) );
642 : fd_wksp_new( shmem, name, seed, part_max, data_max );
643 : fd_shmem_leave( shmem, NULL, NULL );
644 :
645 : The 64 KiB above is where fd_alloc currently transitions to directly
646 : allocating from the wksp.
647 :
648 : Returns FD_WKSP_SUCCESS (0) on success and an FD_WKSP_ERR_*
649 : (negative) on failure (logs details). Reasons for failure include
650 : INVAL (user arguments obviously bad) and FAIL (could not procure or
651 : format the shared memory region). */
652 :
653 : int
654 : fd_wksp_new_named( char const * name,
655 : ulong page_sz,
656 : ulong sub_cnt,
657 : ulong const * sub_page_cnt,
658 : ulong const * sub_cpu_idx,
659 : ulong mode,
660 : uint seed,
661 : ulong opt_part_max );
662 :
663 : /* fd_wksp_delete_named deletes a workspace created with
664 : fd_wksp_new_named. There should not be any other joins / attachments
665 : to wksp when this is called. Returns FD_WKSP_SUCCESS (0) on success
666 : and FD_WKSP_ERR_* (negative) on failure (logs details). */
667 :
668 : int
669 : fd_wksp_delete_named( char const * name );
670 :
671 : /* fd_wksp_new_anon creates a workspace local to this thread group that
672 : otherwise looks and behaves _exactly_ like a workspace shared between
673 : multiple thread groups on this host of the same name, TLB and NUMA
674 : properties. Ignoring error trapping, this is a shorthand for:
675 :
676 : // Size the workspace to use all the memory
677 : ulong page_cnt = sum( sub_page_cnt[*] );
678 : ulong footprint = page_cnt*page_sz;
679 : ulong part_max = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
680 : ulong data_max = fd_wksp_data_max_est( footprint, part_max );
681 :
682 : // Create the anonymous memory region and format as a workspace
683 : void * mem = fd_shmem_acquire_multi( page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx );
684 : fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) );
685 : fd_shmem_join_anonymous( name, FD_SHMEM_JOIN_MODE_READ_WRITE, wksp, mem, page_sz, page_cnt );
686 :
687 : There should be must no current shmem joins to name and the anonymous
688 : join will shadow any preexisting fd_shmem region with the same name
689 : in the calling thread group). Returns the joined workspace on
690 : success and NULL on failure (logs details). The final leave and
691 : delete to this workspace should be through fd_wksp_delete_anon. */
692 :
693 : fd_wksp_t *
694 : fd_wksp_new_anon( char const * name,
695 : ulong page_sz,
696 : ulong sub_cnt,
697 : ulong const * sub_page_cnt,
698 : ulong const * sub_cpu_idx,
699 : uint seed,
700 : ulong opt_part_max );
701 :
702 : /* fd_wksp_delete_anon deletes a workspace created with fd_wksp_new_anon
703 : There should not be any other joins / attachments to wksp when this
704 : is called. This cannot fail from the caller's POV; logs details if
705 : any wonkiness is detected during the delete. */
706 :
707 : void
708 : fd_wksp_delete_anon( fd_wksp_t * wksp );
709 :
710 : /* TODO: eliminate these legacy versions of the in favor of the above. */
711 :
712 : static inline fd_wksp_t *
713 : fd_wksp_new_anonymous( ulong page_sz,
714 : ulong page_cnt,
715 : ulong cpu_idx,
716 : char const * name,
717 72 : ulong opt_part_max ) {
718 72 : return fd_wksp_new_anon( name, page_sz, 1UL, &page_cnt, &cpu_idx, 0U, opt_part_max );
719 72 : }
720 :
721 48 : static inline void fd_wksp_delete_anonymous( fd_wksp_t * wksp ) { fd_wksp_delete_anon( wksp ); }
722 :
723 : /* fd_wksp_attach attach to the workspace held by the shared memory
724 : region with the given name. If there are regions with the same name
725 : backed by different page sizes, defaults to the region backed by the
726 : largest page size. Returns wksp on success and NULL on failure
727 : (details are logged). Multiple attachments within are fine (all but
728 : the first attachment will be a reasonably fast O(1) call); all
729 : attachments in a process will use the same local fd_wksp_t handle.
730 : Every attach should be paired with a detach. TODO: CONST-VARIANTS? */
731 :
732 : fd_wksp_t *
733 : fd_wksp_attach( char const * name );
734 :
735 : /* fd_wksp_detach detaches from the given workspace. All but the last
736 : detach should be a reasonably fast O(1) call. Returns non-zero on
737 : failure. */
738 :
739 : int
740 : fd_wksp_detach( fd_wksp_t * wksp );
741 :
742 : /* fd_wksp_containing maps a fd_wksp local addr to the corresponding
743 : fd_wksp local join. Returns NULL if laddr does not appear to be from
744 : a locally joined fd_wksp. Always silent such that this can be used
745 : to detect if a pointer is from a fd_wksp or not. This is not a
746 : terribly fast call. This API can only be used on laddrs in wksp are
747 : either named or anonymous workspaces. */
748 :
749 : fd_wksp_t *
750 : fd_wksp_containing( void const * laddr );
751 :
752 : /* fd_wksp_alloc_laddr is the same as fd_wksp_alloc but returns a
753 : pointer in the caller's local address space if the allocation was
754 : successful (and NULL if not). Ignoring error trapping, this is a
755 : shorthand for:
756 :
757 : fd_wksp_laddr( wksp, fd_wksp_alloc( wksp, align, sz, tag ) ) */
758 :
759 : void *
760 : fd_wksp_alloc_laddr( fd_wksp_t * wksp,
761 : ulong align,
762 : ulong sz,
763 : ulong tag );
764 :
765 : /* fd_wksp_free_laddr is the same as fd_wksp_free but takes a pointer
766 : in the caller's local address space into a workspace allocation.
767 : Ignoring error trapping, this is a shorthand for:
768 :
769 : fd_wksp_t * wksp = fd_wksp_containing( laddr );
770 : fd_wksp_free( wksp, fd_wksp_gaddr( wksp, laddr ) );
771 :
772 : This API can only be used on laddrs in wksp are either named or
773 : anonymous workspaces. */
774 :
775 : void
776 : fd_wksp_free_laddr( void * laddr );
777 :
778 : /* cstr helper APIs ***************************************************/
779 :
780 : /* Overall, these are meant for use at application startup / shutdown
781 : and not in critical loops. */
782 :
783 : /* fd_wksp_cstr prints the wksp global address gaddr into cstr as a
784 : [fd_wksp_name(wksp)]:[gaddr]. Caller promises that cstr has room for
785 : FD_WKSP_CSTR_MAX bytes. Returns cstr on success and NULL on failure
786 : (logs details). Reasons for failure include NULL wksp, gaddr not in
787 : the data region (or one past), NULL cstr. */
788 :
789 : char *
790 : fd_wksp_cstr( fd_wksp_t const * wksp,
791 : ulong gaddr,
792 : char * cstr );
793 :
794 : /* fd_wksp_cstr_laddr is the same fd_wksp_cstr but takes a pointer in
795 : the caller's local address space to a wksp location. Ignoring error
796 : trapping, this is a shorthand for:
797 :
798 : fd_wksp_t * wksp = fd_wksp_containing( laddr );
799 : return fd_wksp_cstr( wksp, fd_wksp_gaddr( wksp, laddr ), cstr );
800 :
801 : Returns NULL if laddr does not point strictly inside a workspace
802 : (logs details). This API can only be used on laddrs in wksp are
803 : either named or anonymous workspaces. */
804 :
805 : char *
806 : fd_wksp_cstr_laddr( void const * laddr,
807 : char * cstr );
808 :
809 : /* fd_wksp_cstr_alloc allocates sz bytes with alignment align from name
810 : or anonymous wksp with name. align and sz have the exact same
811 : semantics as fd_wksp_alloc. cstr must be non-NULL with space for up
812 : to FD_WKSP_CSTR_MAX bytes.
813 :
814 : Returns cstr on success and NULL on failure (logs details). On
815 : success, cstr will contain a [name]:[gaddr] string suitable for use
816 : by fd_wksp_map and fd_wksp_cstr_free. cstr will be untouched
817 : otherwise. Ignoring error trapping, this is a shorthand for:
818 :
819 : fd_wksp_t * wksp = fd_wksp_attach( name );
820 : ulong gaddr = fd_wksp_alloc( wksp, align, sz );
821 : fd_wksp_detach( wksp );
822 : sprintf( cstr, "%s:%lu", name, gaddr );
823 : return cstr;
824 :
825 : As such, if doing many allocations from the same wksp, it is faster
826 : to do a fd_wksp_attach upfront, followed by the allocations and then
827 : a wksp detach (and faster still to use the advanced APIs to further
828 : amortize the fd_wksp_attach / fd_wksp_detach calls). */
829 :
830 : char *
831 : fd_wksp_cstr_alloc( char const * name,
832 : ulong align,
833 : ulong sz,
834 : ulong tag,
835 : char * cstr );
836 :
837 : /* fd_wksp_cstr_free frees a wksp allocation specified by a cstr
838 : containing [name]:[gaddr]. Ignoring parsing and error trapping, this
839 : is a shorthand for:
840 :
841 : fd_wksp_t * wksp = fd_wksp_attach( name );
842 : fd_wksp_free( wksp, gaddr );
843 : fd_wksp_detach( wksp );
844 :
845 : As such, if doing many frees from the same wksp, it is faster to do a
846 : fd_wksp_attach upfront, followed by the frees and then a
847 : fd_wksp_detach (and faster still to use the advanced APIs to further
848 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
849 :
850 : void
851 : fd_wksp_cstr_free( char const * cstr );
852 :
853 : /* fd_wksp_cstr_tag queries the tag of a wksp allocation specified by a
854 : cstr containing [name]:[gaddr]. Ignoring parsing and error trapping,
855 : this is a shorthand for:
856 :
857 : fd_wksp_t * wksp = fd_wksp_attach( name );
858 : ulong tag = fd_wksp_tag( wksp, gaddr );
859 : fd_wksp_detach( wksp );
860 :
861 : As such, if doing many queries on the same wksp, it is faster to do
862 : fd_wksp_attach upfront, followed by the queries and then a
863 : fd_wksp_detach (and faster still to use the advanced APIs to further
864 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
865 :
866 : ulong
867 : fd_wksp_cstr_tag( char const * cstr );
868 :
869 : /* fd_wksp_cstr_memset memsets a wksp allocation specified by a cstr
870 : containing [name]:[gaddr] to c. Ignoring parsing and error trapping,
871 : equivalent to:
872 :
873 : fd_wksp_t * wksp = fd_wksp_attach( name );
874 : fd_wksp_memset( wksp, gaddr, c );
875 : fd_wksp_detach( wksp );
876 :
877 : As such, if doing many memset in the same wksp, it is faster to do a
878 : fd_wksp_attach upfront, followed by the memsets and then a
879 : fd_wksp_detach (and faster still to use the advanced APIs to further
880 : amortize the fd_wksp_attach / fd_wksp_detach calls.) */
881 :
882 : void
883 : fd_wksp_cstr_memset( char const * cstr,
884 : int c );
885 :
886 : /* fd_wksp_map returns a pointer in the caller's address space to
887 : the wksp allocation specified by a cstr containing [name]:[gaddr].
888 : [name] is the name of the shared memory region holding the wksp.
889 : [gaddr] is converted to a number via fd_cstr_to_ulong that should
890 : correspond to a valid non-NULL global address in that wksp. Ignoring
891 : parsing, edge cases and error trapping, this is a shorthand for:
892 :
893 : fd_wksp_laddr( fd_wksp_attach( name ), gaddr )
894 :
895 : Returns non-NULL on successful (the lifetime of the returned pointer
896 : will be until fd_wksp_unmap is called on it). Returns NULL and logs
897 : details on failure.
898 :
899 : fd_wksp_map is algorithmically efficient and reasonably low overhead
900 : (especially if is this not the first attachment to the wksp).
901 :
902 : TODO: consider const-correct variant? */
903 :
904 : void *
905 : fd_wksp_map( char const * cstr );
906 :
907 : /* fd_wksp_unmap unmaps a pointer returned by fd_wksp_map, logs details
908 : if anything weird is detected. Ignoring error trapping, this is a
909 : shorthand for:
910 :
911 : fd_wksp_detach( fd_wksp_containing( laddr ) )
912 :
913 : Undefined behavior if laddr is not currently mapped by fd_wksp_map.
914 : fd_wksp_unmap is not algorithmically efficient but practically still
915 : quite fast (especially if this is not the last attachment to wksp).
916 : This API can only be used on laddrs in wksp are either named or
917 : anonymous workspaces. */
918 :
919 : void
920 : fd_wksp_unmap( void const * laddr );
921 :
922 : /* pod helper APIs ****************************************************/
923 :
924 : /* Ignoring error trapping, fd_wksp_pod_attach( cstr ) is shorthand
925 : for:
926 :
927 : fd_pod_join( fd_wksp_map( cstr ) )
928 :
929 : Cannot fail from the caller's point of view (will terminate the
930 : thread group of the caller with a detailed FD_LOG_ERR message on
931 : failure. Calls to fd_wksp_pod_attach should be paired with calls to
932 : fd_wksp_pod_detach when pod usage is done. */
933 :
934 : uchar const *
935 : fd_wksp_pod_attach( char const * cstr );
936 :
937 : /* Ignoring error trapping, fd_wksp_pod_detach( pod ) is shorthand for:
938 :
939 : fd_wksp_unmap( fd_pod_leave( pod ) )
940 :
941 : Provided for symmetry with fd_wksp_pod_attach. Cannot fail from the
942 : caller's point of view (will terminate the thread group of the caller
943 : with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
944 : if anything wonky occurs in the unmap under the hood). */
945 :
946 : void
947 : fd_wksp_pod_detach( uchar const * pod );
948 :
949 : /* Ignoring error trapping, fd_wksp_pod_map( pod, path ) is shorthand
950 : for:
951 :
952 : fd_wksp_map( fd_pod_query_cstr( pod, path, NULL ) )
953 :
954 : Cannot fail from the caller's point of view (will terminate the
955 : thread group of the caller with detailed FD_LOG_ERR message on
956 : failure). Calls to fd_wksp_pod_map should be paired with calls to
957 : fd_wksp_pod_unmap. */
958 :
959 : void *
960 : fd_wksp_pod_map( uchar const * pod,
961 : char const * path );
962 :
963 : /* Ignoring error trapping, fd_wksp_pod_unmap( obj ) is shorthand for:
964 :
965 : fd_wksp_unmap( obj )
966 :
967 : Provided for symmetry with fd_wksp_pod_map. Cannot fail from the
968 : caller's point of view (will terminate the thread group of the caller
969 : with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
970 : if anything wonky occurs in the unmap under the hood). */
971 :
972 : void
973 : fd_wksp_pod_unmap( void * obj );
974 :
975 : /* io APIs ************************************************************/
976 :
977 : /* fd_wksp_checkpt_tpool will write the wksp's state to a file using
978 : tpool threads [t0,t1). Assumes the caller is thread t0 and threads
979 : (t0,t1) are available. The file will be located at path with UNIX
980 : style permissions given by mode. style specifies the checkpt style
981 : and should be a FD_WKSP_CHECKPT_STYLE_* value or 0 (0 indicates to
982 : use FD_WKSP_CHECKPT_STYLE_DEFAULT). uinfo points to a cstr with
983 : optional additional user context (NULL will be treated as the empty
984 : string "" ... if the strlen is longer than 16384 bytes, the info will
985 : be truncated to a strlen of 16383).
986 :
987 : Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
988 : (logs details). Reasons for failure include INVAL (NULL wksp, NULL
989 : path, bad mode, unsupported style), CORRUPT (wksp memory corruption
990 : detected), FAIL (fail already exists, I/O error). On failure, this
991 : will make a best effort to clean up after any partially written
992 : checkpt file.
993 :
994 : fd_wksp_checkpt is a convenience wrapper for serial checkpts. */
995 :
996 : int
997 : fd_wksp_checkpt_tpool( fd_tpool_t * tpool,
998 : ulong t0,
999 : ulong t1,
1000 : fd_wksp_t * wksp,
1001 : char const * path,
1002 : ulong mode,
1003 : int style,
1004 : char const * uinfo );
1005 :
1006 : static inline int
1007 : fd_wksp_checkpt( fd_wksp_t * wksp,
1008 : char const * path,
1009 : ulong mode,
1010 : int style,
1011 72 : char const * uinfo ) {
1012 72 : return fd_wksp_checkpt_tpool( NULL, 0UL, 1UL, wksp, path, mode, style, uinfo );
1013 72 : }
1014 :
1015 : /* fd_wksp_restore_tpool will replace all allocations in the current
1016 : workspace with the allocations from the checkpt at path. The
1017 : restored workspace will use the given seed. Tpool threads [t0,t1)
1018 : will be used for the restore. Assumes the caller is thread t0 and
1019 : threads (t0,t1) are available.
1020 :
1021 : IMPORTANT! It is okay for wksp to have a different size, backing
1022 : page sz and/or numa affinity than the original wksp. The only
1023 : requirements are the wksp be able to support as many allocations as
1024 : are in the checkpt and that these partitions can be restored to their
1025 : original positions in wksp's global address space. If wksp has
1026 : part_max in checkpt's [alloc_cnt,part_max] and a data_max>=checkpt's
1027 : data_max, this is guaranteed. Likewise, the number and range of
1028 : threads used on restore does _not_ need to match the range used on
1029 : checkpt.
1030 :
1031 : Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
1032 : (logs details). Reasons for failure include INVAL (NULL wksp, NULL
1033 : path), FAIL or CORRUPT (couldn't open checkpt, I/O error, checkpt
1034 : format error, incompatible wksp for checkpt, etc ... logs details).
1035 : For the INVAL and FAIL cases, the original workspace allocations was
1036 : untouched. For the CORRUPT case, original workspace allocations were
1037 : removed because the checkpt issues were detected after the restore
1038 : process began (a best effort to reset wksp to the empty state was
1039 : done before return).
1040 :
1041 : fd_wksp_restore is a convenience wrapper for serial restores. */
1042 :
1043 : int
1044 : fd_wksp_restore_tpool( fd_tpool_t * tpool,
1045 : ulong t0,
1046 : ulong t1,
1047 : fd_wksp_t * wksp,
1048 : char const * path,
1049 : uint seed );
1050 :
1051 : static inline int
1052 : fd_wksp_restore( fd_wksp_t * wksp,
1053 : char const * path,
1054 84 : uint seed ) {
1055 84 : return fd_wksp_restore_tpool( NULL, 0UL, 1UL, wksp, path, seed );
1056 84 : }
1057 :
1058 : /* fd_wksp_preview previews the wksp checkpt at path. On success,
1059 : returns FD_WKSP_SUCCESS (0), path seems to contain a supported wksp
1060 : checkpt and, if opt_preview was non-NULL, *opt_preview will contain,
1061 : at a minimum, the info needed to create a new wksp with the same
1062 : parameters as the wksp at path. On failure, returns a FD_WKSP_ERR
1063 : (negative, silent) and *_opt_preview is unchanged. Returns for
1064 : failure include INVAL (NULL path), FAIL (unable to read checkpt
1065 : header at path), CORRUPT (the leading bytes at path don't appear to
1066 : be a wksp checkpt). */
1067 :
1068 : struct fd_wksp_preview {
1069 : int style;
1070 : uint seed;
1071 : ulong part_max;
1072 : ulong data_max;
1073 : char name[ FD_SHMEM_NAME_MAX ]; /* cstr holding the original wksp name */
1074 : };
1075 :
1076 : typedef struct fd_wksp_preview fd_wksp_preview_t;
1077 :
1078 : int
1079 : fd_wksp_preview( char const * path,
1080 : fd_wksp_preview_t * _opt_preview );
1081 :
1082 : /* fd_wksp_printf pretty prints to fd (e.g. fileno(stdout)) information
1083 : about the wksp checkpt at path. verbose specifies the verbosity
1084 : level. Typical verbose levels are:
1085 :
1086 : <0 - do not print
1087 : 0 - preview info
1088 : 1 - verbose 0 + metadata
1089 : 2 - verbose 1 + build and user info
1090 : 3 - verbose 2 + partition summary info
1091 : 4 - verbose 3 + individual allocated partition metdata
1092 : >4 - verbose 4 + hex dumps of allocated partition data
1093 :
1094 : but this can vary for different checkpt styles. The return value has
1095 : the same interpretation as printf. */
1096 :
1097 : int
1098 : fd_wksp_printf( int fd,
1099 : char const * path,
1100 : int verbose );
1101 :
1102 : /* fd_wksp_mprotect marks all the memory in a workspace as read-only
1103 : (flag==1) or read-write (flag==0). Accessing read-only memory produces
1104 : a seg fault. */
1105 :
1106 : void
1107 : fd_wksp_mprotect( fd_wksp_t * wksp, int flag );
1108 :
1109 : FD_PROTOTYPES_END
1110 :
1111 : #endif /* HEADER_fd_src_util_wksp_fd_wksp_h */
|