Merge branch 'path-info' into ca-drv-exotic

This commit is contained in:
John Ericson 2023-01-06 15:37:31 -05:00
commit 81727f85cb
17 changed files with 153 additions and 119 deletions

View file

@ -1532,7 +1532,8 @@ static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, V
StorePathSet refs; StorePathSet refs;
if (state.store->isInStore(path)) { if (state.store->isInStore(path)) {
try { try {
refs = state.store->queryPathInfo(state.store->toStorePath(path).first)->references; // FIXME: Are self references becoming non-self references OK?
refs = state.store->queryPathInfo(state.store->toStorePath(path).first)->referencesPossiblyToSelf();
} catch (Error &) { // FIXME: should be InvalidPathError } catch (Error &) { // FIXME: should be InvalidPathError
} }
// Re-scan references to filter down to just the ones that actually occur in the file. // Re-scan references to filter down to just the ones that actually occur in the file.
@ -1968,7 +1969,7 @@ static void addPath(
try { try {
auto [storePath, subPath] = state.store->toStorePath(path); auto [storePath, subPath] = state.store->toStorePath(path);
// FIXME: we should scanForReferences on the path before adding it // FIXME: we should scanForReferences on the path before adding it
refs = state.store->queryPathInfo(storePath)->references; refs = state.store->queryPathInfo(storePath)->referencesPossiblyToSelf();
path = state.store->toRealPath(storePath) + subPath; path = state.store->toRealPath(storePath) + subPath;
} catch (Error &) { // FIXME: should be InvalidPathError } catch (Error &) { // FIXME: should be InvalidPathError
} }
@ -2007,7 +2008,7 @@ static void addPath(
.method = method, .method = method,
.hash = *expectedHash, .hash = *expectedHash,
}, },
{}, .references = {},
}); });
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {

View file

@ -180,8 +180,9 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
duration); duration);
/* Verify that all references are valid. This may do some .narinfo /* Verify that all references are valid. This may do some .narinfo
reads, but typically they'll already be cached. */ reads, but typically they'll already be cached. Note that
for (auto & ref : info.references) self-references are always valid. */
for (auto & ref : info.references.others)
try { try {
queryPathInfo(ref); queryPathInfo(ref);
} catch (InvalidPath &) { } catch (InvalidPath &) {
@ -314,8 +315,8 @@ StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view n
.hash = nar.first, .hash = nar.first,
}, },
.references = { .references = {
.references = references, .others = references,
.hasSelfReference = false, .self = false,
}, },
}, },
}, },
@ -434,8 +435,8 @@ StorePath BinaryCacheStore::addToStore(
.hash = h, .hash = h,
}, },
.references = { .references = {
.references = references, .others = references,
.hasSelfReference = false, .self = false,
}, },
}, },
}, },

View file

@ -2421,26 +2421,26 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
} }
}; };
auto rewriteRefs = [&]() -> PathReferences<StorePath> { auto rewriteRefs = [&]() -> StoreReferences {
/* In the CA case, we need the rewritten refs to calculate the /* In the CA case, we need the rewritten refs to calculate the
final path, therefore we look for a *non-rewritten final path, therefore we look for a *non-rewritten
self-reference, and use a bool rather try to solve the self-reference, and use a bool rather try to solve the
computationally intractable fixed point. */ computationally intractable fixed point. */
PathReferences<StorePath> res { StoreReferences res {
.hasSelfReference = false, .self = false,
}; };
for (auto & r : references) { for (auto & r : references) {
auto name = r.name(); auto name = r.name();
auto origHash = std::string { r.hashPart() }; auto origHash = std::string { r.hashPart() };
if (r == *scratchPath) { if (r == *scratchPath) {
res.hasSelfReference = true; res.self = true;
} else if (auto outputRewrite = get(outputRewrites, origHash)) { } else if (auto outputRewrite = get(outputRewrites, origHash)) {
std::string newRef = *outputRewrite; std::string newRef = *outputRewrite;
newRef += '-'; newRef += '-';
newRef += name; newRef += name;
res.references.insert(StorePath { newRef }); res.others.insert(StorePath { newRef });
} else { } else {
res.references.insert(r); res.others.insert(r);
} }
} }
return res; return res;
@ -2529,7 +2529,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
auto narHashAndSize = hashPath(htSHA256, actualPath); auto narHashAndSize = hashPath(htSHA256, actualPath);
ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first }; ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first };
newInfo0.narSize = narHashAndSize.second; newInfo0.narSize = narHashAndSize.second;
static_cast<PathReferences<StorePath> &>(newInfo0) = rewriteRefs(); newInfo0.references = rewriteRefs();
return newInfo0; return newInfo0;
}, },
@ -2554,7 +2554,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
wanted.to_string(SRI, true), wanted.to_string(SRI, true),
got.to_string(SRI, true))); got.to_string(SRI, true)));
} }
if (static_cast<const PathReferences<StorePath> &>(newInfo0) != PathReferences<StorePath> {}) if (!newInfo.references.empty())
delayedException = std::make_exception_ptr( delayedException = std::make_exception_ptr(
BuildError("illegal path references in fixed-output derivation '%s'", BuildError("illegal path references in fixed-output derivation '%s'",
worker.store.printStorePath(drvPath))); worker.store.printStorePath(drvPath)));

