Keep the Config Dirty After a Failed Write and Sweep a Write's Own Leftovers

Before this change a config whose temporary could not be written stayed
dirty, so the idle handler tried again; the last round cleared the flag
regardless, which lost a pending change to a transient failure. The
writer reports whether the config itself was written and the flag clears
only then, as it always did.

The Windows rename retry duplicated what WindowsSupport::rename already
does, retrying and moving an open destination aside, and multiplied its
error logging; it is gone. The file a refused rename moves aside is
named so the sweep can clear it after a crash in between, and every
successful atomic write sweeps leftovers of earlier writes to the same
target, so the caches and the smaller state files are covered too; the
name shapes are strict enough that nothing of the user's matches.

The lock wait defaults to a second, long against a critical section of
milliseconds and short against the GUI thread; a lock file that cannot
be opened says to check its owner and permissions; the test timing
bounds tolerate a loaded runner; and the helper's header includes what
its declarations use.
This commit is contained in:
Hanif Koh
2026-09-24 22:44:09 +08:00
parent 16f44a9dfd
commit 1b30ae7424
8 changed files with 61 additions and 45 deletions
+3 -2
View File
@@ -32,7 +32,8 @@ TEST_CASE("InstanceLock creates its lock file and holds it for the guard's scope
const auto started = std::chrono::steady_clock::now();
InstanceLock again(path, 5000ms);
REQUIRE(again.locked());
REQUIRE(std::chrono::steady_clock::now() - started < 1000ms);
// Well inside the timeout it would otherwise have waited out; loose enough for a loaded runner.
REQUIRE(std::chrono::steady_clock::now() - started < 4000ms);
}
TEST_CASE("InstanceLock nests within one thread", "[InstanceLock]")
@@ -193,7 +194,7 @@ TEST_CASE("InstanceLock yields to another process and reports it", "[InstanceLoc
REQUIRE_FALSE(locked_while_child_holds);
REQUIRE_FALSE(locked_during_cooldown);
REQUIRE(cooldown_wait < 1000ms);
REQUIRE(cooldown_wait < 4000ms);
// A guard inside the cool-down still takes the lock when it is free.
InstanceLock lock(path);
REQUIRE(lock.locked());