diff options
Diffstat (limited to 'lib/io_mem.c')
-rw-r--r-- | lib/io_mem.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/lib/io_mem.c b/lib/io_mem.c new file mode 100644 index 0000000..4f27c02 --- /dev/null +++ b/lib/io_mem.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "internal.h" +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +typedef struct hkvs_iomem_file hkvs_iomem_file; +struct hkvs_iomem_file { + uintptr_t data_mode; + size_t size; +}; + +typedef struct hkvs_iomem hkvs_iomem; +struct hkvs_iomem { + hkvs_io base; + uint64_t rand_ctr; + char rand_key[16]; + size_t n_files; + struct hkvs_iomem_file *files; +}; + +static void hkvs_iomem_destroy(hkvs_io *iov) { + hkvs_iomem *io = (hkvs_iomem*)iov; + size_t n = io->n_files; + for(size_t i = 0; i < n; i++) { + struct hkvs_iomem_file *f = io->files + i; + uintptr_t mode = f->data_mode & 3; + char *p = (char*)(f->data_mode - mode); + free(p); + } + free(io->files); + free(io); +} + +static int hkvs_iomem_random(hkvs_io *iov, char *buf, size_t n) { + hkvs_iomem *io = (hkvs_iomem*)iov; + while(true) { + uint64_t h = hkvs_hash(io->rand_key, (const char*)&io->rand_ctr, sizeof(io->rand_ctr)); + io->rand_ctr++; + if(n > 8) { + memcpy(buf, &h, 8); + buf += 8; + n -= 8; + } else { + memcpy(buf, &h, n); + return 0; + } + } +} + +static int hkvs_iomem_open(hkvs_io *iov, uint64_t fi, char **pmem, size_t *psz) { + hkvs_iomem *io = (hkvs_iomem*)iov; + + if(fi >= io->n_files) return -ENOENT; + + hkvs_iomem_file *f = io->files + (size_t)fi; + uintptr_t mode = f->data_mode & 3; + char *p = (char*)(f->data_mode - mode); + if(mode == 0) { + if(fi != 0) return -ENOENT; + } else if(mode != 1) { + hkvs_die("bad file state"); + } + + f->data_mode = (uintptr_t)p + 2; + *pmem = p; + *psz = f->size; + return 0; +} + +static int hkvs_iomem_create(hkvs_io *iov, uint64_t *pfi, char **pmem, size_t sz) { + hkvs_iomem *io = (hkvs_iomem*)iov; + + hkvs_iomem_file *f = io->files; + size_t n = io->n_files; + for(size_t i = 1; i < n; i++) { + if(!f[i].data_mode) { + n = i; + f += n; + goto done; + } + } + + f = realloc(f, (n + 1) * sizeof(hkvs_iomem_file)); + if(!f) return -ENOMEM; + io->files = f; + io->n_files = n + 1; + f += n; + f->data_mode = 0; + +done:; + char *p = malloc(sz); + if(!p) return -ENOMEM; + memset(p, 0, sz); + + f->data_mode = (uintptr_t)p + 2; + f->size = sz; + *pfi = n; + *pmem = p; + return 0; +} + +static int hkvs_iomem_resize(hkvs_io *iov, uint64_t fi, char **pmem, size_t old_sz, size_t new_sz) { + hkvs_iomem *io = (hkvs_iomem*)iov; + + if(fi > io->n_files) hkvs_die("bad file index"); + + hkvs_iomem_file *f = io->files + (size_t)fi; + uintptr_t mode = f->data_mode & 3; + char *p = (char*)(f->data_mode - mode); + if(mode != 2) hkvs_die("bad file state"); + if(*pmem != p) hkvs_die("bad file mem"); + if(old_sz != f->size) hkvs_die("bad file old_size"); + + p = realloc(p, new_sz); + if(new_sz && !p) return -ENOMEM; + + f->data_mode = (uintptr_t)p + 2; + f->size = new_sz; + *pmem = p; + return 0; +} + +static void hkvs_iomem_close(hkvs_io *iov, uint64_t fi, char *mem, size_t sz) { + hkvs_iomem *io = (hkvs_iomem*)iov; + + if(fi > io->n_files) hkvs_die("bad file index"); + + hkvs_iomem_file *f = io->files + (size_t)fi; + uintptr_t mode = f->data_mode & 3; + char *p = (char*)(f->data_mode - mode); + if(mode != 2) hkvs_die("bad file state"); + if(mem != p) hkvs_die("bad file mem"); + if(sz != f->size) hkvs_die("bad file size"); + + f->data_mode = (uintptr_t)p + 1; +} + +static void hkvs_iomem_unlink(hkvs_io *iov, uint64_t fi) { + hkvs_iomem *io = (hkvs_iomem*)iov; + + if(fi > io->n_files) hkvs_die("bad file index"); + + hkvs_iomem_file *f = io->files + (size_t)fi; + uintptr_t mode = f->data_mode & 3; + char *p = (char*)(f->data_mode - mode); + if(mode != 1) hkvs_die("bad file state"); + + free(p); + f->data_mode = 0; + f->size = 0; +} + +hkvs_io *hkvs_io_new_mem(uint64_t rand_seed) { + hkvs_iomem_file *files = malloc(sizeof(hkvs_iomem_file)); + if(!files) return NULL; + files[0].data_mode = 0; + files[0].size = 0; + + hkvs_iomem *io = malloc(sizeof(*io)); + if(!io) { + free(files); + return NULL; + } + io->base = (hkvs_io){ + .destroy = &hkvs_iomem_destroy, + .random = &hkvs_iomem_random, + .open = &hkvs_iomem_open, + .create = &hkvs_iomem_create, + .close = &hkvs_iomem_close, + .resize = &hkvs_iomem_resize, + .unlink = &hkvs_iomem_unlink, + }; + hkvs_write_u64(io->rand_key, rand_seed); + hkvs_write_u64(io->rand_key + 8, rand_seed); + io->rand_ctr = 0; + io->n_files = 1; + io->files = files; + return &io->base; +} |