diff options
Diffstat (limited to 'lib/table.c')
-rw-r--r-- | lib/table.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/lib/table.c b/lib/table.c new file mode 100644 index 0000000..331a865 --- /dev/null +++ b/lib/table.c @@ -0,0 +1,212 @@ +// 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; +} |