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

View file

@ -2,6 +2,7 @@
///@file
#include "lix/libcmd/installable-value.hh"
#include "lix/libexpr/eval-cache.hh"
#include "lix/libutil/args.hh"
#include "lix/libcmd/common-eval-args.hh"
#include "lix/libstore/path.hh"
@ -76,12 +77,12 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
ref<Store> getEvalStore();
ref<EvalState> getEvalState();
ref<eval_cache::CachingEvalState> getEvalState();
private:
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(
AddCompletions & completions,
ref<EvalState> evalState,
ref<eval_cache::CachingEvalState> evalState,
flake::LockFlags lockFlags,
Strings attrPathPrefixes,
const Strings & defaultFlakeAttrPaths,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,13 +13,34 @@ namespace nix::eval_cache {
struct AttrDb;
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>
{
friend class AttrCursor;
std::shared_ptr<AttrDb> db;
EvalState & state;
typedef std::function<Value *()> RootLoader;
RootLoader rootLoader;
RootValue value;

View file

@ -321,11 +321,6 @@ public:
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:
/* Cache for calls to addToStore(); maps source paths to the store