From 6396416dfaeff1bdaf338d3d8a1433a4ecad137c Mon Sep 17 00:00:00 2001 From: regnat Date: Thu, 3 Jun 2021 06:40:54 +0200 Subject: [PATCH] Query the eval cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (It’s still always empty) --- src/libexpr/attr-set.hh | 4 +-- src/libexpr/eval.cc | 70 ++++++++++++++++++++++++++++++++++++++ src/libexpr/value-cache.hh | 51 +++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/libexpr/value-cache.hh diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh index 7793e53b5..827f6bb5e 100644 --- a/src/libexpr/attr-set.hh +++ b/src/libexpr/attr-set.hh @@ -2,7 +2,7 @@ #include "nixexpr.hh" #include "symbol-table.hh" -#include "tree-cache.hh" +#include "value-cache.hh" #include #include @@ -37,7 +37,7 @@ class Bindings public: typedef uint32_t size_t; Pos *pos; - std::shared_ptr eval_cache; + ValueCache eval_cache; private: size_t size_, capacity_; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 080027f3f..5ca4ecfe7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -8,6 +8,7 @@ #include "filetransfer.hh" #include "json.hh" #include "function-trace.hh" +#include "value-cache.hh" #include #include @@ -1109,10 +1110,79 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v) unsigned long nrLookups = 0; +std::pair ValueCache::getValue(EvalState & state, const std::vector & selector, Value & dest) +{ + if (!rawCache) + return { {NoCacheKey}, ValueCache(nullptr) }; + auto resultingCursor = rawCache->findAlongAttrPath(selector); + if (!resultingCursor) + return { {CacheMiss}, ValueCache(nullptr) }; + + auto cachedValue = resultingCursor->getCachedValue(); + auto cacheResult = std::visit( + overloaded{ + [&](tree_cache::attributeSet_t) { return ValueCache::CacheResult{ Forward }; }, + [&](tree_cache::unknown_t) { return ValueCache::CacheResult{ UnCacheable }; }, + [&](tree_cache::thunk_t) { return ValueCache::CacheResult{ CacheMiss }; }, + [&](tree_cache::failed_t x) -> ValueCache::CacheResult {throw EvalError(x.error); }, + [&](tree_cache::missing_t x) { + return ValueCache::CacheResult{ + .returnCode = CacheHit, + .lastQueriedSymbolIfMissing = x.attrName + }; + }, + [&](tree_cache::string_t s) { + PathSet context; + for (auto& [pathName, outputName] : s.second) { + // If the cached value depends on some non-existent + // path, we need to discard it and force the evaluation + // to bring back the context in the store + if (!state.store->isValidPath( + state.store->parseStorePath(pathName))) + return ValueCache::CacheResult{UnCacheable}; + context.insert("!" + outputName + "!" + pathName); + } + mkString(dest, s.first, context); + return ValueCache::CacheResult{CacheHit}; + }, + [&](tree_cache::wrapped_basetype b) { + dest.mkBool(b.value); + return ValueCache::CacheResult{CacheHit}; + }, + [&](tree_cache::wrapped_basetype i) { + dest.mkInt(i.value); + return ValueCache::CacheResult{CacheHit}; + }, + [&](tree_cache::wrapped_basetype d) { + dest.mkFloat(d.value); + return ValueCache::CacheResult{CacheHit}; + }, + }, + cachedValue); + + return { cacheResult, ValueCache(resultingCursor) }; +} + bool EvalState::getAttrField(Value & attrs, const std::vector & selector, const Pos & pos, Value & dest) { Pos * pos2 = 0; + forceValue(attrs, pos); + if (attrs.type() == nAttrs) { + auto eval_cache = attrs.attrs->eval_cache; + auto [ cacheResult, resultingCursor ] = eval_cache.getValue(*this, selector, dest); + switch (cacheResult.returnCode) { + case ValueCache::CacheHit: + return true; + case ValueCache::CacheMiss: + return false; + case ValueCache::Forward: // Fixme: Handle properly + case ValueCache::NoCacheKey: + case ValueCache::UnCacheable: + ; + } + } + Value * vAttrs = &attrs; try { for (auto & name : selector) { diff --git a/src/libexpr/value-cache.hh b/src/libexpr/value-cache.hh new file mode 100644 index 000000000..e36e03ad8 --- /dev/null +++ b/src/libexpr/value-cache.hh @@ -0,0 +1,51 @@ +#pragma once +#include "tree-cache.hh" + +namespace nix { +struct Value; +class EvalState; +class Bindings; + +class ValueCache { + tree_cache::Cursor::Ref rawCache; + +public: + + ValueCache(tree_cache::Cursor::Ref rawCache) : rawCache(rawCache) {} + + const static ValueCache empty; + + bool isEmpty () { return rawCache == nullptr; } + + enum ReturnCode { + // The cache result was an attribute set, so we forward it later in the + // chain + Forward, + CacheMiss, + CacheHit, + UnCacheable, + NoCacheKey, + }; + + struct CacheResult { + ReturnCode returnCode; + + // In case the query returns a `missing_t`, the symbol that's missing + std::optional lastQueriedSymbolIfMissing; + }; + std::pair getValue(EvalState & state, const std::vector & selector, Value & dest); + + ValueCache addChild(const Symbol & attrName, const Value & value); + ValueCache addFailedChild(const Symbol & attrName, const Error & error); + ValueCache addNumChild(SymbolTable & symbols, int idx, const Value & value); + void addAttrSetChilds(Bindings & children); + void addListChilds(SymbolTable & symbols, Value** elems, int listSize); + + std::optional> listChildren(SymbolTable&); + std::optional> listChildrenAtPath(SymbolTable&, const std::vector & attrPath); + + std::optional getRawValue(); + + ValueCache() : rawCache(nullptr) {} +}; +}