From 96670ed2163d3d1a296c9b053833362ec8c06985 Mon Sep 17 00:00:00 2001 From: regnat Date: Wed, 27 Oct 2021 11:36:51 +0200 Subject: [PATCH] Expose an async interface for `queryRealisation` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doesn’t change much so far because everything is still using it synchronously, but should allow the binary cache to fetch stuff in parallel --- src/libstore/binary-cache-store.cc | 30 ++------ src/libstore/binary-cache-store.hh | 3 +- .../build/drv-output-substitution-goal.hh | 2 +- src/libstore/build/local-derivation-goal.cc | 7 +- src/libstore/dummy-store.cc | 5 +- src/libstore/legacy-ssh-store.cc | 3 +- src/libstore/local-store.cc | 23 +++++-- src/libstore/local-store.hh | 3 +- src/libstore/remote-store.cc | 34 ++++++---- src/libstore/remote-store.hh | 3 +- src/libstore/store-api.cc | 68 +++++++++++++++++++ src/libstore/store-api.hh | 12 +++- 12 files changed, 138 insertions(+), 55 deletions(-) diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 943132754..fb687db42 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -437,39 +437,19 @@ StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s })->path; } -std::optional BinaryCacheStore::queryRealisation(const DrvOutput & id) +void BinaryCacheStore::queryRealisationUncached(const DrvOutput & id, + Callback> callback) noexcept { - if (diskCache) { - auto [cacheOutcome, maybeCachedRealisation] = - diskCache->lookupRealisation(getUri(), id); - switch (cacheOutcome) { - case NarInfoDiskCache::oValid: - debug("Returning a cached realisation for %s", id.to_string()); - return *maybeCachedRealisation; - case NarInfoDiskCache::oInvalid: - debug("Returning a cached missing realisation for %s", id.to_string()); - return {}; - case NarInfoDiskCache::oUnknown: - break; - } - } - auto outputInfoFilePath = realisationsPrefix + "/" + id.to_string() + ".doi"; auto rawOutputInfo = getFile(outputInfoFilePath); if (rawOutputInfo) { auto realisation = Realisation::fromJSON( nlohmann::json::parse(*rawOutputInfo), outputInfoFilePath); - - if (diskCache) - diskCache->upsertRealisation( - getUri(), realisation); - - return {realisation}; + callback(std::make_shared(realisation)); + return; } else { - if (diskCache) - diskCache->upsertAbsentRealisation(getUri(), id); - return std::nullopt; + callback(nullptr); } } diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index 723f2e805..87ce610af 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -108,7 +108,8 @@ public: void registerDrvOutput(const Realisation & info) override; - std::optional queryRealisation(const DrvOutput &) override; + void queryRealisationUncached(const DrvOutput &, + Callback> callback) noexcept override; void narFromPath(const StorePath & path, Sink & sink) override; diff --git a/src/libstore/build/drv-output-substitution-goal.hh b/src/libstore/build/drv-output-substitution-goal.hh index 63ab53d89..1b11a298e 100644 --- a/src/libstore/build/drv-output-substitution-goal.hh +++ b/src/libstore/build/drv-output-substitution-goal.hh @@ -20,7 +20,7 @@ private: // The realisation corresponding to the given output id. // Will be filled once we can get it. - std::optional outputInfo; + std::shared_ptr outputInfo; /* The remaining substituters. */ std::list> subs; diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 2182f0bb4..b076bf998 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -1224,13 +1224,14 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo // corresponds to an allowed derivation { throw Error("registerDrvOutput"); } - std::optional queryRealisation(const DrvOutput & id) override + void queryRealisationUncached(const DrvOutput & id, + Callback> callback) noexcept override // XXX: This should probably be allowed if the realisation corresponds to // an allowed derivation { if (!goal.isAllowed(id)) - throw InvalidPath("cannot query an unknown output id '%s' in recursive Nix", id.to_string()); - return next->queryRealisation(id); + callback(nullptr); + next->queryRealisation(id, std::move(callback)); } void buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc index 36c6e725c..62dc21c59 100644 --- a/src/libstore/dummy-store.cc +++ b/src/libstore/dummy-store.cc @@ -50,8 +50,9 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store void narFromPath(const StorePath & path, Sink & sink) override { unsupported("narFromPath"); } - std::optional queryRealisation(const DrvOutput&) override - { unsupported("queryRealisation"); } + void queryRealisationUncached(const DrvOutput &, + Callback> callback) noexcept override + { callback(nullptr); } }; static RegisterStoreImplementation regDummyStore; diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index 814960bb5..c9c3be1b0 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -367,7 +367,8 @@ public: return conn->remoteVersion; } - std::optional queryRealisation(const DrvOutput&) override + void queryRealisationUncached(const DrvOutput &, + Callback> callback) noexcept override // TODO: Implement { unsupported("queryRealisation"); } }; diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 225a19e1e..92d8c36ac 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1838,13 +1838,24 @@ std::optional LocalStore::queryRealisation_( return { res }; } -std::optional -LocalStore::queryRealisation(const DrvOutput & id) +void LocalStore::queryRealisationUncached(const DrvOutput & id, + Callback> callback) noexcept { - return retrySQLite>([&]() { - auto state(_state.lock()); - return queryRealisation_(*state, id); - }); + try { + auto maybeRealisation + = retrySQLite>([&]() { + auto state(_state.lock()); + return queryRealisation_(*state, id); + }); + if (maybeRealisation) + callback( + std::make_shared(maybeRealisation.value())); + else + callback(nullptr); + + } catch (...) { + callback.rethrow(); + } } FixedOutputHash LocalStore::hashCAPath( diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 301425eb1..b172e897a 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -207,7 +207,8 @@ public: std::optional queryRealisation_(State & state, const DrvOutput & id); std::optional> queryRealisationCore_(State & state, const DrvOutput & id); - std::optional queryRealisation(const DrvOutput&) override; + void queryRealisationUncached(const DrvOutput&, + Callback> callback) noexcept override; private: diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 7decc059c..9c00d6212 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -677,23 +677,33 @@ void RemoteStore::registerDrvOutput(const Realisation & info) conn.processStderr(); } -std::optional RemoteStore::queryRealisation(const DrvOutput & id) +void RemoteStore::queryRealisationUncached(const DrvOutput & id, + Callback> callback) noexcept { auto conn(getConnection()); conn->to << wopQueryRealisation; conn->to << id.to_string(); conn.processStderr(); - if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) { - auto outPaths = worker_proto::read(*this, conn->from, Phantom>{}); - if (outPaths.empty()) - return std::nullopt; - return {Realisation{.id = id, .outPath = *outPaths.begin()}}; - } else { - auto realisations = worker_proto::read(*this, conn->from, Phantom>{}); - if (realisations.empty()) - return std::nullopt; - return *realisations.begin(); - } + + auto real = [&]() -> std::shared_ptr { + if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) { + auto outPaths = worker_proto::read( + *this, conn->from, Phantom> {}); + if (outPaths.empty()) + return nullptr; + return std::make_shared(Realisation { .id = id, .outPath = *outPaths.begin() }); + } else { + auto realisations = worker_proto::read( + *this, conn->from, Phantom> {}); + if (realisations.empty()) + return nullptr; + return std::make_shared(*realisations.begin()); + } + }(); + + try { + callback(std::shared_ptr(real)); + } catch (...) { return callback.rethrow(); } } static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, const std::vector & reqs) diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index a3036e6b0..79d031a24 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -88,7 +88,8 @@ public: void registerDrvOutput(const Realisation & info) override; - std::optional queryRealisation(const DrvOutput &) override; + void queryRealisationUncached(const DrvOutput &, + Callback> callback) noexcept override; void buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override; diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index b0d3688ce..b8d702200 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -542,6 +542,74 @@ void Store::queryPathInfo(const StorePath & storePath, }}); } +void Store::queryRealisation(const DrvOutput & id, + Callback> callback) noexcept +{ + + try { + if (diskCache) { + auto [cacheOutcome, maybeCachedRealisation] + = diskCache->lookupRealisation(getUri(), id); + switch (cacheOutcome) { + case NarInfoDiskCache::oValid: + debug("Returning a cached realisation for %s", id.to_string()); + callback(maybeCachedRealisation); + return; + case NarInfoDiskCache::oInvalid: + debug( + "Returning a cached missing realisation for %s", + id.to_string()); + callback(nullptr); + return; + case NarInfoDiskCache::oUnknown: + break; + } + } + } catch (...) { + return callback.rethrow(); + } + + auto callbackPtr + = std::make_shared(std::move(callback)); + + queryRealisationUncached( + id, + { [this, id, callbackPtr]( + std::future> fut) { + try { + auto info = fut.get(); + + if (diskCache) { + if (info) + diskCache->upsertRealisation(getUri(), *info); + else + diskCache->upsertAbsentRealisation(getUri(), id); + } + + (*callbackPtr)(std::shared_ptr(info)); + + } catch (...) { + callbackPtr->rethrow(); + } + } }); +} + +std::shared_ptr Store::queryRealisation(const DrvOutput & id) +{ + using RealPtr = std::shared_ptr; + std::promise promise; + + queryRealisation(id, + {[&](std::future result) { + try { + promise.set_value(result.get()); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }}); + + return promise.get_future().get(); +} void Store::substitutePaths(const StorePathSet & paths) { diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 7d02340df..8adcf276f 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -369,6 +369,14 @@ public: void queryPathInfo(const StorePath & path, Callback> callback) noexcept; + /* Query the information about a realisation. */ + std::shared_ptr queryRealisation(const DrvOutput &); + + /* Asynchronous version of queryRealisation(). */ + void queryRealisation(const DrvOutput &, + Callback> callback) noexcept; + + /* Check whether the given valid path info is sufficiently attested, by either being signed by a trusted public key or content-addressed, in order to be included in the given store. @@ -393,11 +401,11 @@ protected: virtual void queryPathInfoUncached(const StorePath & path, Callback> callback) noexcept = 0; + virtual void queryRealisationUncached(const DrvOutput &, + Callback> callback) noexcept = 0; public: - virtual std::optional 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)