• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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