ww: invalidate partial package commits

This commit is contained in:
2026-08-14 05:12:45 +09:00
parent 402f50ac8d
commit 351f4a25bc
5 changed files with 282 additions and 17 deletions

View File

@@ -5093,6 +5093,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
return 1;
};
let anyfailed: bool = false;
let commitopen: bool = false;
let commitintegrityfailed: bool = false;
producti = 0;
for (producti < nproducts) {
if (g.pkg[products[producti].root].failed) { anyfailed = true; };
@@ -5139,6 +5141,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
};
if (sepdiscardactionstaging(warm, unitnew, wwinew, asmnew,
objnew, anew) < 0) {
if (warm) {
let unitrr: i32 = os.remove(pathstr(unitf));
if (unitrr != 0 && unitrr != -2) {
commitintegrityfailed = true;
};
};
g.pkg[pi].failed = true;
anyfailed = true;
oi += 1;
@@ -5147,6 +5155,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
if (sepcomposeunit(g, pi, cu) < 0) {
sepdiscardactionstaging(warm, unitnew, wwinew, asmnew,
objnew, anew);
if (warm) {
let unitrr: i32 = os.remove(pathstr(unitf));
if (unitrr != 0 && unitrr != -2) {
commitintegrityfailed = true;
};
};
g.pkg[pi].failed = true;
anyfailed = true;
oi += 1;
@@ -5162,7 +5176,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
};
let fresh: bool = false;
if (warm) {
if (!staleall && !depschanged) {
if (!staleall && !depschanged && !commitintegrityfailed) {
fresh = fileequal(unitnew, unitf);
if (fresh) { fresh = fileisreg(asmf); };
if (fresh) { fresh = fileisreg(wwi); };
@@ -5190,6 +5204,22 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
oi += 1;
continue;
};
// Once an action is not reusable, its old unit must not vouch for
// artifacts after a later producer or commit failure. This also makes a
// failed importer retry after a dependency committed a changed export.
if (warm) {
let unitrr: i32 = os.remove(pathstr(unitf));
if (unitrr != 0 && unitrr != -2) {
cerrpath("ww: cannot invalidate package unit ", unitf, "\n");
sepdiscardactionstaging(warm, unitnew, wwinew, asmnew,
objnew, anew);
g.pkg[pi].failed = true;
anyfailed = true;
commitintegrityfailed = true;
oi += 1;
continue;
};
};
{
let rawtest: bool = (istest != 0) && g.pkg[pi].root
&& g.pkg[pi].isdir == 0;
@@ -5378,9 +5408,23 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
continue;
};
};
// Commit order: artifacts before the unit that vouches for
// them, unit strictly last.
// Commit order: artifacts before the unit that vouches for them, unit
// strictly last. Remove the workdir identity before the first artifact
// rename; failure is a pre-commit rejection with old artifacts intact.
if (warm) {
if (!commitopen) {
let stamprr: i32 = os.remove(pathstr(stampf));
if (stamprr != 0 && stamprr != -2) {
cerr("ww: cannot invalidate package workdir\n");
g.pkg[pi].failed = true;
anyfailed = true;
sepdiscardactionstaging(warm, unitnew, wwinew, asmnew,
objnew, anew);
oi += 1;
continue;
};
commitopen = true;
};
let bad: bool = false;
if (os.rename(pathstr(wwinew), pathstr(wwi)) != 0) {
bad = true;
@@ -5418,6 +5462,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
};
g.pkg[pi].failed = true;
anyfailed = true;
// A failed rename sequence may already have replaced the
// interface or another artifact. The stamp is already absent;
// invalidate all vouchers and force later actions through tools.
commitintegrityfailed = true;
invalidateworkdirunits(scratch);
sepdiscardactionstaging(warm, unitnew, wwinew, asmnew,
objnew, anew);
oi += 1;
@@ -5427,9 +5476,10 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
oi += 1;
};
// A stale pass removed every old unit voucher before compiling. Current
// successful units remain safe to vouch for when a sibling root fails;
// a killed pass retains the old identity and invalidates again next time.
if (warm) {
// successful units remain safe when a sibling compiler rejects. A partial
// artifact commit invalidates all vouchers and suppresses the workdir
// identity so the next pass starts stale.
if (warm && !commitintegrityfailed) {
let sametool: bool = fileequal(toolw, selfpath);
if (sepfatalallocation) { return 1; };
if (!sametool) {
@@ -5456,7 +5506,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
};
};
};
if (!stampok) {
if (!stampok || commitopen) {
if (writestampatomic(stampf, stampwant) != 0) {
cerrpath("ww: cannot record ", stampf, "\n");
return 1;