aboutsummaryrefslogtreecommitdiff
path: root/lib/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/db.c')
-rw-r--r--lib/db.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/lib/db.c b/lib/db.c
new file mode 100644
index 0000000..81cce47
--- /dev/null
+++ b/lib/db.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include "impl.h"
+
+#ifdef FUZZING
+static const size_t hkvs_slab_sizes[HKVS_N_SLABS] = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
+ 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48,
+ 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72,
+ 74, 76, 78, 80,
+};
+#else
+static const size_t hkvs_slab_sizes[HKVS_N_SLABS] = {
+ (2 << 6), (3 << 6), (4 << 6), (5 << 6), (6 << 6), (7 << 6),
+ (8 << 6), (9 << 6), (10 << 6), (11 << 6), (12 << 6), (14 << 6),
+ (8 << 7), (9 << 7), (10 << 7), (11 << 7), (12 << 7), (14 << 7),
+ (8 << 8), (9 << 8), (10 << 8), (11 << 8), (12 << 8), (14 << 8),
+ (8 << 9), (9 << 9), (10 << 9), (11 << 9), (12 << 9), (14 << 9),
+ (8 << 10), (9 << 10), (10 << 10), (11 << 10), (12 << 10), (14 << 10),
+ (8 << 11), (9 << 11), (10 << 11), (11 << 11),
+};
+#endif
+
+int hkvs_new(hkvs **pc, hkvs_io *io) {
+ int r;
+ bool created = false;
+
+ hkvs *c = malloc(sizeof(*c));
+ if(!c) return -ENOMEM;
+
+ c->io = io;
+
+ r = io->open(io, 0, &c->root_param, &c->root_param_size);
+ if(r < 0) {
+ goto fail_free;
+ }
+
+ char *at = c->root_param;
+ size_t param_size = c->root_param_size;
+ if(param_size == 0) {
+ r = io->resize(io, 0, &c->root_param, param_size, HKVS_POFF_TABLE);
+ if(r < 0) goto fail_close;
+ at = c->root_param;
+ param_size = HKVS_POFF_TABLE;
+ c->root_param_size = param_size;
+ memset(at, 0, HKVS_POFF_TABLE);
+ hkvs_write_u64(at + HKVS_PARAM_HEADER_MAGIC, HKVS_MAGIC);
+ created = true;
+ } else if(param_size < HKVS_PSIZE_HEADER || hkvs_read_u64(at + HKVS_PARAM_HEADER_MAGIC) != HKVS_MAGIC) {
+ r = -EBADMSG;
+ goto fail_close;
+ }
+
+ uint64_t version = hkvs_read_u64(at + HKVS_PARAM_HEADER_VERSION);
+ if(version != 0) {
+ r = -ENOTSUP;
+ goto fail_close;
+ }
+
+ uint64_t n_tables_u64 = hkvs_read_u64(at + 16);
+ at += HKVS_PSIZE_HEADER;
+
+ if(param_size < HKVS_POFF_TABLE || n_tables_u64 > (param_size - HKVS_POFF_TABLE) / HKVS_PSIZE_TABLE) {
+ r = -EBADMSG;
+ goto fail_close;
+ }
+ size_t n_tables = (size_t)n_tables_u64;
+
+ for(size_t i = 0; i < HKVS_N_SLABS; i++) {
+ r = hkvs_slab_init(&c->slabs[i], io, at, hkvs_slab_sizes[i]);
+ at += HKVS_PSIZE_SLAB;
+ if(r < 0) goto fail_slabs;
+ }
+
+ hkvs_table **tables = calloc(n_tables, sizeof(hkvs_table*));
+ c->tables = tables;
+ c->n_tables = n_tables;
+ c->alloc_tables = n_tables;
+ for(size_t i = 0; i < n_tables; i++) {
+ r = hkvs_table_new(&tables[i], io, at);
+ at += HKVS_PSIZE_TABLE;
+ if(r < 0) goto fail_tables;
+ }
+
+ c->extfiles = NULL;
+ c->n_extfiles = 0;
+ c->alloc_extfiles = 0;
+ c->extfile_gen = 0;
+
+ *pc = c;
+ return created;
+
+fail_tables:
+ for(size_t i = 0; i < n_tables; i++) {
+ hkvs_table *t = tables[i];
+ if(t) hkvs_table_free(t, io);
+ }
+ free(tables);
+
+fail_slabs:;
+ size_t n_slabs = (size_t)(at - (char*)c->root_param) / HKVS_PSIZE_SLAB;
+ if(n_slabs > HKVS_N_SLABS) n_slabs = HKVS_N_SLABS;
+ while(n_slabs--) {
+ hkvs_slab_destroy(&c->slabs[n_slabs], io);
+ }
+
+fail_close:
+ io->close(io, 0, c->root_param, c->root_param_size);
+fail_free:
+ free(c);
+ io->destroy(io);
+ return r;
+}
+
+int hkvs_resize_param(hkvs *c) {
+ if(c->n_tables > (SIZE_MAX - HKVS_POFF_TABLE) / HKVS_PSIZE_TABLE) return -EFBIG;
+
+ size_t param_size = HKVS_POFF_TABLE + c->n_tables * HKVS_PSIZE_TABLE;
+ int r = c->io->resize(c->io, 0, &c->root_param, c->root_param_size, param_size);
+ if(r < 0) return r;
+ c->root_param_size = param_size;
+
+ char *at = c->root_param;
+ if(hkvs_read_u64(at + HKVS_PARAM_HEADER_MAGIC) != HKVS_MAGIC || hkvs_read_u64(at + HKVS_PARAM_HEADER_VERSION) != 0) {
+ hkvs_die("magic corrupted");
+ }
+ hkvs_write_u64(at + 16, c->n_tables);
+ at += HKVS_PSIZE_HEADER;
+
+ for(size_t i = 0; i < HKVS_N_SLABS; i++) {
+ c->slabs[i].param = at;
+ at += HKVS_PSIZE_SLAB;
+ }
+
+ 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) t->slab.param = at;
+ at += HKVS_PSIZE_TABLE;
+ }
+
+ return 0;
+}
+
+void hkvs_free(hkvs *c) {
+ hkvs_io *io = c->io;
+
+ hkvs_extfile *ext = c->extfiles;
+ size_t n_ext = c->n_extfiles;
+ for(size_t i = 0; i < n_ext; i++) {
+ io->close(io, ext[i].fi, ext[i].addr, ext[i].size);
+ }
+ free(ext);
+
+ 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) hkvs_table_free(t, io);
+ }
+ free(tables);
+
+ for(size_t i = 0; i < HKVS_N_SLABS; i++) {
+ hkvs_slab_destroy(&c->slabs[i], io);
+ }
+
+ io->close(io, 0, c->root_param, c->root_param_size);
+ free(c);
+ io->destroy(io);
+ return;
+}
+
+uint8_t hkvs_slab_for_size(size_t data_size) {
+ // TODO: faster
+ for(uint8_t i = 0; i < HKVS_N_SLABS; i++) {
+ if(data_size <= hkvs_slab_sizes[i]) return i;
+ }
+ return 255;
+}