forked from lix-project/lix
Properly fail when trying to register an incoherent realisation
This commit is contained in:
parent
a5df669bc6
commit
b8f7177a7b
|
@ -53,6 +53,7 @@ struct LocalStore::State::Stmts {
|
||||||
SQLiteStmt InvalidatePath;
|
SQLiteStmt InvalidatePath;
|
||||||
SQLiteStmt AddDerivationOutput;
|
SQLiteStmt AddDerivationOutput;
|
||||||
SQLiteStmt RegisterRealisedOutput;
|
SQLiteStmt RegisterRealisedOutput;
|
||||||
|
SQLiteStmt UpdateRealisedOutput;
|
||||||
SQLiteStmt QueryValidDerivers;
|
SQLiteStmt QueryValidDerivers;
|
||||||
SQLiteStmt QueryDerivationOutputs;
|
SQLiteStmt QueryDerivationOutputs;
|
||||||
SQLiteStmt QueryRealisedOutput;
|
SQLiteStmt QueryRealisedOutput;
|
||||||
|
@ -345,6 +346,15 @@ LocalStore::LocalStore(const Params & params)
|
||||||
values (?, ?, (select id from ValidPaths where path = ?), ?)
|
values (?, ?, (select id from ValidPaths where path = ?), ?)
|
||||||
;
|
;
|
||||||
)");
|
)");
|
||||||
|
state->stmts->UpdateRealisedOutput.create(state->db,
|
||||||
|
R"(
|
||||||
|
update Realisations
|
||||||
|
set signatures = ?
|
||||||
|
where
|
||||||
|
drvPath = ? and
|
||||||
|
outputName = ?
|
||||||
|
;
|
||||||
|
)");
|
||||||
state->stmts->QueryRealisedOutput.create(state->db,
|
state->stmts->QueryRealisedOutput.create(state->db,
|
||||||
R"(
|
R"(
|
||||||
select Realisations.id, Output.path, Realisations.signatures from Realisations
|
select Realisations.id, Output.path, Realisations.signatures from Realisations
|
||||||
|
@ -710,14 +720,41 @@ void LocalStore::registerDrvOutput(const Realisation & info)
|
||||||
settings.requireExperimentalFeature("ca-derivations");
|
settings.requireExperimentalFeature("ca-derivations");
|
||||||
retrySQLite<void>([&]() {
|
retrySQLite<void>([&]() {
|
||||||
auto state(_state.lock());
|
auto state(_state.lock());
|
||||||
|
if (auto oldR = queryRealisation_(*state, info.id)) {
|
||||||
|
if (info.isCompatibleWith(*oldR)) {
|
||||||
|
auto combinedSignatures = oldR->signatures;
|
||||||
|
combinedSignatures.insert(info.signatures.begin(),
|
||||||
|
info.signatures.end());
|
||||||
|
state->stmts->UpdateRealisedOutput.use()
|
||||||
|
(concatStringsSep(" ", combinedSignatures))
|
||||||
|
(info.id.strHash())
|
||||||
|
(info.id.outputName)
|
||||||
|
.exec();
|
||||||
|
} else {
|
||||||
|
throw Error("Trying to register a realisation of '%s', but we already "
|
||||||
|
"have another one locally",
|
||||||
|
info.id.to_string());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
state->stmts->RegisterRealisedOutput.use()
|
state->stmts->RegisterRealisedOutput.use()
|
||||||
(info.id.strHash())
|
(info.id.strHash())
|
||||||
(info.id.outputName)
|
(info.id.outputName)
|
||||||
(printStorePath(info.outPath))
|
(printStorePath(info.outPath))
|
||||||
(concatStringsSep(" ", info.signatures))
|
(concatStringsSep(" ", info.signatures))
|
||||||
.exec();
|
.exec();
|
||||||
|
}
|
||||||
uint64_t myId = state->db.getLastInsertedRowId();
|
uint64_t myId = state->db.getLastInsertedRowId();
|
||||||
for (auto & [outputId, _] : info.dependentRealisations) {
|
for (auto & [outputId, depPath] : info.dependentRealisations) {
|
||||||
|
auto localRealisation = queryRealisationCore_(*state, outputId);
|
||||||
|
if (!localRealisation)
|
||||||
|
throw Error("unable to register the derivation '%s' as it "
|
||||||
|
"depends on the non existent '%s'",
|
||||||
|
info.id.to_string(), outputId.to_string());
|
||||||
|
if (localRealisation->second.outPath != depPath)
|
||||||
|
throw Error("unable to register the derivation '%s' as it "
|
||||||
|
"depends on a realisation of '%s' that doesn’t"
|
||||||
|
"match what we have locally",
|
||||||
|
info.id.to_string(), outputId.to_string());
|
||||||
state->stmts->AddRealisationReference.use()
|
state->stmts->AddRealisationReference.use()
|
||||||
(myId)
|
(myId)
|
||||||
(outputId.strHash())
|
(outputId.strHash())
|
||||||
|
@ -1734,12 +1771,12 @@ void LocalStore::createUser(const std::string & userName, uid_t userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<const Realisation> LocalStore::queryRealisation(
|
std::optional<std::pair<int64_t, Realisation>> LocalStore::queryRealisationCore_(
|
||||||
const DrvOutput& id) {
|
LocalStore::State & state,
|
||||||
typedef std::optional<const Realisation> Ret;
|
const DrvOutput & id)
|
||||||
return retrySQLite<Ret>([&]() -> Ret {
|
{
|
||||||
auto state(_state.lock());
|
auto useQueryRealisedOutput(
|
||||||
auto useQueryRealisedOutput(state->stmts->QueryRealisedOutput.use()
|
state.stmts->QueryRealisedOutput.use()
|
||||||
(id.strHash())
|
(id.strHash())
|
||||||
(id.outputName));
|
(id.outputName));
|
||||||
if (!useQueryRealisedOutput.next())
|
if (!useQueryRealisedOutput.next())
|
||||||
|
@ -1749,31 +1786,52 @@ std::optional<const Realisation> LocalStore::queryRealisation(
|
||||||
auto signatures =
|
auto signatures =
|
||||||
tokenizeString<StringSet>(useQueryRealisedOutput.getStr(2));
|
tokenizeString<StringSet>(useQueryRealisedOutput.getStr(2));
|
||||||
|
|
||||||
std::map<DrvOutput, StorePath> dependentRealisations;
|
return {{
|
||||||
auto useRealisationRefs(
|
realisationDbId,
|
||||||
state->stmts->QueryRealisationReferences.use()
|
Realisation{
|
||||||
(realisationDbId));
|
|
||||||
while (useRealisationRefs.next()) {
|
|
||||||
auto depHash = useRealisationRefs.getStr(0);
|
|
||||||
auto depOutputName = useRealisationRefs.getStr(1);
|
|
||||||
auto useQueryRealisedOutput(state->stmts->QueryRealisedOutput.use()
|
|
||||||
(depHash)
|
|
||||||
(depOutputName));
|
|
||||||
assert(useQueryRealisedOutput.next());
|
|
||||||
auto outputPath = parseStorePath(useQueryRealisedOutput.getStr(1));
|
|
||||||
auto depId = DrvOutput { Hash::parseAnyPrefixed(depHash), depOutputName };
|
|
||||||
dependentRealisations.insert({depId, outputPath});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ret{Realisation{
|
|
||||||
.id = id,
|
.id = id,
|
||||||
.outPath = outputPath,
|
.outPath = outputPath,
|
||||||
.signatures = signatures,
|
.signatures = signatures,
|
||||||
.dependentRealisations = dependentRealisations,
|
}
|
||||||
}};
|
}};
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<const Realisation> LocalStore::queryRealisation_(
|
||||||
|
LocalStore::State & state,
|
||||||
|
const DrvOutput & id)
|
||||||
|
{
|
||||||
|
auto maybeCore = queryRealisationCore_(state, id);
|
||||||
|
if (!maybeCore)
|
||||||
|
return std::nullopt;
|
||||||
|
auto [realisationDbId, res] = *maybeCore;
|
||||||
|
|
||||||
|
std::map<DrvOutput, StorePath> dependentRealisations;
|
||||||
|
auto useRealisationRefs(
|
||||||
|
state.stmts->QueryRealisationReferences.use()
|
||||||
|
(realisationDbId));
|
||||||
|
while (useRealisationRefs.next()) {
|
||||||
|
auto depId = DrvOutput {
|
||||||
|
Hash::parseAnyPrefixed(useRealisationRefs.getStr(0)),
|
||||||
|
useRealisationRefs.getStr(1),
|
||||||
|
};
|
||||||
|
auto dependentRealisation = queryRealisationCore_(state, depId);
|
||||||
|
assert(dependentRealisation); // Enforced by the db schema
|
||||||
|
auto outputPath = dependentRealisation->second.outPath;
|
||||||
|
dependentRealisations.insert({depId, outputPath});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.dependentRealisations = dependentRealisations;
|
||||||
|
|
||||||
|
return { res };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<const Realisation>
|
||||||
|
LocalStore::queryRealisation(const DrvOutput &id) {
|
||||||
|
return retrySQLite<std::optional<const Realisation>>([&]() {
|
||||||
|
auto state(_state.lock());
|
||||||
|
return queryRealisation_(*state, id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
FixedOutputHash LocalStore::hashCAPath(
|
FixedOutputHash LocalStore::hashCAPath(
|
||||||
const FileIngestionMethod & method, const HashType & hashType,
|
const FileIngestionMethod & method, const HashType & hashType,
|
||||||
|
|
|
@ -203,6 +203,8 @@ public:
|
||||||
void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
|
void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
|
||||||
void cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output);
|
void cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output);
|
||||||
|
|
||||||
|
std::optional<const Realisation> queryRealisation_(State & state, const DrvOutput & id);
|
||||||
|
std::optional<std::pair<int64_t, Realisation>> queryRealisationCore_(State & state, const DrvOutput & id);
|
||||||
std::optional<const Realisation> queryRealisation(const DrvOutput&) override;
|
std::optional<const Realisation> queryRealisation(const DrvOutput&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -140,6 +140,12 @@ StorePath RealisedPath::path() const {
|
||||||
return std::visit([](auto && arg) { return arg.getPath(); }, raw);
|
return std::visit([](auto && arg) { return arg.getPath(); }, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Realisation::isCompatibleWith(const Realisation & other) const
|
||||||
|
{
|
||||||
|
assert (id == other.id);
|
||||||
|
return outPath == other.outPath;
|
||||||
|
}
|
||||||
|
|
||||||
void RealisedPath::closure(
|
void RealisedPath::closure(
|
||||||
Store& store,
|
Store& store,
|
||||||
const RealisedPath::Set& startPaths,
|
const RealisedPath::Set& startPaths,
|
||||||
|
|
|
@ -47,6 +47,8 @@ struct Realisation {
|
||||||
static std::set<Realisation> closure(Store &, const std::set<Realisation> &);
|
static std::set<Realisation> closure(Store &, const std::set<Realisation> &);
|
||||||
static void closure(Store &, const std::set<Realisation> &, std::set<Realisation>& res);
|
static void closure(Store &, const std::set<Realisation> &, std::set<Realisation>& res);
|
||||||
|
|
||||||
|
bool isCompatibleWith(const Realisation & other) const;
|
||||||
|
|
||||||
StorePath getPath() const { return outPath; }
|
StorePath getPath() const { return outPath; }
|
||||||
|
|
||||||
GENERATE_CMP(Realisation, me->id, me->outPath);
|
GENERATE_CMP(Realisation, me->id, me->outPath);
|
||||||
|
|
Loading…
Reference in a new issue