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