aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/eval-cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/eval-cache.cc')
-rw-r--r--src/libexpr/eval-cache.cc201
1 files changed, 150 insertions, 51 deletions
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index 7d3fd01a4..afe575fee 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -35,13 +35,19 @@ struct AttrDb
std::unique_ptr<Sync<State>> _state;
- AttrDb(const Store & cfg, const Hash & fingerprint)
+ SymbolTable & symbols;
+
+ AttrDb(
+ const Store & cfg,
+ const Hash & fingerprint,
+ SymbolTable & symbols)
: cfg(cfg)
, _state(std::make_unique<Sync<State>>())
+ , symbols(symbols)
{
auto state(_state->lock());
- Path cacheDir = getCacheDir() + "/nix/eval-cache-v2";
+ Path cacheDir = getCacheDir() + "/nix/eval-cache-v4";
createDirs(cacheDir);
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
@@ -100,7 +106,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::FullAttrs)
(0, false).exec();
@@ -110,7 +116,7 @@ struct AttrDb
for (auto & attr : attrs)
state->insertAttribute.use()
(rowId)
- (attr)
+ (symbols[attr])
(AttrType::Placeholder)
(0, false).exec();
@@ -135,14 +141,14 @@ struct AttrDb
}
state->insertAttributeWithContext.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::String)
(s)
(ctx).exec();
} else {
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::String)
(s).exec();
}
@@ -161,7 +167,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::Bool)
(b ? 1 : 0).exec();
@@ -169,6 +175,42 @@ struct AttrDb
});
}
+ AttrId setInt(
+ AttrKey key,
+ int n)
+ {
+ return doSQLite([&]()
+ {
+ auto state(_state->lock());
+
+ state->insertAttribute.use()
+ (key.first)
+ (symbols[key.second])
+ (AttrType::Int)
+ (n).exec();
+
+ return state->db.getLastInsertedRowId();
+ });
+ }
+
+ AttrId setListOfStrings(
+ AttrKey key,
+ const std::vector<std::string> & l)
+ {
+ return doSQLite([&]()
+ {
+ auto state(_state->lock());
+
+ state->insertAttribute.use()
+ (key.first)
+ (symbols[key.second])
+ (AttrType::ListOfStrings)
+ (concatStringsSep("\t", l)).exec();
+
+ return state->db.getLastInsertedRowId();
+ });
+ }
+
AttrId setPlaceholder(AttrKey key)
{
return doSQLite([&]()
@@ -177,7 +219,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::Placeholder)
(0, false).exec();
@@ -193,7 +235,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::Missing)
(0, false).exec();
@@ -209,7 +251,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::Misc)
(0, false).exec();
@@ -225,7 +267,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
- (key.second)
+ (symbols[key.second])
(AttrType::Failed)
(0, false).exec();
@@ -233,16 +275,14 @@ struct AttrDb
});
}
- std::optional<std::pair<AttrId, AttrValue>> getAttr(
- AttrKey key,
- SymbolTable & symbols)
+ std::optional<std::pair<AttrId, AttrValue>> getAttr(AttrKey key)
{
auto state(_state->lock());
- auto queryAttribute(state->queryAttribute.use()(key.first)(key.second));
+ auto queryAttribute(state->queryAttribute.use()(key.first)(symbols[key.second]));
if (!queryAttribute.next()) return {};
- auto rowId = (AttrType) queryAttribute.getInt(0);
+ auto rowId = (AttrId) queryAttribute.getInt(0);
auto type = (AttrType) queryAttribute.getInt(1);
switch (type) {
@@ -253,7 +293,7 @@ struct AttrDb
std::vector<Symbol> attrs;
auto queryAttributes(state->queryAttributes.use()(rowId));
while (queryAttributes.next())
- attrs.push_back(symbols.create(queryAttributes.getStr(0)));
+ attrs.emplace_back(symbols.create(queryAttributes.getStr(0)));
return {{rowId, attrs}};
}
case AttrType::String: {
@@ -265,6 +305,10 @@ struct AttrDb
}
case AttrType::Bool:
return {{rowId, queryAttribute.getInt(2) != 0}};
+ case AttrType::Int:
+ return {{rowId, int_t{queryAttribute.getInt(2)}}};
+ case AttrType::ListOfStrings:
+ return {{rowId, tokenizeString<std::vector<std::string>>(queryAttribute.getStr(2), "\t")}};
case AttrType::Missing:
return {{rowId, missing_t()}};
case AttrType::Misc:
@@ -277,10 +321,13 @@ struct AttrDb
}
};
-static std::shared_ptr<AttrDb> makeAttrDb(const Store & cfg, const Hash & fingerprint)
+static std::shared_ptr<AttrDb> makeAttrDb(
+ const Store & cfg,
+ const Hash & fingerprint,
+ SymbolTable & symbols)
{
try {
- return std::make_shared<AttrDb>(cfg, fingerprint);
+ return std::make_shared<AttrDb>(cfg, fingerprint, symbols);
} catch (SQLiteError &) {
ignoreException();
return nullptr;
@@ -291,7 +338,7 @@ EvalCache::EvalCache(
std::optional<std::reference_wrapper<const Hash>> useCache,
EvalState & state,
RootLoader rootLoader)
- : db(useCache ? makeAttrDb(*state.store, *useCache) : nullptr)
+ : db(useCache ? makeAttrDb(*state.store, *useCache, state.symbols) : nullptr)
, state(state)
, rootLoader(rootLoader)
{
@@ -327,8 +374,7 @@ AttrKey AttrCursor::getKey()
if (!parent)
return {0, root->state.sEpsilon};
if (!parent->first->cachedValue) {
- parent->first->cachedValue = root->db->getAttr(
- parent->first->getKey(), root->state.symbols);
+ parent->first->cachedValue = root->db->getAttr(parent->first->getKey());
assert(parent->first->cachedValue);
}
return {parent->first->cachedValue->first, parent->second};
@@ -339,7 +385,7 @@ Value & AttrCursor::getValue()
if (!_value) {
if (parent) {
auto & vParent = parent->first->getValue();
- root->state.forceAttrs(vParent, noPos);
+ root->state.forceAttrs(vParent, noPos, "while searching for an attribute");
auto attr = vParent.attrs->get(parent->second);
if (!attr)
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
@@ -369,17 +415,17 @@ std::vector<Symbol> AttrCursor::getAttrPath(Symbol name) const
std::string AttrCursor::getAttrPathStr() const
{
- return concatStringsSep(".", getAttrPath());
+ return concatStringsSep(".", root->state.symbols.resolve(getAttrPath()));
}
std::string AttrCursor::getAttrPathStr(Symbol name) const
{
- return concatStringsSep(".", getAttrPath(name));
+ return concatStringsSep(".", root->state.symbols.resolve(getAttrPath(name)));
}
Value & AttrCursor::forceValue()
{
- debug("evaluating uncached attribute %s", getAttrPathStr());
+ debug("evaluating uncached attribute '%s'", getAttrPathStr());
auto & v = getValue();
@@ -400,6 +446,8 @@ Value & AttrCursor::forceValue()
cachedValue = {root->db->setString(getKey(), v.path), string_t{v.path, {}}};
else if (v.type() == nBool)
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
+ else if (v.type() == nInt)
+ cachedValue = {root->db->setInt(getKey(), v.integer), int_t{v.integer}};
else if (v.type() == nAttrs)
; // FIXME: do something?
else
@@ -414,31 +462,31 @@ Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
auto attrNames = getAttrs();
std::set<std::string> strAttrNames;
for (auto & name : attrNames)
- strAttrNames.insert(std::string(name));
+ strAttrNames.insert(root->state.symbols[name]);
- return Suggestions::bestMatches(strAttrNames, name);
+ return Suggestions::bestMatches(strAttrNames, root->state.symbols[name]);
}
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
{
if (root->db) {
if (!cachedValue)
- cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ cachedValue = root->db->getAttr(getKey());
if (cachedValue) {
if (auto attrs = std::get_if<std::vector<Symbol>>(&cachedValue->second)) {
for (auto & attr : *attrs)
if (attr == name)
- return std::make_shared<AttrCursor>(root, std::make_pair(shared_from_this(), name));
+ return std::make_shared<AttrCursor>(root, std::make_pair(shared_from_this(), attr));
return nullptr;
} else if (std::get_if<placeholder_t>(&cachedValue->second)) {
- auto attr = root->db->getAttr({cachedValue->first, name}, root->state.symbols);
+ auto attr = root->db->getAttr({cachedValue->first, name});
if (attr) {
if (std::get_if<missing_t>(&attr->second))
return nullptr;
else if (std::get_if<failed_t>(&attr->second)) {
if (forceErrors)
- debug("reevaluating failed cached attribute '%s'");
+ debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name));
else
throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name));
} else
@@ -459,11 +507,6 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
return nullptr;
//throw TypeError("'%s' is not an attribute set", getAttrPathStr());
- for (auto & attr : *v.attrs) {
- if (root->db)
- root->db->setPlaceholder({cachedValue->first, attr.name});
- }
-
auto attr = v.attrs->get(name);
if (!attr) {
@@ -522,20 +565,20 @@ std::string AttrCursor::getString()
{
if (root->db) {
if (!cachedValue)
- cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ cachedValue = root->db->getAttr(getKey());
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
if (auto s = std::get_if<string_t>(&cachedValue->second)) {
debug("using cached string attribute '%s'", getAttrPathStr());
return s->first;
} else
- throw TypeError("'%s' is not a string", getAttrPathStr());
+ root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow<TypeError>();
}
}
auto & v = forceValue();
if (v.type() != nString && v.type() != nPath)
- throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()));
+ root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
return v.type() == nString ? v.string.s : v.path;
}
@@ -544,7 +587,7 @@ string_t AttrCursor::getStringWithContext()
{
if (root->db) {
if (!cachedValue)
- cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ cachedValue = root->db->getAttr(getKey());
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
if (auto s = std::get_if<string_t>(&cachedValue->second)) {
bool valid = true;
@@ -559,7 +602,7 @@ string_t AttrCursor::getStringWithContext()
return *s;
}
} else
- throw TypeError("'%s' is not a string", getAttrPathStr());
+ root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow<TypeError>();
}
}
@@ -570,55 +613,111 @@ string_t AttrCursor::getStringWithContext()
else if (v.type() == nPath)
return {v.path, {}};
else
- throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()));
+ root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
}
bool AttrCursor::getBool()
{
if (root->db) {
if (!cachedValue)
- cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ cachedValue = root->db->getAttr(getKey());
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
if (auto b = std::get_if<bool>(&cachedValue->second)) {
debug("using cached Boolean attribute '%s'", getAttrPathStr());
return *b;
} else
- throw TypeError("'%s' is not a Boolean", getAttrPathStr());
+ root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow<TypeError>();
}
}
auto & v = forceValue();
if (v.type() != nBool)
- throw TypeError("'%s' is not a Boolean", getAttrPathStr());
+ root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow<TypeError>();
return v.boolean;
}
+NixInt AttrCursor::getInt()
+{
+ if (root->db) {
+ if (!cachedValue)
+ cachedValue = root->db->getAttr(getKey());
+ if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
+ if (auto i = std::get_if<int_t>(&cachedValue->second)) {
+ debug("using cached integer attribute '%s'", getAttrPathStr());
+ return i->x;
+ } else
+ throw TypeError("'%s' is not an integer", getAttrPathStr());
+ }
+ }
+
+ auto & v = forceValue();
+
+ if (v.type() != nInt)
+ throw TypeError("'%s' is not an integer", getAttrPathStr());
+
+ return v.integer;
+}
+
+std::vector<std::string> AttrCursor::getListOfStrings()
+{
+ if (root->db) {
+ if (!cachedValue)
+ cachedValue = root->db->getAttr(getKey());
+ if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
+ if (auto l = std::get_if<std::vector<std::string>>(&cachedValue->second)) {
+ debug("using cached list of strings attribute '%s'", getAttrPathStr());
+ return *l;
+ } else
+ throw TypeError("'%s' is not a list of strings", getAttrPathStr());
+ }
+ }
+
+ debug("evaluating uncached attribute '%s'", getAttrPathStr());
+
+ auto & v = getValue();
+ root->state.forceValue(v, noPos);
+
+ if (v.type() != nList)
+ throw TypeError("'%s' is not a list", getAttrPathStr());
+
+ std::vector<std::string> res;
+
+ for (auto & elem : v.listItems())
+ res.push_back(std::string(root->state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching")));
+
+ if (root->db)
+ cachedValue = {root->db->setListOfStrings(getKey(), res), res};
+
+ return res;
+}
+
std::vector<Symbol> AttrCursor::getAttrs()
{
if (root->db) {
if (!cachedValue)
- cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ cachedValue = root->db->getAttr(getKey());
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
if (auto attrs = std::get_if<std::vector<Symbol>>(&cachedValue->second)) {
debug("using cached attrset attribute '%s'", getAttrPathStr());
return *attrs;
} else
- throw TypeError("'%s' is not an attribute set", getAttrPathStr());
+ root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow<TypeError>();
}
}
auto & v = forceValue();
if (v.type() != nAttrs)
- throw TypeError("'%s' is not an attribute set", getAttrPathStr());
+ root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow<TypeError>();
std::vector<Symbol> attrs;
for (auto & attr : *getValue().attrs)
attrs.push_back(attr.name);
- std::sort(attrs.begin(), attrs.end(), [](const Symbol & a, const Symbol & b) {
- return (const std::string &) a < (const std::string &) b;
+ std::sort(attrs.begin(), attrs.end(), [&](Symbol a, Symbol b) {
+ std::string_view sa = root->state.symbols[a], sb = root->state.symbols[b];
+ return sa < sb;
});
if (root->db)