1 #pragma once 2 #ifndef IWEXFILE_H 3 #define IWEXFILE_H 4 5 /************************************************************************************************** 6 * IOWOW library 7 * 8 * MIT License 9 * 10 * Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com> 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a copy 13 * of this software and associated documentation files (the "Software"), to deal 14 * in the Software without restriction, including without limitation the rights 15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 * copies of the Software, and to permit persons to whom the Software is 17 * furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included in all 20 * copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 * SOFTWARE. 29 *************************************************************************************************/ 30 31 /** @file 32 * @brief Auto-expandable file. 33 * @author Anton Adamansky (adamansky@softmotions.com) 34 * 35 * @note Before using API of this module you should call 36 * 37 * `iw_init(void)` iowow module initialization routine. 38 * 39 * <strong>Features:</strong> 40 * - Tuneable file expansion policies. 41 * Custom file resize policies supported by specifying 42 * `IWFS_EXT_OPTS::rspolicy` option value. 43 * The following policies are implemented: 44 * - Exact. File resizing fits exactly to the size required by `write` 45 * operation. This is the default behaviour. 46 * - Fibonacci policy. Next file size computed accourding to 47 * fibonacci sequence of previous file sizes: 48 `file_size(n+1) = MAX(file_size(n) + file_size(n-1), nsize)` 49 * - Multiplication resize policy. Next file size: 50 `file_size(n+1) = N * file_size(n)` where 51 * `N` is a rational number `IW_RNUM` greater than `1` 52 * - Read/write locking over a file's address space in multithreaded 53 * environment. 54 * - File shrinking/truncation support. 55 * - A number mmaped regions can be registered in the file's address space. 56 * These regions used in read/write operation and automatically maintained 57 * during file resize operations. 58 * 59 * File operations implemented as function pointers contained in `IWFS_EXT` `C` 60 * structure. 61 * The `iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts);` opens 62 * file and initializes a given `IWFS_EXT` structure. 63 */ 64 65 #include "iwfile.h" 66 67 IW_EXTERN_C_START 68 69 struct IWFS_EXT_OPTS; 70 struct IWFS_EXT; 71 72 /** 73 * @enum iwfs_ext_ecode 74 * @brief Error codes specific to this module. 75 */ 76 typedef enum { 77 _IWFS_EXT_ERROR_START = (IW_ERROR_START + 3000UL), 78 IWFS_ERROR_MMAP_OVERLAP, /**< Region is mmaped already, mmaping overlaps */ 79 IWFS_ERROR_NOT_MMAPED, /**< Region is not mmaped */ 80 IWFS_ERROR_RESIZE_POLICY_FAIL, /**< Invalid result of resize policy function.*/ 81 IWFS_ERROR_MAXOFF, /**< Maximum file offset reached. */ 82 _IWFS_EXT_ERROR_END, 83 } iwfs_ext_ecode; 84 85 typedef uint8_t iwfs_ext_mmap_opts_t; 86 /** Use shared mmaping synchronized with file data */ 87 #define IWFS_MMAP_SHARED ((iwfs_ext_mmap_opts_t) 0x00U) 88 /** Use private mmap */ 89 #define IWFS_MMAP_PRIVATE ((iwfs_ext_mmap_opts_t) 0x01U) 90 /** Use mmap in random access pattern */ 91 #define IWFS_MMAP_RANDOM ((iwfs_ext_mmap_opts_t) 0x02U) 92 93 /** 94 * @brief File resize policy function type. 95 * 96 * This function called in the following cases: 97 * - When a file needs to be resized. Returned new file size cannot 98 * be lesser than requested @a nsize and must be `page aligned`. 99 * - When a file is closed. In this case the first argument @a nsize 100 * will be set to `-1` and function should return `0`. 101 * This call can be used in order to release resources allocated for @a ctx 102 * private data used in function. 103 * 104 * @param nsize Desired file size. 105 * @param csize Current file size. 106 * @param f File reference. 107 * @param ctx Function context data pointer. A function is allowed to initialize 108 * this pointer by own private data stucture. 109 * 110 * @return Computed new file size. 111 */ 112 typedef off_t (*IW_EXT_RSPOLICY)( 113 off_t nsize, off_t csize, struct IWFS_EXT *f, 114 void **ctx); 115 116 /** 117 * @brief Fibonacci resize file policy. 118 * 119 * New `file_size(n+1) = MAX(file_size(n) + file_size(n-1), nsize)` 120 */ 121 IW_EXPORT off_t iw_exfile_szpolicy_fibo( 122 off_t nsize, off_t csize, 123 struct IWFS_EXT *f, void **ctx); 124 125 /** 126 * @brief Rational number `IW_RNUM` file size multiplication policy. 127 * 128 * New `file_size = MAX(file_size * (N/D), nsize)` 129 */ 130 IW_EXPORT off_t iw_exfile_szpolicy_mul( 131 off_t nsize, off_t csize, 132 struct IWFS_EXT *f, void **ctx); 133 134 /** 135 * @brief `IWFS_EXT` file options. 136 * @see iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts) 137 */ 138 typedef struct IWFS_EXT_OPTS { 139 IWFS_FILE_OPTS file; /**< Underlying file options */ 140 off_t initial_size; /**< Initial file size */ 141 bool use_locks; /**< If `true` file operations will be guarded by rw lock. Default: `false` */ 142 143 IW_EXT_RSPOLICY rspolicy; /**< File resize policy function ptr. Default: 144 `exact size policy` */ 145 void *rspolicy_ctx; /**< Custom opaque data for policy functions. 146 Default: `0` */ 147 uint64_t maxoff; /**< Maximum allowed file offset. Unlimited if zero. 148 If maximum offset is reached `IWFS_ERROR_MAXOFF` will be reported. */ 149 } IWFS_EXT_OPTS; 150 151 /** 152 * @struct IWFS_EXT_STATE 153 * @brief `IWFS_EXT` file state info. 154 * @see IWFS_EXT::state 155 */ 156 typedef struct IWFS_EXT_STATE { 157 IWFS_FILE_STATE file; /**< Simple file state */ 158 off_t fsize; /**< Current file size */ 159 } IWFS_EXT_STATE; 160 161 /** 162 * @brief Auto-expandable file. 163 */ 164 typedef struct IWFS_EXT { 165 struct IWFS_EXT_IMPL *impl; 166 167 /** 168 * @brief Ensures that a file's physical address space contains a given offset 169 * @a off 170 * 171 * Various algorithms can be used for new space allocation, 172 * see the features section for further explanation. 173 * 174 * @param f `IWFS_EXT` 175 * @param off File offset what have to be within physically allocated file 176 * address space. 177 * @return `0` on success or error code. 178 * 179 * @see off_t iw_exfile_szpolicy_fibo(off_t nsize, off_t csize, struct 180 * IWFS_EXT *f, void **ctx) 181 * @see off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize, struct IWFS_EXT 182 * *f, void **ctx) 183 */ 184 iwrc (*ensure_size)(struct IWFS_EXT *f, off_t off); 185 186 /** 187 * @brief Set the end of this file to the specified offset @a off exactly. 188 */ 189 iwrc (*truncate)(struct IWFS_EXT *f, off_t off); 190 191 iwrc (*truncate_unsafe)(struct IWFS_EXT *f, off_t off); 192 193 /** 194 * @brief Register an address space specified by @a off and @a len as memory 195 * mmaped region 196 * within this file. 197 * 198 * It is not required for this region be physically represented in the file's 199 * address space. 200 * As soon as this region will be used for reading/writing it will be mmaped 201 * and direct mmaped memory access will be used for IO in this area. 202 * 203 * For example: 204 * @code {.c} 205 * f.add_mmap(&f, 10, 20); 206 * f.read(&f, 5, buf, 10, sp); // read [5-15) bytes 207 * // [5-10) bytes will be read using system `pread` 208 * // [10-15) bytes will be retrieved by direct `memcpy` from mmapped 209 * region 210 * @endcode 211 * 212 * Pointer to this region can be retrieved by `IWFS_EXT::acquire_mmap` 213 * 214 * @param f `IWFS_EXT` 215 * @param off Offset of mmaped region 216 * @param len Length of mmaped region 217 * @return `0` on success or error code. 218 */ 219 iwrc (*add_mmap)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts); 220 221 iwrc (*add_mmap_unsafe)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts); 222 223 /** 224 * @brief Retrieve mmaped region by its offset @a off and keep file as read locked. 225 * 226 * If region was not mmaped previously with IWFS_EXT::add_mmap 227 * the `IWFS_ERROR_NOT_MMAPED` error code will be returned. 228 * 229 * WARNING: Internal read lock will be acquired and 230 * must be released by subsequent `release_mmap()` call 231 * after all activity with mmaped region has finished. 232 * 233 * @param f `IWFS_EXT` 234 * @param off Region start offset 235 * @param [out] mm Pointer assigned to start of mmaped region of `NULL` if 236 * error occurred. 237 * @param [out] sp Length of region 238 * @return `0` on success or error code. 239 */ 240 iwrc (*acquire_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 241 242 /** 243 * @brief Retrieve mmaped region by its offset @a off 244 */ 245 iwrc (*probe_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 246 247 iwrc (*probe_mmap_unsafe)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 248 249 /** 250 * @brief Release the lock acquired by successfull call of `acquire_mmap()` 251 */ 252 iwrc (*release_mmap)(struct IWFS_EXT *f); 253 254 /** 255 * @brief Unmap mmaped region identified by @a off 256 * 257 * The `IWFS_ERROR_NOT_MMAPED` will returned 258 * if region was not previously mapped with IWFS_EXT::add_mmap 259 * 260 * @param f `IWFS_EXT` 261 * @param off Region start offset 262 * @return `0` on success or error code. 263 */ 264 iwrc (*remove_mmap)(struct IWFS_EXT *f, off_t off); 265 266 iwrc (*remove_mmap_unsafe)(struct IWFS_EXT *f, off_t off); 267 268 /** 269 * @brief Synchronize a file with a mmaped region identified by @a off offset. 270 * 271 * The `IWFS_ERROR_NOT_MMAPED` will returned 272 * if region was not previously mapped with IWFS_EXT::add_mmap 273 * 274 * @param f `IWFS_EXT` 275 * @param off Region start offset 276 * @param flags Sync flags. 277 * @return `0` on success or error code. 278 */ 279 iwrc (*sync_mmap)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags); 280 281 iwrc (*sync_mmap_unsafe)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags); 282 283 /** 284 * @brief Remap all mmaped regions. 285 * 286 * @param f `IWFS_EXT` 287 */ 288 iwrc (*remap_all)(struct IWFS_EXT *f); 289 290 /* See iwfile.h */ 291 292 /** @see IWFS_FILE::write */ 293 iwrc (*write)( 294 struct IWFS_EXT *f, off_t off, const void *buf, size_t siz, 295 size_t *sp); 296 297 /** @see IWFS_FILE::read */ 298 iwrc (*read)( 299 struct IWFS_EXT *f, off_t off, void *buf, size_t siz, 300 size_t *sp); 301 302 /** @see IWFS_FILE::close */ 303 iwrc (*close)(struct IWFS_EXT *f); 304 305 /** @see IWFS_FILE::sync */ 306 iwrc (*sync)(struct IWFS_EXT *f, iwfs_sync_flags flags); 307 308 /** @see IWFS_FILE::state */ 309 iwrc (*state)(struct IWFS_EXT *f, IWFS_EXT_STATE *state); 310 311 /** @see IWFS_FILE::copy */ 312 iwrc (*copy)(struct IWFS_EXT *f, off_t off, size_t siz, off_t noff); 313 } IWFS_EXT; 314 315 /** 316 * @brief Open exfile. 317 * 318 * <strong>Example:</strong> 319 * 320 * Open a file for multithreaded env with fibonacci file resize policy and 321 * initial size to 4K 322 * 323 * @code {.c} 324 * IWFS_EXT_OPTS opts = { 325 * .file = { 326 * .path = "myfile.dat", 327 * .omode = IWFS_OWRITE | IWFS_OCREATE, 328 * .lock_mode = IWP_WLOCK 329 * }, 330 * .initial_size = 4096, 331 * .use_locks = true, 332 * .rspolicy = iw_exfile_szpolicy_fibo 333 * }; 334 * IWFS_EXT f; 335 * iwrc rc = iwfs_exfile_open(&f, &opts); 336 * 337 * rc = f.write(&f, ...); 338 * ... 339 * @endcode 340 * 341 * 342 * @param f Exfile handle. Simple memory placeholder. 343 * @param opts File open options. Initialized file options. 344 * @return Error code of `0` on success. 345 * @relatesalso IWFS_EXT 346 */ 347 IW_EXPORT WUR iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts); 348 349 /** 350 * @brief Init `iwexfile` submodule. 351 */ 352 IW_EXPORT WUR iwrc iwfs_exfile_init(void); 353 354 IW_EXTERN_C_END 355 356 #endif 357