diff options
-rw-r--r-- | src/rmd_cache.c | 57 | ||||
-rw-r--r-- | src/rmd_initialize_data.c | 1 | ||||
-rw-r--r-- | src/rmd_parseargs.c | 5 | ||||
-rw-r--r-- | src/rmd_types.h | 4 |
4 files changed, 61 insertions, 6 deletions
diff --git a/src/rmd_cache.c b/src/rmd_cache.c index db7682e..9e42be3 100644 --- a/src/rmd_cache.c +++ b/src/rmd_cache.c @@ -28,18 +28,48 @@ #include "rmd_cache.h" #include "rmd_specsfile.h" +#include "rmd_threads.h" #include "rmd_types.h" -#include <sys/types.h> -#include <unistd.h> -#include <stdlib.h> +#include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #define CACHE_FILE_SIZE_LIMIT (500 * 1024 * 1024) +/* periodic fdatasync thread for cache writers when fdatasyncing is enabled */ +static void * rmdCacheFileSyncer(CacheFile *file) +{ + struct timespec delay; + int fd; + + assert(file); + assert(file->periodic_datasync_ms); + + rmdThreadsSetName("rmdCacheSyncer"); + + delay.tv_sec = file->periodic_datasync_ms / 1000; + delay.tv_nsec = (file->periodic_datasync_ms - delay.tv_sec * 1000) * 1000000; + + if (file->gzfp) + fd = file->gzfd; + else + fd = fileno(file->fp); + + for (;;) { + nanosleep(&delay, NULL); + fdatasync(fd); + } + + return NULL; +} + + /* 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 @@ -48,10 +78,12 @@ static int _rmdCacheFileOpen(CacheFile *file, const char *path) { const char *modestr = "rb"; + int flags = O_RDONLY; assert(file); if (file->mode == RMD_CACHE_FILE_MODE_WRITE) { + flags = O_CREAT|O_WRONLY; modestr = "wb"; if (file->compressed) @@ -59,7 +91,12 @@ static int _rmdCacheFileOpen(CacheFile *file, const char *path) } if (file->compressed) { - file->gzfp = gzopen(path, modestr); + /* zlib doesn't expose a fileno() equivalent for the syncer */ + file->gzfd = open(path, flags, S_IRUSR|S_IWUSR); + if (file->gzfd < 0) + return -1; + + file->gzfp = gzdopen(file->gzfd, modestr); } else { file->fp = fopen(path, modestr); } @@ -69,6 +106,9 @@ static int _rmdCacheFileOpen(CacheFile *file, const char *path) file->chapter_n_bytes = 0; + if (file->mode == RMD_CACHE_FILE_MODE_WRITE && file->periodic_datasync_ms) + pthread_create(&file->syncer_thread, NULL, (void *(*)(void *))rmdCacheFileSyncer, file); + return 0; } @@ -78,6 +118,11 @@ static int _rmdCacheFileClose(CacheFile *file) { assert(file); + if (file->mode == RMD_CACHE_FILE_MODE_WRITE && file->periodic_datasync_ms) { + pthread_cancel(file->syncer_thread); + pthread_join(file->syncer_thread, NULL); + } + /* TODO: return meaningful -errno on errors? */ if (file->gzfp) { if (gzclose(file->gzfp) != Z_OK) @@ -114,8 +159,8 @@ CacheFile * rmdCacheFileOpen(ProgData *pdata, const char *path, CacheFileMode mo } f->mode = mode; - if (!pdata->args.zerocompression) - f->compressed = 1; + f->compressed = !pdata->args.zerocompression; + f->periodic_datasync_ms = pdata->args.periodic_datasync_ms; if (_rmdCacheFileOpen(f, path) < 0) return NULL; diff --git a/src/rmd_initialize_data.c b/src/rmd_initialize_data.c index 4cd015f..6f2af89 100644 --- a/src/rmd_initialize_data.c +++ b/src/rmd_initialize_data.c @@ -211,6 +211,7 @@ void rmdSetupDefaultArgs(ProgArgs *args) args->jack_nports = 0; args->jack_ringbuffer_secs = 3.0; args->zerocompression = 1; + args->periodic_datasync_ms = 100; args->no_quick_subsample = 1; args->cursor_color = 1; args->have_dummy_cursor = 0; diff --git a/src/rmd_parseargs.c b/src/rmd_parseargs.c index 5a39f2a..e4cfdd7 100644 --- a/src/rmd_parseargs.c +++ b/src/rmd_parseargs.c @@ -262,6 +262,11 @@ boolean rmdParseArgs(int argc, char **argv, ProgArgs *arg_return) "Image data are cached with light compression.", NULL }, + { "periodic-datasync-ms", '\0', + POPT_ARG_INT, &arg_return->periodic_datasync_ms, 0, + "Asynchronously fdatasync() cache files every specified ms while writing, 0 disables (default 100).", + "N>=0"}, + { "workdir", '\0', POPT_ARG_STRING, &arg_return->workdir, 0, "Location where a temporary directory will be created to hold project files(default $HOME).", diff --git a/src/rmd_types.h b/src/rmd_types.h index 252861c..9be5ca7 100644 --- a/src/rmd_types.h +++ b/src/rmd_types.h @@ -153,6 +153,7 @@ typedef struct _ProgArgs{ char *stop_shortcut; //stop shortcut sequence(Control+Alt+s) int noframe; //don't draw a frame around the recording area int zerocompression; //image data are always flushed uncompressed + unsigned periodic_datasync_ms; //interval between background async fdatasync calls while writing cache files, when zero no periodic fdatasync is performed int overwrite; //overwite a previously existing file //(do not add a .number postfix) int use_jack; //record audio with jack @@ -195,9 +196,12 @@ typedef struct CacheFile { unsigned chapter; size_t chapter_n_bytes, total_n_bytes; unsigned compressed:1; + unsigned periodic_datasync_ms; CacheFileMode mode; gzFile gzfp; + int gzfd; FILE *fp; + pthread_t syncer_thread; } CacheFile; //this struct will hold a few basic |