From cb2a50691fb0cddb64e1b5a9ed242a6a0b42d503 Mon Sep 17 00:00:00 2001 From: Hristo Venev Date: Mon, 22 Jun 2020 12:32:11 +0300 Subject: Initial commit. --- lib/slab.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 lib/slab.c (limited to 'lib/slab.c') diff --git a/lib/slab.c b/lib/slab.c new file mode 100644 index 0000000..2d2d8e1 --- /dev/null +++ b/lib/slab.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "impl.h" +#include +#include + +static size_t hkvs_slab_size_to_count(size_t elt_size, size_t size) { + size_t block_size = (elt_size + 1) * HKVS_SLAB_BLOCK; + + size_t blocks = size / block_size; + size %= block_size; + size_t rest = 0; + if(size > HKVS_SLAB_BLOCK) { + rest = (size - HKVS_SLAB_BLOCK) / elt_size; + } + + return blocks * HKVS_SLAB_BLOCK + rest; +} + +static size_t hkvs_slab_count_to_size(size_t elt_size, size_t count) { + size_t size; + if(__builtin_mul_overflow(count, elt_size + 1, &size)) return SIZE_MAX; + if(__builtin_add_overflow(size, (-count) % HKVS_SLAB_BLOCK, &size)) return SIZE_MAX; + return size; +} + +int hkvs_slab_init(hkvs_slab *s, hkvs_io *io, char *param, size_t elt_size) { + s->param = param; + s->elt_size = elt_size; + + uint64_t fi = hkvs_read_u64(param + HKVS_PARAM_SLAB_FI); + if(fi == 0) { + s->addr = NULL; + s->map_size = 0; + return 0; + } + + int r = io->open(io, fi, &s->addr, &s->map_size); + if(r < 0) return r; + + uint64_t alloc_count = hkvs_read_u64(param + HKVS_PARAM_SLAB_ALLOC); + if(alloc_count > hkvs_slab_size_to_count(elt_size, s->map_size)) { + io->close(io, fi, s->addr, s->map_size); + return -EBADMSG; + } + + return 0; +} + +int hkvs_slab_alloc(hkvs *c, hkvs_slab *s, size_t *pi) { + size_t alloc_count = hkvs_slab_size(s); + + uint64_t at_64 = hkvs_read_u64(s->param + HKVS_PARAM_SLAB_FREE); + if(at_64 < alloc_count) { + size_t at = (size_t)at_64; + + char *p = hkvs_slab_at(s, at); + + for(size_t i = 1; i < HKVS_SLAB_FREEPTRS; i++) { + uint64_t v = hkvs_read_u64(p + i * 8); + if(v <= at) return -EBADMSG; + if(v < alloc_count) { + size_t id = (size_t)v; + hkvs_write_u64(p + i * 8, UINT64_MAX); + *pi = id; + return 0; + } + } + + at_64 = hkvs_read_u64(p); + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_FREE, at_64); + + *pi = at; + return 0; + } + + if(at_64 != UINT64_MAX) { + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_FREE, UINT64_MAX); + } + + size_t cap_count = hkvs_slab_size_to_count(s->elt_size, s->map_size); + hkvs_assume(alloc_count <= cap_count); + if(alloc_count == cap_count) { + size_t grow_count = cap_count + (cap_count >> 3) + 1; + size_t grow_size; + while(true) { + grow_size = hkvs_slab_count_to_size(s->elt_size, grow_count); + if(grow_size != 0) break; + size_t dec = (grow_count - cap_count) / 2; + if(dec == 0) return -EFBIG; + grow_count -= dec; + } + + hkvs_io *io = c->io; + uint64_t fi = hkvs_read_u64(s->param + HKVS_PARAM_SLAB_FI); + if(fi == 0) { + int r = io->create(io, &fi, &s->addr, grow_size); + if(r < 0) return r; + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_FI, fi); + } else { + int r = io->resize(io, fi, &s->addr, s->map_size, grow_size); + if(r < 0) return r; + } + s->map_size = grow_size; + } + + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_ALLOC, alloc_count + 1); + *pi = alloc_count; + return 0; +} + +void hkvs_slab_discard(hkvs_slab *s, size_t id) { + size_t alloc_count = hkvs_slab_size(s); + hkvs_assume(id < alloc_count); + if(id == alloc_count - 1) { + do { + alloc_count--; + } while(alloc_count > 0 && hkvs_slab_mark(s, alloc_count - 1) == 0); + + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_ALLOC, alloc_count); + return; + } + + hkvs_slab_set_mark(s, id, 0); + + uint64_t free_64 = hkvs_read_u64(s->param + HKVS_PARAM_SLAB_FREE); + if(id < free_64) { + hkvs_write_u64(s->param + HKVS_PARAM_SLAB_FREE, id); + char *p = hkvs_slab_at(s, id); + hkvs_write_u64(p, free_64); + for(size_t i = 1; i < HKVS_SLAB_FREEPTRS; i++) { + hkvs_write_u64(p + i * 8, UINT64_MAX); + } + return; + } + + char *p = hkvs_slab_at(s, (size_t)free_64); + uint64_t v = hkvs_read_u64(p + 8); + + if(v >= alloc_count) { + size_t i = 2; + while(true) { + v = hkvs_read_u64(p + i * 8); + if(v < alloc_count) break; + i++; + if(i == HKVS_SLAB_FREEPTRS) { + hkvs_write_u64(p + 8, id); + return; + } + } + while(v < id) { + hkvs_write_u64(p + (i - 1) * 8, v); + i++; + if(i == HKVS_SLAB_FREEPTRS) break; + v = hkvs_read_u64(p + i * 8); + } + hkvs_write_u64(p + (i - 1) * 8, id); + return; + } + + if(hkvs_read_u64(p + (HKVS_SLAB_FREEPTRS - 1) * 8) >= alloc_count) { + size_t i = 1; + while(v < id) { + i++; + v = hkvs_read_u64(p + i * 8); + } + uint64_t v2 = id; + while(true) { + hkvs_write_u64(p + i * 8, v2); + if(v >= alloc_count) break; + v2 = v; + i++; + v = hkvs_read_u64(p + i * 8); + } + return; + } + + if(v < id) { + uint64_t v2 = id; + id = (size_t)v; + size_t i = 2; + do { + v = hkvs_read_u64(p + i * 8); + if(v >= v2) break; + hkvs_write_u64(p + (i - 1) * 8, v); + i++; + } while(i < HKVS_SLAB_FREEPTRS); + hkvs_write_u64(p + (i - 1) * 8, v2); + } + + char *p2 = hkvs_slab_at(s, id); + memcpy(p2, p, HKVS_SLAB_FREEPTRS * 8); + + hkvs_write_u64(p, id); + for(size_t i = 1; i < HKVS_SLAB_FREEPTRS; i++) { + hkvs_write_u64(p + i * 8, UINT64_MAX); + } + return; +} -- cgit