forked from lix-project/lix
EvalCache: Store string contexts
This commit is contained in:
parent
b681408879
commit
50f13b06fb
|
@ -12,6 +12,7 @@ create table if not exists Attributes (
|
||||||
name text,
|
name text,
|
||||||
type integer not null,
|
type integer not null,
|
||||||
value text,
|
value text,
|
||||||
|
context text,
|
||||||
primary key (parent, name)
|
primary key (parent, name)
|
||||||
);
|
);
|
||||||
)sql";
|
)sql";
|
||||||
|
@ -22,6 +23,7 @@ struct AttrDb
|
||||||
{
|
{
|
||||||
SQLite db;
|
SQLite db;
|
||||||
SQLiteStmt insertAttribute;
|
SQLiteStmt insertAttribute;
|
||||||
|
SQLiteStmt insertAttributeWithContext;
|
||||||
SQLiteStmt queryAttribute;
|
SQLiteStmt queryAttribute;
|
||||||
SQLiteStmt queryAttributes;
|
SQLiteStmt queryAttributes;
|
||||||
std::unique_ptr<SQLiteTxn> txn;
|
std::unique_ptr<SQLiteTxn> txn;
|
||||||
|
@ -34,7 +36,7 @@ struct AttrDb
|
||||||
{
|
{
|
||||||
auto state(_state->lock());
|
auto state(_state->lock());
|
||||||
|
|
||||||
Path cacheDir = getCacheDir() + "/nix/eval-cache-v1";
|
Path cacheDir = getCacheDir() + "/nix/eval-cache-v2";
|
||||||
createDirs(cacheDir);
|
createDirs(cacheDir);
|
||||||
|
|
||||||
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
Path dbPath = cacheDir + "/" + fingerprint.to_string(Base16, false) + ".sqlite";
|
||||||
|
@ -46,8 +48,11 @@ struct AttrDb
|
||||||
state->insertAttribute.create(state->db,
|
state->insertAttribute.create(state->db,
|
||||||
"insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)");
|
"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,
|
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,
|
state->queryAttributes.create(state->db,
|
||||||
"select name from Attributes where parent = ?");
|
"select name from Attributes where parent = ?");
|
||||||
|
@ -93,15 +98,30 @@ struct AttrDb
|
||||||
|
|
||||||
AttrId setString(
|
AttrId setString(
|
||||||
AttrKey key,
|
AttrKey key,
|
||||||
std::string_view s)
|
std::string_view s,
|
||||||
|
const char * * context = nullptr)
|
||||||
{
|
{
|
||||||
auto state(_state->lock());
|
auto state(_state->lock());
|
||||||
|
|
||||||
|
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()
|
state->insertAttribute.use()
|
||||||
(key.first)
|
(key.first)
|
||||||
(key.second)
|
(key.second)
|
||||||
(AttrType::String)
|
(AttrType::String)
|
||||||
(s).exec();
|
(s).exec();
|
||||||
|
}
|
||||||
|
|
||||||
return state->db.getLastInsertedRowId();
|
return state->db.getLastInsertedRowId();
|
||||||
}
|
}
|
||||||
|
@ -196,8 +216,13 @@ struct AttrDb
|
||||||
attrs.push_back(symbols.create(queryAttributes.getStr(0)));
|
attrs.push_back(symbols.create(queryAttributes.getStr(0)));
|
||||||
return {{rowId, attrs}};
|
return {{rowId, attrs}};
|
||||||
}
|
}
|
||||||
case AttrType::String:
|
case AttrType::String: {
|
||||||
return {{rowId, queryAttribute.getStr(2)}};
|
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:
|
case AttrType::Bool:
|
||||||
return {{rowId, queryAttribute.getInt(2) != 0}};
|
return {{rowId, queryAttribute.getInt(2) != 0}};
|
||||||
case AttrType::Missing:
|
case AttrType::Missing:
|
||||||
|
@ -320,7 +345,7 @@ Value & AttrCursor::forceValue()
|
||||||
|
|
||||||
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
|
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
|
||||||
if (v.type == tString)
|
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)
|
else if (v.type == tPath)
|
||||||
cachedValue = {root->db->setString(getKey(), v.path), v.path};
|
cachedValue = {root->db->setString(getKey(), v.path), v.path};
|
||||||
else if (v.type == tBool)
|
else if (v.type == tBool)
|
||||||
|
@ -427,9 +452,9 @@ std::string AttrCursor::getString()
|
||||||
if (!cachedValue)
|
if (!cachedValue)
|
||||||
cachedValue = root->db->getAttr(getKey(), root->state.symbols);
|
cachedValue = root->db->getAttr(getKey(), root->state.symbols);
|
||||||
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
|
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());
|
debug("using cached string attribute '%s'", getAttrPathStr());
|
||||||
return *s;
|
return s->first;
|
||||||
} else
|
} else
|
||||||
throw TypeError("'%s' is not a string", getAttrPathStr());
|
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;
|
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()
|
bool AttrCursor::getBool()
|
||||||
{
|
{
|
||||||
if (root->db) {
|
if (root->db) {
|
||||||
|
|
|
@ -50,7 +50,17 @@ struct misc_t {};
|
||||||
struct failed_t {};
|
struct failed_t {};
|
||||||
typedef uint64_t AttrId;
|
typedef uint64_t AttrId;
|
||||||
typedef std::pair<AttrId, Symbol> AttrKey;
|
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>
|
class AttrCursor : public std::enable_shared_from_this<AttrCursor>
|
||||||
{
|
{
|
||||||
|
@ -94,6 +104,8 @@ public:
|
||||||
|
|
||||||
std::string getString();
|
std::string getString();
|
||||||
|
|
||||||
|
string_t getStringWithContext();
|
||||||
|
|
||||||
bool getBool();
|
bool getBool();
|
||||||
|
|
||||||
std::vector<Symbol> getAttrs();
|
std::vector<Symbol> getAttrs();
|
||||||
|
|
|
@ -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)
|
void copyContext(const Value & v, PathSet & context)
|
||||||
{
|
{
|
||||||
if (v.string.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 EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
|
||||||
{
|
{
|
||||||
string s = forceString(v, pos);
|
string s = forceString(v, pos);
|
||||||
|
|
|
@ -333,7 +333,7 @@ string showType(const Value & v);
|
||||||
|
|
||||||
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
||||||
name>. */
|
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". */
|
/* If `path' refers to a directory, then append "/default.nix". */
|
||||||
Path resolveExprPath(Path path);
|
Path resolveExprPath(Path path);
|
||||||
|
|
|
@ -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) :
|
InvalidPathError::InvalidPathError(const Path & path) :
|
||||||
EvalError("path '%s' is not valid", path), path(path) {}
|
EvalError("path '%s' is not valid", path), path(path) {}
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,8 @@ struct Value
|
||||||
computation. In particular, function applications are
|
computation. In particular, function applications are
|
||||||
non-trivial. */
|
non-trivial. */
|
||||||
bool isTrivial() const;
|
bool isTrivial() const;
|
||||||
|
|
||||||
|
std::vector<std::pair<Path, std::string>> getContext();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue