mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
Merge f124293024
into f9afc1e68c
This commit is contained in:
commit
0cb70501e6
4 changed files with 123 additions and 43 deletions
|
@ -1,4 +1,5 @@
|
|||
#include "nix/store/indirect-root-store.hh"
|
||||
#include "nix/util/file-system.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -7,12 +8,32 @@ void IndirectRootStore::makeSymlink(const Path & link, const Path & target)
|
|||
/* Create directories up to `gcRoot'. */
|
||||
createDirs(dirOf(link));
|
||||
|
||||
/* Create the new symlink. */
|
||||
Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), rand());
|
||||
/* Retry loop for temporary symlink creation to handle race conditions */
|
||||
while (true) {
|
||||
Path tempLink = makeTempPath(dirOf(link), baseNameOf(link) + ".tmp");
|
||||
|
||||
createSymlink(target, tempLink);
|
||||
|
||||
/* Atomically replace the old one. */
|
||||
try {
|
||||
std::filesystem::rename(tempLink, link);
|
||||
break; /* Success! */
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
try {
|
||||
std::filesystem::remove(tempLink);
|
||||
} catch (...) {
|
||||
/* Ignore errors removing the temp link */
|
||||
}
|
||||
|
||||
if (e.code() == std::errc::file_exists) {
|
||||
/* Race condition: another process created the same temp link.
|
||||
Try again with a different name. */
|
||||
continue;
|
||||
}
|
||||
|
||||
throw SysError("failed to create symlink '%1%' -> '%2%'", link, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot)
|
||||
|
|
|
@ -58,13 +58,32 @@ protected:
|
|||
const std::string & mimeType) override
|
||||
{
|
||||
auto path2 = config->binaryCacheDir + "/" + path;
|
||||
static std::atomic<int> counter{0};
|
||||
Path tmp = fmt("%s.tmp.%d.%d", path2, getpid(), ++counter);
|
||||
|
||||
/* Retry loop for handling race conditions */
|
||||
while (true) {
|
||||
Path tmp = makeTempPath(dirOf(path2), baseNameOf(path2) + ".tmp");
|
||||
AutoDelete del(tmp, false);
|
||||
|
||||
StreamToSourceAdapter source(istream);
|
||||
try {
|
||||
writeFile(tmp, source);
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "while writing to temporary file '%s' for '%s'", tmp, path2);
|
||||
}
|
||||
|
||||
try {
|
||||
std::filesystem::rename(tmp, path2);
|
||||
del.cancel();
|
||||
break; /* Success! */
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
if (e.code() == std::errc::file_exists) {
|
||||
/* Race condition: another process created the same file.
|
||||
Try again with a different name. */
|
||||
continue;
|
||||
}
|
||||
throw SysError("renaming '%s' to '%s'", tmp, path2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getFile(const std::string & path, Sink & sink) override
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <sys/types.h>
|
||||
|
@ -1666,11 +1667,35 @@ void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log)
|
|||
|
||||
createDirs(dirOf(logPath));
|
||||
|
||||
auto tmpFile = fmt("%s.tmp.%d", logPath, getpid());
|
||||
/* Retry loop for temporary log file creation to handle race conditions */
|
||||
while (true) {
|
||||
auto tmpFile = makeTempPath(dirOf(logPath), baseNameOf(logPath) + ".tmp");
|
||||
|
||||
try {
|
||||
writeFile(tmpFile, compress("bzip2", log));
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "writing build log to '%s'", tmpFile);
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
std::filesystem::rename(tmpFile, logPath);
|
||||
break; /* Success! */
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
try {
|
||||
std::filesystem::remove(tmpFile);
|
||||
} catch (...) {
|
||||
/* Ignore errors removing the temp file */
|
||||
}
|
||||
|
||||
if (e.code() == std::errc::file_exists) {
|
||||
/* Another process created the log file. That's fine, we're done. */
|
||||
break;
|
||||
}
|
||||
|
||||
throw SysError("renaming temporary file '%1%' to '%2%'", tmpFile, logPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> LocalStore::getVersion()
|
||||
|
|
|
@ -223,7 +223,9 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
|
|||
its timestamp back to 0. */
|
||||
MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : "");
|
||||
|
||||
std::filesystem::path tempLink = fmt("%1%/.tmp-link-%2%-%3%", config->realStoreDir, getpid(), rand());
|
||||
/* Retry loop for temporary link creation to handle race conditions */
|
||||
while (true) {
|
||||
Path tempLink = makeTempPath(config->realStoreDir.get(), ".tmp-link");
|
||||
|
||||
try {
|
||||
std::filesystem::create_hard_link(linkPath, tempLink);
|
||||
|
@ -237,24 +239,37 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
|
|||
printInfo("'%1%' has maximum number of links", linkPath);
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
throw SysError("creating temporary link '%1%'", tempLink);
|
||||
}
|
||||
|
||||
/* Atomically replace the old file with the new hard link. */
|
||||
try {
|
||||
std::filesystem::rename(tempLink, path);
|
||||
break; /* Success! */
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
try {
|
||||
std::filesystem::remove(tempLink);
|
||||
printError("unable to unlink '%1%'", tempLink);
|
||||
} catch (...) {
|
||||
/* Ignore errors removing the temp link */
|
||||
}
|
||||
|
||||
if (e.code() == std::errc::too_many_links) {
|
||||
/* Some filesystems generate too many links on the rename,
|
||||
rather than on the original link. (Probably it
|
||||
temporarily increases the st_nlink field before
|
||||
decreasing it again.) */
|
||||
debug("'%s' has reached maximum number of links", linkPath);
|
||||
debug("%s has reached maximum number of links", linkPath);
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
|
||||
if (e.code() == std::errc::file_exists) {
|
||||
/* Race condition: another process created the same temp link.
|
||||
Try again with a different name. */
|
||||
continue;
|
||||
}
|
||||
|
||||
throw SysError("renaming temporary link '%1%' to '%2%'", tempLink, path);
|
||||
}
|
||||
}
|
||||
|
||||
stats.filesLinked++;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue