aboutsummaryrefslogtreecommitdiff
path: root/lib/table.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/table.c')
-rw-r--r--lib/table.c212
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;
+}