aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/binary-cache-store.cc48
-rw-r--r--src/libstore/build/local-derivation-goal.cc56
-rw-r--r--src/libstore/build/substitution-goal.cc4
-rw-r--r--src/libstore/content-address.cc87
-rw-r--r--src/libstore/content-address.hh198
-rw-r--r--src/libstore/daemon.cc10
-rw-r--r--src/libstore/derivations.cc6
-rw-r--r--src/libstore/legacy-ssh-store.cc2
-rw-r--r--src/libstore/local-store.cc37
-rw-r--r--src/libstore/make-content-addressed.cc33
-rw-r--r--src/libstore/nar-info-disk-cache.cc2
-rw-r--r--src/libstore/nar-info.cc2
-rw-r--r--src/libstore/nar-info.hh3
-rw-r--r--src/libstore/path-info.cc67
-rw-r--r--src/libstore/path-info.hh10
-rw-r--r--src/libstore/remote-store.cc8
-rw-r--r--src/libstore/store-api.cc117
-rw-r--r--src/libstore/store-api.hh12
18 files changed, 489 insertions, 213 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 751cf8c30..fcd763a9d 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -306,11 +306,22 @@ StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view n
unsupported("addToStoreFromDump");
return addToStoreCommon(dump, repair, CheckSigs, [&](HashResult nar) {
ValidPathInfo info {
- makeFixedOutputPath(method, nar.first, name, references),
+ *this,
+ name,
+ FixedOutputInfo {
+ .hash = {
+ .method = method,
+ .hash = nar.first,
+ },
+ .references = {
+ .others = references,
+ // caller is not capable of creating a self-reference, because this is content-addressed without modulus
+ .self = false,
+ },
+ },
nar.first,
};
info.narSize = nar.second;
- info.references = references;
return info;
})->path;
}
@@ -414,15 +425,22 @@ StorePath BinaryCacheStore::addToStore(
});
return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) {
ValidPathInfo info {
- makeFixedOutputPath(method, h, name, references),
+ *this,
+ name,
+ FixedOutputInfo {
+ .hash = {
+ .method = method,
+ .hash = h,
+ },
+ .references = {
+ .others = references,
+ // caller is not capable of creating a self-reference, because this is content-addressed without modulus
+ .self = false,
+ },
+ },
nar.first,
};
info.narSize = nar.second;
- info.references = references;
- info.ca = FixedOutputHash {
- .method = method,
- .hash = h,
- };
return info;
})->path;
}
@@ -434,7 +452,7 @@ StorePath BinaryCacheStore::addTextToStore(
RepairFlag repair)
{
auto textHash = hashString(htSHA256, s);
- auto path = makeTextPath(name, textHash, references);
+ auto path = makeTextPath(name, TextInfo { { textHash }, references });
if (!repair && isValidPath(path))
return path;
@@ -443,10 +461,16 @@ StorePath BinaryCacheStore::addTextToStore(
dumpString(s, sink);
StringSource source(sink.s);
return addToStoreCommon(source, repair, CheckSigs, [&](HashResult nar) {
- ValidPathInfo info { path, nar.first };
+ ValidPathInfo info {
+ *this,
+ std::string { name },
+ TextInfo {
+ { .hash = textHash },
+ references,
+ },
+ nar.first,
+ };
info.narSize = nar.second;
- info.ca = TextHash { textHash };
- info.references = references;
return info;
})->path;
}
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 58d6901d3..31fea9259 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -2395,27 +2395,26 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
}
};
- auto rewriteRefs = [&]() -> std::pair<bool, StorePathSet> {
+ auto rewriteRefs = [&]() -> StoreReferences {
/* In the CA case, we need the rewritten refs to calculate the
final path, therefore we look for a *non-rewritten
self-reference, and use a bool rather try to solve the
computationally intractable fixed point. */
- std::pair<bool, StorePathSet> res {
- false,
- {},
+ StoreReferences res {
+ .self = false,
};
for (auto & r : references) {
auto name = r.name();
auto origHash = std::string { r.hashPart() };
if (r == *scratchPath) {
- res.first = true;
+ res.self = true;
} else if (auto outputRewrite = get(outputRewrites, origHash)) {
std::string newRef = *outputRewrite;
newRef += '-';
newRef += name;
- res.second.insert(StorePath { newRef });
+ res.others.insert(StorePath { newRef });
} else {
- res.second.insert(r);
+ res.others.insert(r);
}
}
return res;
@@ -2448,18 +2447,22 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
break;
}
auto got = caSink.finish().first;
- auto refs = rewriteRefs();
-
- auto finalPath = worker.store.makeFixedOutputPath(
- outputHash.method,
- got,
- outputPathName(drv->name, outputName),
- refs.second,
- refs.first);
- if (*scratchPath != finalPath) {
+ ValidPathInfo newInfo0 {
+ worker.store,
+ outputPathName(drv->name, outputName),
+ FixedOutputInfo {
+ .hash = {
+ .method = outputHash.method,
+ .hash = got,
+ },
+ .references = rewriteRefs(),
+ },
+ Hash::dummy,
+ };
+ if (*scratchPath != newInfo0.path) {
// Also rewrite the output path
auto source = sinkToSource([&](Sink & nextSink) {
- RewritingSink rsink2(oldHashPart, std::string(finalPath.hashPart()), nextSink);
+ RewritingSink rsink2(oldHashPart, std::string(newInfo0.path.hashPart()), nextSink);
dumpPath(actualPath, rsink2);
rsink2.flush();
});
@@ -2470,19 +2473,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
}
HashResult narHashAndSize = hashPath(htSHA256, actualPath);
- ValidPathInfo newInfo0 {
- finalPath,
- narHashAndSize.first,
- };
-
+ newInfo0.narHash = narHashAndSize.first;
newInfo0.narSize = narHashAndSize.second;
- newInfo0.ca = FixedOutputHash {
- .method = outputHash.method,
- .hash = got,
- };
- newInfo0.references = refs.second;
- if (refs.first)
- newInfo0.references.insert(newInfo0.path);
assert(newInfo0.ca);
return newInfo0;
@@ -2504,8 +2496,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first };
newInfo0.narSize = narHashAndSize.second;
auto refs = rewriteRefs();
- newInfo0.references = refs.second;
- if (refs.first)
+ newInfo0.references = std::move(refs.others);
+ if (refs.self)
newInfo0.references.insert(newInfo0.path);
return newInfo0;
},
@@ -2519,7 +2511,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
/* Check wanted hash */
const Hash & wanted = dof.hash.hash;
assert(newInfo0.ca);
- auto got = getContentAddressHash(*newInfo0.ca);
+ auto got = newInfo0.ca->getHash();
if (wanted != got) {
/* Throw an error after registering the path as
valid. */
diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc
index 2af105b4d..190fb455a 100644
--- a/src/libstore/build/substitution-goal.cc
+++ b/src/libstore/build/substitution-goal.cc
@@ -95,7 +95,9 @@ void PathSubstitutionGoal::tryNext()
subs.pop_front();
if (ca) {
- subPath = sub->makeFixedOutputPathFromCA(storePath.name(), *ca);
+ subPath = sub->makeFixedOutputPathFromCA(
+ std::string { storePath.name() },
+ ContentAddressWithReferences::withoutRefs(*ca));
if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath);
} else if (sub->storeDir != worker.store.storeDir) {
diff --git a/src/libstore/content-address.cc b/src/libstore/content-address.cc
index cf32ccdc4..055b216db 100644
--- a/src/libstore/content-address.cc
+++ b/src/libstore/content-address.cc
@@ -9,7 +9,7 @@ std::string FixedOutputHash::printMethodAlgo() const
return makeFileIngestionPrefix(method) + printHashType(hash.type);
}
-std::string makeFileIngestionPrefix(const FileIngestionMethod m)
+std::string makeFileIngestionPrefix(FileIngestionMethod m)
{
switch (m) {
case FileIngestionMethod::Flat:
@@ -21,39 +21,35 @@ std::string makeFileIngestionPrefix(const FileIngestionMethod m)
}
}
-std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash)
-{
- return "fixed:"
- + makeFileIngestionPrefix(method)
- + hash.to_string(Base32, true);
-}
-
-std::string renderContentAddress(ContentAddress ca)
+std::string ContentAddress::render() const
{
return std::visit(overloaded {
- [](TextHash & th) {
- return "text:" + th.hash.to_string(Base32, true);
+ [](const TextHash & th) {
+ return "text:"
+ + th.hash.to_string(Base32, true);
},
- [](FixedOutputHash & fsh) {
- return makeFixedOutputCA(fsh.method, fsh.hash);
+ [](const FixedOutputHash & fsh) {
+ return "fixed:"
+ + makeFileIngestionPrefix(fsh.method)
+ + fsh.hash.to_string(Base32, true);
}
- }, ca);
+ }, raw);
}
-std::string renderContentAddressMethod(ContentAddressMethod cam)
+std::string ContentAddressMethod::render() const
{
return std::visit(overloaded {
- [](TextHashMethod & th) {
+ [](const TextHashMethod & th) {
return std::string{"text:"} + printHashType(htSHA256);
},
- [](FixedOutputHashMethod & fshm) {
+ [](const FixedOutputHashMethod & fshm) {
return "fixed:" + makeFileIngestionPrefix(fshm.fileIngestionMethod) + printHashType(fshm.hashType);
}
- }, cam);
+ }, raw);
}
-/*
- Parses content address strings up to the hash.
+/**
+ * Parses content address strings up to the hash.
*/
static ContentAddressMethod parseContentAddressMethodPrefix(std::string_view & rest)
{
@@ -97,7 +93,7 @@ static ContentAddressMethod parseContentAddressMethodPrefix(std::string_view & r
throw UsageError("content address prefix '%s' is unrecognized. Recogonized prefixes are 'text' or 'fixed'", prefix);
}
-ContentAddress parseContentAddress(std::string_view rawCa) {
+ContentAddress ContentAddress::parse(std::string_view rawCa) {
auto rest = rawCa;
ContentAddressMethod caMethod = parseContentAddressMethodPrefix(rest);
@@ -115,10 +111,10 @@ ContentAddress parseContentAddress(std::string_view rawCa) {
.hash = Hash::parseNonSRIUnprefixed(rest, std::move(fohMethod.hashType)),
});
},
- }, caMethod);
+ }, caMethod.raw);
}
-ContentAddressMethod parseContentAddressMethod(std::string_view caMethod)
+ContentAddressMethod ContentAddressMethod::parse(std::string_view caMethod)
{
std::string asPrefix = std::string{caMethod} + ":";
// parseContentAddressMethodPrefix takes its argument by reference
@@ -126,26 +122,55 @@ ContentAddressMethod parseContentAddressMethod(std::string_view caMethod)
return parseContentAddressMethodPrefix(asPrefixView);
}
-std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt)
+std::optional<ContentAddress> ContentAddress::parseOpt(std::string_view rawCaOpt)
{
- return rawCaOpt == "" ? std::optional<ContentAddress>() : parseContentAddress(rawCaOpt);
+ return rawCaOpt == ""
+ ? std::nullopt
+ : std::optional { ContentAddress::parse(rawCaOpt) };
};
std::string renderContentAddress(std::optional<ContentAddress> ca)
{
- return ca ? renderContentAddress(*ca) : "";
+ return ca ? ca->render() : "";
}
-Hash getContentAddressHash(const ContentAddress & ca)
+const Hash & ContentAddress::getHash() const
{
return std::visit(overloaded {
- [](const TextHash & th) {
+ [](const TextHash & th) -> auto & {
return th.hash;
},
- [](const FixedOutputHash & fsh) {
+ [](const FixedOutputHash & fsh) -> auto & {
return fsh.hash;
- }
- }, ca);
+ },
+ }, raw);
+}
+
+bool StoreReferences::empty() const
+{
+ return !self && others.empty();
+}
+
+size_t StoreReferences::size() const
+{
+ return (self ? 1 : 0) + others.size();
+}
+
+ContentAddressWithReferences ContentAddressWithReferences::withoutRefs(const ContentAddress & ca) {
+ return std::visit(overloaded {
+ [&](const TextHash & h) -> ContentAddressWithReferences {
+ return TextInfo {
+ .hash = h,
+ .references = {},
+ };
+ },
+ [&](const FixedOutputHash & h) -> ContentAddressWithReferences {
+ return FixedOutputInfo {
+ .hash = h,
+ .references = {},
+ };
+ },
+ }, ca.raw);
}
}
diff --git a/src/libstore/content-address.hh b/src/libstore/content-address.hh
index 368a7ec48..2f98950fb 100644
--- a/src/libstore/content-address.hh
+++ b/src/libstore/content-address.hh
@@ -3,12 +3,30 @@
#include <variant>
#include "hash.hh"
+#include "path.hh"
#include "comparator.hh"
namespace nix {
+/*
+ * Content addressing method
+ */
+
+/* We only have one way to hash text with references, so this is a single-value
+ type, mainly useful with std::variant.
+*/
+
+/**
+ * The single way we can serialize "text" file system objects.
+ *
+ * Somewhat obscure, used by \ref Derivation derivations and
+ * `builtins.toFile` currently.
+ */
+struct TextHashMethod : std::monostate { };
+
/**
- * An enumeration of the ways we can serialize file system objects.
+ * An enumeration of the main ways we can serialize file system
+ * objects.
*/
enum struct FileIngestionMethod : uint8_t {
/**
@@ -23,6 +41,53 @@ enum struct FileIngestionMethod : uint8_t {
};
/**
+ * Compute the prefix to the hash algorithm which indicates how the
+ * files were ingested.
+ */
+std::string makeFileIngestionPrefix(FileIngestionMethod m);
+
+struct FixedOutputHashMethod {
+ FileIngestionMethod fileIngestionMethod;
+ HashType hashType;
+
+ GENERATE_CMP(FixedOutputHashMethod, me->fileIngestionMethod, me->hashType);
+};
+
+/**
+ * An enumeration of all the ways we can serialize file system objects.
+ *
+ * Just the type of a content address. Combine with the hash itself, and
+ * we have a `ContentAddress` as defined below. Combine that, in turn,
+ * with info on references, and we have `ContentAddressWithReferences`,
+ * as defined further below.
+ */
+struct ContentAddressMethod
+{
+ typedef std::variant<
+ TextHashMethod,
+ FixedOutputHashMethod
+ > Raw;
+
+ Raw raw;
+
+ GENERATE_CMP(ContentAddressMethod, me->raw);
+
+ /* The moral equivalent of `using Raw::Raw;` */
+ ContentAddressMethod(auto &&... arg)
+ : raw(std::forward<decltype(arg)>(arg)...)
+ { }
+
+ static ContentAddressMethod parse(std::string_view rawCaMethod);
+
+ std::string render() const;
+};
+
+
+/*
+ * Mini content address
+ */
+
+/**
* Somewhat obscure, used by \ref Derivation derivations and
* `builtins.toFile` currently.
*/
@@ -36,7 +101,7 @@ struct TextHash {
};
/**
- * For path computed by makeFixedOutputPath.
+ * Used by most store objects that are content-addressed.
*/
struct FixedOutputHash {
/**
@@ -65,41 +130,96 @@ struct FixedOutputHash {
* - ‘fixed:<r?>:<ht>:<h>’: For paths computed by
* Store::makeFixedOutputPath() / Store::addToStore().
*/
-typedef std::variant<
- TextHash,
- FixedOutputHash
-> ContentAddress;
+struct ContentAddress
+{
+ typedef std::variant<
+ TextHash,
+ FixedOutputHash
+ > Raw;
-/**
- * Compute the prefix to the hash algorithm which indicates how the
- * files were ingested.
+ Raw raw;
+
+ GENERATE_CMP(ContentAddress, me->raw);
+
+ /* The moral equivalent of `using Raw::Raw;` */
+ ContentAddress(auto &&... arg)
+ : raw(std::forward<decltype(arg)>(arg)...)
+ { }
+
+ /**
+ * Compute the content-addressability assertion (ValidPathInfo::ca) for
+ * paths created by Store::makeFixedOutputPath() / Store::addToStore().
+ */
+ std::string render() const;
+
+ static ContentAddress parse(std::string_view rawCa);
+
+ static std::optional<ContentAddress> parseOpt(std::string_view rawCaOpt);
+
+ const Hash & getHash() const;
+};
+
+std::string renderContentAddress(std::optional<ContentAddress> ca);
+
+
+/*
+ * Full content address
+ *
+ * See the schema for store paths in store-api.cc
*/
-std::string makeFileIngestionPrefix(const FileIngestionMethod m);
/**
- * Compute the content-addressability assertion (ValidPathInfo::ca) for
- * paths created by Store::makeFixedOutputPath() / Store::addToStore().
+ * A set of references to other store objects.
+ *
+ * References to other store objects are tracked with store paths, self
+ * references however are tracked with a boolean.
*/
-std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash);
+struct StoreReferences {
+ /**
+ * References to other store objects
+ */
+ StorePathSet others;
-std::string renderContentAddress(ContentAddress ca);
+ /**
+ * Reference to this store object
+ */
+ bool self = false;
-std::string renderContentAddress(std::optional<ContentAddress> ca);
+ /**
+ * @return true iff no references, i.e. others is empty and self is
+ * false.
+ */
+ bool empty() const;
-ContentAddress parseContentAddress(std::string_view rawCa);
+ /**
+ * Returns the numbers of references, i.e. the size of others + 1
+ * iff self is true.
+ */
+ size_t size() const;
-std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt);
+ GENERATE_CMP(StoreReferences, me->self, me->others);
+};
-Hash getContentAddressHash(const ContentAddress & ca);
+// This matches the additional info that we need for makeTextPath
+struct TextInfo {
+ TextHash hash;
+ /**
+ * References to other store objects only; self references
+ * disallowed
+ */
+ StorePathSet references;
-/*
- We only have one way to hash text with references, so this is single-value
- type is only useful in std::variant.
-*/
-struct TextHashMethod { };
-struct FixedOutputHashMethod {
- FileIngestionMethod fileIngestionMethod;
- HashType hashType;
+ GENERATE_CMP(TextInfo, me->hash, me->references);
+};
+
+struct FixedOutputInfo {
+ FixedOutputHash hash;
+ /**
+ * References to other store objects or this one.
+ */
+ StoreReferences references;
+
+ GENERATE_CMP(FixedOutputInfo, me->hash, me->references);
};
/**
@@ -107,13 +227,27 @@ struct FixedOutputHashMethod {
*
* A ContentAddress without a Hash.
*/
-typedef std::variant<
- TextHashMethod,
- FixedOutputHashMethod
- > ContentAddressMethod;
+struct ContentAddressWithReferences
+{
+ typedef std::variant<
+ TextInfo,
+ FixedOutputInfo
+ > Raw;
+
+ Raw raw;
-ContentAddressMethod parseContentAddressMethod(std::string_view rawCaMethod);
+ GENERATE_CMP(ContentAddressWithReferences, me->raw);
-std::string renderContentAddressMethod(ContentAddressMethod caMethod);
+ /* The moral equivalent of `using Raw::Raw;` */
+ ContentAddressWithReferences(auto &&... arg)
+ : raw(std::forward<decltype(arg)>(arg)...)
+ { }
+
+ /**
+ * Create a ContentAddressWithReferences from a mere ContentAddress, by
+ * assuming no references in all cases.
+ */
+ static ContentAddressWithReferences withoutRefs(const ContentAddress &);
+};
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 63898f8dc..ed2d15c10 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -401,21 +401,21 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork();
auto pathInfo = [&]() {
// NB: FramedSource must be out of scope before logger->stopWork();
- ContentAddressMethod contentAddressMethod = parseContentAddressMethod(camStr);
+ ContentAddressMethod contentAddressMethod = ContentAddressMethod::parse(camStr);
FramedSource source(from);
// TODO this is essentially RemoteStore::addCAToStore. Move it up to Store.
return std::visit(overloaded {
- [&](TextHashMethod &) {
+ [&](const TextHashMethod &) {
// We could stream this by changing Store
std::string contents = source.drain();
auto path = store->addTextToStore(name, contents, refs, repair);
return store->queryPathInfo(path);
},
- [&](FixedOutputHashMethod & fohm) {
+ [&](const FixedOutputHashMethod & fohm) {
auto path = store->addToStoreFromDump(source, name, fohm.fileIngestionMethod, fohm.hashType, repair, refs);
return store->queryPathInfo(path);
},
- }, contentAddressMethod);
+ }, contentAddressMethod.raw);
}();
logger->stopWork();
@@ -880,7 +880,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
info.references = worker_proto::read(*store, from, Phantom<StorePathSet> {});
from >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(from);
- info.ca = parseContentAddressOpt(readString(from));
+ info.ca = ContentAddress::parseOpt(readString(from));
from >> repair >> dontCheckSigs;
if (!trusted && dontCheckSigs)
dontCheckSigs = false;
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 7eb5cd275..0de36504b 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -36,8 +36,8 @@ std::optional<StorePath> DerivationOutput::path(const Store & store, std::string
StorePath DerivationOutput::CAFixed::path(const Store & store, std::string_view drvName, std::string_view outputName) const
{
return store.makeFixedOutputPath(
- hash.method, hash.hash,
- outputPathName(drvName, outputName));
+ outputPathName(drvName, outputName),
+ { hash, {} });
}
@@ -942,7 +942,7 @@ void Derivation::checkInvariants(Store & store, const StorePath & drvPath) const
envHasRightPath(doia.path, i.first);
},
[&](const DerivationOutput::CAFixed & dof) {
- StorePath path = store.makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName);
+ StorePath path = store.makeFixedOutputPath(drvName, { dof.hash, {} });
envHasRightPath(path, i.first);
},
[&](const DerivationOutput::CAFloating &) {
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index d2ddbbe5f..c3cb3032a 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -156,7 +156,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
throw Error("NAR hash is now mandatory");
info->narHash = Hash::parseAnyPrefixed(s);
}
- info->ca = parseContentAddressOpt(readString(conn->from));
+ info->ca = ContentAddress::parseOpt(readString(conn->from));
info->sigs = readStrings<StringSet>(conn->from);
auto s = readString(conn->from);
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index c3be1b461..7fb312c37 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -710,6 +710,7 @@ void canonicalisePathMetaData(const Path & path,
canonicalisePathMetaData(path, uidRange, inodesSeen);
}
+
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{
experimentalFeatureSettings.require(Xp::CaDerivations);
@@ -888,7 +889,7 @@ std::shared_ptr<const ValidPathInfo> LocalStore::queryPathInfoInternal(State & s
if (s) info->sigs = tokenizeString<StringSet>(s, " ");
s = (const char *) sqlite3_column_text(state.stmts->QueryPathInfo, 7);
- if (s) info->ca = parseContentAddressOpt(s);
+ if (s) info->ca = ContentAddress::parseOpt(s);
/* Get the references. */
auto useQueryReferences(state.stmts->QueryReferences.use()(info->id));
@@ -1221,7 +1222,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
printStorePath(info.path), info.narSize, hashResult.second);
if (info.ca) {
- if (auto foHash = std::get_if<FixedOutputHash>(&*info.ca)) {
+ if (auto foHash = std::get_if<FixedOutputHash>(&info.ca->raw)) {
auto actualFoHash = hashCAPath(
foHash->method,
foHash->hash.type,
@@ -1234,7 +1235,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
actualFoHash.hash.to_string(Base32, true));
}
}
- if (auto textHash = std::get_if<TextHash>(&*info.ca)) {
+ if (auto textHash = std::get_if<TextHash>(&info.ca->raw)) {
auto actualTextHash = hashString(htSHA256, readFile(realPath));
if (textHash->hash != actualTextHash) {
throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s",
@@ -1320,7 +1321,19 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
auto [hash, size] = hashSink->finish();
- auto dstPath = makeFixedOutputPath(method, hash, name, references);
+ ContentAddressWithReferences desc = FixedOutputInfo {
+ .hash = {
+ .method = method,
+ .hash = hash,
+ },
+ .references = {
+ .others = references,
+ // caller is not capable of creating a self-reference, because this is content-addressed without modulus
+ .self = false,
+ },
+ };
+
+ auto dstPath = makeFixedOutputPathFromCA(name, desc);
addTempRoot(dstPath);
@@ -1340,7 +1353,7 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
autoGC();
if (inMemory) {
- StringSource dumpSource { dump };
+ StringSource dumpSource { dump };
/* Restore from the NAR in memory. */
if (method == FileIngestionMethod::Recursive)
restorePath(realPath, dumpSource);
@@ -1364,10 +1377,13 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
optimisePath(realPath, repair);
- ValidPathInfo info { dstPath, narHash.first };
+ ValidPathInfo info {
+ *this,
+ name,
+ std::move(desc),
+ narHash.first
+ };
info.narSize = narHash.second;
- info.references = references;
- info.ca = FixedOutputHash { .method = method, .hash = hash };
registerValidPath(info);
}
@@ -1384,7 +1400,10 @@ StorePath LocalStore::addTextToStore(
const StorePathSet & references, RepairFlag repair)
{
auto hash = hashString(htSHA256, s);
- auto dstPath = makeTextPath(name, hash, references);
+ auto dstPath = makeTextPath(name, TextInfo {
+ { .hash = hash },
+ references,
+ });
addTempRoot(dstPath);
diff --git a/src/libstore/make-content-addressed.cc b/src/libstore/make-content-addressed.cc
index 64d172918..53fe04704 100644
--- a/src/libstore/make-content-addressed.cc
+++ b/src/libstore/make-content-addressed.cc
@@ -27,18 +27,17 @@ std::map<StorePath, StorePath> makeContentAddressed(
StringMap rewrites;
- StorePathSet references;
- bool hasSelfReference = false;
+ StoreReferences refs;
for (auto & ref : oldInfo->references) {
if (ref == path)
- hasSelfReference = true;
+ refs.self = true;
else {
auto i = remappings.find(ref);
auto replacement = i != remappings.end() ? i->second : ref;
// FIXME: warn about unremapped paths?
if (replacement != ref)
rewrites.insert_or_assign(srcStore.printStorePath(ref), srcStore.printStorePath(replacement));
- references.insert(std::move(replacement));
+ refs.others.insert(std::move(replacement));
}
}
@@ -49,24 +48,28 @@ std::map<StorePath, StorePath> makeContentAddressed(
auto narModuloHash = hashModuloSink.finish().first;
- auto dstPath = dstStore.makeFixedOutputPath(
- FileIngestionMethod::Recursive, narModuloHash, path.name(), references, hasSelfReference);
+ ValidPathInfo info {
+ dstStore,
+ path.name(),
+ FixedOutputInfo {
+ .hash = {
+ .method = FileIngestionMethod::Recursive,
+ .hash = narModuloHash,
+ },
+ .references = std::move(refs),
+ },
+ Hash::dummy,
+ };
- printInfo("rewriting '%s' to '%s'", pathS, srcStore.printStorePath(dstPath));
+ printInfo("rewriting '%s' to '%s'", pathS, dstStore.printStorePath(info.path));
StringSink sink2;
- RewritingSink rsink2(oldHashPart, std::string(dstPath.hashPart()), sink2);
+ RewritingSink rsink2(oldHashPart, std::string(info.path.hashPart()), sink2);
rsink2(sink.s);
rsink2.flush();
- ValidPathInfo info { dstPath, hashString(htSHA256, sink2.s) };
- info.references = std::move(references);
- if (hasSelfReference) info.references.insert(info.path);
+ info.narHash = hashString(htSHA256, sink2.s);
info.narSize = sink.s.size();
- info.ca = FixedOutputHash {
- .method = FileIngestionMethod::Recursive,
- .hash = narModuloHash,
- };
StringSource source(sink2.s);
dstStore.addToStore(info, source);
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 2645f468b..c7176d30f 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -273,7 +273,7 @@ public:
narInfo->deriver = StorePath(queryNAR.getStr(9));
for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(10), " "))
narInfo->sigs.insert(sig);
- narInfo->ca = parseContentAddressOpt(queryNAR.getStr(11));
+ narInfo->ca = ContentAddress::parseOpt(queryNAR.getStr(11));
return {oValid, narInfo};
});
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index 071d8355e..274cd861c 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -74,7 +74,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
else if (name == "CA") {
if (ca) throw corrupt();
// FIXME: allow blank ca or require skipping field?
- ca = parseContentAddressOpt(value);
+ ca = ContentAddress::parseOpt(value);
}
pos = eol + 1;
diff --git a/src/libstore/nar-info.hh b/src/libstore/nar-info.hh
index 3cae8e659..5dbdafac3 100644
--- a/src/libstore/nar-info.hh
+++ b/src/libstore/nar-info.hh
@@ -17,6 +17,9 @@ struct NarInfo : ValidPathInfo
uint64_t fileSize = 0;
NarInfo() = delete;
+ NarInfo(const Store & store, std::string && name, ContentAddressWithReferences && ca, Hash narHash)
+ : ValidPathInfo(store, std::move(name), std::move(ca), narHash)
+ { }
NarInfo(StorePath && path, Hash narHash) : ValidPathInfo(std::move(path), narHash) { }
NarInfo(const ValidPathInfo & info) : ValidPathInfo(info) { }
NarInfo(const Store & store, const std::string & s, const std::string & whence);
diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc
index bd55a9d06..e60d7abe0 100644
--- a/src/libstore/path-info.cc
+++ b/src/libstore/path-info.cc
@@ -21,25 +21,45 @@ void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey)
sigs.insert(secretKey.signDetached(fingerprint(store)));
}
-
-bool ValidPathInfo::isContentAddressed(const Store & store) const
+std::optional<ContentAddressWithReferences> ValidPathInfo::contentAddressWithReferences() const
{
- if (! ca) return false;
-
- auto caPath = std::visit(overloaded {
- [&](const TextHash & th) {
- return store.makeTextPath(path.name(), th.hash, references);
+ if (! ca)
+ return std::nullopt;
+
+ return std::visit(overloaded {
+ [&](const TextHash & th) -> ContentAddressWithReferences {
+ assert(references.count(path) == 0);
+ return TextInfo {
+ .hash = th,
+ .references = references,
+ };
},
- [&](const FixedOutputHash & fsh) {
+ [&](const FixedOutputHash & foh) -> ContentAddressWithReferences {
auto refs = references;
bool hasSelfReference = false;
if (refs.count(path)) {
hasSelfReference = true;
refs.erase(path);
}
- return store.makeFixedOutputPath(fsh.method, fsh.hash, path.name(), refs, hasSelfReference);
- }
- }, *ca);
+ return FixedOutputInfo {
+ .hash = foh,
+ .references = {
+ .others = std::move(refs),
+ .self = hasSelfReference,
+ },
+ };
+ },
+ }, ca->raw);
+}
+
+bool ValidPathInfo::isContentAddressed(const Store & store) const
+{
+ auto fullCaOpt = contentAddressWithReferences();
+
+ if (! fullCaOpt)
+ return false;
+
+ auto caPath = store.makeFixedOutputPathFromCA(path.name(), *fullCaOpt);
bool res = caPath == path;
@@ -77,6 +97,29 @@ Strings ValidPathInfo::shortRefs() const
}
+ValidPathInfo::ValidPathInfo(
+ const Store & store,
+ std::string_view name,
+ ContentAddressWithReferences && ca,
+ Hash narHash)
+ : path(store.makeFixedOutputPathFromCA(name, ca))
+ , narHash(narHash)
+{
+ std::visit(overloaded {
+ [this](TextInfo && ti) {
+ this->references = std::move(ti.references);
+ this->ca = std::move((TextHash &&) ti);
+ },
+ [this](FixedOutputInfo && foi) {
+ this->references = std::move(foi.references.others);
+ if (foi.references.self)
+ this->references.insert(path);
+ this->ca = std::move((FixedOutputHash &&) foi);
+ },
+ }, std::move(ca).raw);
+}
+
+
ValidPathInfo ValidPathInfo::read(Source & source, const Store & store, unsigned int format)
{
return read(source, store, format, store.parseStorePath(readString(source)));
@@ -93,7 +136,7 @@ ValidPathInfo ValidPathInfo::read(Source & source, const Store & store, unsigned
if (format >= 16) {
source >> info.ultimate;
info.sigs = readStrings<StringSet>(source);
- info.ca = parseContentAddressOpt(readString(source));
+ info.ca = ContentAddress::parseOpt(readString(source));
}
return info;
}
diff --git a/src/libstore/path-info.hh b/src/libstore/path-info.hh
index 9af1309a0..221523622 100644
--- a/src/libstore/path-info.hh
+++ b/src/libstore/path-info.hh
@@ -92,6 +92,13 @@ struct ValidPathInfo
void sign(const Store & store, const SecretKey & secretKey);
+ /**
+ * @return The `ContentAddressWithReferences` that determines the
+ * store path for a content-addressed store object, `std::nullopt`
+ * for an input-addressed store object.
+ */
+ std::optional<ContentAddressWithReferences> contentAddressWithReferences() const;
+
/**
* @return true iff the path is verifiably content-addressed.
*/
@@ -118,6 +125,9 @@ struct ValidPathInfo
ValidPathInfo(StorePath && path, Hash narHash) : path(std::move(path)), narHash(narHash) { };
ValidPathInfo(const StorePath & path, Hash narHash) : path(path), narHash(narHash) { };
+ ValidPathInfo(const Store & store,
+ std::string_view name, ContentAddressWithReferences && ca, Hash narHash);
+
virtual ~ValidPathInfo() { }
static ValidPathInfo read(Source & source, const Store & store, unsigned int format);
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index b862902d1..d0ce0bce9 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -78,7 +78,7 @@ void write(const Store & store, Sink & out, const std::optional<TrustedFlag> & o
ContentAddress read(const Store & store, Source & from, Phantom<ContentAddress> _)
{
- return parseContentAddress(readString(from));
+ return ContentAddress::parse(readString(from));
}
void write(const Store & store, Sink & out, const ContentAddress & ca)
@@ -168,7 +168,7 @@ void write(const Store & store, Sink & out, const std::optional<StorePath> & sto
std::optional<ContentAddress> read(const Store & store, Source & from, Phantom<std::optional<ContentAddress>> _)
{
- return parseContentAddressOpt(readString(from));
+ return ContentAddress::parseOpt(readString(from));
}
void write(const Store & store, Sink & out, const std::optional<ContentAddress> & caOpt)
@@ -586,7 +586,7 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
conn->to
<< wopAddToStore
<< name
- << renderContentAddressMethod(caMethod);
+ << caMethod.render();
worker_proto::write(*this, conn->to, references);
conn->to << repair;
@@ -644,7 +644,7 @@ ref<const ValidPathInfo> RemoteStore::addCAToStore(
}
}
- }, caMethod);
+ }, caMethod.raw);
auto path = parseStorePath(readString(conn->from));
// Release our connection to prevent a deadlock in queryPathInfo().
conn_.reset();
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 8fc3ed46a..5bee1af9f 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -7,6 +7,7 @@
#include "nar-info-disk-cache.hh"
#include "thread-pool.hh"
#include "url.hh"
+#include "references.hh"
#include "archive.hh"
#include "callback.hh"
#include "remote-store.hh"
@@ -98,10 +99,12 @@ StorePath Store::followLinksToStorePath(std::string_view path) const
silly, but it's done that way for compatibility). <id> is the
name of the output (usually, "out").
- <h2> = base-16 representation of a SHA-256 hash of:
+ <h2> = base-16 representation of a SHA-256 hash of <s2>
+
+ <s2> =
if <type> = "text:...":
the string written to the resulting store path
- if <type> = "source":
+ if <type> = "source:...":
the serialisation of the path from which this store path is
copied, as returned by hashPath()
if <type> = "output:<id>":
@@ -162,63 +165,63 @@ StorePath Store::makeOutputPath(std::string_view id,
}
+/* Stuff the references (if any) into the type. This is a bit
+ hacky, but we can't put them in, say, <s2> (per the grammar above)
+ since that would be ambiguous. */
static std::string makeType(
const Store & store,
std::string && type,
- const StorePathSet & references,
- bool hasSelfReference = false)
+ const StoreReferences & references)
{
- for (auto & i : references) {
+ for (auto & i : references.others) {
type += ":";
type += store.printStorePath(i);
}
- if (hasSelfReference) type += ":self";
+ if (references.self) type += ":self";
return std::move(type);
}
-StorePath Store::makeFixedOutputPath(
- FileIngestionMethod method,
- const Hash & hash,
- std::string_view name,
- const StorePathSet & references,
- bool hasSelfReference) const
+StorePath Store::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const
{
- if (hash.type == htSHA256 && method == FileIngestionMethod::Recursive) {
- return makeStorePath(makeType(*this, "source", references, hasSelfReference), hash, name);
+ if (info.hash.hash.type == htSHA256 && info.hash.method == FileIngestionMethod::Recursive) {
+ return makeStorePath(makeType(*this, "source", info.references), info.hash.hash, name);
} else {
- assert(references.empty());
+ assert(info.references.size() == 0);
return makeStorePath("output:out",
hashString(htSHA256,
"fixed:out:"
- + makeFileIngestionPrefix(method)
- + hash.to_string(Base16, true) + ":"),
+ + makeFileIngestionPrefix(info.hash.method)
+ + info.hash.hash.to_string(Base16, true) + ":"),
name);
}
}
-StorePath Store::makeFixedOutputPathFromCA(std::string_view name, ContentAddress ca,
- const StorePathSet & references, bool hasSelfReference) const
+
+StorePath Store::makeTextPath(std::string_view name, const TextInfo & info) const
+{
+ assert(info.hash.hash.type == htSHA256);
+ return makeStorePath(
+ makeType(*this, "text", StoreReferences {
+ .others = info.references,
+ .self = false,
+ }),
+ info.hash.hash,
+ name);
+}
+
+
+StorePath Store::makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const
{
// New template
return std::visit(overloaded {
- [&](const TextHash & th) {
- return makeTextPath(name, th.hash, references);
+ [&](const TextInfo & ti) {
+ return makeTextPath(name, ti);
},
- [&](const FixedOutputHash & fsh) {
- return makeFixedOutputPath(fsh.method, fsh.hash, name, references, hasSelfReference);
+ [&](const FixedOutputInfo & foi) {
+ return makeFixedOutputPath(name, foi);
}
- }, ca);
-}
-
-StorePath Store::makeTextPath(std::string_view name, const Hash & hash,
- const StorePathSet & references) const
-{
- assert(hash.type == htSHA256);
- /* Stuff the references (if any) into the type. This is a bit
- hacky, but we can't put them in `s' since that would be
- ambiguous. */
- return makeStorePath(makeType(*this, "text", references), hash, name);
+ }, ca.raw);
}
@@ -228,7 +231,14 @@ std::pair<StorePath, Hash> Store::computeStorePathForPath(std::string_view name,
Hash h = method == FileIngestionMethod::Recursive
? hashPath(hashAlgo, srcPath, filter).first
: hashFile(hashAlgo, srcPath);
- return std::make_pair(makeFixedOutputPath(method, h, name), h);
+ FixedOutputInfo caInfo {
+ .hash = {
+ .method = method,
+ .hash = h,
+ },
+ .references = {},
+ };
+ return std::make_pair(makeFixedOutputPath(name, caInfo), h);
}
@@ -237,7 +247,10 @@ StorePath Store::computeStorePathForText(
std::string_view s,
const StorePathSet & references) const
{
- return makeTextPath(name, hashString(htSHA256, s), references);
+ return makeTextPath(name, TextInfo {
+ { .hash = hashString(htSHA256, s) },
+ references,
+ });
}
@@ -425,11 +438,18 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
throw Error("hash mismatch for '%s'", srcPath);
ValidPathInfo info {
- makeFixedOutputPath(method, hash, name),
+ *this,
+ name,
+ FixedOutputInfo {
+ .hash = {
+ .method = method,
+ .hash = hash,
+ },
+ .references = {},
+ },
narHash,
};
info.narSize = narSize;
- info.ca = FixedOutputHash { .method = method, .hash = hash };
if (!isValidPath(info.path)) {
auto source = sinkToSource([&](Sink & scratchpadSink) {
@@ -521,7 +541,9 @@ void Store::querySubstitutablePathInfos(const StorePathCAMap & paths, Substituta
// Recompute store path so that we can use a different store root.
if (path.second) {
- subPath = makeFixedOutputPathFromCA(path.first.name(), *path.second);
+ subPath = makeFixedOutputPathFromCA(
+ path.first.name(),
+ ContentAddressWithReferences::withoutRefs(*path.second));
if (sub->storeDir == storeDir)
assert(subPath == path.first);
if (subPath != path.first)
@@ -538,10 +560,11 @@ void Store::querySubstitutablePathInfos(const StorePathCAMap & paths, Substituta
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
std::shared_ptr<const ValidPathInfo>(info));
infos.insert_or_assign(path.first, SubstitutablePathInfo{
- info->deriver,
- info->references,
- narInfo ? narInfo->fileSize : 0,
- info->narSize});
+ .deriver = info->deriver,
+ .references = info->references,
+ .downloadSize = narInfo ? narInfo->fileSize : 0,
+ .narSize = info->narSize,
+ });
} catch (InvalidPath &) {
} catch (SubstituterDisabled &) {
} catch (Error & e) {
@@ -1025,7 +1048,9 @@ void copyStorePath(
// recompute store path on the chance dstStore does it differently
if (info->ca && info->references.empty()) {
auto info2 = make_ref<ValidPathInfo>(*info);
- info2->path = dstStore.makeFixedOutputPathFromCA(info->path.name(), *info->ca);
+ info2->path = dstStore.makeFixedOutputPathFromCA(
+ info->path.name(),
+ info->contentAddressWithReferences().value());
if (dstStore.storeDir == srcStore.storeDir)
assert(info->path == info2->path);
info = info2;
@@ -1137,7 +1162,9 @@ std::map<StorePath, StorePath> copyPaths(
auto storePathForSrc = currentPathInfo.path;
auto storePathForDst = storePathForSrc;
if (currentPathInfo.ca && currentPathInfo.references.empty()) {
- storePathForDst = dstStore.makeFixedOutputPathFromCA(storePathForSrc.name(), *currentPathInfo.ca);
+ storePathForDst = dstStore.makeFixedOutputPathFromCA(
+ currentPathInfo.path.name(),
+ currentPathInfo.contentAddressWithReferences().value());
if (dstStore.storeDir == srcStore.storeDir)
assert(storePathForDst == storePathForSrc);
if (storePathForDst != storePathForSrc)
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 5bee272bf..74f50a00d 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -268,17 +268,11 @@ public:
StorePath makeOutputPath(std::string_view id,
const Hash & hash, std::string_view name) const;
- StorePath makeFixedOutputPath(FileIngestionMethod method,
- const Hash & hash, std::string_view name,
- const StorePathSet & references = {},
- bool hasSelfReference = false) const;
+ StorePath makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const;
- StorePath makeTextPath(std::string_view name, const Hash & hash,
- const StorePathSet & references = {}) const;
+ StorePath makeTextPath(std::string_view name, const TextInfo & info) const;
- StorePath makeFixedOutputPathFromCA(std::string_view name, ContentAddress ca,
- const StorePathSet & references = {},
- bool hasSelfReference = false) const;
+ StorePath makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const;
/**
* Preparatory part of addToStore().