Skip to content

Commit f124293

Browse files
committed
local-binary-cache-store: Add retry loop to upsertFile
Handle race conditions in binary cache file creation by retrying with a new temporary name on EEXIST errors. Uses existing makeTempPath which already has an atomic counter.
1 parent bc73faf commit f124293

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

src/libstore/local-binary-cache-store.cc

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,32 @@ struct LocalBinaryCacheStore :
5858
const std::string & mimeType) override
5959
{
6060
auto path2 = config->binaryCacheDir + "/" + path;
61-
static std::atomic<int> counter{0};
62-
Path tmp = fmt("%s.tmp.%d.%d", path2, getpid(), ++counter);
63-
AutoDelete del(tmp, false);
64-
StreamToSourceAdapter source(istream);
65-
writeFile(tmp, source);
66-
std::filesystem::rename(tmp, path2);
67-
del.cancel();
61+
62+
/* Retry loop for handling race conditions */
63+
while (true) {
64+
Path tmp = makeTempPath(dirOf(path2), baseNameOf(path2) + ".tmp");
65+
AutoDelete del(tmp, false);
66+
67+
StreamToSourceAdapter source(istream);
68+
try {
69+
writeFile(tmp, source);
70+
} catch (Error & e) {
71+
e.addTrace({}, "while writing to temporary file '%s' for '%s'", tmp, path2);
72+
}
73+
74+
try {
75+
std::filesystem::rename(tmp, path2);
76+
del.cancel();
77+
break; /* Success! */
78+
} catch (std::filesystem::filesystem_error & e) {
79+
if (e.code() == std::errc::file_exists) {
80+
/* Race condition: another process created the same file.
81+
Try again with a different name. */
82+
continue;
83+
}
84+
throw SysError("renaming '%s' to '%s'", tmp, path2);
85+
}
86+
}
6887
}
6988

7089
void getFile(const std::string & path, Sink & sink) override

0 commit comments

Comments
 (0)