diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index ed6772377..5683e1afa 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -444,12 +444,10 @@ ref openEvalCache( std::shared_ptr lockedFlake) { auto fingerprint = lockedFlake->getFingerprint(state.store); - return make_ref( - evalSettings.useEvalCache && evalSettings.pureEval - ? fingerprint - : std::nullopt, - state, - [&state, lockedFlake]() + auto hash = evalSettings.useEvalCache && evalSettings.pureEval + ? fingerprint + : std::nullopt; + auto rootLoader = [&state, lockedFlake]() { /* For testing whether the evaluation cache is complete. */ @@ -465,7 +463,17 @@ ref openEvalCache( assert(aOutputs); return aOutputs->value; - }); + }; + + if (hash) { + auto search = state.evalCaches.find(hash.value()); + if (search == state.evalCaches.end()) { + search = state.evalCaches.emplace(hash.value(), make_ref(hash, state, rootLoader)).first; + } + return search->second; + } else { + return make_ref(hash, state, rootLoader); + } } Installables SourceExprCommand::parseInstallables( diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3477f6c46..508361301 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -34,6 +34,9 @@ class StorePath; struct SingleDerivedPath; enum RepairFlag : bool; struct MemoryInputAccessor; +namespace eval_cache { + class EvalCache; +} /** @@ -282,6 +285,11 @@ public: return *new EvalErrorBuilder(*this, args...); } + /** + * A cache for evaluation caches, so as to reuse the same root value if possible + */ + std::map> evalCaches; + private: /* Cache for calls to addToStore(); maps source paths to the store