summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/primops.cc9
-rw-r--r--src/libstore/binary-cache-store.cc22
-rw-r--r--src/libstore/binary-cache-store.hh7
-rw-r--r--src/libstore/build/derivation-goal.cc39
-rw-r--r--src/libstore/ca-specific-schema.sql11
-rw-r--r--src/libstore/daemon.cc22
-rw-r--r--src/libstore/derivations.cc81
-rw-r--r--src/libstore/derivations.hh26
-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.cc257
-rw-r--r--src/libstore/local-store.hh29
-rw-r--r--src/libstore/local.mk4
-rw-r--r--src/libstore/realisation.cc49
-rw-r--r--src/libstore/realisation.hh39
-rw-r--r--src/libstore/remote-store.cc21
-rw-r--r--src/libstore/remote-store.hh4
-rw-r--r--src/libstore/s3-binary-cache-store.cc3
-rw-r--r--src/libstore/store-api.cc72
-rw-r--r--src/libstore/store-api.hh24
-rw-r--r--src/libstore/worker-protocol.hh5
-rw-r--r--src/libutil/error.hh1
-rw-r--r--src/libutil/logging.hh1
-rw-r--r--src/libutil/url-parts.hh3
-rw-r--r--src/nix/installables.cc2
-rw-r--r--src/nix/main.cc2
-rw-r--r--src/nix/make-content-addressable.cc2
-rw-r--r--tests/build-remote-input-addressed.sh28
-rw-r--r--tests/build-remote.sh3
-rw-r--r--tests/content-addressed.sh9
-rw-r--r--tests/init.sh1
32 files changed, 604 insertions, 180 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 41f06c219..e9c1f3b43 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1107,7 +1107,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
// Shouldn't happen as the toplevel derivation is not CA.
assert(false);
},
- [&](UnknownHashes) {
+ [&](DeferredHash _) {
for (auto & i : outputs) {
drv.outputs.insert_or_assign(i,
DerivationOutput {
@@ -1621,7 +1621,12 @@ static RegisterPrimOp primop_toJSON({
static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
string s = state.forceStringNoCtx(*args[0], pos);
- parseJSON(state, s, v);
+ try {
+ parseJSON(state, s, v);
+ } catch (JSONParseError &e) {
+ e.addTrace(pos, "while decoding a JSON string");
+ throw e;
+ }
}
static RegisterPrimOp primop_fromJSON({
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index a918b7208..4f5f8607d 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -433,7 +433,9 @@ StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s
if (!repair && isValidPath(path))
return path;
- auto source = StringSource { s };
+ StringSink sink;
+ dumpString(s, sink);
+ auto source = StringSource { *sink.s };
return addToStoreCommon(source, repair, CheckSigs, [&](HashResult nar) {
ValidPathInfo info { path, nar.first };
info.narSize = nar.second;
@@ -443,6 +445,24 @@ 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::fromJSON(
+ nlohmann::json::parse(*rawOutputInfo), outputInfoFilePath)};
+ } else {
+ return std::nullopt;
+ }
+}
+
+void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
+ auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
+ upsertFile(filePath, info.toJSON().dump(), "application/json");
+}
+
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 1db85bd37..f494545fb 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -493,8 +493,9 @@ void DerivationGoal::inputsRealised()
if (useDerivation) {
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
- if ((!fullDrv.inputDrvs.empty() && derivationIsCA(fullDrv.type()))
- || fullDrv.type() == DerivationType::DeferredInputAddressed) {
+ if (settings.isExperimentalFeatureEnabled("ca-derivations") &&
+ ((!fullDrv.inputDrvs.empty() && derivationIsCA(fullDrv.type()))
+ || fullDrv.type() == DerivationType::DeferredInputAddressed)) {
/* We are be able to resolve this derivation based on the
now-known results of dependencies. If so, we become a stub goal
aliasing that resolved derivation goal */
@@ -503,9 +504,6 @@ void DerivationGoal::inputsRealised()
Derivation drvResolved { *std::move(attempt) };
auto pathResolved = writeDerivation(worker.store, drvResolved);
- /* Add to memotable to speed up downstream goal's queries with the
- original derivation. */
- drvPathResolutions.lock()->insert_or_assign(drvPath, pathResolved);
auto msg = fmt("Resolved derivation: '%s' -> '%s'",
worker.store.printStorePath(drvPath),
@@ -2094,6 +2092,16 @@ struct RestrictedStore : public LocalFSStore, public virtual RestrictedStoreConf
/* Nothing to be done; 'path' must already be valid. */
}
+ void registerDrvOutput(const Realisation & info) override
+ // XXX: This should probably be allowed as a no-op if the realisation
+ // corresponds to an allowed derivation
+ { throw Error("registerDrvOutput"); }
+
+ std::optional<const Realisation> queryRealisation(const DrvOutput & id) override
+ // XXX: This should probably be allowed if the realisation corresponds to
+ // an allowed derivation
+ { throw Error("queryRealisation"); }
+
void buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode) override
{
if (buildMode != bmNormal) throw Error("unsupported build mode");
@@ -2872,6 +2880,8 @@ void DerivationGoal::registerOutputs()
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
if (!i.second.second || !worker.store.isValidPath(*i.second.second))
allValid = false;
+ else
+ finalOutputs.insert_or_assign(i.first, *i.second.second);
}
if (allValid) return;
}
@@ -3377,21 +3387,14 @@ void DerivationGoal::registerOutputs()
means it's safe to link the derivation to the output hash. We must do
that for floating CA derivations, which otherwise couldn't be cached,
but it's fine to do in all cases. */
- bool isCaFloating = drv->type() == DerivationType::CAFloating;
- auto drvPathResolved = drvPath;
- if (!useDerivation && isCaFloating) {
- /* Once a floating CA derivations reaches this point, it
- must already be resolved, so we don't bother trying to
- downcast drv to get would would just be an empty
- inputDrvs field. */
- Derivation drv2 { *drv };
- drvPathResolved = writeDerivation(worker.store, drv2);
+ if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
+ auto outputHashes = staticOutputHashes(worker.store, *drv);
+ for (auto& [outputName, newInfo] : infos)
+ worker.store.registerDrvOutput(Realisation{
+ .id = DrvOutput{outputHashes.at(outputName), outputName},
+ .outPath = newInfo.path});
}
-
- if (useDerivation || isCaFloating)
- for (auto & [outputName, newInfo] : infos)
- worker.store.linkDeriverToPath(drvPathResolved, outputName, newInfo.path);
}
diff --git a/src/libstore/ca-specific-schema.sql b/src/libstore/ca-specific-schema.sql
new file mode 100644
index 000000000..93c442826
--- /dev/null
+++ b/src/libstore/ca-specific-schema.sql
@@ -0,0 +1,11 @@
+-- Extension of the sql schema for content-addressed derivations.
+-- Won't be loaded unless the experimental feature `ca-derivations`
+-- is enabled
+
+create table if not exists Realisations (
+ drvPath text not null,
+ outputName text not null, -- symbolic output id, usually "out"
+ outputPath integer not null,
+ primary key (drvPath, outputName),
+ foreign key (outputPath) references ValidPaths(id) on delete cascade
+);
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/derivations.cc b/src/libstore/derivations.cc
index 231ca26c2..7466c7d41 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -496,10 +496,9 @@ static const DrvHashModulo pathDerivationModulo(Store & store, const StorePath &
*/
DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutputs)
{
+ bool isDeferred = false;
/* Return a fixed hash for fixed-output derivations. */
switch (drv.type()) {
- case DerivationType::CAFloating:
- return UnknownHashes {};
case DerivationType::CAFixed: {
std::map<std::string, Hash> outputHashes;
for (const auto & i : drv.outputs) {
@@ -512,6 +511,9 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
}
return outputHashes;
}
+ case DerivationType::CAFloating:
+ isDeferred = true;
+ break;
case DerivationType::InputAddressed:
break;
case DerivationType::DeferredInputAddressed:
@@ -522,13 +524,16 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
calls to this function. */
std::map<std::string, StringSet> inputs2;
for (auto & i : drv.inputDrvs) {
- bool hasUnknownHash = false;
const auto & res = pathDerivationModulo(store, i.first);
std::visit(overloaded {
// Regular non-CA derivation, replace derivation
[&](Hash drvHash) {
inputs2.insert_or_assign(drvHash.to_string(Base16, false), i.second);
},
+ [&](DeferredHash deferredHash) {
+ isDeferred = true;
+ inputs2.insert_or_assign(deferredHash.hash.to_string(Base16, false), i.second);
+ },
// CA derivation's output hashes
[&](CaOutputHashes outputHashes) {
std::set<std::string> justOut = { "out" };
@@ -540,16 +545,37 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
justOut);
}
},
- [&](UnknownHashes) {
- hasUnknownHash = true;
- },
}, res);
- if (hasUnknownHash) {
- return UnknownHashes {};
- }
}
- return hashString(htSHA256, drv.unparse(store, maskOutputs, &inputs2));
+ auto hash = hashString(htSHA256, drv.unparse(store, maskOutputs, &inputs2));
+
+ if (isDeferred)
+ return DeferredHash { hash };
+ else
+ return hash;
+}
+
+
+std::map<std::string, Hash> staticOutputHashes(Store& store, const Derivation& drv)
+{
+ std::map<std::string, Hash> res;
+ std::visit(overloaded {
+ [&](Hash drvHash) {
+ for (auto & outputName : drv.outputNames()) {
+ res.insert({outputName, drvHash});
+ }
+ },
+ [&](DeferredHash deferredHash) {
+ for (auto & outputName : drv.outputNames()) {
+ res.insert({outputName, deferredHash.hash});
+ }
+ },
+ [&](CaOutputHashes outputHashes) {
+ res = outputHashes;
+ },
+ }, hashDerivationModulo(store, drv, true));
+ return res;
}
@@ -719,10 +745,7 @@ static void rewriteDerivation(Store & store, BasicDerivation & drv, const String
}
-
-Sync<DrvPathResolutions> drvPathResolutions;
-
-std::optional<BasicDerivation> Derivation::tryResolve(Store & store) {
+std::optional<BasicDerivation> Derivation::tryResolveUncached(Store & store) {
BasicDerivation resolved { *this };
// Input paths that we'll want to rewrite in the derivation
@@ -748,4 +771,34 @@ std::optional<BasicDerivation> Derivation::tryResolve(Store & store) {
return resolved;
}
+std::optional<BasicDerivation> Derivation::tryResolve(Store& store)
+{
+ auto drvPath = writeDerivation(store, *this, NoRepair, false);
+ return Derivation::tryResolve(store, drvPath);
+}
+
+std::optional<BasicDerivation> Derivation::tryResolve(Store& store, const StorePath& drvPath)
+{
+ // This is quite dirty and leaky, but will disappear once #4340 is merged
+ static Sync<std::map<StorePath, std::optional<Derivation>>> resolutionsCache;
+
+ {
+ auto resolutions = resolutionsCache.lock();
+ auto resolvedDrvIter = resolutions->find(drvPath);
+ if (resolvedDrvIter != resolutions->end()) {
+ auto & [_, resolvedDrv] = *resolvedDrvIter;
+ return *resolvedDrv;
+ }
+ }
+
+ /* Try resolve drv and use that path instead. */
+ auto drv = store.readDerivation(drvPath);
+ auto attempt = drv.tryResolveUncached(store);
+ if (!attempt)
+ return std::nullopt;
+ /* Store in memo table. */
+ resolutionsCache.lock()->insert_or_assign(drvPath, *attempt);
+ return *attempt;
+}
+
}
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index b966d6d90..3d8f19aef 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -18,8 +18,6 @@ namespace nix {
/* The traditional non-fixed-output derivation type. */
struct DerivationOutputInputAddressed
{
- /* Will need to become `std::optional<StorePath>` once input-addressed
- derivations are allowed to depend on cont-addressed derivations */
StorePath path;
};
@@ -140,10 +138,14 @@ struct Derivation : BasicDerivation
2. Input placeholders are replaced with realized input store paths. */
std::optional<BasicDerivation> tryResolve(Store & store);
+ static std::optional<BasicDerivation> tryResolve(Store & store, const StorePath & drvPath);
Derivation() = default;
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
+
+private:
+ std::optional<BasicDerivation> tryResolveUncached(Store & store);
};
@@ -174,12 +176,12 @@ std::string outputPathName(std::string_view drvName, std::string_view outputName
// whose output hashes are always known since they are fixed up-front.
typedef std::map<std::string, Hash> CaOutputHashes;
-struct UnknownHashes {};
+struct DeferredHash { Hash hash; };
typedef std::variant<
Hash, // regular DRV normalized hash
CaOutputHashes, // Fixed-output derivation hashes
- UnknownHashes // Deferred hashes for floating outputs drvs and their dependencies
+ DeferredHash // Deferred hashes for floating outputs drvs and their dependencies
> DrvHashModulo;
/* Returns hashes with the details of fixed-output subderivations
@@ -207,22 +209,18 @@ typedef std::variant<
*/
DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutputs);
+/*
+ Return a map associating each output to a hash that uniquely identifies its
+ derivation (modulo the self-references).
+ */
+std::map<std::string, Hash> staticOutputHashes(Store& store, const Derivation& drv);
+
/* Memoisation of hashDerivationModulo(). */
typedef std::map<StorePath, DrvHashModulo> DrvHashes;
// FIXME: global, though at least thread-safe.
extern Sync<DrvHashes> drvHashes;
-/* Memoisation of `readDerivation(..).resove()`. */
-typedef std::map<
- StorePath,
- std::optional<StorePath>
-> DrvPathResolutions;
-
-// FIXME: global, though at least thread-safe.
-// FIXME: arguably overlaps with hashDerivationModulo memo table.
-extern Sync<DrvPathResolutions> drvPathResolutions;
-
bool wantOutput(const string & output, const std::set<string> & wanted);
struct Source;
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 348e5d0d4..e9f9bde4d 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -42,6 +42,61 @@
namespace nix {
+struct LocalStore::State::Stmts {
+ /* Some precompiled SQLite statements. */
+ SQLiteStmt RegisterValidPath;
+ SQLiteStmt UpdatePathInfo;
+ SQLiteStmt AddReference;
+ SQLiteStmt QueryPathInfo;
+ SQLiteStmt QueryReferences;
+ SQLiteStmt QueryReferrers;
+ SQLiteStmt InvalidatePath;
+ SQLiteStmt AddDerivationOutput;
+ SQLiteStmt RegisterRealisedOutput;
+ SQLiteStmt QueryValidDerivers;
+ SQLiteStmt QueryDerivationOutputs;
+ SQLiteStmt QueryRealisedOutput;
+ SQLiteStmt QueryAllRealisedOutputs;
+ SQLiteStmt QueryPathFromHashPart;
+ SQLiteStmt QueryValidPaths;
+};
+
+int getSchema(Path schemaPath)
+{
+ int curSchema = 0;
+ if (pathExists(schemaPath)) {
+ string s = readFile(schemaPath);
+ if (!string2Int(s, curSchema))
+ throw Error("'%1%' is corrupt", schemaPath);
+ }
+ return curSchema;
+}
+
+void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
+{
+ const int nixCASchemaVersion = 1;
+ int curCASchema = getSchema(schemaPath);
+ if (curCASchema != nixCASchemaVersion) {
+ if (curCASchema > nixCASchemaVersion) {
+ throw Error("current Nix store ca-schema is version %1%, but I only support %2%",
+ curCASchema, nixCASchemaVersion);
+ }
+
+ if (!lockFile(lockFd.get(), ltWrite, false)) {
+ printInfo("waiting for exclusive access to the Nix store for ca drvs...");
+ lockFile(lockFd.get(), ltWrite, true);
+ }
+
+ if (curCASchema == 0) {
+ static const char schema[] =
+ #include "ca-specific-schema.sql.gen.hh"
+ ;
+ db.exec(schema);
+ }
+ writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
+ lockFile(lockFd.get(), ltRead, true);
+ }
+}
LocalStore::LocalStore(const Params & params)
: StoreConfig(params)
@@ -60,6 +115,7 @@ LocalStore::LocalStore(const Params & params)
, locksHeld(tokenizeString<PathSet>(getEnv("NIX_HELD_LOCKS").value_or("")))
{
auto state(_state.lock());
+ state->stmts = std::make_unique<State::Stmts>();
/* Create missing state directories if they don't already exist. */
createDirs(realStoreDir);
@@ -222,32 +278,58 @@ LocalStore::LocalStore(const Params & params)
else openDB(*state, false);
+ if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
+ migrateCASchema(state->db, dbDir + "/ca-schema", globalLock);
+ }
+
/* Prepare SQL statements. */
- state->stmtRegisterValidPath.create(state->db,
+ state->stmts->RegisterValidPath.create(state->db,
"insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate, sigs, ca) values (?, ?, ?, ?, ?, ?, ?, ?);");
- state->stmtUpdatePathInfo.create(state->db,
+ state->stmts->UpdatePathInfo.create(state->db,
"update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ?, ca = ? where path = ?;");
- state->stmtAddReference.create(state->db,
+ state->stmts->AddReference.create(state->db,
"insert or replace into Refs (referrer, reference) values (?, ?);");
- state->stmtQueryPathInfo.create(state->db,
+ state->stmts->QueryPathInfo.create(state->db,
"select id, hash, registrationTime, deriver, narSize, ultimate, sigs, ca from ValidPaths where path = ?;");
- state->stmtQueryReferences.create(state->db,
+ state->stmts->QueryReferences.create(state->db,
"select path from Refs join ValidPaths on reference = id where referrer = ?;");
- state->stmtQueryReferrers.create(state->db,
+ state->stmts->QueryReferrers.create(state->db,
"select path from Refs join ValidPaths on referrer = id where reference = (select id from ValidPaths where path = ?);");
- state->stmtInvalidatePath.create(state->db,
+ state->stmts->InvalidatePath.create(state->db,
"delete from ValidPaths where path = ?;");
- state->stmtAddDerivationOutput.create(state->db,
+ state->stmts->AddDerivationOutput.create(state->db,
"insert or replace into DerivationOutputs (drv, id, path) values (?, ?, ?);");
- state->stmtQueryValidDerivers.create(state->db,
+ state->stmts->QueryValidDerivers.create(state->db,
"select v.id, v.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where d.path = ?;");
- state->stmtQueryDerivationOutputs.create(state->db,
+ state->stmts->QueryDerivationOutputs.create(state->db,
"select id, path from DerivationOutputs where drv = ?;");
// Use "path >= ?" with limit 1 rather than "path like '?%'" to
// ensure efficient lookup.
- state->stmtQueryPathFromHashPart.create(state->db,
+ state->stmts->QueryPathFromHashPart.create(state->db,
"select path from ValidPaths where path >= ? limit 1;");
- state->stmtQueryValidPaths.create(state->db, "select path from ValidPaths");
+ state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths");
+ if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
+ state->stmts->RegisterRealisedOutput.create(state->db,
+ R"(
+ insert or replace into Realisations (drvPath, outputName, outputPath)
+ values (?, ?, (select id from ValidPaths where path = ?))
+ ;
+ )");
+ state->stmts->QueryRealisedOutput.create(state->db,
+ R"(
+ select Output.path from Realisations
+ inner join ValidPaths as Output on Output.id = Realisations.outputPath
+ where drvPath = ? and outputName = ?
+ ;
+ )");
+ state->stmts->QueryAllRealisedOutputs.create(state->db,
+ R"(
+ select outputName, Output.path from Realisations
+ inner join ValidPaths as Output on Output.id = Realisations.outputPath
+ where drvPath = ?
+ ;
+ )");
+ }
}
@@ -285,16 +367,7 @@ std::string LocalStore::getUri()
int LocalStore::getSchema()
-{
- int curSchema = 0;
- if (pathExists(schemaPath)) {
- string s = readFile(schemaPath);
- if (!string2Int(s, curSchema))
- throw Error("'%1%' is corrupt", schemaPath);
- }
- return curSchema;
-}
-
+{ return nix::getSchema(schemaPath); }
void LocalStore::openDB(State & state, bool create)
{
@@ -581,16 +654,22 @@ 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);
+ retrySQLite<void>([&]() {
+ state->stmts->RegisterRealisedOutput.use()
+ (info.id.strHash())
+ (info.id.outputName)
+ (printStorePath(info.outPath))
+ .exec();
+ });
}
-void LocalStore::linkDeriverToPath(State & state, uint64_t deriver, const string & outputName, const StorePath & output)
+void LocalStore::cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output)
{
retrySQLite<void>([&]() {
- state.stmtAddDerivationOutput.use()
+ state.stmts->AddDerivationOutput.use()
(deriver)
(outputName)
(printStorePath(output))
@@ -607,7 +686,7 @@ uint64_t LocalStore::addValidPath(State & state,
throw Error("cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't",
printStorePath(info.path));
- state.stmtRegisterValidPath.use()
+ state.stmts->RegisterValidPath.use()
(printStorePath(info.path))
(info.narHash.to_string(Base16, true))
(info.registrationTime == 0 ? time(0) : info.registrationTime)
@@ -637,7 +716,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);
+ cacheDrvOutputMapping(state, id, i.first, *i.second.second);
}
}
@@ -659,7 +738,7 @@ void LocalStore::queryPathInfoUncached(const StorePath & path,
auto state(_state.lock());
/* Get the path info. */
- auto useQueryPathInfo(state->stmtQueryPathInfo.use()(printStorePath(path)));
+ auto useQueryPathInfo(state->stmts->QueryPathInfo.use()(printStorePath(path)));
if (!useQueryPathInfo.next())
return std::shared_ptr<ValidPathInfo>();
@@ -679,7 +758,7 @@ void LocalStore::queryPathInfoUncached(const StorePath & path,
info->registrationTime = useQueryPathInfo.getInt(2);
- auto s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 3);
+ auto s = (const char *) sqlite3_column_text(state->stmts->QueryPathInfo, 3);
if (s) info->deriver = parseStorePath(s);
/* Note that narSize = NULL yields 0. */
@@ -687,14 +766,14 @@ void LocalStore::queryPathInfoUncached(const StorePath & path,
info->ultimate = useQueryPathInfo.getInt(5) == 1;
- s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 6);
+ s = (const char *) sqlite3_column_text(state->stmts->QueryPathInfo, 6);
if (s) info->sigs = tokenizeString<StringSet>(s, " ");
- s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 7);
+ s = (const char *) sqlite3_column_text(state->stmts->QueryPathInfo, 7);
if (s) info->ca = parseContentAddressOpt(s);
/* Get the references. */
- auto useQueryReferences(state->stmtQueryReferences.use()(info->id));
+ auto useQueryReferences(state->stmts->QueryReferences.use()(info->id));
while (useQueryReferences.next())
info->references.insert(parseStorePath(useQueryReferences.getStr(0)));
@@ -709,7 +788,7 @@ void LocalStore::queryPathInfoUncached(const StorePath & path,
/* Update path info in the database. */
void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info)
{
- state.stmtUpdatePathInfo.use()
+ state.stmts->UpdatePathInfo.use()
(info.narSize, info.narSize != 0)
(info.narHash.to_string(Base16, true))
(info.ultimate ? 1 : 0, info.ultimate)
@@ -722,7 +801,7 @@ void LocalStore::updatePathInfo(State & state, const ValidPathInfo &