A SIGKILL mid-write (OOM killer, #106667) can leave state.db with a garbage page-1 header. SQLite refuses the file outright ("file is not a database", SQLITE_NOTADB) and the sqlite3 shell's .recover opens the file like any other client, so the lost_and_found lane failed with the same rc=26 twice although every data page after the header survived. The #106587 quarantine now preserves such a file as state.db.notadb-<ts>-<pid>.bak; this makes that preserved file recoverable with `hermes sessions recover --source <bak> --allow-partial`. When both .recover attempts fail with "not a database", zero the 100-byte header of the lane's private snapshot copy and rerun them. .recover trips only on the magic check and infers page size and layout from the pages themselves, so a zeroed header is enough; a spliced donor header (the PR's original mechanism) instead advertises a database size / freelist that contradicts the file and yields "database disk image is malformed" on a direct open — verified live on a 139-page fixture, which also showed the zeroed header recovers 60/60 sessions and 300/300 messages whether the damage covers 100 bytes or the whole first page. The user's file is never written; the report carries `sqlite3_cli.header_zeroed` and a warning about the WAL boundary. Live repro (sqlite3 shell 3.53.1 on PATH, header overwritten with random bytes): BEFORE "page-level .recover salvage failed: ... file is not a database (26)"; AFTER "Recovered 60 sessions and 300 messages", source md5 unchanged. Salvaged from PR #102808 (intent; trimmed from 302 to ~40 source LOC by dropping the donor-header/page-size sweep and the redundant preopen probe — the shell's own refusal is the detector). Independent review on the PR by @strzhao. Refs #106667 Refs #106587 Reported-by: TaoMasterCoder Cross-referenced-by: kshitijk4poor
3 lines
94 B
Plaintext
3 lines
94 B
Plaintext
TaoMasterCoder
|
|
# PR #102808 salvage (header-damaged state.db in lost_and_found lane; #106667)
|