summaryrefslogtreecommitdiff
path: root/src/rmd_cache.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2020-11-08 16:15:52 -0800
committerVito Caputo <vcaputo@pengaru.com>2020-11-08 19:50:50 -0800
commitf2f4c34760de661f1dfe33c06760053692fece90 (patch)
tree97a56e0bf2b5a73825422a5f057ed44e7d189865 /src/rmd_cache.c
parent937f09dd3532a2033e9bf159bed842bfd1f3ad2a (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.
Diffstat (limited to 'src/rmd_cache.c')
-rw-r--r--src/rmd_cache.c211
1 files changed, 187 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++;
}
© All Rights Reserved