• 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-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