EvalCache: Ignore SQLite errors

Fixes #3794.
This commit is contained in:
Eelco Dolstra 2020-07-14 15:17:38 +02:00
parent 832e111494
commit da3aea291d
2 changed files with 119 additions and 73 deletions

View file

@ -19,6 +19,8 @@ create table if not exists Attributes (
struct AttrDb struct AttrDb
{ {
std::atomic_bool failed{false};
struct State struct State
{ {
SQLite db; SQLite db;
@ -64,36 +66,53 @@ struct AttrDb
{ {
try { try {
auto state(_state->lock()); auto state(_state->lock());
state->txn->commit(); if (!failed)
state->txn->commit();
state->txn.reset(); state->txn.reset();
} catch (...) { } catch (...) {
ignoreException(); ignoreException();
} }
} }
template<typename F>
AttrId doSQLite(F && fun)
{
if (failed) return 0;
try {
return fun();
} catch (SQLiteError &) {
ignoreException();
failed = true;
return 0;
}
}
AttrId setAttrs( AttrId setAttrs(
AttrKey key, AttrKey key,
const std::vector<Symbol> & attrs) const std::vector<Symbol> & attrs)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use()
(key.first)
(key.second)
(AttrType::FullAttrs)
(0, false).exec();
AttrId rowId = state->db.getLastInsertedRowId();
assert(rowId);
for (auto & attr : attrs)
state->insertAttribute.use() state->insertAttribute.use()
(rowId) (key.first)
(attr) (key.second)
(AttrType::Placeholder) (AttrType::FullAttrs)
(0, false).exec(); (0, false).exec();
return rowId; AttrId rowId = state->db.getLastInsertedRowId();
assert(rowId);
for (auto & attr : attrs)
state->insertAttribute.use()
(rowId)
(attr)
(AttrType::Placeholder)
(0, false).exec();
return rowId;
});
} }
AttrId setString( AttrId setString(
@ -101,96 +120,114 @@ struct AttrDb
std::string_view s, std::string_view s,
const char * * context = nullptr) const char * * context = nullptr)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
if (context) { if (context) {
std::string ctx; std::string ctx;
for (const char * * p = context; *p; ++p) { for (const char * * p = context; *p; ++p) {
if (p != context) ctx.push_back(' '); if (p != context) ctx.push_back(' ');
ctx.append(*p); ctx.append(*p);
} }
state->insertAttributeWithContext.use() state->insertAttributeWithContext.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::String) (AttrType::String)
(s) (s)
(ctx).exec(); (ctx).exec();
} else { } 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();
});
} }
AttrId setBool( AttrId setBool(
AttrKey key, AttrKey key,
bool b) bool b)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use() state->insertAttribute.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::Bool) (AttrType::Bool)
(b ? 1 : 0).exec(); (b ? 1 : 0).exec();
return state->db.getLastInsertedRowId(); return state->db.getLastInsertedRowId();
});
} }
AttrId setPlaceholder(AttrKey key) AttrId setPlaceholder(AttrKey key)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use() state->insertAttribute.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::Placeholder) (AttrType::Placeholder)
(0, false).exec(); (0, false).exec();
return state->db.getLastInsertedRowId(); return state->db.getLastInsertedRowId();
});
} }
AttrId setMissing(AttrKey key) AttrId setMissing(AttrKey key)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use() state->insertAttribute.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::Missing) (AttrType::Missing)
(0, false).exec(); (0, false).exec();
return state->db.getLastInsertedRowId(); return state->db.getLastInsertedRowId();
});
} }
AttrId setMisc(AttrKey key) AttrId setMisc(AttrKey key)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use() state->insertAttribute.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::Misc) (AttrType::Misc)
(0, false).exec(); (0, false).exec();
return state->db.getLastInsertedRowId(); return state->db.getLastInsertedRowId();
});
} }
AttrId setFailed(AttrKey key) AttrId setFailed(AttrKey key)
{ {
auto state(_state->lock()); return doSQLite([&]()
{
auto state(_state->lock());
state->insertAttribute.use() state->insertAttribute.use()
(key.first) (key.first)
(key.second) (key.second)
(AttrType::Failed) (AttrType::Failed)
(0, false).exec(); (0, false).exec();
return state->db.getLastInsertedRowId(); return state->db.getLastInsertedRowId();
});
} }
std::optional<std::pair<AttrId, AttrValue>> getAttr( std::optional<std::pair<AttrId, AttrValue>> getAttr(
@ -237,12 +274,22 @@ struct AttrDb
} }
}; };
static std::shared_ptr<AttrDb> makeAttrDb(const Hash & fingerprint)
{
try {
return std::make_shared<AttrDb>(fingerprint);
} catch (SQLiteError &) {
ignoreException();
return nullptr;
}
}
EvalCache::EvalCache( EvalCache::EvalCache(
bool useCache, bool useCache,
const Hash & fingerprint, const Hash & fingerprint,
EvalState & state, EvalState & state,
RootLoader rootLoader) RootLoader rootLoader)
: db(useCache ? std::make_shared<AttrDb>(fingerprint) : nullptr) : db(useCache ? makeAttrDb(fingerprint) : nullptr)
, state(state) , state(state)
, rootLoader(rootLoader) , rootLoader(rootLoader)
{ {

View file

@ -63,7 +63,6 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
debug("got tree '%s' from '%s'", debug("got tree '%s' from '%s'",
state.store->printStorePath(tree.storePath), lockedRef); state.store->printStorePath(tree.storePath), lockedRef);
if (state.allowedPaths) if (state.allowedPaths)
state.allowedPaths->insert(tree.actualPath); state.allowedPaths->insert(tree.actualPath);