View file

@ -128,7 +128,7 @@ void PathSubstitutionGoal::tryNext()
} }
if (info->path != storePath) { if (info->path != storePath) {
if (info->isContentAddressed(*sub) && info->references.empty() && !info->hasSelfReference) { if (info->isContentAddressed(*sub) && info->references.empty()) {
auto info2 = std::make_shared<ValidPathInfo>(*info); auto info2 = std::make_shared<ValidPathInfo>(*info);
info2->path = storePath; info2->path = storePath;
info = info2; info = info2;
@ -165,7 +165,7 @@ void PathSubstitutionGoal::tryNext()
/* To maintain the closure invariant, we first have to realise the /* To maintain the closure invariant, we first have to realise the
paths referenced by this one. */ paths referenced by this one. */
for (auto & i : info->references) for (auto & i : info->references.others)
addWaitee(worker.makePathSubstitutionGoal(i)); addWaitee(worker.makePathSubstitutionGoal(i));
if (waitees.empty()) /* to prevent hang (no wake-up event) */ if (waitees.empty()) /* to prevent hang (no wake-up event) */
@ -187,7 +187,7 @@ void PathSubstitutionGoal::referencesValid()
return; return;
} }
for (auto & i : info->references) for (auto & i : info->references.others)
assert(worker.store.isValidPath(i)); assert(worker.store.isValidPath(i));
state = &PathSubstitutionGoal::tryToRun; state = &PathSubstitutionGoal::tryToRun;

View file

@ -161,15 +161,15 @@ std::string renderContentAddress(std::optional<ContentAddress> ca)
} }
ContentAddressWithReferences contentAddressFromMethodHashAndRefs( ContentAddressWithReferences contentAddressFromMethodHashAndRefs(
ContentAddressMethod method, Hash && hash, PathReferences<StorePath> && refs) ContentAddressMethod method, Hash && hash, StoreReferences && refs)
{ {
return std::visit(overloaded { return std::visit(overloaded {
[&](TextHashMethod _) -> ContentAddressWithReferences { [&](TextHashMethod _) -> ContentAddressWithReferences {
if (refs.hasSelfReference) if (refs.self)
throw UsageError("Cannot have a self reference with text hashing scheme"); throw UsageError("Cannot have a self reference with text hashing scheme");
return TextInfo { return TextInfo {
{ .hash = std::move(hash) }, { .hash = std::move(hash) },
std::move(refs.references), .references = std::move(refs.others),
}; };
}, },
[&](FileIngestionMethod m2) -> ContentAddressWithReferences { [&](FileIngestionMethod m2) -> ContentAddressWithReferences {
@ -178,7 +178,7 @@ ContentAddressWithReferences contentAddressFromMethodHashAndRefs(
.method = m2, .method = m2,
.hash = std::move(hash), .hash = std::move(hash),
}, },
std::move(refs), .references = std::move(refs),
}; };
}, },
}, method); }, method);

View file

@ -4,6 +4,7 @@
#include "hash.hh" #include "hash.hh"
#include "path.hh" #include "path.hh"
#include "comparator.hh" #include "comparator.hh"
#include "reference-set.hh"
namespace nix { namespace nix {
@ -101,48 +102,7 @@ Hash getContentAddressHash(const ContentAddress & ca);
* References set * References set
*/ */
template<typename Ref> typedef References<StorePath> StoreReferences;
struct PathReferences
{
std::set<Ref> references;
bool hasSelfReference = false;
/* Functions to view references + hasSelfReference as one set, mainly for
compatibility's sake. */
StorePathSet referencesPossiblyToSelf(const Ref & self) const;
void insertReferencePossiblyToSelf(const Ref & self, Ref && ref);
void setReferencesPossiblyToSelf(const Ref & self, std::set<Ref> && refs);
GENERATE_CMP(PathReferences<Ref>, me->references, me->hasSelfReference);
};
template<typename Ref>
StorePathSet PathReferences<Ref>::referencesPossiblyToSelf(const Ref & self) const
{
StorePathSet refs { references };
if (hasSelfReference)
refs.insert(self);
return refs;
}
template<typename Ref>
void PathReferences<Ref>::insertReferencePossiblyToSelf(const Ref & self, Ref && ref)
{
if (ref == self)
hasSelfReference = true;
else
references.insert(std::move(ref));
}
template<typename Ref>
void PathReferences<Ref>::setReferencesPossiblyToSelf(const Ref & self, std::set<Ref> && refs)
{
if (refs.count(self))
hasSelfReference = true;
refs.erase(self);
references = refs;
}
/* /*
* Full content address * Full content address
@ -160,7 +120,7 @@ struct TextInfo : TextHash {
struct FixedOutputInfo : FixedOutputHash { struct FixedOutputInfo : FixedOutputHash {
// References for the paths // References for the paths
PathReferences<StorePath> references; StoreReferences references;
GENERATE_CMP(FixedOutputInfo, *(const FixedOutputHash *)me, me->references); GENERATE_CMP(FixedOutputInfo, *(const FixedOutputHash *)me, me->references);
}; };
@ -173,7 +133,7 @@ typedef std::variant<
ContentAddressWithReferences caWithoutRefs(const ContentAddress &); ContentAddressWithReferences caWithoutRefs(const ContentAddress &);
ContentAddressWithReferences contentAddressFromMethodHashAndRefs( ContentAddressWithReferences contentAddressFromMethodHashAndRefs(
ContentAddressMethod method, Hash && hash, PathReferences<StorePath> && refs); ContentAddressMethod method, Hash && hash, StoreReferences && refs);
ContentAddressMethod getContentAddressMethod(const ContentAddressWithReferences & ca); ContentAddressMethod getContentAddressMethod(const ContentAddressWithReferences & ca);
Hash getContentAddressHash(const ContentAddressWithReferences & ca); Hash getContentAddressHash(const ContentAddressWithReferences & ca);

View file

@ -762,7 +762,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
else { else {
to << 1 to << 1
<< (i->second.deriver ? store->printStorePath(*i->second.deriver) : ""); << (i->second.deriver ? store->printStorePath(*i->second.deriver) : "");
worker_proto::write(*store, to, i->second.referencesPossiblyToSelf(path)); worker_proto::write(*store, to, i->second.references.possiblyToSelf(path));
to << i->second.downloadSize to << i->second.downloadSize
<< i->second.narSize; << i->second.narSize;
} }
@ -785,7 +785,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
for (auto & i : infos) { for (auto & i : infos) {
to << store->printStorePath(i.first) to << store->printStorePath(i.first)
<< (i.second.deriver ? store->printStorePath(*i.second.deriver) : ""); << (i.second.deriver ? store->printStorePath(*i.second.deriver) : "");
worker_proto::write(*store, to, i.second.referencesPossiblyToSelf(i.first)); worker_proto::write(*store, to, i.second.references.possiblyToSelf(i.first));
to << i.second.downloadSize << i.second.narSize; to << i.second.downloadSize << i.second.narSize;
} }
break; break;

View file

@ -1157,11 +1157,10 @@ void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, Subst
auto narInfo = std::dynamic_pointer_cast<const NarInfo>( auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
std::shared_ptr<const ValidPathInfo>(info)); std::shared_ptr<const ValidPathInfo>(info));
infos.insert_or_assign(path.first, SubstitutablePathInfo{ infos.insert_or_assign(path.first, SubstitutablePathInfo{
info->references, .deriver = info->deriver,
info->hasSelfReference, .references = info->references,
info->deriver, .downloadSize = narInfo ? narInfo->fileSize : 0,
narInfo ? narInfo->fileSize : 0, .narSize = info->narSize,
info->narSize,
}); });
} catch (InvalidPath &) { } catch (InvalidPath &) {
} catch (SubstituterDisabled &) { } catch (SubstituterDisabled &) {
@ -1228,7 +1227,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
topoSort(paths, topoSort(paths,
{[&](const StorePath & path) { {[&](const StorePath & path) {
auto i = infos.find(path); auto i = infos.find(path);
return i == infos.end() ? StorePathSet() : i->second.references; return i == infos.end() ? StorePathSet() : i->second.references.others;
}}, }},
{[&](const StorePath & path, const StorePath & parent) { {[&](const StorePath & path, const StorePath & parent) {
return BuildError( return BuildError(
@ -1427,8 +1426,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
.hash = hash, .hash = hash,
}, },
.references = { .references = {
.references = references, .others = references,
.hasSelfReference = false, .self = false,
}, },
}, },
}; };
@ -1526,7 +1525,8 @@ StorePath LocalStore::addTextToStore(
ValidPathInfo info { dstPath, narHash }; ValidPathInfo info { dstPath, narHash };
info.narSize = sink.s.size(); info.narSize = sink.s.size();
info.references = references; // No self reference allowed with text-hashing
info.references.others = references;
info.ca = TextHash { .hash = hash }; info.ca = TextHash { .hash = hash };
registerValidPath(info); registerValidPath(info);
} }

View file

@ -27,15 +27,15 @@ std::map<StorePath, StorePath> makeContentAddressed(
StringMap rewrites; StringMap rewrites;
PathReferences<StorePath> refs; StoreReferences refs;
refs.hasSelfReference = oldInfo->hasSelfReference; refs.self = oldInfo->references.self;
for (auto & ref : oldInfo->references) { for (auto & ref : oldInfo->references.others) {
auto i = remappings.find(ref); auto i = remappings.find(ref);
auto replacement = i != remappings.end() ? i->second : ref; auto replacement = i != remappings.end() ? i->second : ref;
// FIXME: warn about unremapped paths? // FIXME: warn about unremapped paths?
if (replacement != ref) { if (replacement != ref) {
rewrites.insert_or_assign(srcStore.printStorePath(ref), srcStore.printStorePath(replacement)); rewrites.insert_or_assign(srcStore.printStorePath(ref), srcStore.printStorePath(replacement));
refs.references.insert(std::move(replacement)); refs.others.insert(std::move(replacement));
} }
} }

View file

@ -21,16 +21,16 @@ void Store::computeFSClosure(const StorePathSet & startPaths,
StorePathSet res; StorePathSet res;
StorePathSet referrers; StorePathSet referrers;
queryReferrers(path, referrers); queryReferrers(path, referrers);
for (auto& ref : referrers) for (auto & ref : referrers)
if (ref != path) if (ref != path)
res.insert(ref); res.insert(ref);
if (includeOutputs) if (includeOutputs)
for (auto& i : queryValidDerivers(path)) for (auto & i : queryValidDerivers(path))
res.insert(i); res.insert(i);
if (includeDerivers && path.isDerivation()) if (includeDerivers && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) for (auto & [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath)) if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath); res.insert(*maybeOutPath);
return res; return res;
@ -40,11 +40,11 @@ void Store::computeFSClosure(const StorePathSet & startPaths,
std::future<ref<const ValidPathInfo>> & fut) { std::future<ref<const ValidPathInfo>> & fut) {
StorePathSet res; StorePathSet res;
auto info = fut.get(); auto info = fut.get();
for (auto& ref : info->references) for (auto & ref : info->references.others)
res.insert(ref); res.insert(ref);
if (includeOutputs && path.isDerivation()) if (includeOutputs && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) for (auto & [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath)) if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath); res.insert(*maybeOutPath);
@ -95,7 +95,7 @@ std::optional<ContentAddress> getDerivationCA(const BasicDerivation & drv)
return static_cast<TextHash>(ti); return static_cast<TextHash>(ti);
}, },
[&](const FixedOutputInfo & fi) -> std::optional<ContentAddress> { [&](const FixedOutputInfo & fi) -> std::optional<ContentAddress> {
if (fi.references != PathReferences<StorePath> {}) if (!fi.references.empty())
return std::nullopt; return std::nullopt;
return static_cast<FixedOutputHash>(fi); return static_cast<FixedOutputHash>(fi);
}, },
@ -235,7 +235,7 @@ void Store::queryMissing(const std::vector<DerivedPath> & targets,
state->narSize += info->second.narSize; state->narSize += info->second.narSize;
} }
for (auto & ref : info->second.references) for (auto & ref : info->second.references.others)
pool.enqueue(std::bind(doPath, DerivedPath::Opaque { ref })); pool.enqueue(std::bind(doPath, DerivedPath::Opaque { ref }));
}, },
}, req.raw()); }, req.raw());
@ -253,7 +253,7 @@ StorePaths Store::topoSortPaths(const StorePathSet & paths)
return topoSort(paths, return topoSort(paths,
{[&](const StorePath & path) { {[&](const StorePath & path) {
try { try {
return queryPathInfo(path)->references; return queryPathInfo(path)->references.others;
} catch (InvalidPath &) { } catch (InvalidPath &) {
return StorePathSet(); return StorePathSet();
} }
@ -309,7 +309,7 @@ std::map<DrvOutput, StorePath> drvOutputReferences(
auto info = store.queryPathInfo(outputPath); auto info = store.queryPathInfo(outputPath);
return drvOutputReferences(Realisation::closure(store, inputRealisations), info->references); return drvOutputReferences(Realisation::closure(store, inputRealisations), info->referencesPossiblyToSelf());
} }
} }

View file

@ -14,20 +14,22 @@ namespace nix {
class Store; class Store;
struct SubstitutablePathInfo : PathReferences<StorePath> struct SubstitutablePathInfo
{ {
std::optional<StorePath> deriver; std::optional<StorePath> deriver;
StoreReferences references;
uint64_t downloadSize; /* 0 = unknown or inapplicable */ uint64_t downloadSize; /* 0 = unknown or inapplicable */
uint64_t narSize; /* 0 = unknown */ uint64_t narSize; /* 0 = unknown */
}; };
typedef std::map<StorePath, SubstitutablePathInfo> SubstitutablePathInfos; typedef std::map<StorePath, SubstitutablePathInfo> SubstitutablePathInfos;
struct ValidPathInfo : PathReferences<StorePath> struct ValidPathInfo
{ {
StorePath path; StorePath path;
std::optional<StorePath> deriver; std::optional<StorePath> deriver;
Hash narHash; Hash narHash;
StoreReferences references;
time_t registrationTime = 0; time_t registrationTime = 0;
uint64_t narSize = 0; // 0 = unknown uint64_t narSize = 0; // 0 = unknown
uint64_t id; // internal use only uint64_t id; // internal use only
@ -61,7 +63,6 @@ struct ValidPathInfo : PathReferences<StorePath>
return return
path == i.path path == i.path
&& narHash == i.narHash && narHash == i.narHash
&& hasSelfReference == i.hasSelfReference
&& references == i.references; && references == i.references;
} }

View file

@ -402,7 +402,7 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
auto deriver = readString(conn->from); auto deriver = readString(conn->from);
if (deriver != "") if (deriver != "")
info.deriver = parseStorePath(deriver); info.deriver = parseStorePath(deriver);
info.setReferencesPossiblyToSelf(i.first, worker_proto::read(*this, conn->from, Phantom<StorePathSet> {})); info.references.setPossiblyToSelf(i.first, worker_proto::read(*this, conn->from, Phantom<StorePathSet> {}));
info.downloadSize = readLongLong(conn->from); info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from);
infos.insert_or_assign(i.first, std::move(info)); infos.insert_or_assign(i.first, std::move(info));
@ -426,7 +426,7 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
auto deriver = readString(conn->from); auto deriver = readString(conn->from);
if (deriver != "") if (deriver != "")
info.deriver = parseStorePath(deriver); info.deriver = parseStorePath(deriver);
info.setReferencesPossiblyToSelf(path, worker_proto::read(*this, conn->from, Phantom<StorePathSet> {})); info.references.setPossiblyToSelf(path, worker_proto::read(*this, conn->from, Phantom<StorePathSet> {}));
info.downloadSize = readLongLong(conn->from); info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from);
} }

View file

@ -169,13 +169,13 @@ StorePath Store::makeOutputPath(std::string_view id,
static std::string makeType( static std::string makeType(
const Store & store, const Store & store,
std::string && type, std::string && type,
const PathReferences<StorePath> & references) const StoreReferences & references)
{ {
for (auto & i : references.references) { for (auto & i : references.others) {
type += ":"; type += ":";
type += store.printStorePath(i); type += store.printStorePath(i);
} }
if (references.hasSelfReference) type += ":self"; if (references.self) type += ":self";
return std::move(type); return std::move(type);
} }
@ -185,8 +185,7 @@ StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInf
if (info.hash.type == htSHA256 && info.method == FileIngestionMethod::Recursive) { if (info.hash.type == htSHA256 && info.method == FileIngestionMethod::Recursive) {
return makeStorePath(makeType(*this, "source", info.references), info.hash, name); return makeStorePath(makeType(*this, "source", info.references), info.hash, name);
} else { } else {
assert(info.references.references.size() == 0); assert(info.references.size() == 0);
assert(!info.references.hasSelfReference);
return makeStorePath("output:out", return makeStorePath("output:out",
hashString(htSHA256, hashString(htSHA256,
"fixed:out:" "fixed:out:"
@ -201,7 +200,7 @@ StorePath Store::makeTextPath(std::string_view name, const TextInfo & info) cons
{ {
assert(info.hash.type == htSHA256); assert(info.hash.type == htSHA256);
return makeStorePath( return makeStorePath(
makeType(*this, "text", PathReferences<StorePath> { info.references }), makeType(*this, "text", StoreReferences { info.references }),
info.hash, info.hash,
name); name);
} }
@ -311,7 +310,7 @@ void Store::addMultipleToStore(
bytesExpected += info.narSize; bytesExpected += info.narSize;
act.setExpected(actCopyPath, bytesExpected); act.setExpected(actCopyPath, bytesExpected);
return info.references; return info.references.others;
}, },
[&](const StorePath & path) { [&](const StorePath & path) {
@ -816,7 +815,7 @@ std::string Store::makeValidityRegistration(const StorePathSet & paths,
s += (format("%1%\n") % info->references.size()).str(); s += (format("%1%\n") % info->references.size()).str();
for (auto & j : info->references) for (auto & j : info->referencesPossiblyToSelf())
s += printStorePath(j) + "\n"; s += printStorePath(j) + "\n";
} }
@ -878,7 +877,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
{ {
auto& jsonRefs = (jsonPath["references"] = json::array()); auto& jsonRefs = (jsonPath["references"] = json::array());
for (auto & ref : info->references) for (auto & ref : info->referencesPossiblyToSelf())
jsonRefs.emplace_back(printStorePath(ref)); jsonRefs.emplace_back(printStorePath(ref));
} }
@ -1231,17 +1230,17 @@ std::string showPaths(const PathSet & paths)
StorePathSet ValidPathInfo::referencesPossiblyToSelf() const StorePathSet ValidPathInfo::referencesPossiblyToSelf() const
{ {
return PathReferences<StorePath>::referencesPossiblyToSelf(path); return references.possiblyToSelf(path);
} }
void ValidPathInfo::insertReferencePossiblyToSelf(StorePath && ref) void ValidPathInfo::insertReferencePossiblyToSelf(StorePath && ref)
{ {
return PathReferences<StorePath>::insertReferencePossiblyToSelf(path, std::move(ref)); return references.insertPossiblyToSelf(path, std::move(ref));
} }
void ValidPathInfo::setReferencesPossiblyToSelf(StorePathSet && refs) void ValidPathInfo::setReferencesPossiblyToSelf(StorePathSet && refs)
{ {
return PathReferences<StorePath>::setReferencesPossiblyToSelf(path, std::move(refs)); return references.setPossiblyToSelf(path, std::move(refs));
} }
std::string ValidPathInfo::fingerprint(const Store & store) const std::string ValidPathInfo::fingerprint(const Store & store) const
@ -1271,16 +1270,16 @@ std::optional<StorePathDescriptor> ValidPathInfo::fullStorePathDescriptorOpt() c
.name = std::string { path.name() }, .name = std::string { path.name() },
.info = std::visit(overloaded { .info = std::visit(overloaded {
[&](const TextHash & th) -> ContentAddressWithReferences { [&](const TextHash & th) -> ContentAddressWithReferences {
assert(!hasSelfReference); assert(!references.self);
return TextInfo { return TextInfo {
th, th,
.references = references, .references = references.others,
}; };
}, },
[&](const FixedOutputHash & foh) -> ContentAddressWithReferences { [&](const FixedOutputHash & foh) -> ContentAddressWithReferences {
return FixedOutputInfo { return FixedOutputInfo {
foh, foh,
.references = static_cast<PathReferences<StorePath>>(*this), .references = references,
}; };
}, },
}, *ca), }, *ca),
@ -1341,11 +1340,14 @@ ValidPathInfo::ValidPathInfo(
{ {
std::visit(overloaded { std::visit(overloaded {
[this](TextInfo && ti) { [this](TextInfo && ti) {
this->references = std::move(ti.references); this->references = {
.others = std::move(ti.references),
.self = false,
};
this->ca = std::move((TextHash &&) ti); this->ca = std::move((TextHash &&) ti);
}, },
[this](FixedOutputInfo && foi) { [this](FixedOutputInfo && foi) {
*(static_cast<PathReferences<StorePath> *>(this)) = std::move(foi.references); this->references = std::move(foi.references);
this->ca = std::move((FixedOutputHash &&) foi); this->ca = std::move((FixedOutputHash &&) foi);
}, },
}, std::move(info.info)); }, std::move(info.info));

View file

@ -0,0 +1,68 @@
#pragma once
#include "comparator.hh"
#include <set>
namespace nix {
template<typename Ref>
struct References
{
std::set<Ref> others;
bool self = false;
bool empty() const;
size_t size() const;
/* Functions to view references + self as one set, mainly for
compatibility's sake. */
std::set<Ref> possiblyToSelf(const Ref & self) const;
void insertPossiblyToSelf(const Ref & self, Ref && ref);
void setPossiblyToSelf(const Ref & self, std::set<Ref> && refs);
GENERATE_CMP(References<Ref>, me->others, me->self);
};
template<typename Ref>
bool References<Ref>::empty() const
{
return !self && others.empty();
}
template<typename Ref>
size_t References<Ref>::size() const
{
return (self ? 1 : 0) + others.size();
}
template<typename Ref>
std::set<Ref> References<Ref>::possiblyToSelf(const Ref & selfRef) const
{
std::set<Ref> refs { others };
if (self)
refs.insert(selfRef);
return refs;
}
template<typename Ref>
void References<Ref>::insertPossiblyToSelf(const Ref & selfRef, Ref && ref)
{
if (ref == selfRef)
self = true;
else
others.insert(std::move(ref));
}
template<typename Ref>
void References<Ref>::setPossiblyToSelf(const Ref & selfRef, std::set<Ref> && refs)
{
if (refs.count(selfRef)) {
self = true;
refs.erase(selfRef);
}
others = refs;
}
}

View file

@ -205,12 +205,14 @@ struct ProfileManifest
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hash = narHash, .hash = narHash,
}, },
.references = { references }, .references = {
.others = std::move(references),
.self = false,
},
}, },
}, },
narHash, narHash,
}; };
info.references = std::move(references);
info.narSize = sink.s.size(); info.narSize = sink.s.size();
StringSource source(sink.s); StringSource source(sink.s);

View file

@ -63,8 +63,7 @@ struct CmdCopySigs : StorePathsCommand
binary. */ binary. */
if (info->narHash != info2->narHash || if (info->narHash != info2->narHash ||
info->narSize != info2->narSize || info->narSize != info2->narSize ||
info->references != info2->references || info->references != info2->references)
info->hasSelfReference != info2->hasSelfReference)
continue; continue;
for (auto & sig : info2->sigs) for (auto & sig : info2->sigs)

View file

@ -136,7 +136,7 @@ struct CmdWhyDepends : SourceExprCommand
for (auto & path : closure) for (auto & path : closure)
graph.emplace(path, Node { graph.emplace(path, Node {
.path = path, .path = path,
.refs = store->queryPathInfo(path)->references, .refs = store->queryPathInfo(path)->references.others,
.dist = path == dependencyPath ? 0 : inf .dist = path == dependencyPath ? 0 : inf
}); });