]> git.ipfire.org Git - people/ms/libloc.git/blobdiff - src/stringpool.c
Split database into a writer and reader
[people/ms/libloc.git] / src / stringpool.c
index 299816cf989e9863b21f8cbf681733c84ef2fc3d..4a0a46b06027120b21116428f389ac548b18216c 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include <loc/libloc.h>
+#include <loc/format.h>
 #include "libloc-private.h"
 #include "stringpool.h"
 
@@ -34,21 +37,64 @@ struct loc_stringpool {
        ssize_t max_length;
 };
 
-LOC_EXPORT int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool, size_t max_length) {
-       if (max_length <= 0)
-               return -EINVAL;
+static int loc_stringpool_deallocate(struct loc_stringpool* pool) {
+       if (pool->data) {
+               int r = munmap(pool->data, pool->max_length);
+               if (r) {
+                       ERROR(pool->ctx, "Could not unmap data at %p: %s\n",
+                               pool->data, strerror(errno));
+
+                       return r;
+               }
+       }
+
+       return 0;
+}
+
+static int loc_stringpool_allocate(struct loc_stringpool* pool, size_t length) {
+       // Drop old data
+       int r = loc_stringpool_deallocate(pool);
+       if (r)
+               return r;
+
+       pool->max_length = length;
+
+       // Align to page size
+       while (pool->max_length % sysconf(_SC_PAGE_SIZE) > 0)
+               pool->max_length++;
+
+       DEBUG(pool->ctx, "Allocating pool of %zu bytes\n", pool->max_length);
+
+       // Allocate some memory
+       pool->data = pool->pos = mmap(NULL, pool->max_length,
+               PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+
+       if (pool->data == MAP_FAILED) {
+               DEBUG(pool->ctx, "%s\n", strerror(errno));
+               return -errno;
+       }
+
+       DEBUG(pool->ctx, "Allocated pool at %p\n", pool->data);
+
+       return 0;
+}
 
+LOC_EXPORT int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool, size_t max_length) {
        struct loc_stringpool* p = calloc(1, sizeof(*p));
        if (!p)
                return -ENOMEM;
 
        p->ctx = loc_ref(ctx);
        p->refcount = 1;
-       p->max_length = max_length;
 
        // Allocate the data section
-       p->data = malloc(p->max_length);
-       p->pos = p->data;
+       if (max_length > 0) {
+               int r = loc_stringpool_allocate(p, max_length);
+               if (r) {
+                       loc_stringpool_unref(p);
+                       return r;
+               }
+       }
 
        DEBUG(p->ctx, "String pool allocated at %p\n", p);
        DEBUG(p->ctx, "  Maximum size: %zu bytes\n", p->max_length);
@@ -66,9 +112,8 @@ LOC_EXPORT struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool
 static void loc_stringpool_free(struct loc_stringpool* pool) {
        DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
 
+       loc_stringpool_deallocate(pool);
        loc_unref(pool->ctx);
-
-       free(pool->data);
        free(pool);
 }
 
@@ -98,7 +143,7 @@ static off_t loc_stringpool_get_next_offset(struct loc_stringpool* pool, off_t o
 }
 
 static size_t loc_stringpool_space_left(struct loc_stringpool* pool) {
-       return pool->max_length - loc_stringpool_get_offset(pool, pool->pos);
+       return pool->max_length - loc_stringpool_get_size(pool);
 }
 
 LOC_EXPORT const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
@@ -114,6 +159,10 @@ LOC_EXPORT const char* loc_stringpool_get(struct loc_stringpool* pool, off_t off
        return string;
 }
 
+LOC_EXPORT size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
+       return loc_stringpool_get_offset(pool, pool->pos);
+}
+
 static off_t loc_stringpool_find(struct loc_stringpool* pool, const char* s) {
        if (!s || !*s)
                return -EINVAL;
@@ -184,3 +233,22 @@ LOC_EXPORT void loc_stringpool_dump(struct loc_stringpool* pool) {
                offset = loc_stringpool_get_next_offset(pool, offset);
        }
 }
+
+LOC_EXPORT int loc_stringpool_read(struct loc_stringpool* pool, FILE* f, off_t offset, size_t length) {
+       DEBUG(pool->ctx, "Reading string pool from %zu (%zu bytes)\n", offset, length);
+
+       pool->data = pool->pos = mmap(NULL, length, PROT_READ,
+               MAP_PRIVATE, fileno(f), offset);
+       pool->max_length = length;
+
+       if (pool->data == MAP_FAILED)
+               return -errno;
+
+       return 0;
+}
+
+LOC_EXPORT size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
+       size_t size = loc_stringpool_get_size(pool);
+
+       return fwrite(pool->data, sizeof(*pool->data), size, f);
+}