aboutsummaryrefslogblamecommitdiff
path: root/lib/table.c
blob: 331a8656b4f939baa6cce2ebc3afb1d6be9e7ba6 (plain) (tree)



















































































































































































































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