xref: /openbsd-src/usr.sbin/nsd/udb.h (revision b71395ea3d4830c6fd338870b804059761b8292d)
1d3fecca9Ssthen /* udb.h - u(micro) data base, stores data and index information in mmap file.
2d3fecca9Ssthen  * By W.C.A. Wijngaards
3d3fecca9Ssthen  * Copyright 2010, NLnet Labs.
4d3fecca9Ssthen  * BSD, see LICENSE.
5d3fecca9Ssthen  */
6d3fecca9Ssthen #ifndef UDB_H
7d3fecca9Ssthen #define UDB_H
8d3fecca9Ssthen #include <assert.h>
9d3fecca9Ssthen 
10d3fecca9Ssthen /**
11d3fecca9Ssthen  * The micro data base UDB.
12d3fecca9Ssthen  *
13d3fecca9Ssthen  * File data.udb is mmapped and used to lookup and edit.
14d3fecca9Ssthen  * it contains a header with space-allocation-info, and a reference to the
15d3fecca9Ssthen  * base information, an object that is the entry point for the file.
16d3fecca9Ssthen  * Then it contains a lot of data and index objects.
17d3fecca9Ssthen  *
18d3fecca9Ssthen  * The space allocator is 'buddy system', 1megareas, larger get own area.
19d3fecca9Ssthen  * So worst case is 2xdata filesize (+header).  Growth semi-linear.
20d3fecca9Ssthen  * Chunks have size and type (for recovery).  Call to reserve space.
21d3fecca9Ssthen  * Call to 'realloc-in-place', if space permits.
22d3fecca9Ssthen  *
23d3fecca9Ssthen  * Usually you want a record-type and its indexes (sorted) to be stored in
24d3fecca9Ssthen  * the file.  This is a table (named by string).  The record is opaque
25d3fecca9Ssthen  * data.
26d3fecca9Ssthen  *
27d3fecca9Ssthen  * To be able to use pointers in the mmapped file, there is conversion of
28d3fecca9Ssthen  * relative-pointers(to file base) to system-pointers.
29d3fecca9Ssthen  *
30d3fecca9Ssthen  * If an item is moved its internal pointers need to be recalculated.
31d3fecca9Ssthen  * Thus a recordtype (that has internal pointers) must provide a routine.
32d3fecca9Ssthen  * Structures that are 'on-disk', are denoted with _d. Except rel_ptr which
33d3fecca9Ssthen  * is also on-disk.
34d3fecca9Ssthen  *
35d3fecca9Ssthen  * About 64-bit trouble.  The pointer-size which which the application is
36d3fecca9Ssthen  * compiled determines the file layout, because this makes it perform well
37d3fecca9Ssthen  * in a mmap.  It could in theory be converted if you really wanted to.
38d3fecca9Ssthen  * Nonpointer data is best stored as a fixed bitsize (uint8, 16, 32, 64).
39d3fecca9Ssthen  */
40d3fecca9Ssthen typedef struct udb_base udb_base;
41d3fecca9Ssthen typedef struct udb_alloc udb_alloc;
42d3fecca9Ssthen 
43ab0a6c35Ssthen /** these checks are very slow, disabled by default */
44ab0a6c35Ssthen #if 0
45d3fecca9Ssthen /** perform extra checks (when --enable-checking is used) */
46d3fecca9Ssthen #ifndef NDEBUG
47d3fecca9Ssthen #define UDB_CHECK 1
48d3fecca9Ssthen #endif
49ab0a6c35Ssthen #endif
50d3fecca9Ssthen 
51d3fecca9Ssthen /** pointers are stored like this */
52d3fecca9Ssthen typedef uint64_t udb_void;
53d3fecca9Ssthen 
54d3fecca9Ssthen /** convert relptr to usable pointer */
55308d2509Sflorian #define UDB_REL(base, relptr) ((void*)((char*)(base) + (relptr)))
56d3fecca9Ssthen /** from system pointer to relative pointer */
57308d2509Sflorian #define UDB_SYSTOREL(base, ptr) ((udb_void)((char*)(ptr) - (char*)(base)))
58d3fecca9Ssthen 
59d3fecca9Ssthen /** MAX 2**x exponent of alloced chunks, for 1Mbytes.  The smallest
60d3fecca9Ssthen  * chunk is 16bytes (8preamble+8data), so 0-3 is unused. */
61d3fecca9Ssthen #define UDB_ALLOC_CHUNKS_MAX 20
62d3fecca9Ssthen /** size of areas that are subdivided */
63d3fecca9Ssthen #define UDB_ALLOC_CHUNK_SIZE ((uint64_t)1<<UDB_ALLOC_CHUNKS_MAX)
64d3fecca9Ssthen /** the minimum alloc in exp, 2**x.  32bytes because of chunk_free_d size (8aligned) */
65d3fecca9Ssthen #define UDB_ALLOC_CHUNK_MINEXP 5
66d3fecca9Ssthen /** size of minimum alloc */
67d3fecca9Ssthen #define UDB_ALLOC_CHUNK_MINSIZE ((uint64_t)1<<UDB_ALLOC_CHUNK_MINEXP)
68d3fecca9Ssthen /** exp size used to mark the header (cannot be reallocated) */
69d3fecca9Ssthen #define UDB_EXP_HEADER 0
70d3fecca9Ssthen /** exp size used to mark XL(extralarge) allocations (in whole mbs) */
71d3fecca9Ssthen #define UDB_EXP_XL 1
72d3fecca9Ssthen 
73d3fecca9Ssthen typedef struct udb_ptr udb_ptr;
74d3fecca9Ssthen /**
75d3fecca9Ssthen  * This structure is there for when you want to have a pointer into
76d3fecca9Ssthen  * the mmap-ed file.  It is kept track of.  Set it to NULL to unlink it.
77d3fecca9Ssthen  * For pointers to the mmap-ed file from within the mmap-ed file, use the
78d3fecca9Ssthen  * rel_pre construct below.
79d3fecca9Ssthen  */
80d3fecca9Ssthen struct udb_ptr {
81d3fecca9Ssthen 	/** the data segment it points to (relative file offset) */
82d3fecca9Ssthen 	uint64_t data;
83d3fecca9Ssthen 	/** pointer to the base pointer (for convenience) */
84d3fecca9Ssthen 	void** base;
85d3fecca9Ssthen 	/** prev in udb_ptr list for this data segment */
86d3fecca9Ssthen 	udb_ptr* prev;
87d3fecca9Ssthen 	/** next in udb_ptr list for this data segment */
88d3fecca9Ssthen 	udb_ptr* next;
89d3fecca9Ssthen };
90d3fecca9Ssthen 
91d3fecca9Ssthen typedef struct udb_rel_ptr udb_rel_ptr;
92d3fecca9Ssthen /**
93d3fecca9Ssthen  * A relative pointer that keeps track of the list of pointers,
94d3fecca9Ssthen  * so that it can be reallocated.
95d3fecca9Ssthen  */
96d3fecca9Ssthen struct udb_rel_ptr {
97d3fecca9Ssthen 	/** the relative pointer to the data itself (subtract chunk_d size
98d3fecca9Ssthen 	 * to get the chunk_d type, this is for usage speed in dereferencing
99d3fecca9Ssthen 	 * to the userdata). */
100d3fecca9Ssthen 	udb_void data;
101d3fecca9Ssthen 	/** udb_rel_ptr* prev in relptr list */
102d3fecca9Ssthen 	udb_void prev;
103d3fecca9Ssthen 	/** udb_rel_ptr* next in relptr list */
104d3fecca9Ssthen 	udb_void next;
105d3fecca9Ssthen };
106d3fecca9Ssthen 
107d3fecca9Ssthen /**
108d3fecca9Ssthen  * This is the routine that is called for every relptr
109d3fecca9Ssthen  * @param base: the baseptr for REL.
110d3fecca9Ssthen  * @param p: the relptr, a real pointer to it.
111d3fecca9Ssthen  * @param arg: user argument.
112d3fecca9Ssthen  */
113d3fecca9Ssthen typedef void udb_walk_relptr_cb(void*, udb_rel_ptr*, void*);
114d3fecca9Ssthen 
115d3fecca9Ssthen /**
116d3fecca9Ssthen  * This routine calls the callback for every relptr in a datablock
117d3fecca9Ssthen  * params in order:
118d3fecca9Ssthen  * base: the baseptr for REL macro.
119d3fecca9Ssthen  * warg: the walkfunc user argument.
120d3fecca9Ssthen  * t: the type of the chunk.
121d3fecca9Ssthen  * d: pointer to the data part of the chunk (real pointer).
122d3fecca9Ssthen  * s: max size of the data part.
123d3fecca9Ssthen  * cb: the callback to call for every element.
124d3fecca9Ssthen  * arg: user argument to pass to the callback.
125d3fecca9Ssthen  */
126d3fecca9Ssthen typedef void udb_walk_relptr_func(void*, void*, uint8_t, void*, uint64_t,
127d3fecca9Ssthen 	udb_walk_relptr_cb*, void*);
128d3fecca9Ssthen 
129d3fecca9Ssthen /** What sort of salvage should be performed by alloc */
130d3fecca9Ssthen enum udb_dirty_alloc {
131d3fecca9Ssthen 	udb_dirty_clean = 0, /* all clean */
132d3fecca9Ssthen 	udb_dirty_fl,        /* allocs, freelists are messed up */
133d3fecca9Ssthen 	udb_dirty_fsize,     /* file size and fsize are messed up */
134d3fecca9Ssthen 	udb_dirty_compact    /* allocs, freelists and relptrs are messed up */
135d3fecca9Ssthen };
136d3fecca9Ssthen 
137d3fecca9Ssthen typedef struct udb_glob_d udb_glob_d;
138d3fecca9Ssthen /**
139d3fecca9Ssthen  * The UDB global data for a file.  This structure is mmapped.
140d3fecca9Ssthen  * Make sure it has no structure-padding problems.
141d3fecca9Ssthen  */
142d3fecca9Ssthen struct udb_glob_d {
143d3fecca9Ssthen 	/** size of header in the file (offset to the first alloced chunk) */
144d3fecca9Ssthen 	uint64_t hsize;
145d3fecca9Ssthen 	/** version number of this file */
146d3fecca9Ssthen 	uint8_t version;
147ab0a6c35Ssthen 	/** was the file cleanly closed, 0 is not clean, 1 is clean */
148d3fecca9Ssthen 	uint8_t clean_close;
149d3fecca9Ssthen 	/** an allocation operation was in progress, file needs to be salvaged
150d3fecca9Ssthen 	 * type enum udb_dirty_alloc */
151d3fecca9Ssthen 	uint8_t dirty_alloc;
152d3fecca9Ssthen 	/** user flags */
153d3fecca9Ssthen 	uint8_t userflags;
154d3fecca9Ssthen 	/** padding to 8-bytes alignment */
155d3fecca9Ssthen 	uint8_t pad1[4];
156d3fecca9Ssthen 	/** size to mmap */
157d3fecca9Ssthen 	uint64_t fsize;
158d3fecca9Ssthen 	/** chunk move rollback info: oldchunk (0 is nothing).
159d3fecca9Ssthen 	 * volatile because these values prevent dataloss, they need to be
160d3fecca9Ssthen 	 * written immediately. */
161d3fecca9Ssthen 	volatile udb_void rb_old;
162d3fecca9Ssthen 	/** chunk move rollback info: newchunk (0 is nothing) */
163d3fecca9Ssthen 	volatile udb_void rb_new;
164d3fecca9Ssthen 	/** size of move rollback chunks */
165d3fecca9Ssthen 	volatile uint64_t rb_size;
166d3fecca9Ssthen 	/** segment of move rollback, for an XL chunk that overlaps. */
167d3fecca9Ssthen 	volatile uint64_t rb_seg;
168a1bac035Sflorian 	/** linked list for content-listing, 0 if empty;
169a1bac035Sflorian 	 * this pointer is unused; and could be removed if the database
170a1bac035Sflorian 	 * format is modified or updated. */
171d3fecca9Ssthen 	udb_rel_ptr content_list;
172d3fecca9Ssthen 	/** user global data pointer */
173d3fecca9Ssthen 	udb_rel_ptr user_global;
174d3fecca9Ssthen };
175d3fecca9Ssthen 
176d3fecca9Ssthen /**
177d3fecca9Ssthen  * The UDB database file.  Contains all the data
178d3fecca9Ssthen  */
179d3fecca9Ssthen struct udb_base {
180d3fecca9Ssthen 	/** name of the file, alloced */
181d3fecca9Ssthen 	char* fname;
182d3fecca9Ssthen 
183d3fecca9Ssthen 	/** mmap base pointer (or NULL) */
184d3fecca9Ssthen 	void* base;
185d3fecca9Ssthen 	/** size of mmap */
186d3fecca9Ssthen 	size_t base_size;
187d3fecca9Ssthen 	/** fd of mmap (if -1, closed). */
188d3fecca9Ssthen 	int fd;
189d3fecca9Ssthen 
190d3fecca9Ssthen 	/** space allocator that is used for this base */
191d3fecca9Ssthen 	udb_alloc* alloc;
192d3fecca9Ssthen 	/** real pointer to the global data in the file */
193d3fecca9Ssthen 	udb_glob_d* glob_data;
194d3fecca9Ssthen 
195d3fecca9Ssthen 	/** store all linked udb_ptrs in this table, by hash(offset).
196d3fecca9Ssthen 	 * then a linked list of ptrs (all that match the hash).
197d3fecca9Ssthen 	 * this avoids buckets, and thus memory allocation. */
198d3fecca9Ssthen 	udb_ptr** ram_hash;
199d3fecca9Ssthen 	/** size of the current udb_ptr hashtable array */
200d3fecca9Ssthen 	size_t ram_size;
201*bc6311d7Sflorian 	/** mask for the current udb_ptr hashtable lookups */
202d3fecca9Ssthen 	int ram_mask;
203d3fecca9Ssthen 	/** number of ptrs in ram, used to decide when to grow */
204d3fecca9Ssthen 	size_t ram_num;
205d3fecca9Ssthen 	/** for relocation, this walks through all relptrs in chunk */
206d3fecca9Ssthen 	udb_walk_relptr_func* walkfunc;
207d3fecca9Ssthen 	/** user data for walkfunc */
208d3fecca9Ssthen 	void* walkarg;
20915ed76cbSbrad 
21015ed76cbSbrad 	/** compaction is inhibited */
21115ed76cbSbrad 	int inhibit_compact;
21215ed76cbSbrad 	/** compaction is useful; deletions performed. */
21315ed76cbSbrad 	int useful_compact;
214d3fecca9Ssthen };
215d3fecca9Ssthen 
216d3fecca9Ssthen typedef enum udb_chunk_type udb_chunk_type;
217d3fecca9Ssthen /** chunk type enum, setting these types help recovery and debug */
218d3fecca9Ssthen enum udb_chunk_type {
219d3fecca9Ssthen 	udb_chunk_type_free = 0,
220d3fecca9Ssthen 	udb_chunk_type_data, /* alloced data */
221d3fecca9Ssthen 	udb_chunk_type_task,
222d3fecca9Ssthen 	udb_chunk_type_internal
223d3fecca9Ssthen };
224d3fecca9Ssthen 
225d3fecca9Ssthen typedef struct udb_chunk_d udb_chunk_d;
226d3fecca9Ssthen /**
227d3fecca9Ssthen  * UDB chunk info (prepended for every allocated chunk).
228d3fecca9Ssthen  * The chunks are in doublelinkedlists per size.
229d3fecca9Ssthen  * At the end of the chunk another exp uint8 is stored (to walk backwards).
230d3fecca9Ssthen  * 17 bytes overhead, datasize for 32byte chunk is 15.
231d3fecca9Ssthen  */
232d3fecca9Ssthen struct udb_chunk_d {
233d3fecca9Ssthen 	/** the size of this chunk (i.e. 2**x) */
234d3fecca9Ssthen 	uint8_t exp;
235d3fecca9Ssthen 	/** type for this chunk (enum chunktype; free, data or index) */
236d3fecca9Ssthen 	uint8_t type;
237d3fecca9Ssthen 	/** flags for this chunk */
238d3fecca9Ssthen 	uint8_t flags;
239d3fecca9Ssthen 	/** padding onto 8-alignment */
240d3fecca9Ssthen 	uint8_t pad[5];
241d3fecca9Ssthen 	/** udb_rel_ptr* first in list of rel-ptrs that point back here
242d3fecca9Ssthen 	 * In the free chunk this is the previous pointer. */
243d3fecca9Ssthen 	udb_void ptrlist;
244d3fecca9Ssthen 	/* user data space starts here, 64-bit aligned */
245d3fecca9Ssthen 	uint8_t data[0];
246d3fecca9Ssthen 	/* last octet: exp of chunk */
247d3fecca9Ssthen };
248d3fecca9Ssthen 
249d3fecca9Ssthen typedef struct udb_free_chunk_d udb_free_chunk_d;
250d3fecca9Ssthen /**
251d3fecca9Ssthen  * A free chunk.  Same start as the udb_chunk_d. minsize is 32 bytes.
252d3fecca9Ssthen  */
253d3fecca9Ssthen struct udb_free_chunk_d {
254d3fecca9Ssthen 	/** the size of this chunk (i.e. 2**x) */
255d3fecca9Ssthen 	uint8_t exp;
256d3fecca9Ssthen 	/** type for this chunk (enum chunktype; free, data or index) */
257d3fecca9Ssthen 	uint8_t type;
258d3fecca9Ssthen 	/** flags for this chunk */
259d3fecca9Ssthen 	uint8_t flags;
260d3fecca9Ssthen 	/** padding onto 8-alignment */
261d3fecca9Ssthen 	uint8_t pad[5];
262d3fecca9Ssthen 	/** udb_chunk_d* prev of free list for this size */
263d3fecca9Ssthen 	udb_void prev;
264d3fecca9Ssthen 	/** udb_chunk_d* next of free list for this size */
265d3fecca9Ssthen 	udb_void next;
266d3fecca9Ssthen 	/* empty stuff */
267d3fecca9Ssthen 	/* last octet: exp of chunk */
268d3fecca9Ssthen };
269d3fecca9Ssthen 
270d3fecca9Ssthen typedef struct udb_xl_chunk_d udb_xl_chunk_d;
271d3fecca9Ssthen /**
272d3fecca9Ssthen  * an Extra Large (XL) chunk.  Same start as the udb_chunk_d.  Allocated in whole
273d3fecca9Ssthen  * MAX_CHUNK_SIZE parts, whole megabytes.  overhead is 5x8=40 bytes.
274d3fecca9Ssthen  */
275d3fecca9Ssthen struct udb_xl_chunk_d {
276d3fecca9Ssthen 	/** the size of this chunk (i.e. 2**x): special XL value */
277d3fecca9Ssthen 	uint8_t exp;
278d3fecca9Ssthen 	/** type for this chunk (enum chunktype; free, data or index) */
279d3fecca9Ssthen 	uint8_t type;
280d3fecca9Ssthen 	/** flags for this chunk */
281d3fecca9Ssthen 	uint8_t flags;
282d3fecca9Ssthen 	/** padding onto 8-alignment */
283d3fecca9Ssthen 	uint8_t pad[5];
284d3fecca9Ssthen 	/** udb_rel_ptr* first in list of rel-ptrs that point back here
285d3fecca9Ssthen 	 * In the free chunk this is the previous pointer. */
286d3fecca9Ssthen 	udb_void ptrlist;
287d3fecca9Ssthen 	/** size of this chunk in bytes */
288d3fecca9Ssthen 	uint64_t size;
289d3fecca9Ssthen 	/** data of the XL chunk */
290d3fecca9Ssthen 	uint8_t data[0];
291d3fecca9Ssthen 	/* uint64_t endsize: before last octet the size again. */
292d3fecca9Ssthen 	/* uint8_t pad[7]: padding to make last octet last. */
293d3fecca9Ssthen 	/* last octet: exp of chunk: special XL value */
294d3fecca9Ssthen };
295d3fecca9Ssthen 
296d3fecca9Ssthen typedef struct udb_alloc_d udb_alloc_d;
297d3fecca9Ssthen /**
298d3fecca9Ssthen  * UDB alloc info on disk.
299d3fecca9Ssthen  */
300d3fecca9Ssthen struct udb_alloc_d {
301d3fecca9Ssthen 	/** stats: number of data bytes allocated, sum of sizes passed to alloc */
302d3fecca9Ssthen 	uint64_t stat_data;
303d3fecca9Ssthen 	/** stats: number of bytes in free chunks, sum of their 2**x size */
304d3fecca9Ssthen 	uint64_t stat_free;
305d3fecca9Ssthen 	/** stats: number of bytes in alloced chunks, sum of their 2**x size */
306d3fecca9Ssthen 	uint64_t stat_alloc;
307d3fecca9Ssthen 	/** offset to create next chunk at. can be before file-end, or be
308d3fecca9Ssthen 	 * fsize, volatile because it is used as a 'commit', and thus we want
309d3fecca9Ssthen 	 * this to be written to memory (and thus disk) immediately. */
310d3fecca9Ssthen 	volatile uint64_t nextgrow;
311d3fecca9Ssthen 	/** fixed size array the points to the 2**x size chunks in the file,
312d3fecca9Ssthen 	 * This is the start of the doublelinked list, ptr to udb_free_chunk_d.
313d3fecca9Ssthen 	 * array starts at UDB_ALLOC_CHUNK_MINEXP entry as [0]. */
314d3fecca9Ssthen 	udb_void free[UDB_ALLOC_CHUNKS_MAX-UDB_ALLOC_CHUNK_MINEXP+1];
315d3fecca9Ssthen };
316d3fecca9Ssthen 
317d3fecca9Ssthen /**
318d3fecca9Ssthen  * The UDB space allocator.  Assigns space in the file.
319d3fecca9Ssthen  */
320d3fecca9Ssthen struct udb_alloc {
321d3fecca9Ssthen 	/** the base this is part of */
322d3fecca9Ssthen 	udb_base* udb;
323d3fecca9Ssthen 	/** real pointer to space allocation info on disk; fixedsize struct */
324d3fecca9Ssthen 	udb_alloc_d* disk;
325d3fecca9Ssthen };
326d3fecca9Ssthen 
327d3fecca9Ssthen /**
328d3fecca9Ssthen  * file header length, the file start with
329d3fecca9Ssthen  * 64bit: magic number to identify file (and prevent stupid mistakes)
330d3fecca9Ssthen  * globdata: global data. Fixed size segment. (starts with size uint64)
331d3fecca9Ssthen  * allocdata: alloc global data. Fixed size segment.
332d3fecca9Ssthen  * size and 0 byte: end marker for reverse search.
333d3fecca9Ssthen  */
334d3fecca9Ssthen #define UDB_HEADER_SIZE (sizeof(uint64_t)+sizeof(udb_glob_d)+ \
335d3fecca9Ssthen 	sizeof(udb_alloc_d)+sizeof(uint64_t)*2)
336d3fecca9Ssthen /** magic string that starts an UDB file, uint64_t, note first byte=0, to mark
337d3fecca9Ssthen  * header start as a chunk. */
338d3fecca9Ssthen #define UDB_MAGIC (((uint64_t)'u'<<48)|((uint64_t)'d'<<40)|((uint64_t)'b' \
339275a8d89Sflorian 	<<32)|((uint64_t)'v'<<24)|((uint64_t)'0'<<16)|((uint64_t)'b'<<8))
340d3fecca9Ssthen 
341d3fecca9Ssthen /* UDB BASE */
342d3fecca9Ssthen /**
343d3fecca9Ssthen  * Create udb base structure and attempt to read the file.
344d3fecca9Ssthen  * @param fname: file name.
345d3fecca9Ssthen  * @param walkfunc: function to walk through relptrs in chunk.
346d3fecca9Ssthen  * @param arg: user argument to pass to walkfunc
347d3fecca9Ssthen  * @return base structure or NULL on failure.
348d3fecca9Ssthen  */
349d3fecca9Ssthen udb_base* udb_base_create_read(const char* fname, udb_walk_relptr_func walkfunc,
350d3fecca9Ssthen 	void* arg);
351d3fecca9Ssthen 
352d3fecca9Ssthen /**
353d3fecca9Ssthen  * Create udb base structure and create a new file.
354d3fecca9Ssthen  * @param fname: file name.
355d3fecca9Ssthen  * @param walkfunc: function to walk through relptrs in chunk.
356d3fecca9Ssthen  * @param arg: user argument to pass to walkfunc
357d3fecca9Ssthen  * @return base structure or NULL on failure.
358d3fecca9Ssthen  */
359d3fecca9Ssthen udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc,
360d3fecca9Ssthen 	void* arg);
361d3fecca9Ssthen 
362d3fecca9Ssthen /**
363d3fecca9Ssthen  * Create udb from (O_RDWR) fd.
364d3fecca9Ssthen  * @param fname: file name.
365d3fecca9Ssthen  * @param fd: file descriptor.
366d3fecca9Ssthen  * @param walkfunc: function to walk through relptrs in chunk.
367d3fecca9Ssthen  * @param arg: user argument to pass to walkfunc
368d3fecca9Ssthen  * @return base structure or NULL on failure.
369d3fecca9Ssthen  */
370d3fecca9Ssthen udb_base* udb_base_create_fd(const char* fname, int fd,
371d3fecca9Ssthen 	udb_walk_relptr_func walkfunc, void* arg);
372d3fecca9Ssthen 
373d3fecca9Ssthen /**
374d3fecca9Ssthen  * Properly close the UDB base file.  Separate from delete so the
375d3fecca9Ssthen  * most important bits (write to disk, sockets) can be done first.
376d3fecca9Ssthen  * @param udb: the udb.
377d3fecca9Ssthen  */
378d3fecca9Ssthen void udb_base_close(udb_base* udb);
379d3fecca9Ssthen 
380d3fecca9Ssthen /**
381d3fecca9Ssthen  * Free the data structure (and close if not already) the udb.
382d3fecca9Ssthen  * @param udb: the udb.
383d3fecca9Ssthen  */
384d3fecca9Ssthen void udb_base_free(udb_base* udb);
385d3fecca9Ssthen 
386d3fecca9Ssthen /**
387d3fecca9Ssthen  * Free the udb, but keep mmap mapped for others.
388d3fecca9Ssthen  * @param udb: the udb.
389d3fecca9Ssthen  */
390d3fecca9Ssthen void udb_base_free_keep_mmap(udb_base* udb);
391d3fecca9Ssthen 
392d3fecca9Ssthen /**
393d3fecca9Ssthen  * Sync the mmap.
394d3fecca9Ssthen  * @param udb: the udb.
395d3fecca9Ssthen  * @param wait: if true, the call blocks until synced.
396d3fecca9Ssthen  */
397d3fecca9Ssthen void udb_base_sync(udb_base* udb, int wait);
398d3fecca9Ssthen 
399d3fecca9Ssthen /**
400d3fecca9Ssthen  * The mmap size is updated to reflect changes by another process.
401d3fecca9Ssthen  * @param udb: the udb.
402d3fecca9Ssthen  */
403d3fecca9Ssthen void udb_base_remap_process(udb_base* udb);
404d3fecca9Ssthen 
405d3fecca9Ssthen /**
406d3fecca9Ssthen  * get the user data (relative) pointer.
407d3fecca9Ssthen  * @param udb: the udb.
408d3fecca9Ssthen  * @return the userdata relative pointer, 0 means nothing.
409d3fecca9Ssthen  */
410d3fecca9Ssthen udb_rel_ptr* udb_base_get_userdata(udb_base* udb);
411d3fecca9Ssthen 
412d3fecca9Ssthen /**
413d3fecca9Ssthen  * Set the user data (relative) pointer.
414d3fecca9Ssthen  * @param udb: the udb.
415d3fecca9Ssthen  * @param user: user data. offset-pointer (or 0).
416d3fecca9Ssthen  */
417d3fecca9Ssthen void udb_base_set_userdata(udb_base* udb, udb_void user);
418d3fecca9Ssthen 
419d3fecca9Ssthen /**
420d3fecca9Ssthen  * Set the user flags (to any value, uint8).
421d3fecca9Ssthen  * @param udb: the udb.
422d3fecca9Ssthen  * @param v: new value.
423d3fecca9Ssthen  */
424d3fecca9Ssthen void udb_base_set_userflags(udb_base* udb, uint8_t v);
425d3fecca9Ssthen 
426d3fecca9Ssthen /**
427d3fecca9Ssthen  * Get the user flags.
428d3fecca9Ssthen  * @param udb: the udb.
429d3fecca9Ssthen  * @param v: new value.
430d3fecca9Ssthen  */
431d3fecca9Ssthen uint8_t udb_base_get_userflags(udb_base* udb);
432d3fecca9Ssthen 
433d3fecca9Ssthen /**
434d3fecca9Ssthen  * Not for users of udb_base, but for udb_ptr.
435d3fecca9Ssthen  * Link in a new ptr that references a data segment.
436d3fecca9Ssthen  * @param udb: the udb.
437d3fecca9Ssthen  * @param ptr: to link in.
438d3fecca9Ssthen  */
439d3fecca9Ssthen void udb_base_link_ptr(udb_base* udb, udb_ptr* ptr);
440d3fecca9Ssthen 
441d3fecca9Ssthen /**
442d3fecca9Ssthen  * Not for users of udb_base, but for udb_ptr.
443d3fecca9Ssthen  * Unlink a ptr that references a data segment.
444d3fecca9Ssthen  * @param udb: the udb.
445d3fecca9Ssthen  * @param ptr: to unlink.
446d3fecca9Ssthen  */
447d3fecca9Ssthen void udb_base_unlink_ptr(udb_base* udb, udb_ptr* ptr);
448d3fecca9Ssthen 
449d3fecca9Ssthen /* UDB ALLOC */
450d3fecca9Ssthen /**
451d3fecca9Ssthen  * Utility for alloc, find 2**x size that is bigger than the given size.
452d3fecca9Ssthen  * Does not work for amount==0.
453d3fecca9Ssthen  * @param amount: amount of memory.
454d3fecca9Ssthen  * @return x; the exponent where 2**x >= amount.
455d3fecca9Ssthen  */
456d3fecca9Ssthen int udb_exp_size(uint64_t amount);
457d3fecca9Ssthen 
458d3fecca9Ssthen /**
459d3fecca9Ssthen  * Utility for alloc, what is the size that the current offset supports
460d3fecca9Ssthen  * as a maximum 2**x chunk.
461d3fecca9Ssthen  * Does not work for offset = 0 (result is infinite).
462d3fecca9Ssthen  * @param offset: the offset into the memory region.
463d3fecca9Ssthen  * @return maximum exponent where 2**x is fits the offset, thus
464d3fecca9Ssthen  * 	offset % (2**x) == 0 and x cannot be larger.
465d3fecca9Ssthen  */
466d3fecca9Ssthen int udb_exp_offset(uint64_t offset);
467d3fecca9Ssthen 
468d3fecca9Ssthen /**
469d3fecca9Ssthen  * Convert pointer to the data part to a pointer to the base of the chunk.
470d3fecca9Ssthen  * @param data: data part.
471d3fecca9Ssthen  * @return pointer to the base of the chunk.
472d3fecca9Ssthen  */
473d3fecca9Ssthen udb_void chunk_from_dataptr_ext(udb_void data);
474d3fecca9Ssthen 
475d3fecca9Ssthen /**
476d3fecca9Ssthen  * Create empty UDB allocate structure to write to disk to initialize file.
477d3fecca9Ssthen  * @param a: allocation structure to initialize.  system pointer.
478d3fecca9Ssthen  */
479d3fecca9Ssthen void udb_alloc_init_new(udb_alloc_d* a);
480d3fecca9Ssthen 
481d3fecca9Ssthen /**
482d3fecca9Ssthen  * Create new udb allocator, with specific data on disk
483d3fecca9Ssthen  * @param udb: the udb.
484d3fecca9Ssthen  * @param disk: disk data.
485d3fecca9Ssthen  * @return udb allocator or NULL on (malloc) failure.
486d3fecca9Ssthen  */
487d3fecca9Ssthen udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk);
488d3fecca9Ssthen 
489d3fecca9Ssthen /**
490d3fecca9Ssthen  * Free the udb allocator from memory.
491d3fecca9Ssthen  * @param alloc: the udb space allocator.
492d3fecca9Ssthen  */
493d3fecca9Ssthen void udb_alloc_delete(udb_alloc* alloc);
494d3fecca9Ssthen 
495d3fecca9Ssthen /**
496d3fecca9Ssthen  * Allocate space on the disk.
497d3fecca9Ssthen  * This may involve closing and reopening the mmap.
498d3fecca9Ssthen  * @param alloc: the udb space allocator.
499d3fecca9Ssthen  * @param sz: size you want to use.
500d3fecca9Ssthen  * @return relative pointer (or 0 on alloc failure).
501d3fecca9Ssthen  */
502d3fecca9Ssthen udb_void udb_alloc_space(udb_alloc* alloc, size_t sz);
503d3fecca9Ssthen 
504d3fecca9Ssthen /**
505d3fecca9Ssthen  * Allocate space on disk, give already the data you want there.
506d3fecca9Ssthen  * This may involve closing and reopening the mmap.
507d3fecca9Ssthen  * @param alloc: the udb space allocator.
508d3fecca9Ssthen  * @param d: data you want there (system pointer).
509d3fecca9Ssthen  * @param sz: size you want to use.
510d3fecca9Ssthen  * @return relative pointer (or 0 on alloc failure).
511d3fecca9Ssthen  */
512d3fecca9Ssthen udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz);
513d3fecca9Ssthen 
514d3fecca9Ssthen /**
515d3fecca9Ssthen  * free allocated space.  It may shrink the file.
516d3fecca9Ssthen  * This may involve closing and reopening the mmap.
517d3fecca9Ssthen  * @param alloc: the udb space allocator.
518d3fecca9Ssthen  * @param r: relative pointer to data you want to free.
519d3fecca9Ssthen  * @param sz: the size of the data you stop using.
520d3fecca9Ssthen  * @return false if the free failed, it failed the close and mmap.
521d3fecca9Ssthen  */
522d3fecca9Ssthen int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz);
523d3fecca9Ssthen 
524d3fecca9Ssthen /**
525d3fecca9Ssthen  * realloc an existing allocated space.  It may grow the file.
526d3fecca9Ssthen  * This may involve closing and reopening the mmap.
527d3fecca9Ssthen  * It could also use the existing space where it is now.
528d3fecca9Ssthen  * @param alloc: the udb space allocator.
529d3fecca9Ssthen  * @param r: relative pointer to data you want to realloc.
530d3fecca9Ssthen  *	if 0 then this is alloc_space(), and osz is ignored.
531d3fecca9Ssthen  * @param osz: the old size of the data.
532d3fecca9Ssthen  * @param sz: the size of the data you want to get.
533d3fecca9Ssthen  *	if this is 0 then a free() is done, but please do it directly,
534d3fecca9Ssthen  *	as you then get a returnvalue (file errors).
535d3fecca9Ssthen  * @return relative pointer (0 on alloc failure, same if not moved).
536d3fecca9Ssthen  */
537d3fecca9Ssthen udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz,
538d3fecca9Ssthen 	size_t sz);
539d3fecca9Ssthen 
540d3fecca9Ssthen /**
541d3fecca9Ssthen  * Prepare for a lot of new entries.  Grow space for that.
542d3fecca9Ssthen  * This can involve closing and reopening the mmap.
543d3fecca9Ssthen  * This space (if large) is going to be released on next free() or close().
544d3fecca9Ssthen  * @param alloc: the udb space allocator.
545d3fecca9Ssthen  * @param sz: size of the entries.
546d3fecca9Ssthen  * @param num: number of entries.
547d3fecca9Ssthen  * @return false on failure to grow or re-mmap.
548d3fecca9Ssthen  */
549d3fecca9Ssthen int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num);
550d3fecca9Ssthen 
551d3fecca9Ssthen /**
55215ed76cbSbrad  * attempt to compact the data and move free space to the end
55315ed76cbSbrad  * can shrink the db, which calls sync on the db (for portability).
55415ed76cbSbrad  * @param udb: the udb base.
55515ed76cbSbrad  * @return 0 on failure (to remap the (possibly) changed udb base).
55615ed76cbSbrad  */
55715ed76cbSbrad int udb_compact(udb_base* udb);
55815ed76cbSbrad 
55915ed76cbSbrad /**
56015ed76cbSbrad  * set the udb to inhibit or uninhibit compaction.  Does not perform
56115ed76cbSbrad  * the compaction itself if enabled, for that call udb_compact.
56215ed76cbSbrad  * @param udb: the udb base
56315ed76cbSbrad  * @param inhibit: 0 or 1.
56415ed76cbSbrad  */
56515ed76cbSbrad void udb_compact_inhibited(udb_base* udb, int inhibit);
56615ed76cbSbrad 
56715ed76cbSbrad /**
568d3fecca9Ssthen  * Set the alloc type for a newly alloced piece of data
569d3fecca9Ssthen  * @param alloc: the udb space allocator.
570d3fecca9Ssthen  * @param r: relativeptr to the data.
571d3fecca9Ssthen  * @param tp: the type of that block.
572d3fecca9Ssthen  */
573d3fecca9Ssthen void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp);
574d3fecca9Ssthen 
575d3fecca9Ssthen /**
576d3fecca9Ssthen  * See if a pointer could be valid (it points within valid space),
577d3fecca9Ssthen  * for the given type side.  For debug checks.
578d3fecca9Ssthen  * @param udb: the udb
579d3fecca9Ssthen  * @param to: the ptr (offset).
580d3fecca9Ssthen  * @param destsize: the size_of of the destination of the pointer.
581d3fecca9Ssthen  * @return true if it points to a valid region.
582d3fecca9Ssthen  */
583d3fecca9Ssthen int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize);
584d3fecca9Ssthen 
585d3fecca9Ssthen /**
586d3fecca9Ssthen  * See if a pointer is valid (it points to a chunk).  For debug checks.
587d3fecca9Ssthen  * @param udb: the udb.
588d3fecca9Ssthen  * @param to: the ptr (offset).
589d3fecca9Ssthen  * @return true if it points to the start of a chunks data region.
590d3fecca9Ssthen  */
591d3fecca9Ssthen int udb_valid_dataptr(udb_base* udb, udb_void to);
592d3fecca9Ssthen 
593d3fecca9Ssthen /**
594d3fecca9Ssthen  * See if a pointer is on the relptrlist for dataptr.  For debug checks.
595d3fecca9Ssthen  * @param udb: the udb.
596d3fecca9Ssthen  * @param rptr: the rel_ptr (offset).
597d3fecca9Ssthen  * @param to: dataptr of the chunk on which ptrlist the rptr is searched.
598d3fecca9Ssthen  * @return true if rptr is valid and on the ptrlist.
599d3fecca9Ssthen  */
600d3fecca9Ssthen int udb_valid_rptr(udb_base* udb, udb_void rptr, udb_void to);
601d3fecca9Ssthen 
602d3fecca9Ssthen /*** UDB_REL_PTR ***/
603d3fecca9Ssthen /**
604d3fecca9Ssthen  * Init a new UDB rel ptr at NULL.
605d3fecca9Ssthen  * @param ptr: sysptr, becomes inited.
606d3fecca9Ssthen  */
607d3fecca9Ssthen void udb_rel_ptr_init(udb_rel_ptr* ptr);
608d3fecca9Ssthen 
609d3fecca9Ssthen /**
610d3fecca9Ssthen  * Unlink a UDB rel ptr.
611d3fecca9Ssthen  * @param base: the udb base
612d3fecca9Ssthen  * @param ptr: sysptr, unlinked
613d3fecca9Ssthen  */
614d3fecca9Ssthen void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr);
615d3fecca9Ssthen 
616d3fecca9Ssthen /**
617d3fecca9Ssthen  * Link a UDB rel ptr to a new chunk
618d3fecca9Ssthen  * @param base: the udb base
619d3fecca9Ssthen  * @param ptr: sysptr, linked to new value.
620d3fecca9Ssthen  * @param to: the data to point to (relative ptr).
621d3fecca9Ssthen  */
622d3fecca9Ssthen void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to);
623d3fecca9Ssthen 
624d3fecca9Ssthen /**
625d3fecca9Ssthen  * Change rel ptr to a new value (point to another record)
626d3fecca9Ssthen  * @param base: the udb base
627d3fecca9Ssthen  * @param ptr: sysptr, points to new value.
628d3fecca9Ssthen  * @param to: the data to point to (relative ptr).
629d3fecca9Ssthen  */
630d3fecca9Ssthen void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to);
631d3fecca9Ssthen 
632d3fecca9Ssthen /**
633d3fecca9Ssthen  * A chunk has moved and now edit all the relptrs in list to fix them up
634d3fecca9Ssthen  * @param base: the udb base
635d3fecca9Ssthen  * @param list: start of the ptr list
636d3fecca9Ssthen  * @param to: where the chunk has moved to relptr to its userdata.
637d3fecca9Ssthen  */
638d3fecca9Ssthen void udb_rel_ptr_edit(void* base, udb_void list, udb_void to);
639d3fecca9Ssthen 
640d3fecca9Ssthen /**
641d3fecca9Ssthen  * Get system pointer.  Assumes there is a variable named 'base'
642d3fecca9Ssthen  * that points to the udb base.
643d3fecca9Ssthen  * @param ptr: the relative pointer (a sysptr to it).
644d3fecca9Ssthen  * @return void* to the data.
645d3fecca9Ssthen  */
646d3fecca9Ssthen #define UDB_SYSPTR(ptr) UDB_REL(base, (ptr)->data)
647d3fecca9Ssthen 
648d3fecca9Ssthen /** get sys ptr for char* string */
649d3fecca9Ssthen #define UDB_CHAR(ptr) ((char*)UDB_REL(base, ptr))
650d3fecca9Ssthen /** get sys ptr for udb_rel_ptr */
651d3fecca9Ssthen #define UDB_REL_PTR(ptr) ((udb_rel_ptr*)UDB_REL(base, ptr))
652d3fecca9Ssthen /** get sys ptr for udb_glob_d */
653d3fecca9Ssthen #define UDB_GLOB(ptr) ((udb_glob_d*)UDB_REL(base, ptr))
654d3fecca9Ssthen /** get sys ptr for udb_chunk_d */
655d3fecca9Ssthen #define UDB_CHUNK(ptr) ((udb_chunk_d*)UDB_REL(base, ptr))
656d3fecca9Ssthen /** get sys ptr for udb_free_chunk_d */
657d3fecca9Ssthen #define UDB_FREE_CHUNK(ptr) ((udb_free_chunk_d*)UDB_REL(base, ptr))
658d3fecca9Ssthen /** get sys ptr for udb_xl_chunk_d */
659d3fecca9Ssthen #define UDB_XL_CHUNK(ptr) ((udb_xl_chunk_d*)UDB_REL(base, ptr))
660d3fecca9Ssthen 
661d3fecca9Ssthen /* udb_ptr */
662d3fecca9Ssthen /**
663d3fecca9Ssthen  * Initialize an udb ptr.  Set to NULL.  (and thus not linked can be deleted).
664d3fecca9Ssthen  * You MUST set it to 0 before you stop using the ptr.
665d3fecca9Ssthen  * @param ptr: the ptr to initialise (caller has allocated it).
666d3fecca9Ssthen  * @param udb: the udb base to link it to.
667d3fecca9Ssthen  */
668d3fecca9Ssthen void udb_ptr_init(udb_ptr* ptr, udb_base* udb);
669d3fecca9Ssthen 
670d3fecca9Ssthen /**
671d3fecca9Ssthen  * Set udp ptr to a new value.  If set to NULL you can delete it.
672d3fecca9Ssthen  * @param ptr: the ptr.
673d3fecca9Ssthen  * @param udb: the udb base to link up with that data segment's administration.
674d3fecca9Ssthen  * @param newval: new value to point to (udb_void relative file offset to data).
675d3fecca9Ssthen  */
676d3fecca9Ssthen void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval);
677d3fecca9Ssthen 
678d3fecca9Ssthen /** dereference udb_ptr */
679d3fecca9Ssthen #define UDB_PTR(ptr) (UDB_REL(*((ptr)->base), (ptr)->data))
680d3fecca9Ssthen 
681d3fecca9Ssthen /**
682d3fecca9Ssthen  * Ease of use udb ptr, allocate space and return ptr to it
683d3fecca9Ssthen  * You MUST udb_ptr_set it to 0 before you stop using the ptr.
684d3fecca9Ssthen  * @param base: udb base to use.
685d3fecca9Ssthen  * @param ptr: ptr is overwritten, can be uninitialised.
686d3fecca9Ssthen  * @param type: type of the allocation.
687d3fecca9Ssthen  * 	You need a special type if the block contains udb_rel_ptr's.
688d3fecca9Ssthen  * 	You can use udb_type_data for plain data.
689d3fecca9Ssthen  * @param sz: amount to allocate.
690d3fecca9Ssthen  * @return 0 on alloc failure.
691d3fecca9Ssthen  */
692d3fecca9Ssthen int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type,
693d3fecca9Ssthen 	size_t sz);
694d3fecca9Ssthen 
695d3fecca9Ssthen /**
696d3fecca9Ssthen  * Ease of use udb ptr, free space and set ptr to NULL (to it can be deleted).
697d3fecca9Ssthen  * The space is freed on disk.
698d3fecca9Ssthen  * @param ptr: the ptr.
699d3fecca9Ssthen  * @param udb: udb base.
700d3fecca9Ssthen  * @param sz: the size of the data you stop using.
701d3fecca9Ssthen  */
702d3fecca9Ssthen void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz);
703d3fecca9Ssthen 
704d3fecca9Ssthen /**
705d3fecca9Ssthen  * Get pointer to the data of the ptr.  or use a macro to cast UDB_PTR to
706d3fecca9Ssthen  * the type of your structure(.._d)
707d3fecca9Ssthen  */
udb_ptr_data(udb_ptr * ptr)708d3fecca9Ssthen static inline uint8_t* udb_ptr_data(udb_ptr* ptr) {
709d3fecca9Ssthen 	return (uint8_t*)UDB_PTR(ptr);
710d3fecca9Ssthen }
711d3fecca9Ssthen 
712d3fecca9Ssthen /**
713d3fecca9Ssthen  * See if udb ptr is null
714d3fecca9Ssthen  */
udb_ptr_is_null(udb_ptr * ptr)715d3fecca9Ssthen static inline int udb_ptr_is_null(udb_ptr* ptr) {
716d3fecca9Ssthen 	return (ptr->data == 0);
717d3fecca9Ssthen }
718d3fecca9Ssthen 
719d3fecca9Ssthen /**
720d3fecca9Ssthen  * Get the type of a udb_ptr chunk.
721d3fecca9Ssthen  * @param ptr: udb pointer
722d3fecca9Ssthen  * @return type of chunk */
723d3fecca9Ssthen udb_chunk_type udb_ptr_get_type(udb_ptr* ptr);
724d3fecca9Ssthen 
725d3fecca9Ssthen /** Ease of use, create new pointer to destination relptr
726d3fecca9Ssthen  * You MUST udb_ptr_set it to 0 before you stop using the ptr. */
udb_ptr_new(udb_ptr * ptr,udb_base * udb,udb_rel_ptr * d)727d3fecca9Ssthen static inline void udb_ptr_new(udb_ptr* ptr, udb_base* udb, udb_rel_ptr* d) {
728d3fecca9Ssthen 	udb_ptr_init(ptr, udb);
729d3fecca9Ssthen 	udb_ptr_set(ptr, udb, d->data);
730d3fecca9Ssthen }
731d3fecca9Ssthen 
732d3fecca9Ssthen /** Ease of use.  Stop using this ptr */
udb_ptr_unlink(udb_ptr * ptr,udb_base * udb)733d3fecca9Ssthen static inline void udb_ptr_unlink(udb_ptr* ptr, udb_base* udb) {
734d3fecca9Ssthen 	if(ptr->data)
735d3fecca9Ssthen 		udb_base_unlink_ptr(udb, ptr);
736d3fecca9Ssthen }
737d3fecca9Ssthen 
738d3fecca9Ssthen /* Ease of use.  Assign rptr from rptr */
udb_rptr_set_rptr(udb_rel_ptr * dest,udb_base * udb,udb_rel_ptr * p)739d3fecca9Ssthen static inline void udb_rptr_set_rptr(udb_rel_ptr* dest, udb_base* udb,
740d3fecca9Ssthen 	udb_rel_ptr* p) {
741d3fecca9Ssthen #ifdef UDB_CHECK
742d3fecca9Ssthen 	if(dest->data) { assert(udb_valid_rptr(udb,
743d3fecca9Ssthen 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
744d3fecca9Ssthen 	if(p->data) { assert(udb_valid_rptr(udb,
745d3fecca9Ssthen 		UDB_SYSTOREL(udb->base, p), p->data)); }
746d3fecca9Ssthen #endif
747d3fecca9Ssthen 	udb_rel_ptr_set(udb->base, dest, p->data);
748d3fecca9Ssthen }
749d3fecca9Ssthen 
750d3fecca9Ssthen /* Ease of use.  Assign rptr from ptr */
udb_rptr_set_ptr(udb_rel_ptr * dest,udb_base * udb,udb_ptr * p)751d3fecca9Ssthen static inline void udb_rptr_set_ptr(udb_rel_ptr* dest, udb_base* udb,
752d3fecca9Ssthen 	udb_ptr* p) {
753d3fecca9Ssthen #ifdef UDB_CHECK
754d3fecca9Ssthen 	if(dest->data) { assert(udb_valid_rptr(udb,
755d3fecca9Ssthen 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
756d3fecca9Ssthen 	if(p->data) { assert(udb_valid_dataptr(udb, p->data)); }
757d3fecca9Ssthen #endif
758d3fecca9Ssthen 	udb_rel_ptr_set(udb->base, dest, p->data);
759d3fecca9Ssthen }
760d3fecca9Ssthen 
761d3fecca9Ssthen /* Ease of use.  Assign ptr from rptr */
udb_ptr_set_rptr(udb_ptr * dest,udb_base * udb,udb_rel_ptr * p)762d3fecca9Ssthen static inline void udb_ptr_set_rptr(udb_ptr* dest, udb_base* udb,
763d3fecca9Ssthen 	udb_rel_ptr* p) {
764d3fecca9Ssthen #ifdef UDB_CHECK
765d3fecca9Ssthen 	if(p->data) { assert(udb_valid_rptr(udb,
766d3fecca9Ssthen 		UDB_SYSTOREL(udb->base, p), p->data)); }
767d3fecca9Ssthen #endif
768d3fecca9Ssthen 	udb_ptr_set(dest, udb, p->data);
769d3fecca9Ssthen }
770d3fecca9Ssthen 
771d3fecca9Ssthen /* Ease of use.  Assign ptr from ptr */
udb_ptr_set_ptr(udb_ptr * dest,udb_base * udb,udb_ptr * p)772d3fecca9Ssthen static inline void udb_ptr_set_ptr(udb_ptr* dest, udb_base* udb, udb_ptr* p) {
773d3fecca9Ssthen 	udb_ptr_set(dest, udb, p->data);
774d3fecca9Ssthen }
775d3fecca9Ssthen 
776d3fecca9Ssthen /* Ease of use, zero rptr.  You use this to zero an existing pointer.
777d3fecca9Ssthen  * A new rptr should be rel_ptr_init-ed before it is taken into use. */
udb_rptr_zero(udb_rel_ptr * dest,udb_base * udb)778d3fecca9Ssthen static inline void udb_rptr_zero(udb_rel_ptr* dest, udb_base* udb) {
779d3fecca9Ssthen #ifdef UDB_CHECK
780d3fecca9Ssthen 	if(dest->data) { assert(udb_valid_rptr(udb,
781d3fecca9Ssthen 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
782d3fecca9Ssthen #endif
783d3fecca9Ssthen 	udb_rel_ptr_set(udb->base, dest, 0);
784d3fecca9Ssthen }
785d3fecca9Ssthen 
786d3fecca9Ssthen /* Ease of use, zero ptr */
udb_ptr_zero(udb_ptr * dest,udb_base * udb)787d3fecca9Ssthen static inline void udb_ptr_zero(udb_ptr* dest, udb_base* udb) {
788d3fecca9Ssthen 	udb_ptr_set(dest, udb, 0);
789d3fecca9Ssthen }
790d3fecca9Ssthen 
791d3fecca9Ssthen /** ease of use, delete memory pointed at by relptr */
udb_rel_ptr_free_space(udb_rel_ptr * ptr,udb_base * udb,size_t sz)792d3fecca9Ssthen static inline void udb_rel_ptr_free_space(udb_rel_ptr* ptr, udb_base* udb,
793d3fecca9Ssthen 	size_t sz) {
794d3fecca9Ssthen 	udb_void d = ptr->data;
795d3fecca9Ssthen #ifdef UDB_CHECK
796d3fecca9Ssthen 	if(d) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, ptr), d)); }
797d3fecca9Ssthen #endif
798d3fecca9Ssthen 	udb_rel_ptr_set(udb->base, ptr, 0);
799d3fecca9Ssthen 	udb_alloc_free(udb->alloc, d, sz);
800d3fecca9Ssthen }
801d3fecca9Ssthen 
802d3fecca9Ssthen #endif /* UDB_H */
803