orly/indy/disk/durable_manager.test.cc:183 fails intermittently in CI:
[orly/indy/disk/durable_manager.test.cc, 183](bool)!sem.GetFd().IsReadable(0); !1; fail
end SemFiresOnlyAfterFlush; fail
passed 2, failed 1
Why it is the test, not the product
durable_manager.Save(id, deadline, ttl, blob, &sem);
/* Not yet: the writer flushes on a 300ms cadence, and durability must not be signalled
before the data is written (#277). */
EXPECT_FALSE(sem.GetFd().IsReadable(0));
The assertion is a race by construction. It requires the test thread to reach IsReadable(0) within the 300ms write-delay window. On a loaded runner, if the thread is descheduled for longer than that between Save() and the check, the flush completes, the semaphore fires legitimately, and the test reports a failure for correct behaviour.
So the property it is guarding (#277: durability must not be signalled before the write lands) is real and worth guarding — the encoding of it is what is unsound. It asserts "has not happened yet" using wall-clock luck.
Evidence that it is transient
Same commit tree, three consecutive runs on PR #550:
| run |
new commit contents |
make debug + make test |
| 34921446403 |
prefetch + CI job |
success |
| 34921609238 |
-msse2 removal |
success |
| 34922824232 |
README.md + a changelog fragment only |
fail |
The failing run's only new commit contains no code. The binaries that failed are byte-identical to ones that passed twice. Master's scheduled crons are 18 success / 1 cancelled / 1 null over the last 20.
Why this is worth fixing rather than re-running
It fails in a way that points at the wrong culprit. I hit it on a PR that changes compiler flags and a prefetch intrinsic — the two things most likely to be blamed for a mysterious disk-layer failure — and it cost a full bisect across three runs to establish innocence. The next person gets the same bill, and the standing advice is (rightly) to suspect your own changes before calling anything a flake.
Possible shapes
- Measure, don't assume. Record a timestamp before
Save() and only assert !IsReadable if less than the write delay has actually elapsed; otherwise skip the negative assertion (the positive sem.Pop() + TryLoad checks still run).
- Widen the window. The delay is a constructor argument; a much larger write delay for this one case makes descheduling-sized jitter irrelevant. Cheapest change, keeps the assertion meaningful.
- Assert the ordering directly rather than via a timing proxy — e.g. observe that the sem fires only after the write callback, if the manager exposes a seam for that.
The second is probably the right first move: it preserves exactly what #277 was protecting while removing the dependence on scheduler luck.
orly/indy/disk/durable_manager.test.cc:183fails intermittently in CI:Why it is the test, not the product
The assertion is a race by construction. It requires the test thread to reach
IsReadable(0)within the 300ms write-delay window. On a loaded runner, if the thread is descheduled for longer than that betweenSave()and the check, the flush completes, the semaphore fires legitimately, and the test reports a failure for correct behaviour.So the property it is guarding (#277: durability must not be signalled before the write lands) is real and worth guarding — the encoding of it is what is unsound. It asserts "has not happened yet" using wall-clock luck.
Evidence that it is transient
Same commit tree, three consecutive runs on PR #550:
make debug + make test-msse2removalREADME.md+ a changelog fragment onlyThe failing run's only new commit contains no code. The binaries that failed are byte-identical to ones that passed twice. Master's scheduled crons are 18 success / 1 cancelled / 1 null over the last 20.
Why this is worth fixing rather than re-running
It fails in a way that points at the wrong culprit. I hit it on a PR that changes compiler flags and a prefetch intrinsic — the two things most likely to be blamed for a mysterious disk-layer failure — and it cost a full bisect across three runs to establish innocence. The next person gets the same bill, and the standing advice is (rightly) to suspect your own changes before calling anything a flake.
Possible shapes
Save()and only assert!IsReadableif less than the write delay has actually elapsed; otherwise skip the negative assertion (the positivesem.Pop()+TryLoadchecks still run).The second is probably the right first move: it preserves exactly what #277 was protecting while removing the dependence on scheduler luck.