Commit e4b6ca42 authored by Michael Tremer's avatar Michael Tremer

stringpool: Implement mmap as optional

This patch will allow mmap() to fail and will make the reader
fall back to read from the given file descriptor.
Signed-off-by: default avatarMichael Tremer <michael.tremer@ipfire.org>
parent a27e1f3d
......@@ -27,21 +27,23 @@
#include <libloc/private.h>
#include <libloc/stringpool.h>
enum loc_stringpool_mode {
STRINGPOOL_DEFAULT,
STRINGPOOL_MMAP,
};
struct loc_stringpool {
struct loc_ctx* ctx;
int refcount;
enum loc_stringpool_mode mode;
// A file descriptor when we open an existing stringpool
int fd;
char* data;
off_t offset;
ssize_t length;
// Mapped data (from mmap())
char* mmapped_data;
char* data;
char* pos;
char buffer[LOC_DATABASE_PAGE_SIZE];
};
static off_t loc_stringpool_get_offset(struct loc_stringpool* pool, const char* pos) {
......@@ -59,10 +61,38 @@ static off_t loc_stringpool_get_offset(struct loc_stringpool* pool, const char*
}
static char* __loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
if (offset < 0 || offset >= pool->length)
ssize_t bytes_read;
// Check boundaries
if (offset < 0 || offset >= pool->length) {
errno = ERANGE;
return NULL;
}
// Return any data that we have in memory
if (pool->data)
return pool->data + offset;
// Otherwise read a block from file
bytes_read = pread(pool->fd, pool->buffer, sizeof(pool->buffer),
pool->offset + offset);
// Break on error
if (bytes_read < 0) {
ERROR(pool->ctx, "Could not read from string pool: %m\n");
return NULL;
}
// It is okay, if we did not read as much as we wanted, since we might be reading
// the last block which might be of an unknown size.
return pool->data + offset;
// Search for a complete string. If there is no NULL byte, the block is garbage.
char* end = memchr(pool->buffer, bytes_read, '\0');
if (!end)
return NULL;
// Return what's in the buffer
return pool->buffer;
}
static int loc_stringpool_grow(struct loc_stringpool* pool, size_t length) {
......@@ -113,22 +143,24 @@ static void loc_stringpool_free(struct loc_stringpool* pool) {
DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
int r;
switch (pool->mode) {
case STRINGPOOL_DEFAULT:
if (pool->data)
free(pool->data);
break;
// Close file
if (pool->fd > 0)
close(pool->fd);
case STRINGPOOL_MMAP:
if (pool->data) {
r = munmap(pool->data, pool->length);
if (r)
ERROR(pool->ctx, "Could not unmap data at %p: %m\n",
pool->data);
}
break;
// Unmap any mapped memory
if (pool->mmapped_data) {
r = munmap(pool->mmapped_data, pool->length);
if (r)
ERROR(pool->ctx, "Error unmapping string pool: %m\n");
if (pool->mmapped_data == pool->data)
pool->data = NULL;
}
// Free any data
if (pool->data)
free(pool->data);
loc_unref(pool->ctx);
free(pool);
}
......@@ -141,31 +173,26 @@ int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
p->ctx = loc_ref(ctx);
p->refcount = 1;
// Save mode
p->mode = STRINGPOOL_DEFAULT;
*pool = p;
return 0;
}
static int loc_stringpool_mmap(struct loc_stringpool* pool, FILE* f, size_t length, off_t offset) {
if (pool->mode != STRINGPOOL_MMAP) {
errno = EINVAL;
return 1;
}
DEBUG(pool->ctx, "Reading string pool starting from %jd (%zu bytes)\n", (intmax_t)offset, length);
static int loc_stringpool_mmap(struct loc_stringpool* pool) {
// Try mmap()
char* p = mmap(NULL, pool->length, PROT_READ, MAP_PRIVATE, pool->fd, pool->offset);
// Map file content into memory
pool->data = pool->pos = mmap(NULL, length, PROT_READ,
MAP_PRIVATE, fileno(f), offset);
// Store size of section
pool->length = length;
if (p == MAP_FAILED) {
// Ignore if data hasn't been aligned correctly
if (errno == EINVAL)
return 0;
if (pool->data == MAP_FAILED)
ERROR(pool->ctx, "Could not mmap stringpool: %m\n");
return 1;
}
// Store mapped memory area
pool->data = pool->mmapped_data = pool->pos = p;
return 0;
}
......@@ -177,22 +204,40 @@ int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
// Allocate a new stringpool
int r = loc_stringpool_new(ctx, &p);
if (r)
return r;
goto ERROR;
// Store offset and length
p->offset = offset;
p->length = length;
DEBUG(p->ctx, "Reading string pool starting from %jd (%zu bytes)\n",
(intmax_t)p->offset, p->length);
// Change mode to mmap
p->mode = STRINGPOOL_MMAP;
int fd = fileno(f);
// Copy the file descriptor
p->fd = dup(fd);
if (p->fd < 0) {
ERROR(ctx, "Could not duplicate file the file descriptor: %m\n");
r = 1;
goto ERROR;
}
// Map data into memory
if (length > 0) {
r = loc_stringpool_mmap(p, f, length, offset);
if (r) {
loc_stringpool_free(p);
return r;
}
if (p->length > 0) {
r = loc_stringpool_mmap(p);
if (r)
goto ERROR;
}
*pool = p;
return 0;
ERROR:
if (p)
loc_stringpool_free(p);
return r;
}
struct loc_stringpool* loc_stringpool_ref(struct loc_stringpool* pool) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment