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