aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-06-29 19:08:37 +0200
committerEelco Dolstra <edolstra@gmail.com>2020-06-29 19:08:37 +0200
commit50f13b06fb1b2f50a97323c000d1094d090f08ea (patch)
tree6b99e97ffc6bac40f67d1e83cec8e5eef68cc4a1 /src
parentb681408879c9ad1e500fa6e4566c6d119def4271 (diff)
EvalCache: Store string contexts
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval-cache.cc75
-rw-r--r--src/libexpr/eval-cache.hh14
-rw-r--r--src/libexpr/eval.cc23
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/primops.cc12
-rw-r--r--src/libexpr/value.hh2
6 files changed, 101 insertions, 27 deletions
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index 3a18b71d4..65a3fceeb 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -12,6 +12,7 @@ create table if not exists Attributes (
name text,
type integer not null,
value text,
+ context text,
primary key (parent, name)
);
)sql";
@@ -22,6 +23,7 @@ struct AttrDb
{
SQLite db;
SQLiteStmt insertAttribute;
+ SQLiteStmt insertAttributeWithContext;
SQLiteStmt queryAttribute;
SQLiteStmt queryAttributes;
std::unique_ptr<SQLiteTxn> txn;
@@ -34,7 +36,7 @@ struct AttrDb
{
auto state(_state->lock());
- Path cacheDir = getCacheDir() + "/nix/eval-cache-v1";
+ Path cacheDir = getCacheDir() + "/nix/eval-cache-v2";
createDirs(cacheDir);
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
@@ -46,8 +48,11 @@ struct AttrDb
state->insertAttribute.create(state->db,
"insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)");
+ state->insertAttributeWithContext.create(state->db,
+ "insert or replace into Attributes(parent, name, type, value, context) values (?, ?, ?, ?, ?)");
+
state->queryAttribute.create(state->db,
- "select rowid, type, value from Attributes where parent = ? and name = ?");
+ "select rowid, type, value, context from Attributes where parent = ? and name = ?");
state->queryAttributes.create(state->db,
"select name from Attributes where parent = ?");
@@ -93,15 +98,30 @@ struct AttrDb
AttrId setString(
AttrKey key,
- std::string_view s)
+ std::string_view s,
+ const char * * context = nullptr)
{
auto state(_state->lock());
- state->insertAttribute.use()
- (key.first)
- (key.second)
- (AttrType::String)
- (s).exec();
+ if (context) {
+ std::string ctx;
+ for (const char * * p = context; *p; ++p) {
+ if (p != context) ctx.push_back(' ');
+ ctx.append(*p);
+ }
+ state->insertAttributeWithContext.use()
+ (key.first)
+ (key.second)
+ (AttrType::String)
+ (s)
+ (ctx).exec();
+ } else {
+ state->insertAttribute.use()
+ (key.first)
+ (key.second)
+ (AttrType::String)
+ (s).exec();
+ }
return state->db.getLastInsertedRowId();
}
@@ -196,8 +216,13 @@ struct AttrDb
attrs.push_back(symbols.create(queryAttributes.getStr(0)));
return {{rowId, attrs}};
}
- case AttrType::String:
- return {{rowId, queryAttribute.getStr(2)}};
+ case AttrType::String: {
+ std::vector<std::pair<Path, std::string>> context;
+ if (!queryAttribute.isNull(3))
+ for (auto & s : tokenizeString<std::vector<std::string>>(queryAttribute.getStr(3), ";"))
+ context.push_back(decodeContext(s));
+ return {{rowId, string_t{queryAttribute.getStr(2), context}}};
+ }
case AttrType::Bool:
return {{rowId, queryAttribute.getInt(2) != 0}};
case AttrType::Missing:
@@ -320,7 +345,7 @@ Value & AttrCursor::forceValue()
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
if (v.type == tString)
- cachedValue = {root->db->setString(getKey(), v.string.s), v.string.s};
+ cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), v.string.s};
else if (v.type == tPath)
cachedValue = {root->db->setString(getKey(), v.path), v.path};
else if (v.type == tBool)
@@ -427,9 +452,9 @@ std::string AttrCursor::getString()
if (!cachedValue)
cachedValue = root->db->getAttr(getKey(), root->state.symbols);
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
- if (auto s = std::get_if<std::string>(&cachedValue->second)) {
+ if (auto s = std::get_if<string_t>(&cachedValue->second)) {
debug("using cached string attribute '%s'", getAttrPathStr());
- return *s;
+ return s->first;
} else
throw TypeError("'%s' is not a string", getAttrPathStr());
}
@@ -443,6 +468,30 @@ std::string AttrCursor::getString()
return v.type == tString ? v.string.s : v.path;
}
+string_t AttrCursor::getStringWithContext()
+{
+ if (root->db) {
+ if (!cachedValue)
+ cachedValue = root->db->getAttr(getKey(), root->state.symbols);
+ 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;
+ } else
+ throw TypeError("'%s' is not a string", getAttrPathStr());
+ }
+ }
+
+ auto & v = forceValue();
+
+ if (v.type == tString)
+ return {v.string.s, v.getContext()};
+ else if (v.type == tPath)
+ return {v.path, {}};
+ else
+ throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type));
+}
+
bool AttrCursor::getBool()
{
if (root->db) {
diff --git a/src/libexpr/eval-cache.hh b/src/libexpr/eval-cache.hh
index 30261fd3a..674bb03c1 100644
--- a/src/libexpr/eval-cache.hh
+++ b/src/libexpr/eval-cache.hh
@@ -50,7 +50,17 @@ struct misc_t {};
struct failed_t {};
typedef uint64_t AttrId;
typedef std::pair<AttrId, Symbol> AttrKey;
-typedef std::variant<std::vector<Symbol>, std::string, placeholder_t, missing_t, misc_t, failed_t, bool> AttrValue;
+typedef std::pair<std::string, std::vector<std::pair<Path, std::string>>> string_t;
+
+typedef std::variant<
+ std::vector<Symbol>,
+ string_t,
+ placeholder_t,
+ missing_t,
+ misc_t,
+ failed_t,
+ bool
+ > AttrValue;
class AttrCursor : public std::enable_shared_from_this<AttrCursor>
{
@@ -94,6 +104,8 @@ public:
std::string getString();
+ string_t getStringWithContext();
+
bool getBool();
std::vector<Symbol> getAttrs();
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 5db380f88..ba600ad0c 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1607,6 +1607,18 @@ string EvalState::forceString(Value & v, const Pos & pos)
}
+/* Decode a context string ‘!<name>!<path>’ into a pair <path,
+ name>. */
+std::pair<string, string> decodeContext(std::string_view s)
+{
+ if (s.at(0) == '!') {
+ size_t index = s.find("!", 1);
+ return {std::string(s.substr(index + 1)), std::string(s.substr(1, index - 1))};
+ } else
+ return {s.at(0) == '/' ? std::string(s) : std::string(s.substr(1)), ""};
+}
+
+
void copyContext(const Value & v, PathSet & context)
{
if (v.string.context)
@@ -1615,6 +1627,17 @@ void copyContext(const Value & v, PathSet & context)
}
+std::vector<std::pair<Path, std::string>> Value::getContext()
+{
+ std::vector<std::pair<Path, std::string>> res;
+ assert(type == tString);
+ if (string.context)
+ for (const char * * p = string.context; *p; ++p)
+ res.push_back(decodeContext(*p));
+ return res;
+}
+
+
string EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
{
string s = forceString(v, pos);
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index be34f3f32..87bb42c11 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -333,7 +333,7 @@ string showType(const Value & v);
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
name>. */
-std::pair<string, string> decodeContext(const string & s);
+std::pair<string, string> decodeContext(std::string_view s);
/* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 3830d8107..96c20b227 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -30,18 +30,6 @@ namespace nix {
*************************************************************/
-/* Decode a context string ‘!<name>!<path>’ into a pair <path,
- name>. */
-std::pair<string, string> decodeContext(const string & s)
-{
- if (s.at(0) == '!') {
- size_t index = s.find("!", 1);
- return std::pair<string, string>(string(s, index + 1), string(s, 1, index - 1));
- } else
- return std::pair<string, string>(s.at(0) == '/' ? s : string(s, 1), "");
-}
-
-
InvalidPathError::InvalidPathError(const Path & path) :
EvalError("path '%s' is not valid", path), path(path) {}
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 1a0738241..fe11bb2ed 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -171,6 +171,8 @@ struct Value
computation. In particular, function applications are
non-trivial. */
bool isTrivial() const;
+
+ std::vector<std::pair<Path, std::string>> getContext();
};