libexpr: remove eval caches from EvalState

eval caches are not used by actual eval at all, only by the flake-shaped
wrappers around evaluation. moving caches into a subclass both clarifies
that eval caches and eval states are coupled and separates concerns that
should not have been intermixed as they were here. in the future we will
want to split up and decouple things even further. that'll have to wait.

Change-Id: I7b69510c0f8b212f05fae62e7b992d9475b4841f
This commit is contained in:
eldritch horrors 2024-11-27 02:09:08 +01:00
parent 564f464772
commit 7c650ea241
11 changed files with 54 additions and 31 deletions

View file

@ -102,15 +102,15 @@ ref<Store> EvalCommand::getEvalStore()
return ref<Store>(evalStore); return ref<Store>(evalStore);
} }
ref<EvalState> EvalCommand::getEvalState() ref<eval_cache::CachingEvalState> EvalCommand::getEvalState()
{ {
if (!evalState) { if (!evalState) {
evalState = evalState =
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
std::allocate_shared<EvalState>(traceable_allocator<EvalState>(), std::allocate_shared<eval_cache::CachingEvalState>(traceable_allocator<EvalState>(),
searchPath, getEvalStore(), getStore()) searchPath, getEvalStore(), getStore())
#else #else
std::make_shared<EvalState>( std::make_shared<eval_cache::CachingEvalState>(
searchPath, getEvalStore(), getStore()) searchPath, getEvalStore(), getStore())
#endif #endif
; ;
@ -121,7 +121,7 @@ ref<EvalState> EvalCommand::getEvalState()
evalState->debug = std::make_unique<DebugState>(&AbstractNixRepl::runSimple); evalState->debug = std::make_unique<DebugState>(&AbstractNixRepl::runSimple);
}; };
} }
return ref<EvalState>(evalState); return ref<eval_cache::CachingEvalState>(evalState);
} }
MixOperateOnOptions::MixOperateOnOptions() MixOperateOnOptions::MixOperateOnOptions()

View file

