diff options
author | Tian <skylypig@gmail.com> | 2022-06-21 00:17:23 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-20 19:17:23 +0300 |
commit | 99a425d0f3b7b00896cb855d5de4ae93be1fe3f0 (patch) | |
tree | e786f79d71c642c36e9f48965f830e097a4ef8eb /src/rdb.c | |
parent | 4c72a09b78f6adcc3657b0d1b7ce64f2dd028c72 (diff) | |
download | redis-99a425d0f3b7b00896cb855d5de4ae93be1fe3f0.tar.gz |
Fsync directory while persisting AOF manifest, RDB file, and config file (#10737)
The current process to persist files is `write` the data, `fsync` and `rename` the file,
but a underlying problem is that the rename may be lost when a sudden crash like
power outage and the directory hasn't been persisted.
The article [Ensuring data reaches disk](https://lwn.net/Articles/457667/) mentions
a safe way to update file should be:
1. create a new temp file (on the same file system!)
2. write data to the temp file
3. fsync() the temp file
4. rename the temp file to the appropriate name
5. fsync() the containing directory
This commit handles CONFIG REWRITE, AOF manifest, and RDB file (both for persistence,
and the one the replica gets from the master).
It doesn't handle (yet), ACL SAVE and Cluster configs, since these don't yet follow this pattern.
Diffstat (limited to 'src/rdb.c')
-rw-r--r-- | src/rdb.c | 11 |
1 files changed, 7 insertions, 4 deletions
@@ -1397,6 +1397,7 @@ int rdbSave(int req, char *filename, rdbSaveInfo *rsi) { FILE *fp = NULL; rio rdb; int error = 0; + char *err_op; /* For a detailed log */ snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid()); fp = fopen(tmpfile,"w"); @@ -1420,13 +1421,14 @@ int rdbSave(int req, char *filename, rdbSaveInfo *rsi) { if (rdbSaveRio(req,&rdb,&error,RDBFLAGS_NONE,rsi) == C_ERR) { errno = error; + err_op = "rdbSaveRio"; goto werr; } /* Make sure data will not remain on the OS's output buffers */ - if (fflush(fp)) goto werr; - if (fsync(fileno(fp))) goto werr; - if (fclose(fp)) { fp = NULL; goto werr; } + if (fflush(fp)) { err_op = "fflush"; goto werr; } + if (fsync(fileno(fp))) { err_op = "fsync"; goto werr; } + if (fclose(fp)) { fp = NULL; err_op = "fclose"; goto werr; } fp = NULL; /* Use RENAME to make sure the DB file is changed atomically only @@ -1445,6 +1447,7 @@ int rdbSave(int req, char *filename, rdbSaveInfo *rsi) { stopSaving(0); return C_ERR; } + if (fsyncFileDir(filename) == -1) { err_op = "fsyncFileDir"; goto werr; } serverLog(LL_NOTICE,"DB saved on disk"); server.dirty = 0; @@ -1454,7 +1457,7 @@ int rdbSave(int req, char *filename, rdbSaveInfo *rsi) { return C_OK; werr: - serverLog(LL_WARNING,"Write error saving DB on disk: %s", strerror(errno)); + serverLog(LL_WARNING,"Write error saving DB on disk(%s): %s", err_op, strerror(errno)); if (fp) fclose(fp); unlink(tmpfile); stopSaving(0); |