Line data Source code
1 : #ifndef HEADER_fd_src_groove_fd_groove_volume_h 2 : #define HEADER_fd_src_groove_fd_groove_volume_h 3 : 4 : #include "fd_groove_base.h" /* includes ../util/fd_util.h */ 5 : 6 : /* Groove data objects are stored in groove volumes. A volume has a 7 : uniform size of FD_GROOVE_VOLUME_FOOTPRINT and a unique index. A 8 : volume is mapped into the caller's address space starting at 9 : (ulong)volume0+idx*FD_GROOVE_VOLUME_FOOTPRINT where volume0 is the 10 : start of a region in the user's address space with enough room to 11 : accommodate mapping current and future volumes. To support 12 : persistent and IPC usage across different applications, concurrent 13 : users can use different values for volume0. 14 : 15 : Volume indexing does not need to be contiguous or start at zero. 16 : Further, there is no theoretical limit on the number of volumes. 17 : Practically, the above implies that the address region footprint in 18 : the caller's address space is 19 : 20 : (max_idx_in_use+1)*FD_GROOVE_VOLUME_FOOTPRINT. 21 : 22 : As the FD machine model targets 64-bit address spaces, this implies a 23 : groove instance practically can hold at most < 2^64 B (16 EiB). 24 : (Note that 50 billion data objects at a worst case 10 MiB per object 25 : requires less than 0.5 EiB so this is not a limitation in practice.) 26 : 27 : To support commodity hardware and operating systems efficiently, 28 : volume0 should have at least normal page alignment and 29 : FD_GROOVE_VOLUME_FOOTPRINT should be a normal page multiple. For 30 : highest performance on such systems, 1 GiB aligned volume0 with 31 : gigantic page DRAM backed volumes are recommended but this is not 32 : required. E.g. it is fine for volumes to be a memory mapped file 33 : backed by a NVMe/SSD/RAID array. This implementation uses a 34 : FD_GROOVE_VOLUME_FOOTPRINT of 1 GiB. 35 : 36 : Volumes can be backed by different technologies. Note that while 37 : heterogeneous volumes are supported, this implementation does not 38 : treat a volume backed by fast DRAM differently from a volume backed 39 : by a tape drive. 40 : 41 : Empty groove volumes are stored on a lockfree stack to support adding 42 : / removing volumes from a groove instance dynamically without 43 : impacting on-going groove operations. E.g. to increase the groove's 44 : capacity, create a volume at an unused index and lockfree push it 45 : onto the groove's empty volume stack. To decrease capacity, pop the 46 : stack and reclaim the returned volume. */ 47 : 48 : /* FIXME: consider allowing larger volume headers (or adding a 49 : volume footer) to not waste ~15KiB space with pading */ 50 : 51 : #define FD_GROOVE_VOLUME_ALIGN (4096UL) 52 507 : #define FD_GROOVE_VOLUME_FOOTPRINT (1UL<<30) 53 449592 : #define FD_GROOVE_VOLUME_MAGIC (0xfd67007e701c3300) /* fd groove volume version 0 */ 54 136366497 : #define FD_GROOVE_VOLUME_INFO_MAX (FD_GROOVE_BLOCK_FOOTPRINT-32UL) 55 15 : #define FD_GROOVE_VOLUME_DATA_MAX (FD_GROOVE_VOLUME_FOOTPRINT-FD_GROOVE_BLOCK_FOOTPRINT) 56 : 57 : struct __attribute__((aligned(FD_GROOVE_VOLUME_ALIGN))) fd_groove_volume { 58 : 59 : /* This point is aligned FD_GROOVE_VOLUME_ALIGN >= FD_GROOVE_BLOCK_ALIGN */ 60 : 61 : ulong magic; /* == FD_GROOVE_VOLUME_MAGIC if volume potentially contains groove data allocations, 62 : ==~FD_GROOVE_VOLUME_MAGIC if volume contains no groove data allocations, 63 : other values -> not a volume */ 64 : ulong idx; /* Volume index (this is mapped into the user's address space at groove->volume0 + idx) */ 65 : ulong next; /* Managed by the groove volume pool */ 66 : ulong info_sz; /* in [0,INFO_MAX] */ 67 : 68 : /* This point is aligned 32 */ 69 : 70 : uchar info[ FD_GROOVE_VOLUME_INFO_MAX ]; /* info_sz bytes of user info, bytes [info_sz,INFO_MAX) are arbitrary */ 71 : 72 : /* This point is aligned FD_GROOVE_BLOCK_ALIGN */ 73 : 74 : uchar data[ FD_GROOVE_VOLUME_DATA_MAX ]; 75 : }; 76 : 77 : typedef struct fd_groove_volume fd_groove_volume_t; 78 : 79 : /* Note: given a 2^30 volume footprint, a POOL_IDX_WIDTH of 34 80 : supports up ~2^34 volumes for up to a ~2^64 groove data storage. 81 : (For the default pool index width, this could go as high as 82 : fd_groove_pool_max_max ~ 2^43 but it would not be possible to memory 83 : map such a set of volumes on 64-bit architectures.) */ 84 : 85 : #define POOL_NAME fd_groove_volume_pool 86 : #define POOL_ELE_T fd_groove_volume_t 87 4496757 : #define POOL_IDX_WIDTH (34) 88 : #define POOL_MAGIC (0xfd67007e70190010UL) /* fd groove vol pool version 0 */ 89 : #define POOL_IMPL_STYLE 1 90 : #include "../util/tmpl/fd_pool_para.c" 91 : 92 : FD_PROTOTYPES_BEGIN 93 : 94 : /* fd_groove_volume_pool_add adds the footprint sized memory region 95 : whose first byte is at shmem in the caller's local address space to 96 : the pool. Assumes pool is a current local join, the storage to add 97 : is mapped into a memory region that starts and stops at a 98 : FD_GROOVE_VOLUME_FOOTPRINT multiple offset in the pool's address 99 : space, and this memory region does not conflict with any current 100 : groove volumes. 101 : 102 : The volume info for these will be initialized to the info_sz bytes 103 : pointed in the caller's local address space by info. info_sz will 104 : treated as zero if info is NULL. info_sz>FD_GROOVE_VOLUME_INFO_MAX 105 : will be treated as FD_GROOVE_VOLUME_INFO_MAX. If 106 : info_sz<FD_GROOVE_VOLUME_INFO_MAX, any uninitialized bytes info will 107 : be initialized to zero. Retains no interest in info. 108 : 109 : It is the caller's responsibility to zero / initialize any volume 110 : data region bytes (usually not necessary). 111 : 112 : On success, returns FD_GROOVE_SUCCESS (zero), the volumes were added 113 : to the pool as empty and the pool has ownership of the volumes. 114 : 115 : On failure, returns a FD_GROOVE_ERR code (negative, logs details). 116 : Reasons for failure include INVAL (pool is obviously not a local 117 : join, shmem/footprint obviously not a valid mapping ... no volumes 118 : added) and CORRUPT (memory corruption was detected ... if this was 119 : adding multiple volumes, some volumes might have been added before 120 : the corruption was encountered). 121 : 122 : This is safe to use concurrently, will not block the caller 123 : (reasonably fast O(volume_cnt) worst case) and will not block 124 : concurrent pool users. */ 125 : 126 : int 127 : fd_groove_volume_pool_add( fd_groove_volume_pool_t * pool, 128 : void * shmem, 129 : ulong footprint, 130 : void const * info, 131 : ulong info_sz ); 132 : 133 : /* fd_groove_volume_pool_remove removes an empty volume from the pool. 134 : On success, returns the location in the caller's address space of the 135 : removed volume (the volume will no longer be in the pool and the 136 : caller has ownership). On failure, returns NULL (e.g. no volumes in 137 : pool were empty at some point during the call). Logs details if 138 : anything wonky was detected. 139 : 140 : This is safe to use concurrently, will not block the caller 141 : (reasonably fast O(1) worst case) and will not block concurrent pool 142 : users. */ 143 : 144 : void * 145 : fd_groove_volume_pool_remove( fd_groove_volume_pool_t * pool ); 146 : 147 : FD_PROTOTYPES_END 148 : 149 : #endif /* HEADER_fd_src_groove_fd_groove_volume_h */