@ -2,6 +2,7 @@
///@file ///@file
#include "lix/libcmd/installable-value.hh" #include "lix/libcmd/installable-value.hh"
#include "lix/libexpr/eval-cache.hh"
#include "lix/libutil/args.hh" #include "lix/libutil/args.hh"
#include "lix/libcmd/common-eval-args.hh" #include "lix/libcmd/common-eval-args.hh"
#include "lix/libstore/path.hh" #include "lix/libstore/path.hh"
@ -76,12 +77,12 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
ref<Store> getEvalStore(); ref<Store> getEvalStore();
ref<EvalState> getEvalState(); ref<eval_cache::CachingEvalState> getEvalState();
private: private:
std::shared_ptr<Store> evalStore; std::shared_ptr<Store> evalStore;
std::shared_ptr<EvalState> evalState; std::shared_ptr<eval_cache::CachingEvalState> evalState;
}; };
/** /**
@ -331,7 +332,7 @@ void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::strin
void completeFlakeRefWithFragment( void completeFlakeRefWithFragment(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<eval_cache::CachingEvalState> evalState,
flake::LockFlags lockFlags, flake::LockFlags lockFlags,
Strings attrPathPrefixes, Strings attrPathPrefixes,
const Strings & defaultFlakeAttrPaths, const Strings & defaultFlakeAttrPaths,

View file

@ -12,7 +12,7 @@
namespace nix { namespace nix {
InstallableAttrPath::InstallableAttrPath( InstallableAttrPath::InstallableAttrPath(
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
SourceExprCommand & cmd, SourceExprCommand & cmd,
Value * v, Value * v,
const std::string & attrPath, const std::string & attrPath,
@ -93,7 +93,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
} }
InstallableAttrPath InstallableAttrPath::parse( InstallableAttrPath InstallableAttrPath::parse(
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
SourceExprCommand & cmd, SourceExprCommand & cmd,
Value * v, Value * v,
std::string_view prefix, std::string_view prefix,

View file

@ -2,6 +2,7 @@
///@file ///@file
#include "lix/libcmd/installable-value.hh" #include "lix/libcmd/installable-value.hh"
#include "lix/libexpr/eval-cache.hh"
#include "lix/libstore/outputs-spec.hh" #include "lix/libstore/outputs-spec.hh"
#include "lix/libcmd/command.hh" #include "lix/libcmd/command.hh"
#include "lix/libcmd/common-eval-args.hh" #include "lix/libcmd/common-eval-args.hh"
@ -19,7 +20,7 @@ class InstallableAttrPath : public InstallableValue
ExtendedOutputsSpec extendedOutputsSpec; ExtendedOutputsSpec extendedOutputsSpec;
InstallableAttrPath( InstallableAttrPath(
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
SourceExprCommand & cmd, SourceExprCommand & cmd,
Value * v, Value * v,
const std::string & attrPath, const std::string & attrPath,
@ -34,7 +35,7 @@ class InstallableAttrPath : public InstallableValue
public: public:
static InstallableAttrPath parse( static InstallableAttrPath parse(
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
SourceExprCommand & cmd, SourceExprCommand & cmd,
Value * v, Value * v,
std::string_view prefix, std::string_view prefix,

View file

@ -67,7 +67,7 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
InstallableFlake::InstallableFlake( InstallableFlake::InstallableFlake(
SourceExprCommand * cmd, SourceExprCommand * cmd,
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
FlakeRef && flakeRef, FlakeRef && flakeRef,
std::string_view fragment, std::string_view fragment,
ExtendedOutputsSpec extendedOutputsSpec, ExtendedOutputsSpec extendedOutputsSpec,

View file

@ -40,7 +40,7 @@ struct InstallableFlake : InstallableValue
InstallableFlake( InstallableFlake(
SourceExprCommand * cmd, SourceExprCommand * cmd,
ref<EvalState> state, ref<eval_cache::CachingEvalState> state,
FlakeRef && flakeRef, FlakeRef && flakeRef,
std::string_view fragment, std::string_view fragment,
ExtendedOutputsSpec extendedOutputsSpec, ExtendedOutputsSpec extendedOutputsSpec,
@ -83,7 +83,7 @@ static inline FlakeRef defaultNixpkgsFlakeRef()
} }
ref<eval_cache::EvalCache> openEvalCache( ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, eval_cache::CachingEvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake); std::shared_ptr<flake::LockedFlake> lockedFlake);
} }

View file

@ -2,6 +2,7 @@
///@file ///@file
#include "lix/libcmd/installables.hh" #include "lix/libcmd/installables.hh"
#include "lix/libexpr/eval-cache.hh"
#include "lix/libexpr/flake/flake.hh" #include "lix/libexpr/flake/flake.hh"
namespace nix { namespace nix {
@ -9,8 +10,6 @@ namespace nix {
struct DrvInfo; struct DrvInfo;
struct SourceExprCommand; struct SourceExprCommand;
namespace eval_cache { class EvalCache; class AttrCursor; }
struct App struct App
{ {
std::vector<DerivedPath> context; std::vector<DerivedPath> context;
@ -71,9 +70,9 @@ struct ExtraPathInfoValue : ExtraPathInfo
*/ */
struct InstallableValue : Installable struct InstallableValue : Installable
{ {
ref<EvalState> state; ref<eval_cache::CachingEvalState> state;
InstallableValue(ref<EvalState> state) : state(state) {} InstallableValue(ref<eval_cache::CachingEvalState> state) : state(state) {}
virtual ~InstallableValue() { } virtual ~InstallableValue() { }

View file

@ -267,7 +267,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
void completeFlakeRefWithFragment( void completeFlakeRefWithFragment(
AddCompletions & completions, AddCompletions & completions,
ref<EvalState> evalState, ref<eval_cache::CachingEvalState> evalState,
flake::LockFlags lockFlags, flake::LockFlags lockFlags,
Strings attrPathPrefixes, Strings attrPathPrefixes,
const Strings & defaultFlakeAttrPaths, const Strings & defaultFlakeAttrPaths,
@ -390,7 +390,7 @@ static StorePath getDeriver(
} }
ref<eval_cache::EvalCache> openEvalCache( ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, eval_cache::CachingEvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake) std::shared_ptr<flake::LockedFlake> lockedFlake)
{ {
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
@ -415,11 +415,7 @@ ref<eval_cache::EvalCache> openEvalCache(
}; };
if (fingerprint) { if (fingerprint) {
auto search = state.evalCaches.find(fingerprint.value()); return state.getCacheFor(fingerprint.value(), rootLoader);
if (search == state.evalCaches.end()) {
search = state.evalCaches.emplace(fingerprint.value(), make_ref<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader)).first;
}
return search->second;
} else { } else {
return make_ref<nix::eval_cache::EvalCache>(std::nullopt, state, rootLoader); return make_ref<nix::eval_cache::EvalCache>(std::nullopt, state, rootLoader);
} }

View file

@ -334,6 +334,16 @@ static std::shared_ptr<AttrDb> makeAttrDb(
} }
} }
ref<EvalCache> CachingEvalState::getCacheFor(Hash hash, RootLoader rootLoader)
{
if (auto it = caches.find(hash); it != caches.end()) {
return it->second;
}
auto cache = make_ref<EvalCache>(hash, *this, rootLoader);
caches.emplace(hash, cache);
return cache;
}
EvalCache::EvalCache( EvalCache::EvalCache(
std::optional<std::reference_wrapper<const Hash>> useCache, std::optional<std::reference_wrapper<const Hash>> useCache,
EvalState & state, EvalState & state,

View file

@ -13,13 +13,34 @@ namespace nix::eval_cache {
struct AttrDb; struct AttrDb;
class AttrCursor; class AttrCursor;
typedef std::function<Value *()> RootLoader;
/**
* EvalState with caching support. Historically this was part of EvalState,
* but it was split out to make maintenance easier. This could've been just
* a pair of EvalState and the cache map, but doing so would currently hide
* the rather strong connection between EvalState and these caches. At some
* future time the cache interface should be changed to hide its EvalState.
*/
class CachingEvalState : public EvalState
{
/**
* A cache for evaluation caches, so as to reuse the same root value if possible
*/
std::map<Hash, ref<EvalCache>> caches;
public:
using EvalState::EvalState;
ref<EvalCache> getCacheFor(Hash hash, RootLoader rootLoader);
};
class EvalCache : public std::enable_shared_from_this<EvalCache> class EvalCache : public std::enable_shared_from_this<EvalCache>
{ {
friend class AttrCursor; friend class AttrCursor;
std::shared_ptr<AttrDb> db; std::shared_ptr<AttrDb> db;
EvalState & state; EvalState & state;
typedef std::function<Value *()> RootLoader;
RootLoader rootLoader; RootLoader rootLoader;
RootValue value; RootValue value;

View file

@ -321,11 +321,6 @@ public:
return *new EvalErrorBuilder<T>(*this, args...); return *new EvalErrorBuilder<T>(*this, args...);
} }
/**
* A cache for evaluation caches, so as to reuse the same root value if possible
*/
std::map<const Hash, ref<eval_cache::EvalCache>> evalCaches;
private: private:
/* Cache for calls to addToStore(); maps source paths to the store /* Cache for calls to addToStore(); maps source paths to the store