// 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;
}