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 curren 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 */ 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 */ 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. */ 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 */ 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 */ 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 */ 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 */ 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 */ 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. */ 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 */ 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 */ 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