mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 10:21:00 +00:00
Clear the Read-Only Attribute Before Replacing a Config and Back Off After a Failed Save
Nothing replaces a read-only file on Windows, neither a rename over it nor an in-place write, so the opt-in that keeps a read-only config saveable clears the attribute first; without that the test for it could not pass there. A failed config write still leaves the flag dirty, as before this change, but the next attempt waits ten seconds, so the idle handler does not repeat a hopeless write on every event. A file moved aside by a refused rename can be the only copy left if the process dies in between, so the sweep puts such a file back when its original is missing rather than removing it, and the directory-only errors that could only come from a directory target no longer trigger the move-aside at all. The sweep after a write runs only under the data dir and at most once an hour per directory, so a batch of saves does not read the directory once per file and an export into a user's folder never reads that folder. A lock holder that never lets go doubles the cool-down for each timeout in a row, up to five minutes, instead of costing a stall every ten seconds for good.
This commit is contained in:
@@ -187,9 +187,23 @@ TEST_CASE("write_file_atomically survives two threads writing one target", "[uti
|
||||
REQUIRE(temporaries == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("remove_stale_temp_files puts back a moved-aside file whose original is missing", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
REQUIRE_FALSE(write_file_atomically((dir.path() / "lost.json.4242.old").string(), "last copy"));
|
||||
boost::filesystem::last_write_time(dir.path() / "lost.json.4242.old", std::time(nullptr) - 7200);
|
||||
|
||||
REQUIRE(remove_stale_temp_files(dir.path()) == 0);
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "lost.json"));
|
||||
REQUIRE_FALSE(boost::filesystem::exists(dir.path() / "lost.json.4242.old"));
|
||||
std::string content;
|
||||
load_string_file(dir.path() / "lost.json", content);
|
||||
REQUIRE(content == "last copy");
|
||||
}
|
||||
|
||||
TEST_CASE("remove_stale_temp_files removes only old <name>.<pid>.<n>.tmp files", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
for (const char *name : { "a.json.123.7.tmp", "b.info.4.0.tmp", "c.json", "d.tmp", "e.json.x.1.tmp", "f.json..tmp", "a.json.99", "a.json.12.tmp", "a.json.123.old", "h.json.old" }) {
|
||||
// a.json exists, so its .old is a leftover; a moved-aside file without its original is a different case.
|
||||
for (const char *name : { "a.json", "a.json.123.7.tmp", "b.info.4.0.tmp", "c.json", "d.tmp", "e.json.x.1.tmp", "f.json..tmp", "a.json.99", "a.json.12.tmp", "a.json.123.old", "h.json.old" }) {
|
||||
REQUIRE_FALSE(write_file_atomically((dir.path() / name).string(), "x"));
|
||||
// An hour old: long past the age below which a temporary may still be in flight.
|
||||
boost::filesystem::last_write_time(dir.path() / name, std::time(nullptr) - 3600);
|
||||
@@ -212,7 +226,8 @@ TEST_CASE("remove_stale_temp_files removes only old <name>.<pid>.<n>.tmp files",
|
||||
(void) entry;
|
||||
++entries;
|
||||
}
|
||||
REQUIRE(entries == 8);
|
||||
REQUIRE(entries == 9);
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "a.json"));
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "h.json.old"));
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "a.json.99"));
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "g.json.7.2.tmp"));
|
||||
|
||||
Reference in New Issue
Block a user