diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2021-06-28 21:35:19 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2021-06-28 21:35:19 +0000 |
commit | 4b057ce275a2761656b62a3fa1e57ebf934c3af8 (patch) | |
tree | d11a170b2e871b061e5998eba9b507c198ca2460 /src/server/dynstorage.c | |
parent | ae1a76cad535a04f0c059e8dae9c8a27a84222a4 (diff) | |
download | s6-rc-4b057ce275a2761656b62a3fa1e57ebf934c3af8.tar.xz |
Add dynstorage, finish state IO
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/server/dynstorage.c')
-rw-r--r-- | src/server/dynstorage.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/server/dynstorage.c b/src/server/dynstorage.c new file mode 100644 index 0000000..c17e8e6 --- /dev/null +++ b/src/server/dynstorage.c @@ -0,0 +1,86 @@ +/* ISC license. */ + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> + +#include <skalibs/gensetdyn.h> +#include <skalibs/avltree.h> + +#include "dynstorage.h" + +/* + This is probably way overengineered, we could strdup the instance parameters + into the instances themselves; there would be a little param duplication, but + likely not much, and chances are we would save memory. + However, a fundamental principle of C memory management is: separate structure + from storage. Failing to abide by it leads to spaghettification of storage + paths, and ultimately memory leaks. + So, we store all our dynamic strings (i.e. user-provided strings that only + appear in transient storage like buffers but that need a longer lifetime) here, + and nowhere else. Duplication is prevented via refcounting. +*/ + +typedef struct cell_s cell_t, *cell_t_ref ; +struct cell_s +{ + char *s ; + uint32_t refcount ; +} ; +#define CELL_ZERO { .s = 0, .refcount = 0 } ; + +static gensetdyn cells = GENSETDYN_INIT(cell_t, 3, 3, 8) ; + +static void *dynstorage_dtok (uint32_t d, void *data) +{ + return GENSETDYN_P(cell_t, (gensetdyn *)data, d)->s ; +} + +static int dynstorage_cmp (void const *a, void const *b, void *data) +{ + (void)data ; + return strcmp((char const *)a, (char const *)b) ; +} + +static avltree dynstorage = AVLTREE_INIT(3, 3, 8, &dynstorage_dtok, &dynstorage_cmp, &cells) ; + +char const *dynstorage_add (char const *s) +{ + cell_t *p ; + uint32_t d ; + if (avltree_search(&dynstorage, s, &d)) + { + p = GENSETDYN_P(cell_t, &cells, d) ; + p->refcount++ ; + return p->s ; + } + + if (!gensetdyn_new(&cells, &d)) return 0 ; + p = GENSETDYN_P(cell_t, &cells, d) ; + p->s = strdup(s) ; + if (!p->s) goto err0 ; + p->refcount = 1 ; + if (!avltree_insert(&dynstorage, d)) goto err1 ; + return p->s ; + + err1: + free(p->s) ; + err0: + gensetdyn_delete(&cells, d) ; + return 0 ; +} + +void dynstorage_remove (char const *s) +{ + uint32_t d ; + if (avltree_search(&dynstorage, s, &d) + { + cell_t *p = GENSETDYN_P(cell_t, &cells, d) ; + if (!--p->refcount) + { + avltree_delete(&dynstorage, s) ; + free(p->s) ; + gensetdyn_delete(&cells, d) ; + } + } +} |