From 789baf33a15abb068cc8f83af50beaca549c2039 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 21 Nov 2022 20:31:37 +0000 Subject: [PATCH] Make Db interfaces take varargs. This makes it much more flexible, at the expense of making it a little more fragile. I can think of a number of scenarios where we'll have paths that have variables in multiple spots, and I don't want to do sprintf() magic every time I need to access an object at one of those paths. --- src/Array.c | 64 ++++++++++++++ src/Db.c | 209 +++++++++++++++++++++++++++++++------------- src/Util.c | 27 +++++- src/include/Array.h | 7 ++ src/include/Db.h | 4 +- 5 files changed, 244 insertions(+), 67 deletions(-) diff --git a/src/Array.c b/src/Array.c index a32c2ef..d63c3fd 100644 --- a/src/Array.c +++ b/src/Array.c @@ -247,3 +247,67 @@ ArraySort(Array * array, int (*compare) (void *, void *)) } ArrayQuickSort(array, 0, array->size, compare); } + +/* Even though the following operations could be done using only the + * public Array API defined above, I opted for low-level struct + * manipulation because it allows much more efficient copying; we only + * allocate what we for sure need upfront, and don't have to + * re-allocate during the operation. */ + +Array * +ArrayFromVarArgs(size_t n, va_list ap) +{ + size_t i; + Array *arr = Malloc(sizeof(Array)); + + if (!arr) + { + return NULL; + } + + arr->size = n; + arr->allocated = n; + arr->entries = Malloc(sizeof(void *) * arr->allocated); + + if (!arr->entries) + { + Free(arr); + return NULL; + } + + for (i = 0; i < n; i++) + { + arr->entries[i] = va_arg(ap, void *); + } + + return arr; +} + +Array * +ArrayDuplicate(Array * arr) +{ + size_t i; + Array *arr2 = Malloc(sizeof(Array)); + + if (!arr2) + { + return NULL; + } + + arr2->size = arr->size; + arr2->allocated = arr->size; + arr2->entries = Malloc(sizeof(void *) * arr->allocated); + + if (!arr2->entries) + { + Free(arr2); + return NULL; + } + + for (i = 0; i < arr2->size; i++) + { + arr2->entries[i] = arr->entries[i]; + } + + return arr2; +} diff --git a/src/Db.c b/src/Db.c index 3e80ea7..7c3f5fd 100644 --- a/src/Db.c +++ b/src/Db.c @@ -51,8 +51,7 @@ struct DbRef unsigned long ts; size_t size; - char *prefix; - char *key; + Array *name; DbRef *prev; DbRef *next; @@ -161,27 +160,64 @@ DbComputeSize(HashMap * json) } static char * -DbHashKey(char *prefix, char *key) +DbHashKey(Array * args) { - return UtilStringConcat(prefix, key); + size_t i; + char *str = NULL; + + for (i = 0; i < ArraySize(args); i++) + { + char *tmp = UtilStringConcat(str, ArrayGet(args, i)); + + Free(str); + str = tmp; + } + + return str; } static char * -DbFileName(Db * db, char *prefix, char *key) +DbDirName(Db * db, Array * args) { - char *tmp = UtilStringConcat(prefix, "/"); - char *tmp2 = UtilStringConcat(tmp, key); - char *tmp3 = UtilStringConcat(tmp2, ".json"); + size_t i; + char *str = UtilStringConcat(db->dir, "/"); - char *tmp4 = UtilStringConcat(db->dir, "/"); - char *tmp5 = UtilStringConcat(tmp4, tmp3); + for (i = 0; i < ArraySize(args) - 1; i++) + { + char *tmp, *tmp2; - Free(tmp); - Free(tmp2); - Free(tmp3); - Free(tmp4); + tmp = UtilStringConcat(str, ArrayGet(args, i)); + tmp2 = UtilStringConcat(tmp, "/"); - return tmp5; + Free(str); + Free(tmp); + + str = tmp2; + } + + return str; +} + +static char * +DbFileName(Db * db, Array * args) +{ + size_t i; + char *str = UtilStringConcat(db->dir, "/"); + + for (i = 0; i < ArraySize(args); i++) + { + char *tmp, *tmp2; + + tmp = UtilStringConcat(str, ArrayGet(args, i)); + tmp2 = UtilStringConcat(tmp, (i < ArraySize(args) - 1) ? "/" : ".json"); + + Free(str); + Free(tmp); + + str = tmp2; + } + + return str; } static void @@ -192,7 +228,7 @@ DbCacheEvict(Db * db) while (ref && db->cacheSize > db->maxCache) { - char *hash = DbHashKey(ref->prefix, ref->key); + char *hash = DbHashKey(ref->name); if (pthread_mutex_trylock(&ref->lock) != 0) { @@ -205,12 +241,11 @@ DbCacheEvict(Db * db) pthread_mutex_unlock(&ref->lock); pthread_mutex_destroy(&ref->lock); - hash = DbHashKey(ref->prefix, ref->key); + hash = DbHashKey(ref->name); HashMapDelete(db->cache, hash); Free(hash); - Free(ref->prefix); - Free(ref->key); + ArrayFree(ref->name); db->cacheSize -= ref->size; @@ -281,8 +316,7 @@ DbClose(Db * db) { Free(key); JsonFree(val->json); - Free(val->prefix); - Free(val->key); + ArrayFree(val->name); pthread_mutex_destroy(&val->lock); Free(val); } @@ -291,41 +325,8 @@ DbClose(Db * db) Free(db); } -DbRef * -DbCreate(Db * db, char *prefix, char *key) -{ - FILE *fp; - char *file; - - if (!db || !prefix || !key) - { - return NULL; - } - - file = DbFileName(db, prefix, key); - - if (UtilLastModified(file) || UtilMkdir(prefix, 0750) < 0) - { - Free(file); - return NULL; - } - - fp = fopen(file, "w"); - Free(file); - if (!fp) - { - return NULL; - } - - fprintf(fp, "{}"); - fflush(fp); - fclose(fp); - - return DbLock(db, prefix, key); -} - -DbRef * -DbLock(Db * db, char *prefix, char *key) +static DbRef * +DbLockFromArr(Db * db, Array * args) { char *file; char *hash; @@ -333,7 +334,7 @@ DbLock(Db * db, char *prefix, char *key) FILE *fp; struct flock lock; - if (!db || !prefix || !key) + if (!db || !args) { return NULL; } @@ -344,9 +345,12 @@ DbLock(Db * db, char *prefix, char *key) pthread_mutex_lock(&db->lock); /* Check if the item is in the cache */ - hash = DbHashKey(prefix, key); + hash = DbHashKey(args); ref = HashMapGet(db->cache, hash); - file = DbFileName(db, prefix, key); + file = DbFileName(db, args); + + printf("Object hash: %s\n", hash); + printf("File name: %s\n", file); /* Open the file for reading and writing so we can lock it */ fp = fopen(file, "r+"); @@ -443,8 +447,7 @@ DbLock(Db * db, char *prefix, char *key) ref->ts = UtilServerTs(); ref->size = DbComputeSize(ref->json); - ref->prefix = UtilStringDuplicate(prefix); - ref->key = UtilStringDuplicate(key); + ref->name = ArrayDuplicate(args); HashMapSet(db->cache, hash, ref); db->cacheSize += ref->size; @@ -467,6 +470,90 @@ finish: return ref; } +DbRef * +DbCreate(Db * db, size_t nArgs,...) +{ + FILE *fp; + char *file; + char *dir; + va_list ap; + Array *args; + + if (!db) + { + return NULL; + } + + va_start(ap, nArgs); + args = ArrayFromVarArgs(nArgs, ap); + va_end(ap); + + if (!args) + { + return NULL; + } + + file = DbFileName(db, args); + + if (UtilLastModified(file) || UtilMkdir(dir, 0750) < 0) + { + Free(file); + ArrayFree(args); + return NULL; + } + + dir = DbDirName(db, args); + if (UtilMkdir(dir, 0750) < 0) + { + Free(file); + ArrayFree(args); + Free(dir); + return NULL; + } + + fp = fopen(file, "w"); + Free(file); + if (!fp) + { + ArrayFree(args); + return NULL; + } + + fprintf(fp, "{}"); + fflush(fp); + fclose(fp); + + return DbLockFromArr(db, args); +} + +DbRef * +DbLock(Db * db, size_t nArgs,...) +{ + va_list ap; + Array *args; + DbRef *ret; + + va_start(ap, nArgs); + args = ArrayFromVarArgs(nArgs, ap); + va_end(ap); + + printf("Enter DbLock()\n"); + + if (!args) + { + printf("Failed to parse varargs\n"); + return NULL; + } + + ret = DbLockFromArr(db, args); + + ArrayFree(args); + + printf("Exit DbLock()\n"); + + return ret; +} + int DbUnlock(Db * db, DbRef * ref) { diff --git a/src/Util.c b/src/Util.c index ab98bf9..e12a43b 100644 --- a/src/Util.c +++ b/src/Util.c @@ -208,9 +208,10 @@ char * UtilStringConcat(char *str1, char *str2) { char *ret; + size_t str1Len, str2Len; - size_t str1Len = strlen(str1); - size_t str2Len = strlen(str2); + str1Len = str1 ? strlen(str1) : 0; + str2Len = str2 ? strlen(str2) : 0; ret = Malloc(str1Len + str2Len + 1); @@ -219,8 +220,26 @@ UtilStringConcat(char *str1, char *str2) return NULL; } - strcpy(ret, str1); - strcpy(ret + str1Len, str2); + if (str1 && str2) + { + strcpy(ret, str1); + strcpy(ret + str1Len, str2); + } + else + { + if (str1) + { + strcpy(ret, str1); + } + else if (str2) + { + strcpy(ret, str2); + } + else + { + strcpy(ret, ""); + } + } return ret; } diff --git a/src/include/Array.h b/src/include/Array.h index d699574..fe8f1e0 100644 --- a/src/include/Array.h +++ b/src/include/Array.h @@ -26,6 +26,7 @@ #define TELODENDRIA_ARRAY_H #include +#include typedef struct Array Array; @@ -56,4 +57,10 @@ extern void extern int ArrayTrim(Array *); +extern Array * + ArrayFromVarArgs(size_t, va_list); + +extern Array * + ArrayDuplicate(Array *); + #endif /* TELODENDRIA_ARRAY_H */ diff --git a/src/include/Db.h b/src/include/Db.h index 97a928c..d1f9397 100644 --- a/src/include/Db.h +++ b/src/include/Db.h @@ -42,10 +42,10 @@ extern void DbClose(Db *); extern DbRef * - DbCreate(Db *, char *, char *); + DbCreate(Db *, size_t,...); extern DbRef * - DbLock(Db *, char *, char *); + DbLock(Db *, size_t,...); extern int DbUnlock(Db *, DbRef *);