From 7754455c48c50764ad7291ea508109c53b60517f Mon Sep 17 00:00:00 2001 From: Gediminas Jakutis Date: Fri, 27 Mar 2020 14:40:33 +0200 Subject: cache I/O implementation and fixes. Signed-off-by: Gediminas Jakutis --- src/cache.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/cache.h | 7 +++++ src/datagen.c | 7 +---- src/datagen.h | 3 +- src/defs.h | 9 +++--- src/io.c | 10 +++++-- src/io.h | 6 ++++ src/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 190 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index ebe1047..de182ec 100644 --- a/src/cache.c +++ b/src/cache.c @@ -6,11 +6,14 @@ #include #include "defs.h" +static off_t cache_walker(struct stream * const restrict in, ssize_t idx); + int cache_create(struct stream * const restrict in, const struct settings * const restrict s) { int ret; void *cache; + try(!in->cached, err, EINVAL, "cannot create cache: stream is uncached"); try(!(cache = calloc(in->n, s->stride)), err, ENOMEM, "out of memory"); in->cache = cache; @@ -21,7 +24,9 @@ err: int cache_populate(struct stream * const restrict in) { int ret = 0; - ssize_t i; + size_t i; + + try(!in->cached, err, EINVAL, "cannot populate cache: stream is uncached"); for (i = 0; i < in->n && !ret; ++i) { ret = in->get_element(in, i, in->cache + i); @@ -34,7 +39,10 @@ err: int cache_flush(struct stream * const in) { int ret; - ssize_t i; + size_t i; + + try(!in->cached, err, EINVAL, "no cache to flush: stream is uncached"); + try(in->out != 1, err, EINVAL, "cannot flush a non-output cache"); for (i = 0; i < in->n && !ret; ++i) { ret = in->put_element(in, i, in->cache + i); @@ -48,9 +56,87 @@ int cache_destroy(struct stream * const in) { int ret; - try(!in->cache, err, EINVAL, "trying to destroy cache of uncached streadm"); + try(!in->cached, err, EINVAL, "no cache to destroy: stream uncached"); free(in->cache); in->cache = NULL; err: return ret; } + +int cache_transfer(struct stream * const from, struct stream * const to) +{ + int ret; + + try(!from->cached || !to->cached, err, EINVAL, "cannot transfer caches of uncached streams"); + try(!from->cache, err, EINVAL, "no cache to transfer"); + try(!to->cache, err, EINVAL, "cannot transfer cache: recipient cache already exists"); + + to->cache = from->cache; + from->cache = NULL; +err: + return ret; +} + +int cached_get_array(struct stream * const in, ssize_t idx, struct entry_l * const data) +{ + int ret = 0; + const struct entry * const cache = in->cache; + + data->val = cache[idx].val; + + return ret; +} + +int cached_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data) +{ + int ret = 0; + off_t offset; + + offset = cache_walker(in, idx); + *data = in->cache[offset]; + + return ret; +} + +int cached_put_array(struct stream * const in, ssize_t idx, const struct entry_l * const data) +{ + int ret = 0; + struct entry * const cache = in->cache; + + cache[idx].val = data->val; + + return ret; +} + +int cached_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data) +{ + int ret = 0; + off_t offset; + + offset = cache_walker(in, idx); + in->cache[offset] = *data; + + return ret; +} + +static off_t cache_walker(struct stream * const restrict in, ssize_t idx) +{ + size_t i; + off_t ret = in->prev_off; + + if (in->prev_idx < idx) { /* previous index smaller, walk forward */ + for (i = labs(idx - in->prev_idx); i; --i) { + ret = in->cache[ret].next; + } + + } else if (in->prev_idx > idx) { /* previous index larger, walk backwards */ + for (i = in->prev_idx - idx; i; --i) { + ret = in->cache[ret].prev; + } + } /* ...or we're standing on it already, if neither */ + + in->prev_idx = idx; + in->prev_off = ret; + + return ret; +} diff --git a/src/cache.h b/src/cache.h index 0607112..45215d4 100644 --- a/src/cache.h +++ b/src/cache.h @@ -12,5 +12,12 @@ int cache_create(struct stream * const restrict in, const struct settings * cons int cache_populate(struct stream * const restrict in); int cache_flush(struct stream * const in); int cache_destroy(struct stream * const in); +int cache_transfer(struct stream * const from, struct stream * const to); + +int cached_get_array(struct stream * const in, ssize_t idx, struct entry_l * const data); +int cached_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); + +int cached_put_array(struct stream * const in, ssize_t idx, const struct entry_l * const data); +int cached_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); #endif /* ALGOS_CACHE_H_INCLUDED */ diff --git a/src/datagen.c b/src/datagen.c index d4c8bab..25002e2 100644 --- a/src/datagen.c +++ b/src/datagen.c @@ -10,7 +10,7 @@ #include "datagen.h" #include "defs.h" -int gen_get_array(struct stream * const restrict in, ssize_t idx, struct entry_l * const data) +int gen_get_array(struct stream * const in, ssize_t idx, struct entry_l * const data) { int ret = 0; (void) idx; @@ -40,8 +40,3 @@ int gen_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l return ret; } - -int gen_put(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data) -{ - return ENOSYS; -} diff --git a/src/datagen.h b/src/datagen.h index 63b3461..0b8aa35 100644 --- a/src/datagen.h +++ b/src/datagen.h @@ -7,8 +7,7 @@ #include "defs.h" -int gen_get_array(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); +int gen_get_array(struct stream * const in, ssize_t idx, struct entry_l * const data); int gen_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); -int gen_put(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); #endif /* ALGOS_DATAGEN_H_INCLUDED */ diff --git a/src/defs.h b/src/defs.h index ff19102..f3eb48f 100644 --- a/src/defs.h +++ b/src/defs.h @@ -57,15 +57,16 @@ enum dataformat { struct stream { size_t n; ssize_t prev_idx; + off_t prev_off; int fd; int out; int cached; char *name; struct entry_l *cache; - int (*get_element)(struct stream * const restrict, size_t, struct entry_l *); - int (*put_element)(struct stream * const restrict, size_t, struct entry_l *); - int (*get_element_cache)(struct stream * const restrict, size_t, struct entry_l *); - int (*put_element_cache)(struct stream * const restrict, size_t, struct entry_l *); + int (*get_element)(struct stream * const, ssize_t, struct entry_l * const); + int (*put_element)(struct stream * const restrict, ssize_t, struct entry_l const * const); + int (*get_element_cache)(struct stream * const, ssize_t, struct entry_l * const); + int (*put_element_cache)(struct stream * const restrict, ssize_t, struct entry_l const * const); }; struct settings { diff --git a/src/io.c b/src/io.c index 9fdad38..688ec35 100644 --- a/src/io.c +++ b/src/io.c @@ -45,7 +45,7 @@ int stream_close(struct stream * const in) try(!in || in->fd < 0, early_err, EINVAL, "invalid argunent"); - if (!in->out) { + if (in->out != 1) { goto out; } @@ -135,9 +135,15 @@ static int stream_open_special(struct stream * const in) int ret = 0; try(stat(in->name, &st), err, errno, "stat failed: %s", strerror(ret)); - in->fd = open(in->name, O_RDONLY | O_NOATIME); + in->fd = open(in->name, O_RDONLY); try(in->fd < 0, err, errno, "failed opening input file: %s", strerror(ret)); err: return ret; } + +int direct_get_array(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); +int direct_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); + +int direct_put_array(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); +int direct_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); diff --git a/src/io.h b/src/io.h index 792ebd2..eca6aec 100644 --- a/src/io.h +++ b/src/io.h @@ -10,4 +10,10 @@ int stream_open(struct stream * const in, const struct settings * const s); int stream_close(struct stream * const in); +int direct_get_array(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); +int direct_get_list(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); + +int direct_put_array(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); +int direct_put_list(struct stream * const restrict in, ssize_t idx, const struct entry_l * const data); + #endif /* ALGOS_IO_H_INCLUDED */ diff --git a/src/main.c b/src/main.c index ddae024..1050741 100644 --- a/src/main.c +++ b/src/main.c @@ -10,6 +10,8 @@ #include #include "io.h" #include "defs.h" +#include "cache.h" +#include "datagen.h" static char randfile[] = "/dev/urandom"; @@ -19,7 +21,10 @@ static struct stream file_in = {.prev_idx = -1, .fd = -1}; static struct stream file_out = {.prev_idx = -1, .fd = -1, .out = 1}; static int parseargs(int argc, char **argv, struct settings * settings); +int prime_io_functions(struct settings const * const s, struct stream * const in); void printhelp(const char * const name); +static int stub_get(struct stream * const restrict in, ssize_t idx, struct entry_l * const data); +static int stub_put(struct stream * const restrict in, ssize_t idx, struct entry_l const * const data); int main(int argc, char **argv) { @@ -36,6 +41,9 @@ int main(int argc, char **argv) file_in.name = settings.filein; } + ret = prime_io_functions(&settings, &file_in); + ret = prime_io_functions(&settings, &file_out); + file_out.name = settings.fileout ? settings.fileout : settings.filein; try_s((ret = stream_open(&file_in, &settings)), out); file_out.n = file_in.n; @@ -131,6 +139,51 @@ err: return ret; } +int prime_io_functions(struct settings const * const s, struct stream * const in) +{ + int ret = 0; + + if (in->out == 1) { + if (s->format == array) { + in->get_element = stub_get; + in->put_element = stub_put; + in->get_element_cache = cached_get_array; + in->put_element_cache = cached_put_array; + } else { + in->get_element = stub_get; + in->put_element = stub_put; + in->get_element_cache = cached_get_list; + in->put_element_cache = cached_put_list; + } + } else if (!in->out) { /* reading streams do not support dumping */ + if (s->format == array) { + in->get_element = stub_get; + in->put_element = stub_put; + in->get_element_cache = stub_get; + in->put_element_cache = stub_put; + } else { + in->get_element = stub_get; + in->put_element = stub_put; + in->get_element_cache = stub_get; + in->put_element_cache = stub_put; + } + } else { /* data generation streams do not support dumping nor any cache I/O beyond initial data generation */ + if (s->format == array) { + in->get_element = gen_get_array; + in->put_element = stub_put; + in->get_element_cache = stub_get; + in->put_element_cache = stub_put; + } else { + in->get_element = gen_get_list; + in->put_element = stub_put; + in->get_element_cache = stub_get; + in->put_element_cache = stub_put; + } + } + + return ret; +} + void printhelp(const char * const name) { printf( "This is a mergesort program and such\n" @@ -153,3 +206,23 @@ void printhelp(const char * const name) name); return; } + +static int stub_get(struct stream * const restrict in, ssize_t idx, struct entry_l * const data) +{ + (void) in; + (void) idx; + (void) data; + + rin_warn("stub!"); + return ENOSYS; +} + +static int stub_put(struct stream * const restrict in, ssize_t idx, struct entry_l const * const data) +{ + (void) in; + (void) idx; + (void) data; + + rin_warn("stub!"); + return ENOSYS; +} -- cgit v1.2.3