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-2020 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 91 /** 92 * @brief File resize policy function type. 93 * 94 * This function called in the following cases: 95 * - When a file needs to be resized. Returned new file size cannot 96 * be lesser than requested @a nsize and must be `page aligned`. 97 * - When a file is closed. In this case the first argument @a nsize 98 * will be set to `-1` and function should return `0`. 99 * This call can be used in order to release resources allocated for @a ctx 100 * private data used in function. 101 * 102 * @param nsize Desired file size. 103 * @param csize Current file size. 104 * @param f File reference. 105 * @param ctx Function context data pointer. A function is allowed to initialize 106 * this pointer by own private data stucture. 107 * 108 * @return Computed new file size. 109 */ 110 typedef off_t (*IW_EXT_RSPOLICY)(off_t nsize, off_t csize, struct IWFS_EXT *f, 111 void **ctx); 112 113 /** 114 * @brief Fibonacci resize file policy. 115 * 116 * New `file_size(n+1) = MAX(file_size(n) + file_size(n-1), nsize)` 117 */ 118 IW_EXPORT off_t iw_exfile_szpolicy_fibo(off_t nsize, off_t csize, 119 struct IWFS_EXT *f, void **ctx); 120 121 /** 122 * @brief Rational number `IW_RNUM` file size multiplication policy. 123 * 124 * New `file_size = MAX(file_size * (N/D), nsize)` 125 */ 126 IW_EXPORT off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize, 127 struct IWFS_EXT *f, void **ctx); 128 129 /** 130 * @brief `IWFS_EXT` file options. 131 * @see iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts) 132 */ 133 typedef struct IWFS_EXT_OPTS { 134 IWFS_FILE_OPTS file; /**< Underlying file options */ 135 off_t initial_size; /**< Initial file size */ 136 bool use_locks; /**< If `true` file operations will be guarded by rw lock. Default: `false` */ 137 138 IW_EXT_RSPOLICY rspolicy; /**< File resize policy function ptr. Default: 139 `exact size policy` */ 140 void *rspolicy_ctx; /**< Custom opaque data for policy functions. 141 Default: `0` */ 142 uint64_t maxoff; /**< Maximum allowed file offset. Unlimited if zero. 143 If maximum offset is reached `IWFS_ERROR_MAXOFF` will be reported. */ 144 } IWFS_EXT_OPTS; 145 146 /** 147 * @struct IWFS_EXT_STATE 148 * @brief `IWFS_EXT` file state info. 149 * @see IWFS_EXT::state 150 */ 151 typedef struct IWFS_EXT_STATE { 152 IWFS_FILE_STATE file; /**< Simple file state */ 153 off_t fsize; /**< Current file size */ 154 } IWFS_EXT_STATE; 155 156 /** 157 * @brief Auto-expandable file. 158 */ 159 typedef struct IWFS_EXT { 160 struct IWFS_EXT_IMPL *impl; 161 162 /** 163 * @brief Ensures that a file's physical address space contains a given offset 164 * @a off 165 * 166 * Various algorithms can be used for new space allocation, 167 * see the features section for further explanation. 168 * 169 * @param f `IWFS_EXT` 170 * @param off File offset what have to be within physically allocated file 171 * address space. 172 * @return `0` on success or error code. 173 * 174 * @see off_t iw_exfile_szpolicy_fibo(off_t nsize, off_t csize, struct 175 * IWFS_EXT *f, void **ctx) 176 * @see off_t iw_exfile_szpolicy_mul(off_t nsize, off_t csize, struct IWFS_EXT 177 * *f, void **ctx) 178 */ 179 iwrc(*ensure_size)(struct IWFS_EXT *f, off_t off); 180 181 /** 182 * @brief Set the end of this file to the specified offset @a off exactly. 183 */ 184 iwrc(*truncate)(struct IWFS_EXT *f, off_t off); 185 186 iwrc(*truncate_unsafe)(struct IWFS_EXT *f, off_t off); 187 188 /** 189 * @brief Register an address space specified by @a off and @a len as memory 190 * mmaped region 191 * within this file. 192 * 193 * It is not required for this region be physically represented in the file's 194 * address space. 195 * As soon as this region will be used for reading/writing it will be mmaped 196 * and direct mmaped memory access will be used for IO in this area. 197 * 198 * For example: 199 * @code {.c} 200 * f.add_mmap(&f, 10, 20); 201 * f.read(&f, 5, buf, 10, sp); // read [5-15) bytes 202 * // [5-10) bytes will be read using system `pread` 203 * // [10-15) bytes will be retrieved by direct `memcpy` from mmapped 204 * region 205 * @endcode 206 * 207 * Pointer to this region can be retrieved by `IWFS_EXT::acquire_mmap` 208 * 209 * @param f `IWFS_EXT` 210 * @param off Offset of mmaped region 211 * @param len Length of mmaped region 212 * @return `0` on success or error code. 213 */ 214 iwrc(*add_mmap)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts); 215 216 iwrc(*add_mmap_unsafe)(struct IWFS_EXT *f, off_t off, size_t len, iwfs_ext_mmap_opts_t opts); 217 218 /** 219 * @brief Retrieve mmaped region by its offset @a off and keep file as read locked. 220 * 221 * If region was not mmaped previously with IWFS_EXT::add_mmap 222 * the `IWFS_ERROR_NOT_MMAPED` error code will be returned. 223 * 224 * WARNING: Internal read lock will be acquired and 225 * must be released by subsequent `release_mmap()` call 226 * after all activity with mmaped region has finished. 227 * 228 * @param f `IWFS_EXT` 229 * @param off Region start offset 230 * @param [out] mm Pointer assigned to start of mmaped region of `NULL` if 231 * error occurred. 232 * @param [out] sp Length of region 233 * @return `0` on success or error code. 234 */ 235 iwrc(*acquire_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 236 237 /** 238 * @brief Retrieve mmaped region by its offset @a off 239 */ 240 iwrc(*probe_mmap)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 241 242 iwrc(*probe_mmap_unsafe)(struct IWFS_EXT *f, off_t off, uint8_t **mm, size_t *sp); 243 244 /** 245 * @brief Release the lock acquired by successfull call of `acquire_mmap()` 246 */ 247 iwrc(*release_mmap)(struct IWFS_EXT *f); 248 249 /** 250 * @brief Unmap mmaped region identified by @a off 251 * 252 * The `IWFS_ERROR_NOT_MMAPED` will returned 253 * if region was not previously mapped with IWFS_EXT::add_mmap 254 * 255 * @param f `IWFS_EXT` 256 * @param off Region start offset 257 * @return `0` on success or error code. 258 */ 259 iwrc(*remove_mmap)(struct IWFS_EXT *f, off_t off); 260 261 iwrc(*remove_mmap_unsafe)(struct IWFS_EXT *f, off_t off); 262 263 /** 264 * @brief Synchronize a file with a mmaped region identified by @a off offset. 265 * 266 * The `IWFS_ERROR_NOT_MMAPED` will returned 267 * if region was not previously mapped with IWFS_EXT::add_mmap 268 * 269 * @param f `IWFS_EXT` 270 * @param off Region start offset 271 * @param flags Sync flags. 272 * @return `0` on success or error code. 273 */ 274 iwrc(*sync_mmap)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags); 275 276 iwrc(*sync_mmap_unsafe)(struct IWFS_EXT *f, off_t off, iwfs_sync_flags flags); 277 278 /** 279 * @brief Remap all mmaped regions. 280 * 281 * @param f `IWFS_EXT` 282 */ 283 iwrc(*remap_all)(struct IWFS_EXT *f); 284 285 /* See iwfile.h */ 286 287 /** @see IWFS_FILE::write */ 288 iwrc(*write)(struct IWFS_EXT *f, off_t off, const void *buf, size_t siz, 289 size_t *sp); 290 291 /** @see IWFS_FILE::read */ 292 iwrc(*read)(struct IWFS_EXT *f, off_t off, void *buf, size_t siz, 293 size_t *sp); 294 295 /** @see IWFS_FILE::close */ 296 iwrc(*close)(struct IWFS_EXT *f); 297 298 /** @see IWFS_FILE::sync */ 299 iwrc(*sync)(struct IWFS_EXT *f, iwfs_sync_flags flags); 300 301 /** @see IWFS_FILE::state */ 302 iwrc(*state)(struct IWFS_EXT *f, IWFS_EXT_STATE *state); 303 304 /** @see IWFS_FILE::copy */ 305 iwrc(*copy)(struct IWFS_EXT *f, off_t off, size_t siz, off_t noff); 306 307 } IWFS_EXT; 308 309 /** 310 * @brief Open exfile. 311 * 312 * <strong>Example:</strong> 313 * 314 * Open a file for multithreaded env with fibonacci file resize policy and 315 * initial size to 4K 316 * 317 * @code {.c} 318 * IWFS_EXT_OPTS opts = { 319 * .file = { 320 * .path = "myfile.dat", 321 * .omode = IWFS_OWRITE | IWFS_OCREATE, 322 * .lock_mode = IWP_WLOCK 323 * }, 324 * .initial_size = 4096, 325 * .use_locks = true, 326 * .rspolicy = iw_exfile_szpolicy_fibo 327 * }; 328 * IWFS_EXT f; 329 * iwrc rc = iwfs_exfile_open(&f, &opts); 330 * 331 * rc = f.write(&f, ...); 332 * ... 333 * @endcode 334 * 335 * 336 * @param f Exfile handle. Simple memory placeholder. 337 * @param opts File open options. Initialized file options. 338 * @return Error code of `0` on success. 339 * @relatesalso IWFS_EXT 340 */ 341 IW_EXPORT WUR iwrc iwfs_exfile_open(IWFS_EXT *f, const IWFS_EXT_OPTS *opts); 342 343 /** 344 * @brief Init `iwexfile` submodule. 345 */ 346 IW_EXPORT WUR iwrc iwfs_exfile_init(void); 347 348 IW_EXTERN_C_END 349 350 #endif 351