// SPDX-License-Identifier: LGPL-3.0-or-later #include "impl.h" int hkvs_table_new(hkvs_table **pt, hkvs_io *io, char *param) { size_t elt_size = hkvs_read_u16(param + HKVS_PARAM_TABLE_ELTSZ); if(!elt_size) { *pt = NULL; return 0; } size_t key_size = hkvs_read_u8(param + HKVS_PARAM_TABLE_KEYSZ); if(key_size > elt_size) return -EBADMSG; hkvs_table *t = malloc(sizeof(hkvs_table)); if(!t) return -ENOMEM; int r = hkvs_slab_init(&t->slab, io, param, elt_size); if(r < 0) goto fail_free; uint64_t ix_fi = hkvs_read_u64(param + HKVS_PARAM_TABLE_IXFI); if(ix_fi != 0) { uint8_t ix_bits = hkvs_read_u8(param + HKVS_PARAM_TABLE_IXBIT); if(ix_bits < 4 || ix_bits > 59) goto ix_unlink; r = io->open(io, ix_fi, &t->ix, &t->ix_size); if(r < 0) { if(r == -ENOENT) goto ix_dropped; return r; } if(t->ix_size < HKVS_IX_SIZE(ix_bits)) { goto ix_build; } } ret: *pt = t; return 1; ix_unlink: io->unlink(io, ix_fi); ix_dropped: hkvs_write_u64(param + HKVS_PARAM_TABLE_IXFI, 0); ix_build: r = hkvs_ix_build(t, io); if(r < 0) goto fail_close; goto ret; fail_close: hkvs_slab_destroy(&t->slab, io); fail_free: free(t); return r; } hkvs_table *hkvs_table_at(hkvs *c, size_t i) { size_t n_tables = c->n_tables; if(i >= n_tables) return NULL; hkvs_table **tables = c->tables; for(size_t j = 0; j < n_tables; j++) { hkvs_table *t = tables[j]; if(!t) continue; if(!i--) return t; } return NULL; } uint32_t hkvs_table_id(hkvs *c, hkvs_table *t) { (void)c; return hkvs_table__id(t); } size_t hkvs_table_key_size(hkvs *c, hkvs_table *t) { (void)c; return hkvs_table__key_size(t); } int hkvs_table_delete(hkvs *c, uint32_t id) { hkvs_table **tables = c->tables; size_t n_tables = c->n_tables; for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(!t) continue; if(hkvs_table_id(c, t) == id) { tables[i] = NULL; char *param = t->slab.param; hkvs_io *io = c->io; hkvs_table_free(t, io); uint64_t fi = hkvs_read_u64(param + HKVS_PARAM_SLAB_FI); uint64_t ix_fi = hkvs_read_u64(param + HKVS_PARAM_TABLE_IXFI); memset(param, 0, HKVS_PSIZE_TABLE); assert(fi && ix_fi); io->unlink(io, ix_fi); io->unlink(io, fi); return 1; } } return 0; } hkvs_table *hkvs_table_open(hkvs *c, uint32_t id, size_t key_size) { hkvs_table **tables = c->tables; size_t n_tables = c->n_tables; for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(!t) continue; if(hkvs_table__id(t) == id) { if(hkvs_table__key_size(t) != key_size) return NULL; return t; } } return NULL; } HKVS_INLINE size_t hkvs_elt_size(size_t key_size, size_t val_size_hint) { size_t elt_size; if(val_size_hint >= 16 && val_size_hint <= 248) { elt_size = key_size + val_size_hint; elt_size += (-elt_size) % 64; if(elt_size - key_size <= 248) return elt_size; } elt_size = key_size + 16; elt_size += (-elt_size) % 64; return elt_size; } int hkvs_table_create(hkvs *c, hkvs_table **pt, uint32_t id, size_t key_size_z, size_t val_size_hint) { hkvs_table **tables = c->tables; size_t n_tables = c->n_tables; for(size_t i = 0; i < n_tables; i++) { hkvs_table *t = tables[i]; if(!t) continue; if(hkvs_table__id(t) == id) { if(hkvs_table__key_size(t) != key_size_z) return -EEXIST; *pt = t; return 0; } } if(key_size_z > 255) return -EINVAL; uint8_t key_size = (uint8_t)key_size_z; size_t elt_size = hkvs_elt_size(key_size, val_size_hint); size_t slot; for(slot = 0; slot < n_tables; slot++) { if(!tables[slot]) break; } if(slot == n_tables) { if(c->alloc_tables == n_tables) { size_t new_alloc = c->alloc_tables; new_alloc += (new_alloc >> 2) + 1; tables = realloc(tables, new_alloc * sizeof(hkvs_table*)); if(!tables) return -ENOMEM; c->tables = tables; c->alloc_tables = new_alloc; } c->tables[n_tables++] = NULL; c->n_tables = n_tables; int r = hkvs_resize_param(c); if(r < 0) { c->n_tables = --n_tables; return r; } } char *param = c->root_param + HKVS_POFF_TABLE + slot * HKVS_PSIZE_TABLE; memset(param, 0, HKVS_PSIZE_TABLE); hkvs_table *t = malloc(sizeof(hkvs_table)); if(!t) return -ENOMEM; hkvs_write_u16(param + HKVS_PARAM_TABLE_ELTSZ, (uint16_t)elt_size); hkvs_write_u8(param + HKVS_PARAM_TABLE_KEYSZ, key_size); hkvs_write_u32(param + HKVS_PARAM_TABLE_ID, id); hkvs_io *io = c->io; int r = hkvs_slab_init(&t->slab, io, param, elt_size); if(r < 0) goto fail_free; r = hkvs_ix_build(t, io); if(r < 0) goto fail_close; c->tables[slot] = t; *pt = t; return 1; fail_close: hkvs_slab_destroy(&t->slab, io); uint64_t fi = hkvs_read_u64(param + HKVS_PARAM_SLAB_FI); io->unlink(io, fi); fail_free: free(t); return r; }