Home | History | Annotate | Line # | Download | only in dist
      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) ((void*)((char*)(base) + (relptr)))
     56 /** from system pointer to relative pointer */
     57 #define UDB_SYSTOREL(base, ptr) ((udb_void)((char*)(ptr) - (char*)(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 	 * this pointer is unused; and could be removed if the database
    170 	 * format is modified or updated. */
    171 	udb_rel_ptr content_list;
    172 	/** user global data pointer */
    173 	udb_rel_ptr user_global;
    174 };
    175 
    176 /**
    177  * The UDB database file.  Contains all the data
    178  */
    179 struct udb_base {
    180 	/** name of the file, alloced */
    181 	char* fname;
    182 
    183 	/** mmap base pointer (or NULL) */
    184 	void* base;
    185 	/** size of mmap */
    186 	size_t base_size;
    187 	/** fd of mmap (if -1, closed). */
    188 	int fd;
    189 
    190 	/** space allocator that is used for this base */
    191 	udb_alloc* alloc;
    192 	/** real pointer to the global data in the file */
    193 	udb_glob_d* glob_data;
    194 
    195 	/** store all linked udb_ptrs in this table, by hash(offset).
    196 	 * then a linked list of ptrs (all that match the hash).
    197 	 * this avoids buckets, and thus memory allocation. */
    198 	udb_ptr** ram_hash;
    199 	/** size of the current udb_ptr hashtable array */
    200 	size_t ram_size;
    201 	/** mask for the current udb_ptr hashtable lookups */
    202 	int ram_mask;
    203 	/** number of ptrs in ram, used to decide when to grow */
    204 	size_t ram_num;
    205 	/** for relocation, this walks through all relptrs in chunk */
    206 	udb_walk_relptr_func* walkfunc;
    207 	/** user data for walkfunc */
    208 	void* walkarg;
    209 
    210 	/** compaction is inhibited */
    211 	int inhibit_compact;
    212 	/** compaction is useful; deletions performed. */
    213 	int useful_compact;
    214 };
    215 
    216 typedef enum udb_chunk_type udb_chunk_type;
    217 /** chunk type enum, setting these types help recovery and debug */
    218 enum udb_chunk_type {
    219 	udb_chunk_type_free = 0,
    220 	udb_chunk_type_data, /* alloced data */
    221 	udb_chunk_type_task,
    222 	udb_chunk_type_internal
    223 };
    224 
    225 typedef struct udb_chunk_d udb_chunk_d;
    226 /**
    227  * UDB chunk info (prepended for every allocated chunk).
    228  * The chunks are in doublelinkedlists per size.
    229  * At the end of the chunk another exp uint8 is stored (to walk backwards).
    230  * 17 bytes overhead, datasize for 32byte chunk is 15.
    231  */
    232 struct udb_chunk_d {
    233 	/** the size of this chunk (i.e. 2**x) */
    234 	uint8_t exp;
    235 	/** type for this chunk (enum chunktype; free, data or index) */
    236 	uint8_t type;
    237 	/** flags for this chunk */
    238 	uint8_t flags;
    239 	/** padding onto 8-alignment */
    240 	uint8_t pad[5];
    241 	/** udb_rel_ptr* first in list of rel-ptrs that point back here
    242 	 * In the free chunk this is the previous pointer. */
    243 	udb_void ptrlist;
    244 	/* user data space starts here, 64-bit aligned */
    245 	uint8_t data[0];
    246 	/* last octet: exp of chunk */
    247 };
    248 
    249 typedef struct udb_free_chunk_d udb_free_chunk_d;
    250 /**
    251  * A free chunk.  Same start as the udb_chunk_d. minsize is 32 bytes.
    252  */
    253 struct udb_free_chunk_d {
    254 	/** the size of this chunk (i.e. 2**x) */
    255 	uint8_t exp;
    256 	/** type for this chunk (enum chunktype; free, data or index) */
    257 	uint8_t type;
    258 	/** flags for this chunk */
    259 	uint8_t flags;
    260 	/** padding onto 8-alignment */
    261 	uint8_t pad[5];
    262 	/** udb_chunk_d* prev of free list for this size */
    263 	udb_void prev;
    264 	/** udb_chunk_d* next of free list for this size */
    265 	udb_void next;
    266 	/* empty stuff */
    267 	/* last octet: exp of chunk */
    268 };
    269 
    270 typedef struct udb_xl_chunk_d udb_xl_chunk_d;
    271 /**
    272  * an Extra Large (XL) chunk.  Same start as the udb_chunk_d.  Allocated in whole
    273  * MAX_CHUNK_SIZE parts, whole megabytes.  overhead is 5x8=40 bytes.
    274  */
    275 struct udb_xl_chunk_d {
    276 	/** the size of this chunk (i.e. 2**x): special XL value */
    277 	uint8_t exp;
    278 	/** type for this chunk (enum chunktype; free, data or index) */
    279 	uint8_t type;
    280 	/** flags for this chunk */
    281 	uint8_t flags;
    282 	/** padding onto 8-alignment */
    283 	uint8_t pad[5];
    284 	/** udb_rel_ptr* first in list of rel-ptrs that point back here
    285 	 * In the free chunk this is the previous pointer. */
    286 	udb_void ptrlist;
    287 	/** size of this chunk in bytes */
    288 	uint64_t size;
    289 	/** data of the XL chunk */
    290 	uint8_t data[0];
    291 	/* uint64_t endsize: before last octet the size again. */
    292 	/* uint8_t pad[7]: padding to make last octet last. */
    293 	/* last octet: exp of chunk: special XL value */
    294 };
    295 
    296 typedef struct udb_alloc_d udb_alloc_d;
    297 /**
    298  * UDB alloc info on disk.
    299  */
    300 struct udb_alloc_d {
    301 	/** stats: number of data bytes allocated, sum of sizes passed to alloc */
    302 	uint64_t stat_data;
    303 	/** stats: number of bytes in free chunks, sum of their 2**x size */
    304 	uint64_t stat_free;
    305 	/** stats: number of bytes in alloced chunks, sum of their 2**x size */
    306 	uint64_t stat_alloc;
    307 	/** offset to create next chunk at. can be before file-end, or be
    308 	 * fsize, volatile because it is used as a 'commit', and thus we want
    309 	 * this to be written to memory (and thus disk) immediately. */
    310 	volatile uint64_t nextgrow;
    311 	/** fixed size array the points to the 2**x size chunks in the file,
    312 	 * This is the start of the doublelinked list, ptr to udb_free_chunk_d.
    313 	 * array starts at UDB_ALLOC_CHUNK_MINEXP entry as [0]. */
    314 	udb_void free[UDB_ALLOC_CHUNKS_MAX-UDB_ALLOC_CHUNK_MINEXP+1];
    315 };
    316 
    317 /**
    318  * The UDB space allocator.  Assigns space in the file.
    319  */
    320 struct udb_alloc {
    321 	/** the base this is part of */
    322 	udb_base* udb;
    323 	/** real pointer to space allocation info on disk; fixedsize struct */
    324 	udb_alloc_d* disk;
    325 };
    326 
    327 /**
    328  * file header length, the file start with
    329  * 64bit: magic number to identify file (and prevent stupid mistakes)
    330  * globdata: global data. Fixed size segment. (starts with size uint64)
    331  * allocdata: alloc global data. Fixed size segment.
    332  * size and 0 byte: end marker for reverse search.
    333  */
    334 #define UDB_HEADER_SIZE (sizeof(uint64_t)+sizeof(udb_glob_d)+ \
    335 	sizeof(udb_alloc_d)+sizeof(uint64_t)*2)
    336 /** magic string that starts an UDB file, uint64_t, note first byte=0, to mark
    337  * header start as a chunk. */
    338 #define UDB_MAGIC (((uint64_t)'u'<<48)|((uint64_t)'d'<<40)|((uint64_t)'b' \
    339 	<<32)|((uint64_t)'v'<<24)|((uint64_t)'0'<<16)|((uint64_t)'b'<<8))
    340 
    341 /* UDB BASE */
    342 /**
    343  * Create udb base structure and attempt to read the file.
    344  * @param fname: file name.
    345  * @param walkfunc: function to walk through relptrs in chunk.
    346  * @param arg: user argument to pass to walkfunc
    347  * @return base structure or NULL on failure.
    348  */
    349 udb_base* udb_base_create_read(const char* fname, udb_walk_relptr_func walkfunc,
    350 	void* arg);
    351 
    352 /**
    353  * Create udb base structure and create a new file.
    354  * @param fname: file name.
    355  * @param walkfunc: function to walk through relptrs in chunk.
    356  * @param arg: user argument to pass to walkfunc
    357  * @return base structure or NULL on failure.
    358  */
    359 udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc,
    360 	void* arg);
    361 
    362 /**
    363  * Create udb from (O_RDWR) fd.
    364  * @param fname: file name.
    365  * @param fd: file descriptor.
    366  * @param walkfunc: function to walk through relptrs in chunk.
    367  * @param arg: user argument to pass to walkfunc
    368  * @return base structure or NULL on failure.
    369  */
    370 udb_base* udb_base_create_fd(const char* fname, int fd,
    371 	udb_walk_relptr_func walkfunc, void* arg);
    372 
    373 /**
    374  * Properly close the UDB base file.  Separate from delete so the
    375  * most important bits (write to disk, sockets) can be done first.
    376  * @param udb: the udb.
    377  */
    378 void udb_base_close(udb_base* udb);
    379 
    380 /**
    381  * Free the data structure (and close if not already) the udb.
    382  * @param udb: the udb.
    383  */
    384 void udb_base_free(udb_base* udb);
    385 
    386 /**
    387  * Free the udb, but keep mmap mapped for others.
    388  * @param udb: the udb.
    389  */
    390 void udb_base_free_keep_mmap(udb_base* udb);
    391 
    392 /**
    393  * Sync the mmap.
    394  * @param udb: the udb.
    395  * @param wait: if true, the call blocks until synced.
    396  */
    397 void udb_base_sync(udb_base* udb, int wait);
    398 
    399 /**
    400  * The mmap size is updated to reflect changes by another process.
    401  * @param udb: the udb.
    402  */
    403 void udb_base_remap_process(udb_base* udb);
    404 
    405 /**
    406  * get the user data (relative) pointer.
    407  * @param udb: the udb.
    408  * @return the userdata relative pointer, 0 means nothing.
    409  */
    410 udb_rel_ptr* udb_base_get_userdata(udb_base* udb);
    411 
    412 /**
    413  * Set the user data (relative) pointer.
    414  * @param udb: the udb.
    415  * @param user: user data. offset-pointer (or 0).
    416  */
    417 void udb_base_set_userdata(udb_base* udb, udb_void user);
    418 
    419 /**
    420  * Set the user flags (to any value, uint8).
    421  * @param udb: the udb.
    422  * @param v: new value.
    423  */
    424 void udb_base_set_userflags(udb_base* udb, uint8_t v);
    425 
    426 /**
    427  * Get the user flags.
    428  * @param udb: the udb.
    429  * @param v: new value.
    430  */
    431 uint8_t udb_base_get_userflags(udb_base* udb);
    432 
    433 /**
    434  * Not for users of udb_base, but for udb_ptr.
    435  * Link in a new ptr that references a data segment.
    436  * @param udb: the udb.
    437  * @param ptr: to link in.
    438  */
    439 void udb_base_link_ptr(udb_base* udb, udb_ptr* ptr);
    440 
    441 /**
    442  * Not for users of udb_base, but for udb_ptr.
    443  * Unlink a ptr that references a data segment.
    444  * @param udb: the udb.
    445  * @param ptr: to unlink.
    446  */
    447 void udb_base_unlink_ptr(udb_base* udb, udb_ptr* ptr);
    448 
    449 /* UDB ALLOC */
    450 /**
    451  * Utility for alloc, find 2**x size that is bigger than the given size.
    452  * Does not work for amount==0.
    453  * @param amount: amount of memory.
    454  * @return x; the exponent where 2**x >= amount.
    455  */
    456 int udb_exp_size(uint64_t amount);
    457 
    458 /**
    459  * Utility for alloc, what is the size that the current offset supports
    460  * as a maximum 2**x chunk.
    461  * Does not work for offset = 0 (result is infinite).
    462  * @param offset: the offset into the memory region.
    463  * @return maximum exponent where 2**x is fits the offset, thus
    464  * 	offset % (2**x) == 0 and x cannot be larger.
    465  */
    466 int udb_exp_offset(uint64_t offset);
    467 
    468 /**
    469  * Convert pointer to the data part to a pointer to the base of the chunk.
    470  * @param data: data part.
    471  * @return pointer to the base of the chunk.
    472  */
    473 udb_void chunk_from_dataptr_ext(udb_void data);
    474 
    475 /**
    476  * Create empty UDB allocate structure to write to disk to initialize file.
    477  * @param a: allocation structure to initialize.  system pointer.
    478  */
    479 void udb_alloc_init_new(udb_alloc_d* a);
    480 
    481 /**
    482  * Create new udb allocator, with specific data on disk
    483  * @param udb: the udb.
    484  * @param disk: disk data.
    485  * @return udb allocator or NULL on (malloc) failure.
    486  */
    487 udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk);
    488 
    489 /**
    490  * Free the udb allocator from memory.
    491  * @param alloc: the udb space allocator.
    492  */
    493 void udb_alloc_delete(udb_alloc* alloc);
    494 
    495 /**
    496  * Allocate space on the disk.
    497  * This may involve closing and reopening the mmap.
    498  * @param alloc: the udb space allocator.
    499  * @param sz: size you want to use.
    500  * @return relative pointer (or 0 on alloc failure).
    501  */
    502 udb_void udb_alloc_space(udb_alloc* alloc, size_t sz);
    503 
    504 /**
    505  * Allocate space on disk, give already the data you want there.
    506  * This may involve closing and reopening the mmap.
    507  * @param alloc: the udb space allocator.
    508  * @param d: data you want there (system pointer).
    509  * @param sz: size you want to use.
    510  * @return relative pointer (or 0 on alloc failure).
    511  */
    512 udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz);
    513 
    514 /**
    515  * free allocated space.  It may shrink the file.
    516  * This may involve closing and reopening the mmap.
    517  * @param alloc: the udb space allocator.
    518  * @param r: relative pointer to data you want to free.
    519  * @param sz: the size of the data you stop using.
    520  * @return false if the free failed, it failed the close and mmap.
    521  */
    522 int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz);
    523 
    524 /**
    525  * realloc an existing allocated space.  It may grow the file.
    526  * This may involve closing and reopening the mmap.
    527  * It could also use the existing space where it is now.
    528  * @param alloc: the udb space allocator.
    529  * @param r: relative pointer to data you want to realloc.
    530  *	if 0 then this is alloc_space(), and osz is ignored.
    531  * @param osz: the old size of the data.
    532  * @param sz: the size of the data you want to get.
    533  *	if this is 0 then a free() is done, but please do it directly,
    534  *	as you then get a returnvalue (file errors).
    535  * @return relative pointer (0 on alloc failure, same if not moved).
    536  */
    537 udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz,
    538 	size_t sz);
    539 
    540 /**
    541  * Prepare for a lot of new entries.  Grow space for that.
    542  * This can involve closing and reopening the mmap.
    543  * This space (if large) is going to be released on next free() or close().
    544  * @param alloc: the udb space allocator.
    545  * @param sz: size of the entries.
    546  * @param num: number of entries.
    547  * @return false on failure to grow or re-mmap.
    548  */
    549 int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num);
    550 
    551 /**
    552  * attempt to compact the data and move free space to the end
    553  * can shrink the db, which calls sync on the db (for portability).
    554  * @param udb: the udb base.
    555  * @return 0 on failure (to remap the (possibly) changed udb base).
    556  */
    557 int udb_compact(udb_base* udb);
    558 
    559 /**
    560  * set the udb to inhibit or uninhibit compaction.  Does not perform
    561  * the compaction itself if enabled, for that call udb_compact.
    562  * @param udb: the udb base
    563  * @param inhibit: 0 or 1.
    564  */
    565 void udb_compact_inhibited(udb_base* udb, int inhibit);
    566 
    567 /**
    568  * Set the alloc type for a newly alloced piece of data
    569  * @param alloc: the udb space allocator.
    570  * @param r: relativeptr to the data.
    571  * @param tp: the type of that block.
    572  */
    573 void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp);
    574 
    575 /**
    576  * See if a pointer could be valid (it points within valid space),
    577  * for the given type side.  For debug checks.
    578  * @param udb: the udb
    579  * @param to: the ptr (offset).
    580  * @param destsize: the size_of of the destination of the pointer.
    581  * @return true if it points to a valid region.
    582  */
    583 int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize);
    584 
    585 /**
    586  * See if a pointer is valid (it points to a chunk).  For debug checks.
    587  * @param udb: the udb.
    588  * @param to: the ptr (offset).
    589  * @return true if it points to the start of a chunks data region.
    590  */
    591 int udb_valid_dataptr(udb_base* udb, udb_void to);
    592 
    593 /**
    594  * See if a pointer is on the relptrlist for dataptr.  For debug checks.
    595  * @param udb: the udb.
    596  * @param rptr: the rel_ptr (offset).
    597  * @param to: dataptr of the chunk on which ptrlist the rptr is searched.
    598  * @return true if rptr is valid and on the ptrlist.
    599  */
    600 int udb_valid_rptr(udb_base* udb, udb_void rptr, udb_void to);
    601 
    602 /*** UDB_REL_PTR ***/
    603 /**
    604  * Init a new UDB rel ptr at NULL.
    605  * @param ptr: sysptr, becomes inited.
    606  */
    607 void udb_rel_ptr_init(udb_rel_ptr* ptr);
    608 
    609 /**
    610  * Unlink a UDB rel ptr.
    611  * @param base: the udb base
    612  * @param ptr: sysptr, unlinked
    613  */
    614 void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr);
    615 
    616 /**
    617  * Link a UDB rel ptr to a new chunk
    618  * @param base: the udb base
    619  * @param ptr: sysptr, linked to new value.
    620  * @param to: the data to point to (relative ptr).
    621  */
    622 void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to);
    623 
    624 /**
    625  * Change rel ptr to a new value (point to another record)
    626  * @param base: the udb base
    627  * @param ptr: sysptr, points to new value.
    628  * @param to: the data to point to (relative ptr).
    629  */
    630 void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to);
    631 
    632 /**
    633  * A chunk has moved and now edit all the relptrs in list to fix them up
    634  * @param base: the udb base
    635  * @param list: start of the ptr list
    636  * @param to: where the chunk has moved to relptr to its userdata.
    637  */
    638 void udb_rel_ptr_edit(void* base, udb_void list, udb_void to);
    639 
    640 /**
    641  * Get system pointer.  Assumes there is a variable named 'base'
    642  * that points to the udb base.
    643  * @param ptr: the relative pointer (a sysptr to it).
    644  * @return void* to the data.
    645  */
    646 #define UDB_SYSPTR(ptr) UDB_REL(base, (ptr)->data)
    647 
    648 /** get sys ptr for char* string */
    649 #define UDB_CHAR(ptr) ((char*)UDB_REL(base, ptr))
    650 /** get sys ptr for udb_rel_ptr */
    651 #define UDB_REL_PTR(ptr) ((udb_rel_ptr*)UDB_REL(base, ptr))
    652 /** get sys ptr for udb_glob_d */
    653 #define UDB_GLOB(ptr) ((udb_glob_d*)UDB_REL(base, ptr))
    654 /** get sys ptr for udb_chunk_d */
    655 #define UDB_CHUNK(ptr) ((udb_chunk_d*)UDB_REL(base, ptr))
    656 /** get sys ptr for udb_free_chunk_d */
    657 #define UDB_FREE_CHUNK(ptr) ((udb_free_chunk_d*)UDB_REL(base, ptr))
    658 /** get sys ptr for udb_xl_chunk_d */
    659 #define UDB_XL_CHUNK(ptr) ((udb_xl_chunk_d*)UDB_REL(base, ptr))
    660 
    661 /* udb_ptr */
    662 /**
    663  * Initialize an udb ptr.  Set to NULL.  (and thus not linked can be deleted).
    664  * You MUST set it to 0 before you stop using the ptr.
    665  * @param ptr: the ptr to initialise (caller has allocated it).
    666  * @param udb: the udb base to link it to.
    667  */
    668 void udb_ptr_init(udb_ptr* ptr, udb_base* udb);
    669 
    670 /**
    671  * Set udp ptr to a new value.  If set to NULL you can delete it.
    672  * @param ptr: the ptr.
    673  * @param udb: the udb base to link up with that data segment's administration.
    674  * @param newval: new value to point to (udb_void relative file offset to data).
    675  */
    676 void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval);
    677 
    678 /** dereference udb_ptr */
    679 #define UDB_PTR(ptr) (UDB_REL(*((ptr)->base), (ptr)->data))
    680 
    681 /**
    682  * Ease of use udb ptr, allocate space and return ptr to it
    683  * You MUST udb_ptr_set it to 0 before you stop using the ptr.
    684  * @param base: udb base to use.
    685  * @param ptr: ptr is overwritten, can be uninitialised.
    686  * @param type: type of the allocation.
    687  * 	You need a special type if the block contains udb_rel_ptr's.
    688  * 	You can use udb_type_data for plain data.
    689  * @param sz: amount to allocate.
    690  * @return 0 on alloc failure.
    691  */
    692 int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type,
    693 	size_t sz);
    694 
    695 /**
    696  * Ease of use udb ptr, free space and set ptr to NULL (to it can be deleted).
    697  * The space is freed on disk.
    698  * @param ptr: the ptr.
    699  * @param udb: udb base.
    700  * @param sz: the size of the data you stop using.
    701  */
    702 void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz);
    703 
    704 /**
    705  * Get pointer to the data of the ptr.  or use a macro to cast UDB_PTR to
    706  * the type of your structure(.._d)
    707  */
    708 static inline uint8_t* udb_ptr_data(udb_ptr* ptr) {
    709 	return (uint8_t*)UDB_PTR(ptr);
    710 }
    711 
    712 /**
    713  * See if udb ptr is null
    714  */
    715 static inline int udb_ptr_is_null(udb_ptr* ptr) {
    716 	return (ptr->data == 0);
    717 }
    718 
    719 /**
    720  * Get the type of a udb_ptr chunk.
    721  * @param ptr: udb pointer
    722  * @return type of chunk */
    723 udb_chunk_type udb_ptr_get_type(udb_ptr* ptr);
    724 
    725 /** Ease of use, create new pointer to destination relptr
    726  * You MUST udb_ptr_set it to 0 before you stop using the ptr. */
    727 static inline void udb_ptr_new(udb_ptr* ptr, udb_base* udb, udb_rel_ptr* d) {
    728 	udb_ptr_init(ptr, udb);
    729 	udb_ptr_set(ptr, udb, d->data);
    730 }
    731 
    732 /** Ease of use.  Stop using this ptr */
    733 static inline void udb_ptr_unlink(udb_ptr* ptr, udb_base* udb) {
    734 	if(ptr->data)
    735 		udb_base_unlink_ptr(udb, ptr);
    736 }
    737 
    738 /* Ease of use.  Assign rptr from rptr */
    739 static inline void udb_rptr_set_rptr(udb_rel_ptr* dest, udb_base* udb,
    740 	udb_rel_ptr* p) {
    741 #ifdef UDB_CHECK
    742 	if(dest->data) { assert(udb_valid_rptr(udb,
    743 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
    744 	if(p->data) { assert(udb_valid_rptr(udb,
    745 		UDB_SYSTOREL(udb->base, p), p->data)); }
    746 #endif
    747 	udb_rel_ptr_set(udb->base, dest, p->data);
    748 }
    749 
    750 /* Ease of use.  Assign rptr from ptr */
    751 static inline void udb_rptr_set_ptr(udb_rel_ptr* dest, udb_base* udb,
    752 	udb_ptr* p) {
    753 #ifdef UDB_CHECK
    754 	if(dest->data) { assert(udb_valid_rptr(udb,
    755 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
    756 	if(p->data) { assert(udb_valid_dataptr(udb, p->data)); }
    757 #endif
    758 	udb_rel_ptr_set(udb->base, dest, p->data);
    759 }
    760 
    761 /* Ease of use.  Assign ptr from rptr */
    762 static inline void udb_ptr_set_rptr(udb_ptr* dest, udb_base* udb,
    763 	udb_rel_ptr* p) {
    764 #ifdef UDB_CHECK
    765 	if(p->data) { assert(udb_valid_rptr(udb,
    766 		UDB_SYSTOREL(udb->base, p), p->data)); }
    767 #endif
    768 	udb_ptr_set(dest, udb, p->data);
    769 }
    770 
    771 /* Ease of use.  Assign ptr from ptr */
    772 static inline void udb_ptr_set_ptr(udb_ptr* dest, udb_base* udb, udb_ptr* p) {
    773 	udb_ptr_set(dest, udb, p->data);
    774 }
    775 
    776 /* Ease of use, zero rptr.  You use this to zero an existing pointer.
    777  * A new rptr should be rel_ptr_init-ed before it is taken into use. */
    778 static inline void udb_rptr_zero(udb_rel_ptr* dest, udb_base* udb) {
    779 #ifdef UDB_CHECK
    780 	if(dest->data) { assert(udb_valid_rptr(udb,
    781 		UDB_SYSTOREL(udb->base, dest), dest->data)); }
    782 #endif
    783 	udb_rel_ptr_set(udb->base, dest, 0);
    784 }
    785 
    786 /* Ease of use, zero ptr */
    787 static inline void udb_ptr_zero(udb_ptr* dest, udb_base* udb) {
    788 	udb_ptr_set(dest, udb, 0);
    789 }
    790 
    791 /** ease of use, delete memory pointed at by relptr */
    792 static inline void udb_rel_ptr_free_space(udb_rel_ptr* ptr, udb_base* udb,
    793 	size_t sz) {
    794 	udb_void d = ptr->data;
    795 #ifdef UDB_CHECK
    796 	if(d) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, ptr), d)); }
    797 #endif
    798 	udb_rel_ptr_set(udb->base, ptr, 0);
    799 	udb_alloc_free(udb->alloc, d, sz);
    800 }
    801 
    802 #endif /* UDB_H */
    803