mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-24 17:26:47 +00:00
Fall Back When a Replace Is Refused and Sweep Only Old Temporaries
Some mounts refuse to replace an existing file in one rename, and the old remove-then-rename worked there where the atomic path now fails, so rename_file() takes the two-step route when a one-step replace is refused and write_file_atomically() writes in place whenever the rename fails, not only for the Windows sharing case. An instance that gave up waiting for the lock writes unlocked by design, so a peer holding the lock could sweep its in-flight temporary and make its rename fail; only temporaries older than ten minutes are removed now, and the sweep uses the error-code overloads so an entry vanishing between listing and stat cannot throw out of startup. The registry mutex is leaked like the map it guards, so a save during static destruction does not lock a destroyed mutex. The physical printer loader is never called, so its guard is gone, while the two delete paths that do run now hold the lock. The bundle metadata loader is lock-free again, since the zip import reads it from a scratch folder; the guard sits at the two scans that read the user's bundles. Preset::save() builds what it writes before taking the lock, the cache writer reserves its payload, and the retry test tolerates a slow runner.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
@@ -121,10 +122,15 @@ TEST_CASE("write_file_atomically writes through a symlink and keeps the target's
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("remove_stale_temp_files removes only <name>.<pid>.tmp files", "[utils]") {
|
||||
TEST_CASE("remove_stale_temp_files removes only old <name>.<pid>.tmp files", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
for (const char *name : { "a.json.123.tmp", "b.info.4.tmp", "c.json", "d.tmp", "e.json.x.tmp", "f.json..tmp" })
|
||||
for (const char *name : { "a.json.123.tmp", "b.info.4.tmp", "c.json", "d.tmp", "e.json.x.tmp", "f.json..tmp" }) {
|
||||
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);
|
||||
}
|
||||
// Just written: possibly another instance's in-flight save, so it stays.
|
||||
REQUIRE_FALSE(write_file_atomically((dir.path() / "g.json.7.tmp").string(), "x"));
|
||||
|
||||
SECTION("with a name prefix only matching names go") {
|
||||
REQUIRE(remove_stale_temp_files(dir.path(), "a.json") == 1);
|
||||
@@ -138,7 +144,8 @@ TEST_CASE("remove_stale_temp_files removes only <name>.<pid>.tmp files", "[utils
|
||||
(void) entry;
|
||||
++entries;
|
||||
}
|
||||
REQUIRE(entries == 4);
|
||||
REQUIRE(entries == 5);
|
||||
REQUIRE(boost::filesystem::exists(dir.path() / "g.json.7.tmp"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user