diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-11-08 16:15:52 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-11-08 19:50:50 -0800 |
commit | f2f4c34760de661f1dfe33c06760053692fece90 (patch) | |
tree | 97a56e0bf2b5a73825422a5f057ed44e7d189865 | |
parent | 937f09dd3532a2033e9bf159bed842bfd1f3ad2a (diff) |
cache: introduce rudimentary CacheFile API
Throughout the existing cache-related code there's constant checking
if compression is active or not.
This commit introduces a CacheFile ADT with the intention of
replacing all the open coded stuff with simple calls into
rmdCacheFile* functions operating on CacheFile instances.
The management of split up cache files has also been implemented
behind this API, so the reads and writes will transparently
handle the split files. These have been named "chapters" in new
code.
No callers have been changed, this only adds the new facility. A
subsequent commit will migrate things over.
-rw-r--r-- | src/rmd_cache.c | 211 | ||||
-rw-r--r-- | src/rmd_cache.h | 4 | ||||
-rw-r--r-- | src/rmd_types.h | 16 |
3 files changed, 207 insertions, 24 deletions
diff --git a/src/rmd_cache.c b/src/rmd_cache.c index bef6a83..94c0b68 100644 --- a/src/rmd_cache.c +++ b/src/rmd_cache.c @@ -37,6 +37,107 @@ #include <string.h> #include <sys/stat.h> +#define CACHE_FILE_SIZE_LIMIT (500 * 1024 * 1024) + + +/* open file @ path storing the file handles in *file, + * this doesn't store the new path since it's primarily + * for the purposes of opening new chapters for the same + * base path. + */ +static int _rmdCacheFileOpen(CacheFile *file, const char *path) +{ + const char *modestr = "rb"; + + assert(file); + + if (file->mode == RMD_CACHE_FILE_MODE_WRITE) { + modestr = "wb"; + + if (file->compressed) + modestr = "wb0f"; + } + + if (file->compressed) { + file->gzfp = gzopen(path, modestr); + } else { + file->fp = fopen(path, modestr); + } + + if (!file->gzfp && !file->fp) + return -1; + + file->chapter_n_bytes = 0; + + return 0; +} + + +/* only close the internal file handle, but don't free file */ +static int _rmdCacheFileClose(CacheFile *file) +{ + assert(file); + + /* TODO: return meaningful -errno on errors? */ + if (file->gzfp) { + if (gzclose(file->gzfp) != Z_OK) + return -1; + + file->gzfp = NULL; + } else if (file->fp) { + if (fclose(file->fp)) + return -1; + + file->fp = NULL; + } + + return 0; +} + + +/* open a CacheFile @ path, in the specified mode, returns NULL on error */ +CacheFile * rmdCacheFileOpen(ProgData *pdata, const char *path, CacheFileMode mode) +{ + CacheFile *f; + + assert(pdata); + assert(path); + + f = calloc(1, sizeof(*f)); + if (!f) + return NULL; + + f->path = strdup(path); + if (!f->path) { + free(f); + return NULL; + } + + f->mode = mode; + if (!pdata->args.zerocompression) + f->compressed = 1; + + if (_rmdCacheFileOpen(f, path) < 0) + return NULL; + + return f; +} + + +/* close a CacheFile, returns < 0 on error */ +int rmdCacheFileClose(CacheFile *file) +{ + assert(file); + + if (_rmdCacheFileClose(file) < 0) + return -1; + + free(file->path); + free(file); + + return 0; +} + /** *Construct an number postfixed name @@ -48,7 +149,7 @@ * \n number to be used as a postfix * */ -static void rmdCacheFileN(char *name, char **newname, int n) // Nth cache file +static void _rmdCacheFileN(char *name, char **newname, int n) // Nth cache file { char numbuf[8]; @@ -58,42 +159,104 @@ static void rmdCacheFileN(char *name, char **newname, int n) // Nth cache file strcat(*newname, numbuf); } -int rmdSwapCacheFilesWrite(char *name, int n, gzFile *fp, FILE **ucfp) + +/* read from a CacheFile, identical to gzread() */ +ssize_t rmdCacheFileRead(CacheFile *file, void *ptr, size_t len) { - char *newname = malloc(strlen(name) + 10); + ssize_t ret, read_n_bytes = 0; + + assert(file); + assert(ptr); - rmdCacheFileN(name, &newname, n); - if (*fp == NULL) { - fflush(*ucfp); - fclose(*ucfp); - *ucfp = fopen(newname, "wb"); + assert(file->mode == RMD_CACHE_FILE_MODE_READ); + +retry: + if (file->gzfp) { + int r; + + r = gzread(file->gzfp, ptr + read_n_bytes, len); + if (r < 0) + return -1; + + ret = r; } else { - gzflush(*fp, Z_FINISH); - gzclose(*fp); - *fp = gzopen(newname, "wb0f"); + ret = fread(ptr + read_n_bytes, 1, len, file->fp); + } + + read_n_bytes += ret; + file->chapter_n_bytes += read_n_bytes; + file->total_n_bytes += read_n_bytes; + + if (ret < len) { + char *newpath = malloc(strlen(file->path) + 10); + + len -= ret; + + if (_rmdCacheFileClose(file) < 0) { + free(newpath); + return -1; + } + + /* look for next chapter */ + _rmdCacheFileN(file->path, &newpath, file->chapter + 1); + if (_rmdCacheFileOpen(file, newpath) == 0) { + file->chapter++; + free(newpath); + goto retry; + } + + free(newpath); } - free(newname); - return ((*fp == NULL) && (*ucfp == NULL)); + return read_n_bytes; } -int rmdSwapCacheFilesRead(char *name, int n, gzFile *fp, FILE **ucfp) + +/* write to a CacheFile, identical to gzwrite() */ +ssize_t rmdCacheFileWrite(CacheFile *file, const void *ptr, size_t len) { - char *newname = malloc(strlen(name) + 10); + ssize_t ret; + + assert(file); + assert(ptr); + + assert(file->mode == RMD_CACHE_FILE_MODE_WRITE); + + /* transparently open next chapter if needed */ + if (file->chapter_n_bytes > CACHE_FILE_SIZE_LIMIT) { + char *newpath = malloc(strlen(file->path) + 10); + + if (_rmdCacheFileClose(file) < 0) + return -1; - rmdCacheFileN(name, &newname, n); - if (*fp == NULL) { - fclose(*ucfp); - *ucfp = fopen(newname, "rb"); + file->chapter++; + + _rmdCacheFileN(file->path, &newpath, file->chapter); + if (_rmdCacheFileOpen(file, newpath) < 0) { + free(newpath); + return -1; + } + } + + if (file->gzfp) { + int r; + + r = gzwrite(file->gzfp, ptr, len); + if (r < 0) + return -1; + + ret = r; } else { - gzclose(*fp); - *fp = gzopen(newname, "rb"); + ret = fwrite(ptr, 1, len, file->fp); } - free(newname); - return ((*fp == NULL) && (*ucfp == NULL)); + file->chapter_n_bytes += ret; + file->total_n_bytes += ret; + + return ret; } + int rmdPurgeCache(CacheData *cache_data_t, int sound) { struct stat buff; @@ -109,7 +272,7 @@ int rmdPurgeCache(CacheData *cache_data_t, int sound) fprintf(stderr, "Couldn't remove temporary file %s", cache_data_t->imgdata); exit_value = 1; } - rmdCacheFileN(cache_data_t->imgdata, &fname, nth_cache); + _rmdCacheFileN(cache_data_t->imgdata, &fname, nth_cache); nth_cache++; } diff --git a/src/rmd_cache.h b/src/rmd_cache.h index 9f4acce..cfa6cae 100644 --- a/src/rmd_cache.h +++ b/src/rmd_cache.h @@ -34,6 +34,10 @@ #include <stdio.h> +CacheFile * rmdCacheFileOpen(ProgData *pdata, const char *path, CacheFileMode mode); +int rmdCacheFileClose(CacheFile *file); +ssize_t rmdCacheFileRead(CacheFile *file, void *ptr, size_t len); +ssize_t rmdCacheFileWrite(CacheFile *file, const void *ptr, size_t len); /** * Change file pointer to a new file while writting diff --git a/src/rmd_types.h b/src/rmd_types.h index 1dc5f14..3cc1a84 100644 --- a/src/rmd_types.h +++ b/src/rmd_types.h @@ -184,6 +184,22 @@ typedef struct _EncData{ FILE *fp; } EncData; +/* CacheFiles abstract compressed vs. uncompressed files */ +typedef enum CacheFileMode { + RMD_CACHE_FILE_MODE_WRITE, + RMD_CACHE_FILE_MODE_READ, +} CacheFileMode; + +typedef struct CacheFile { + char *path; + unsigned chapter; + size_t chapter_n_bytes, total_n_bytes; + unsigned compressed:1; + CacheFileMode mode; + gzFile gzfp; + FILE *fp; +} CacheFile; + //this struct will hold a few basic //information, needed for caching the frames. typedef struct _CacheData{ |