aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/binary-cache-store.cc17
-rw-r--r--src/libstore/binary-cache-store.hh7
-rw-r--r--src/libstore/build/derivation-goal.cc19
-rw-r--r--src/libstore/daemon.cc22
-rw-r--r--src/libstore/dummy-store.cc3
-rw-r--r--src/libstore/legacy-ssh-store.cc4
-rw-r--r--src/libstore/local-binary-cache-store.cc1
-rw-r--r--src/libstore/local-store.cc21
-rw-r--r--src/libstore/local-store.hh12
-rw-r--r--src/libstore/realisation.cc72
-rw-r--r--src/libstore/realisation.hh34
-rw-r--r--src/libstore/remote-store.cc21
-rw-r--r--src/libstore/remote-store.hh4
-rw-r--r--src/libstore/store-api.hh15
-rw-r--r--src/libstore/worker-protocol.hh5
15 files changed, 246 insertions, 11 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index a918b7208..085dc7ba1 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -443,6 +443,23 @@ StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s
})->path;
}
+std::optional<const Realisation> BinaryCacheStore::queryRealisation(const DrvOutput & id)
+{
+ auto outputInfoFilePath = realisationsPrefix + "/" + id.to_string() + ".doi";
+ auto rawOutputInfo = getFile(outputInfoFilePath);
+
+ if (rawOutputInfo) {
+ return { Realisation::parse(*rawOutputInfo, outputInfoFilePath) };
+ } else {
+ return std::nullopt;
+ }
+}
+
+void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
+ auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
+ upsertFile(filePath, info.to_string(), "text/x-nix-derivertopath");
+}
+
ref<FSAccessor> BinaryCacheStore::getFSAccessor()
{
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), localNarCache);
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 5224d7ec8..07a8b2beb 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -33,6 +33,9 @@ private:
protected:
+ // The prefix under which realisation infos will be stored
+ const std::string realisationsPrefix = "/realisations";
+
BinaryCacheStore(const Params & params);
public:
@@ -99,6 +102,10 @@ public:
StorePath addTextToStore(const string & name, const string & s,
const StorePathSet & references, RepairFlag repair) override;
+ void registerDrvOutput(const Realisation & info) override;
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput &) override;
+
void narFromPath(const StorePath & path, Sink & sink) override;
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index de58d9f06..a0f10c33d 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -2094,6 +2094,20 @@ struct RestrictedStore : public LocalFSStore, public virtual RestrictedStoreConf
/* Nothing to be done; 'path' must already be valid. */
}
+ void registerDrvOutput(const Realisation & info) override
+ {
+ if (!goal.isAllowed(info.id.drvPath))
+ throw InvalidPath("cannot register unknown drv output '%s' in recursive Nix", printStorePath(info.id.drvPath));
+ next->registerDrvOutput(info);
+ }
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput & id) override
+ {
+ if (!goal.isAllowed(id.drvPath))
+ throw InvalidPath("cannot query the output info for unknown derivation '%s' in recursive Nix", printStorePath(id.drvPath));
+ return next->queryRealisation(id);
+ }
+
void buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode) override
{
if (buildMode != bmNormal) throw Error("unsupported build mode");
@@ -3393,7 +3407,10 @@ void DerivationGoal::registerOutputs()
if (useDerivation || isCaFloating)
for (auto & [outputName, newInfo] : infos)
- worker.store.linkDeriverToPath(drvPathResolved, outputName, newInfo.path);
+ worker.store.registerDrvOutput(
+ DrvOutputId{drvPathResolved, outputName},
+ DrvOutputInfo{.outPath = newInfo.path,
+ .resolvedDrv = drvPathResolved});
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 2224d54d5..ba5788b64 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -868,6 +868,28 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
break;
}
+ case wopRegisterDrvOutput: {
+ logger->startWork();
+ auto outputId = DrvOutput::parse(readString(from));
+ auto outputPath = StorePath(readString(from));
+ auto resolvedDrv = StorePath(readString(from));
+ store->registerDrvOutput(Realisation{
+ .id = outputId, .outPath = outputPath});
+ logger->stopWork();
+ break;
+ }
+
+ case wopQueryRealisation: {
+ logger->startWork();
+ auto outputId = DrvOutput::parse(readString(from));
+ auto info = store->queryRealisation(outputId);
+ logger->stopWork();
+ std::set<StorePath> outPaths;
+ if (info) outPaths.insert(info->outPath);
+ worker_proto::write(*store, to, outPaths);
+ break;
+ }
+
default:
throw Error("invalid operation %1%", op);
}
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 98b745c3a..91fc178db 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -60,6 +60,9 @@ struct DummyStore : public Store, public virtual DummyStoreConfig
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override
{ unsupported("buildDerivation"); }
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput&) override
+ { unsupported("queryRealisation"); }
};
static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore;
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index 467169ce8..ad1779aea 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -333,6 +333,10 @@ public:
auto conn(connections->get());
return conn->remoteVersion;
}
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput&) override
+ // TODO: Implement
+ { unsupported("queryRealisation"); }
};
static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regLegacySSHStore;
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index 7d979c5c2..bb7464989 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -87,6 +87,7 @@ protected:
void LocalBinaryCacheStore::init()
{
createDirs(binaryCacheDir + "/nar");
+ createDirs(binaryCacheDir + realisationsPrefix);
if (writeDebugInfo)
createDirs(binaryCacheDir + "/debuginfo");
BinaryCacheStore::init();
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 2a47b3956..418b3ab9c 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -597,13 +597,16 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
}
-void LocalStore::linkDeriverToPath(const StorePath & deriver, const string & outputName, const StorePath & output)
+void LocalStore::registerDrvOutput(const Realisation & info)
{
auto state(_state.lock());
- return linkDeriverToPath(*state, queryValidPathId(*state, deriver), outputName, output);
+ // XXX: This ignores the references of the output because we can
+ // recompute them later from the drv and the references of the associated
+ // store path, but doing so is both inefficient and fragile.
+ return registerDrvOutput_(*state, queryValidPathId(*state, id.drvPath), id.outputName, info.outPath);
}
-void LocalStore::linkDeriverToPath(State & state, uint64_t deriver, const string & outputName, const StorePath & output)
+void LocalStore::registerDrvOutput_(State & state, uint64_t deriver, const string & outputName, const StorePath & output)
{
retrySQLite<void>([&]() {
state.stmts->AddDerivationOutput.use()
@@ -653,7 +656,7 @@ uint64_t LocalStore::addValidPath(State & state,
/* Floating CA derivations have indeterminate output paths until
they are built, so don't register anything in that case */
if (i.second.second)
- linkDeriverToPath(state, id, i.first, *i.second.second);
+ registerDrvOutput_(state, id, i.first, *i.second.second);
}
}
@@ -1612,5 +1615,13 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
}
}
-
+std::optional<const DrvOutputInfo> LocalStore::queryDrvOutputInfo(const DrvOutputId& id) {
+ auto outputPath = queryOutputPathOf(id.drvPath, id.outputName);
+ if (!(outputPath && isValidPath(*outputPath)))
+ return std::nullopt;
+ else
+ return {DrvOutputInfo{
+ .outPath = *outputPath,
+ }};
}
+} // namespace nix
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 332718af4..440411f01 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -208,6 +208,13 @@ public:
garbage until it exceeds maxFree. */
void autoGC(bool sync = true);
+ /* Register the store path 'output' as the output named 'outputName' of
+ derivation 'deriver'. */
+ void registerDrvOutput(const DrvOutputId & outputId, const DrvOutputInfo & info) override;
+ void registerDrvOutput_(State & state, uint64_t deriver, const string & outputName, const StorePath & output);
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput&) override;
+
private:
int getSchema();
@@ -276,11 +283,6 @@ private:
specified by the ‘secret-key-files’ option. */
void signPathInfo(ValidPathInfo & info);
- /* Register the store path 'output' as the output named 'outputName' of
- derivation 'deriver'. */
- void linkDeriverToPath(const StorePath & deriver, const string & outputName, const StorePath & output);
- void linkDeriverToPath(State & state, uint64_t deriver, const string & outputName, const StorePath & output);
-
Path getRealStoreDir() override { return realStoreDir; }
void createUser(const std::string & userName, uid_t userId) override;
diff --git a/src/libstore/realisation.cc b/src/libstore/realisation.cc
new file mode 100644
index 000000000..fcc1a3825
--- /dev/null
+++ b/src/libstore/realisation.cc
@@ -0,0 +1,72 @@
+#include "realisation.hh"
+#include "store-api.hh"
+
+namespace nix {
+
+MakeError(InvalidDerivationOutputId, Error);
+
+DrvOutput DrvOutput::parse(const std::string &strRep) {
+ const auto &[rawPath, outputs] = parsePathWithOutputs(strRep);
+ if (outputs.size() != 1)
+ throw InvalidDerivationOutputId("Invalid derivation output id %s", strRep);
+
+ return DrvOutput{
+ .drvPath = StorePath(rawPath),
+ .outputName = *outputs.begin(),
+ };
+}
+
+std::string DrvOutput::to_string() const {
+ return std::string(drvPath.to_string()) + "!" + outputName;
+}
+
+std::string Realisation::to_string() const {
+ std::string res;
+
+ res += "Id: " + id.to_string() + '\n';
+ res += "OutPath: " + std::string(outPath.to_string()) + '\n';
+
+ return res;
+}
+
+Realisation Realisation::parse(const std::string & s, const std::string & whence)
+{
+ // XXX: Copy-pasted from NarInfo::NarInfo. Should be factored out
+ auto corrupt = [&]() {
+ return Error("Drv output info file '%1%' is corrupt", whence);
+ };
+
+ std::optional<DrvOutput> id;
+ std::optional<StorePath> outPath;
+
+ size_t pos = 0;
+ while (pos < s.size()) {
+
+ size_t colon = s.find(':', pos);
+ if (colon == std::string::npos) throw corrupt();
+
+ std::string name(s, pos, colon - pos);
+
+ size_t eol = s.find('\n', colon + 2);
+ if (eol == std::string::npos) throw corrupt();
+
+ std::string value(s, colon + 2, eol - colon - 2);
+
+ if (name == "Id")
+ id = DrvOutput::parse(value);
+
+ if (name == "OutPath")
+ outPath = StorePath(value);
+
+ pos = eol + 1;
+ }
+
+ if (!outPath) corrupt();
+ if (!id) corrupt();
+ return Realisation {
+ .id = *id,
+ .outPath = *outPath,
+ };
+}
+
+} // namespace nix
diff --git a/src/libstore/realisation.hh b/src/libstore/realisation.hh
new file mode 100644
index 000000000..c573e1bb4
--- /dev/null
+++ b/src/libstore/realisation.hh
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "path.hh"
+
+namespace nix {
+
+struct DrvOutput {
+ StorePath drvPath;
+ std::string outputName;
+
+ std::string to_string() const;
+
+ static DrvOutput parse(const std::string &);
+
+ bool operator<(const DrvOutput& other) const { return to_pair() < other.to_pair(); }
+ bool operator==(const DrvOutput& other) const { return to_pair() == other.to_pair(); }
+
+private:
+ // Just to make comparison operators easier to write
+ std::pair<StorePath, std::string> to_pair() const
+ { return std::make_pair(drvPath, outputName); }
+};
+
+struct Realisation {
+ DrvOutput id;
+ StorePath outPath;
+
+ std::string to_string() const;
+ static Realisation parse(const std::string & s, const std::string & whence);
+};
+
+typedef std::map<DrvOutput, Realisation> DrvOutputs;
+
+}
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index be29f8e6f..f1f4d0516 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -609,6 +609,27 @@ StorePath RemoteStore::addTextToStore(const string & name, const string & s,
return addCAToStore(source, name, TextHashMethod{}, references, repair)->path;
}
+void RemoteStore::registerDrvOutput(const Realisation & info)
+{
+ auto conn(getConnection());
+ conn->to << wopRegisterDrvOutput;
+ conn->to << info.id.to_string();
+ conn->to << std::string(info.outPath.to_string());
+ conn.processStderr();
+}
+
+std::optional<const Realisation> RemoteStore::queryRealisation(const DrvOutput & id)
+{
+ auto conn(getConnection());
+ conn->to << wopQueryRealisation;
+ conn->to << id.to_string();
+ conn.processStderr();
+ auto outPaths = worker_proto::read(*this, conn->from, Phantom<std::set<StorePath>>{});
+ if (outPaths.empty())
+ return std::nullopt;
+ return {Realisation{.id = id, .outPath = *outPaths.begin()}};
+}
+
void RemoteStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode)
{
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 9f78fcb02..fdd53e6ed 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -81,6 +81,10 @@ public:
StorePath addTextToStore(const string & name, const string & s,
const StorePathSet & references, RepairFlag repair) override;
+ void registerDrvOutput(const Realisation & info) override;
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput &) override;
+
void buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode) override;
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 6b9331495..7cdadc1f3 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -1,5 +1,6 @@
#pragma once
+#include "realisation.hh"
#include "path.hh"
#include "hash.hh"
#include "content-address.hh"
@@ -396,6 +397,8 @@ protected:
public:
+ virtual std::optional<const Realisation> queryRealisation(const DrvOutput &) = 0;
+
/* Queries the set of incoming FS references for a store path.
The result is not cleared. */
virtual void queryReferrers(const StorePath & path, StorePathSet & referrers)
@@ -468,6 +471,18 @@ public:
virtual StorePath addTextToStore(const string & name, const string & s,
const StorePathSet & references, RepairFlag repair = NoRepair) = 0;
+ /**
+ * Add a mapping indicating that `deriver!outputName` maps to the output path
+ * `output`.
+ *
+ * This is redundant for known-input-addressed and fixed-output derivations
+ * as this information is already present in the drv file, but necessary for
+ * floating-ca derivations and their dependencies as there's no way to
+ * retrieve this information otherwise.
+ */
+ virtual void registerDrvOutput(const Realisation & output)
+ { unsupported("registerDrvOutput"); }
+
/* Write a NAR dump of a store path. */
virtual void narFromPath(const StorePath & path, Sink & sink) = 0;
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 63bd6ea49..f2cdc7ca3 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -1,5 +1,8 @@
#pragma once
+#include "store-api.hh"
+#include "serialise.hh"
+
namespace nix {
@@ -50,6 +53,8 @@ typedef enum {
wopAddToStoreNar = 39,
wopQueryMissing = 40,
wopQueryDerivationOutputMap = 41,
+ wopRegisterDrvOutput = 42,
+ wopQueryRealisation = 43,
} WorkerOp;