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