no power loss

This commit is contained in:
Andras Schmelczer 2026-09-21 21:29:56 +01:00
commit 2fcdbfd27d
4 changed files with 1374 additions and 3676 deletions

View file

@ -74,7 +74,7 @@ Network retry timers remain enabled. Separate fake-clock tests in
A barrier checks byte-for-byte replica equality **and** the server's canonical
UUID/path map, file bytes, independently computed base/observed hashes, content
and manifest CAS parents, event watermark,
contiguous event log, and absence of pending requests/application journals.
contiguous event log, and absence of pending requests.
Internal recovery files are excluded from the user-visible file list, but are
present in failure disk images. Scenario assertions separately check intended
content, document identity, or preservation markers; equality alone is not an
@ -106,8 +106,8 @@ distinct UUIDs at one path.
- `wait-for-response-drop`: explicit checkpoint; every armed fault must fire.
Every interrupted request must be retried with an identical request ID, target
and body before a different CAS is sent. Fault kinds match exactly.
- `rename-next-write`: inject an editor rename after the engine's durable install
rename. The historical name is retained for fixtures; v4 never writes in place.
- `rename-next-write`: inject an editor rename after the engine's content write,
before its metadata save.
- `pause-server`, `resume-server`: SIGSTOP/SIGCONT, not a crash.
- `crash-server`, `restart-server`: SIGKILL and restart with the same database/port.
Server-control scenarios have dedicated processes.

View file

@ -43,12 +43,8 @@ export class DeterministicAgent {
});
this.disk.boundary = async (label) => {
const rename = this.nextWriteRename;
// v4 installs through an exclusive rename, never write-in-place.
if (
rename &&
label.startsWith("durable:rename:") &&
label.endsWith(`->${rename.oldPath}`)
) {
// Inject after the content write, before the metadata save.
if (rename && label === `durable:write:${rename.oldPath}`) {
this.nextWriteRename = undefined;
await this.rename(rename.oldPath, rename.newPath);
}

View file

@ -13,10 +13,8 @@ export const sameDocIdCollapseAfterRemoteQuickWriteAndPendingRenameTest: TestDef
steps: [
{ type: "enable-sync", client: 0 },
// Create a deleted latest version before client 1 joins.
// Catch-up will advance MinCovered with a non-contiguous id,
// keeping client 1's create lastSeen low enough to exercise
// the server's same-doc merge path from the e2e failure.
// Seed a deleted document before client 1 bootstraps. Later creates
// at the reused path must still receive separate identities.
{
type: "create",
client: 0,

View file

@ -33,11 +33,8 @@ export const selfMergePendingRenameAliasesSecondCreateTest: TestDefinition = {
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
// Pause client 0's WS so its MinCovered watermark stays at 0
// through the whole bug sequence. The merge condition the
// server is going to fire is `creation_vuid > last_seen`; with
// a non-zero gap the same-device second create gets merged
// into the same-device first create.
// Delay socket notifications while client 0 continues local work.
// HTTP catchup must preserve the two generations at the reused path.
{ type: "pause-websocket", client: 0 },
// Client 1 commits a doc to push the server's vuid above 0.