libstore: asyncify Store::registerDrvOutput

Change-Id: Ib8ba14ba2ce210714181dbb85ca8a42480a32c55
This commit is contained in:
eldritch horrors
2025-03-05 18:49:45 +01:00
parent 749a323597
commit 7d9fad0cf1
13 changed files with 102 additions and 78 deletions
+1 -1
View File
@@ -387,7 +387,7 @@ connected:
// Should hold, because if the feature isn't enabled the set
// of missing realisations should be empty
experimentalFeatureSettings.require(Xp::CaDerivations);
store->registerDrvOutput(realisation);
aio.blockOn(store->registerDrvOutput(realisation));
}
return 0;
+5 -1
View File
@@ -502,11 +502,15 @@ std::shared_ptr<const Realisation> BinaryCacheStore::queryRealisationUncached(co
return std::make_shared<const Realisation>(realisation);
}
void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
kj::Promise<Result<void>> BinaryCacheStore::registerDrvOutput(const Realisation& info)
try {
if (diskCache)
diskCache->upsertRealisation(getUri(), info);
auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
upsertFile(filePath, info.toJSON().dump(), "application/json");
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
ref<FSAccessor> BinaryCacheStore::getFSAccessor()
+1 -1
View File
@@ -144,7 +144,7 @@ public:
const StorePathSet & references,
RepairFlag repair) override;
void registerDrvOutput(const Realisation & info) override;
kj::Promise<Result<void>> registerDrvOutput(const Realisation & info) override;
std::shared_ptr<const Realisation> queryRealisationUncached(const DrvOutput &) override;
+3 -3
View File
@@ -1192,7 +1192,7 @@ try {
);
}
signRealisation(newRealisation);
worker.store.registerDrvOutput(newRealisation);
TRY_AWAIT(worker.store.registerDrvOutput(newRealisation));
}
outputPaths.insert(realisation.outPath);
builtOutputs.emplace(outputName, realisation);
@@ -1691,12 +1691,12 @@ try {
// derivation, and the output path is valid, but we don't have
// its realisation stored (probably because it has been built
// without the `ca-derivations` experimental flag).
worker.store.registerDrvOutput(
TRY_AWAIT(worker.store.registerDrvOutput(
Realisation {
drvOutput,
info.known->path,
}
);
));
}
}
if (info.known && info.known->isValid())
@@ -141,15 +141,15 @@ try {
if (nrFailed > 0) {
debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
return {WorkResult{
co_return WorkResult{
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
}};
};
}
worker.store.registerDrvOutput(*outputInfo);
return finished();
TRY_AWAIT(worker.store.registerDrvOutput(*outputInfo));
co_return TRY_AWAIT(finished());
} catch (...) {
return {result::current_exception()};
co_return result::current_exception();
}
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::finished() noexcept
+3 -3
View File
@@ -1151,10 +1151,10 @@ struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStor
return {result::current_exception()};
}
void registerDrvOutput(const Realisation & info) override
kj::Promise<Result<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"); }
try { throw Error("registerDrvOutput"); } catch (...) { return {result::current_exception()}; }
std::shared_ptr<const Realisation> queryRealisationUncached(const DrvOutput & id) override
// XXX: This should probably be allowed if the realisation corresponds to
@@ -2508,7 +2508,7 @@ try {
&& drv->type().isPure())
{
signRealisation(thisRealisation);
worker.store.registerDrvOutput(thisRealisation);
TRY_AWAIT(worker.store.registerDrvOutput(thisRealisation));
}
builtOutputs.emplace(outputName, thisRealisation);
}
+3 -3
View File
@@ -956,11 +956,11 @@ static void performOp(AsyncIoRoot & aio, TunnelLogger * logger, ref<Store> store
if (GET_PROTOCOL_MINOR(clientVersion) < 31) {
auto outputId = DrvOutput::parse(readString(from));
auto outputPath = StorePath(readString(from));
store->registerDrvOutput(Realisation{
.id = outputId, .outPath = outputPath});
aio.blockOn(store->registerDrvOutput(Realisation{
.id = outputId, .outPath = outputPath}));
} else {
auto realisation = WorkerProto::Serialise<Realisation>::read(*store, rconn);
store->registerDrvOutput(realisation);
aio.blockOn(store->registerDrvOutput(realisation));
}
logger->stopWork();
break;
+62 -49
View File
@@ -772,67 +772,80 @@ void canonicalisePathMetaData(const Path & path,
}
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{
kj::Promise<Result<void>>
LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
try {
experimentalFeatureSettings.require(Xp::CaDerivations);
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
registerDrvOutput(info);
TRY_AWAIT(registerDrvOutput(info));
else
throw Error("cannot register realisation '%s' because it lacks a signature by a trusted key", info.outPath.to_string());
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
void LocalStore::registerDrvOutput(const Realisation & info)
{
kj::Promise<Result<void>> LocalStore::registerDrvOutput(const Realisation & info)
try {
experimentalFeatureSettings.require(Xp::CaDerivations);
retrySQLite([&]() {
auto state = dbPool.get();
if (auto oldR = queryRealisation_(*state, info.id)) {
if (info.isCompatibleWith(*oldR)) {
auto combinedSignatures = oldR->signatures;
combinedSignatures.insert(info.signatures.begin(),
info.signatures.end());
state->stmts->UpdateRealisedOutput.use()
(concatStringsSep(" ", combinedSignatures))
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
TRY_AWAIT(retrySQLite([&]() -> kj::Promise<Result<void>> {
try {
auto state = dbPool.get();
if (auto oldR = queryRealisation_(*state, info.id)) {
if (info.isCompatibleWith(*oldR)) {
auto combinedSignatures = oldR->signatures;
combinedSignatures.insert(info.signatures.begin(),
info.signatures.end());
state->stmts->UpdateRealisedOutput.use()
(concatStringsSep(" ", combinedSignatures))
(info.id.strHash())
(info.id.outputName)
.exec();
} else {
throw Error("Trying to register a realisation of '%s', but we already "
"have another one locally.\n"
"Local: %s\n"
"Remote: %s",
info.id.to_string(),
printStorePath(oldR->outPath),
printStorePath(info.outPath)
);
}
} else {
state->stmts->RegisterRealisedOutput.use()
(info.id.strHash())
(info.id.outputName)
(printStorePath(info.outPath))
(concatStringsSep(" ", info.signatures))
.exec();
} else {
throw Error("Trying to register a realisation of '%s', but we already "
"have another one locally.\n"
"Local: %s\n"
"Remote: %s",
info.id.to_string(),
printStorePath(oldR->outPath),
printStorePath(info.outPath)
);
}
} else {
state->stmts->RegisterRealisedOutput.use()
(info.id.strHash())
(info.id.outputName)
(printStorePath(info.outPath))
(concatStringsSep(" ", info.signatures))
.exec();
for (auto & [outputId, depPath] : info.dependentRealisations) {
auto localRealisation = queryRealisationCore_(*state, outputId);
if (!localRealisation)
throw Error("unable to register the derivation '%s' as it "
"depends on the non existent '%s'",
info.id.to_string(), outputId.to_string());
if (localRealisation->second.outPath != depPath)
throw Error("unable to register the derivation '%s' as it "
"depends on a realisation of '%s' that doesnt"
"match what we have locally",
info.id.to_string(), outputId.to_string());
state->stmts->AddRealisationReference.use()
(info.id.strHash())
(info.id.outputName)
(outputId.strHash())
(outputId.outputName)
.exec();
}
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
for (auto & [outputId, depPath] : info.dependentRealisations) {
auto localRealisation = queryRealisationCore_(*state, outputId);
if (!localRealisation)
throw Error("unable to register the derivation '%s' as it "
"depends on the non existent '%s'",
info.id.to_string(), outputId.to_string());
if (localRealisation->second.outPath != depPath)
throw Error("unable to register the derivation '%s' as it "
"depends on a realisation of '%s' that doesnt"
"match what we have locally",
info.id.to_string(), outputId.to_string());
state->stmts->AddRealisationReference.use()
(info.id.strHash())
(info.id.outputName)
(outputId.strHash())
(outputId.outputName)
.exec();
}
}, always_progresses);
}));
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
void LocalStore::cacheDrvOutputMapping(
+3 -2
View File
@@ -317,8 +317,9 @@ public:
* Register the store path 'output' as the output named 'outputName' of
* derivation 'deriver'.
*/
void registerDrvOutput(const Realisation & info) override;
void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
kj::Promise<Result<void>> registerDrvOutput(const Realisation & info) override;
kj::Promise<Result<void>>
registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
void cacheDrvOutputMapping(
DBState & state,
const uint64_t deriver,
+5 -2
View File
@@ -600,8 +600,8 @@ try {
co_return result::current_exception();
}
void RemoteStore::registerDrvOutput(const Realisation & info)
{
kj::Promise<Result<void>> RemoteStore::registerDrvOutput(const Realisation & info)
try {
auto conn(getConnection());
conn->to << WorkerProto::Op::RegisterDrvOutput;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) {
@@ -612,6 +612,9 @@ void RemoteStore::registerDrvOutput(const Realisation & info)
conn->to << WorkerProto::write(*this, *conn, info);
}
conn.processStderr();
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
std::shared_ptr<const Realisation> RemoteStore::queryRealisationUncached(const DrvOutput & id)
+1 -1
View File
@@ -112,7 +112,7 @@ public:
const StorePathSet & references,
RepairFlag repair) override;
void registerDrvOutput(const Realisation & info) override;
kj::Promise<Result<void>> registerDrvOutput(const Realisation & info) override;
std::shared_ptr<const Realisation> queryRealisationUncached(const DrvOutput &) override;
+3 -3
View File
@@ -1155,7 +1155,7 @@ try {
processGraph<Realisation>(
"copyPaths pool",
TRY_AWAIT(Realisation::closure(srcStore, toplevelRealisations)),
[&](const Realisation & current) -> std::set<Realisation> {
[&](AsyncIoRoot & aio, const Realisation & current) -> std::set<Realisation> {
std::set<Realisation> children;
for (const auto & [drvOutput, _] : current.dependentRealisations) {
auto currentChild = srcStore.queryRealisation(drvOutput);
@@ -1168,8 +1168,8 @@ try {
}
return children;
},
[&](const Realisation& current) -> void {
dstStore.registerDrvOutput(current, checkSigs);
[&](AsyncIoRoot & aio, const Realisation& current) -> void {
aio.blockOn(dstStore.registerDrvOutput(current, checkSigs));
});
} catch (MissingExperimentalFeature & e) {
// Don't fail if the remote doesn't support CA derivations is it might
+7 -4
View File
@@ -589,10 +589,13 @@ public:
* floating-ca derivations and their dependencies as there's no way to
* retrieve this information otherwise.
*/
virtual void registerDrvOutput(const Realisation & output)
{ unsupported("registerDrvOutput"); }
virtual void registerDrvOutput(const Realisation & output, CheckSigsFlag checkSigs)
{ return registerDrvOutput(output); }
virtual kj::Promise<Result<void>> registerDrvOutput(const Realisation & output)
try { unsupported("registerDrvOutput"); } catch (...) { return {result::current_exception()}; }
virtual kj::Promise<Result<void>>
registerDrvOutput(const Realisation & output, CheckSigsFlag checkSigs)
{
return registerDrvOutput(output);
}
/**
* Generate a NAR dump of a store path.