forked from lix-project/lix
Fix the gc with indirect self-references via the realisations
If the derivation `foo` depends on `bar`, and they both have the same output path (because they are CA derivations), then this output path will depend both on the realisation of `foo` and of `bar`, which themselves depend on each other. This confuses SQLite which isn’t able to automatically solve this diamond dependency scheme. Help it by adding a trigger to delete all the references between the relevant realisations. Fix #5320
This commit is contained in:
parent
6ada496311
commit
92656da0b9
|
@ -13,6 +13,19 @@ create table if not exists Realisations (
|
||||||
|
|
||||||
create index if not exists IndexRealisations on Realisations(drvPath, outputName);
|
create index if not exists IndexRealisations on Realisations(drvPath, outputName);
|
||||||
|
|
||||||
|
-- We can end-up in a weird edge-case where a path depends on itself because
|
||||||
|
-- it’s an output of a CA derivation, that happens to be the same as one of its
|
||||||
|
-- dependencies.
|
||||||
|
-- In that case we have a dependency loop (path -> realisation1 -> realisation2
|
||||||
|
-- -> path) that we need to break by removing the dependencies between the
|
||||||
|
-- realisations
|
||||||
|
create trigger if not exists DeleteSelfRefsViaRealisations before delete on ValidPaths
|
||||||
|
begin
|
||||||
|
delete from RealisationsRefs where realisationReference = (
|
||||||
|
select id from Realisations where outputPath = old.id
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
create table if not exists RealisationsRefs (
|
create table if not exists RealisationsRefs (
|
||||||
referrer integer not null,
|
referrer integer not null,
|
||||||
realisationReference integer,
|
realisationReference integer,
|
||||||
|
|
|
@ -81,7 +81,7 @@ int getSchema(Path schemaPath)
|
||||||
|
|
||||||
void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
||||||
{
|
{
|
||||||
const int nixCASchemaVersion = 3;
|
const int nixCASchemaVersion = 4;
|
||||||
int curCASchema = getSchema(schemaPath);
|
int curCASchema = getSchema(schemaPath);
|
||||||
if (curCASchema != nixCASchemaVersion) {
|
if (curCASchema != nixCASchemaVersion) {
|
||||||
if (curCASchema > nixCASchemaVersion) {
|
if (curCASchema > nixCASchemaVersion) {
|
||||||
|
@ -143,6 +143,19 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
||||||
)");
|
)");
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
if (curCASchema < 4) {
|
||||||
|
SQLiteTxn txn(db);
|
||||||
|
db.exec(R"(
|
||||||
|
create trigger if not exists DeleteSelfRefsViaRealisations before delete on ValidPaths
|
||||||
|
begin
|
||||||
|
delete from RealisationsRefs where realisationReference = (
|
||||||
|
select id from Realisations where outputPath = old.id
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
)");
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
|
writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
|
||||||
lockFile(lockFd.get(), ltRead, true);
|
lockFile(lockFd.get(), ltRead, true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue