From 31f3c841edfd89d5fd5f086291e17a02ad978283 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 29 Nov 2021 00:19:46 +0100 Subject: [PATCH 1/3] Lower chance of losing written files by syncing them to disk on close I'm wondering if this helps. Overhead exists, but is not that much (on my system): 333 ms for initialization instead of 311 ms If we only want to do this for files written to, then we need to keep track of how the file was opened. --- src/base/system.cpp | 18 ++++++++++++++++++ src/base/system.h | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/base/system.cpp b/src/base/system.cpp index a19eb66a3..d9c1a8973 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -461,6 +462,14 @@ unsigned io_write_newline(IOHANDLE io) int io_close(IOHANDLE io) { + if(io_flush(io) != 0) + { + dbg_msg("file", "flushing stream failed: %d", errno); + } + if(io_fsync(io) != 0) + { + dbg_msg("file", "flushing file to disk failed: %d", errno); + } return fclose((FILE *)io) != 0; } @@ -469,6 +478,15 @@ int io_flush(IOHANDLE io) return fflush((FILE *)io); } +int io_fsync(IOHANDLE io) +{ +#if defined(CONF_FAMILY_WINDOWS) + return FlushFileBuffers((HANDLE)_get_osfhandle(_fileno((FILE *)io))); +#else + return fsync(fileno((FILE *)io)); +#endif +} + #define ASYNC_BUFSIZE 8 * 1024 #define ASYNC_LOCAL_BUFSIZE 64 * 1024 diff --git a/src/base/system.h b/src/base/system.h index 0db912cc4..6956bea45 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -303,6 +303,18 @@ int io_close(IOHANDLE io); */ int io_flush(IOHANDLE io); +/* + Function: io_fsync + Synchronize file changes to disk + + Parameters: + io - Handle to the file. + + Returns: + Returns 0 on success. +*/ +int io_fsync(IOHANDLE io); + /* Function: io_error Checks whether an error occurred during I/O with the file. From 4d90119f2560ed07c1060c724f64d11895e43fb1 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 31 Jan 2022 22:07:51 +0100 Subject: [PATCH 2/3] Don't flush all files, some improvements to `io_sync` - Empty buffers using `io_flush` before calling the OS function for syncing the file to disk. - Fix error return of `io_sync` on Windows. - Don't indiscriminately flush all files on close. - Add a test that `io_sync` can return without error. --- src/base/system.cpp | 18 +++++++----------- src/base/system.h | 6 +++--- src/test/io.cpp | 10 ++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/base/system.cpp b/src/base/system.cpp index d9c1a8973..b4f596003 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -462,14 +462,6 @@ unsigned io_write_newline(IOHANDLE io) int io_close(IOHANDLE io) { - if(io_flush(io) != 0) - { - dbg_msg("file", "flushing stream failed: %d", errno); - } - if(io_fsync(io) != 0) - { - dbg_msg("file", "flushing file to disk failed: %d", errno); - } return fclose((FILE *)io) != 0; } @@ -478,12 +470,16 @@ int io_flush(IOHANDLE io) return fflush((FILE *)io); } -int io_fsync(IOHANDLE io) +int io_sync(IOHANDLE io) { + if(io_flush(io)) + { + return 1; + } #if defined(CONF_FAMILY_WINDOWS) - return FlushFileBuffers((HANDLE)_get_osfhandle(_fileno((FILE *)io))); + return FlushFileBuffers((HANDLE)_get_osfhandle(_fileno((FILE *)io))) == 0; #else - return fsync(fileno((FILE *)io)); + return fsync(fileno((FILE *)io)) != 0; #endif } diff --git a/src/base/system.h b/src/base/system.h index 6956bea45..b906cf182 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -304,8 +304,8 @@ int io_close(IOHANDLE io); int io_flush(IOHANDLE io); /* - Function: io_fsync - Synchronize file changes to disk + Function: io_sync + Synchronize file changes to disk. Parameters: io - Handle to the file. @@ -313,7 +313,7 @@ int io_flush(IOHANDLE io); Returns: Returns 0 on success. */ -int io_fsync(IOHANDLE io); +int io_sync(IOHANDLE io); /* Function: io_error diff --git a/src/test/io.cpp b/src/test/io.cpp index 51b7b9b57..69ae0f673 100644 --- a/src/test/io.cpp +++ b/src/test/io.cpp @@ -68,3 +68,13 @@ TEST(Io, CurrentExe) EXPECT_GE(io_length(CurrentExe), 1024); io_close(CurrentExe); } +TEST(Io, SyncWorks) +{ + CTestInfo Info; + IOHANDLE File = io_open(Info.m_aFilename, IOFLAG_WRITE); + ASSERT_TRUE(File); + EXPECT_EQ(io_write(File, "abc\n", 4), 4); + EXPECT_FALSE(io_sync(File)); + EXPECT_FALSE(io_close(File)); + EXPECT_FALSE(fs_remove(Info.m_aFilename)); +} From a51875f9b6198e188a446a0006ac08810c8a20b8 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Mon, 31 Jan 2022 22:08:56 +0100 Subject: [PATCH 3/3] Sync the config file replacement to disk before renaming Hopefully, this fixes player's incomplete config issues. --- src/engine/shared/config.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/shared/config.cpp b/src/engine/shared/config.cpp index 788082836..48301a23f 100644 --- a/src/engine/shared/config.cpp +++ b/src/engine/shared/config.cpp @@ -110,6 +110,11 @@ bool CConfigManager::Save() for(int i = 0; i < m_NumCallbacks; i++) m_aCallbacks[i].m_pfnFunc(this, m_aCallbacks[i].m_pUserData); + if(io_sync(m_ConfigFile) != 0) + { + m_Failed = true; + } + if(io_close(m_ConfigFile) != 0) m_Failed = true;