Skip to content

test(coverage): C driver for cold btree/db recover handlers (irep/root/rcuradj/ovref) - #91

Closed
gburd wants to merge 2 commits into
masterfrom
agent/recover-cdriver
Closed

test(coverage): C driver for cold btree/db recover handlers (irep/root/rcuradj/ovref)#91
gburd wants to merge 2 commits into
masterfrom
agent/recover-cdriver

Conversation

@gburd

@gburd gburd commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

What

Adds test/db/recd_handlers.c, a standalone C driver (modeled on
recd_compact.c from PR #82) that produces log records for four
per-operation recovery handlers the Tcl recd0NN suite never reaches, then
replays them under recovery. PR #89's COV_RECD note already flagged these as
still-cold: recd003 "does NOT unlock the cold __bam_root/__bam_irep/
__bam_rcuradj or __db_ovref handlers (they need scenarios no bounded recd
test hits)."

Handler File Trigger the driver builds
__bam_root_recover bt_rec.c create a sub-database under a txn → __bam_root (root page set on file meta page). commit → REDO, abort → UNDO
__bam_irep_recover bt_rec.c compaction of a deep multi-level btree (front-of-keyspace deletes) → __bam_pupdate → __bam_pinsert(BPI_REPLACE) → __bam_irep. (BPI_UPDATE/__bam_pupdate is only ever driven by compaction; plain delete uses BTD_RELINK.) commit + fatal recover → REDO
__bam_rcuradj_recover bt_rec.c rrecno (DB_RENUMBER) cursor adjust logged under a child txn (CURADJ_LOG needs txn->parent != NULL), with a 2nd cursor parked so nc > 0, then abort the child txn (handler acts only on DB_TXN_ABORT)
__db_ovref_recover db_rec.c DB->truncate() of a btree with overflow items → __db_ovref(-1) per overflow page (db_reclaim.c __db_truncate_callback). commit → REDO, abort → UNDO

Each scenario verifies DB integrity after recovery. Hard SIGALRM guard,
self-cleaning home dir, ~9s total. Wired into the COV_BACKUP driver block
(default on) next to recd_compact, and documented in the coverage README.

Coverage result (measured, CC="gcc --coverage", driver alone)

Baseline (no run): all five target handlers at 0 calls (no .gcda).
After recd_handlers:

bt_rec.c  __bam_irep_recover     exec=4790  branch 60.0%   (was 0)
bt_rec.c  __bam_root_recover     exec=5     branch 52.9%   (was 0)
bt_rec.c  __bam_rcuradj_recover  exec=3     branch 74.2%   (was 0)
db_rec.c  __db_ovref_recover     exec=680   branch 68.0%   (was 0)
db_rec.c  __db_cksum_recover     exec=0     branch  0.0%   (still 0 -- see below)

Driver-alone file totals: bt_rec.c 14.7% br / db_rec.c 30.0% br. These
handlers were fully cold before; the driver takes 4 of the 5 flagged handlers
from 0 calls → covered (both REDO and UNDO paths where applicable).

Not covered (documented): __db_cksum_recover

Its __db_cksum marker record is only logged when a checksum error is
detected on a page-in with logging enabled (db_conv.c:161). On the recovery
pass, the redo of the records that built that page re-reads the
still-corrupt page and panics (pgin failed for page N) before recovery
reaches the marker record — so the handler never executes. Confirmed by
running Tcl recd016 (btree) under coverage: it also leaves
__db_cksum_recover at 0 in-process (it drives the standalone db_recover
util, whose in-process handler coverage is likewise 0). This is a genuine
reachability gap, not a driver bug; left documented in the driver header and
README rather than forcing a synthetic hit.

No engine bugs found

All four covered handlers replay cleanly (redo + undo) and every scenario
verifies data/DB integrity after recovery. No recovery misbehavior observed.

Validation

Built --enable-debug --enable-test in the nix dev shell, compiled the driver
against .libs/libdb-5.3.so, ran under timeoutrecd_handlers: PASS,
run_recd_handlers.sh: PASS, 8.75s wall. No coverage artifacts committed;
build_windows/, .github/, AWS, etc. untouched.

gburd added 2 commits July 30, 2026 07:29
The Tcl recd0NN suite never produces the exact log records replayed by
four per-operation recovery handlers (recd003 does NOT unlock them --
they need scenarios no bounded recd test hits):

  bt_rec.c __bam_root_recover   -- subdb-create logs a __bam_root record
                                   (root page set on file meta page)
  bt_rec.c __bam_irep_recover   -- compaction merges pages, replacing a
                                   parent separator via __bam_pupdate ->
                                   __bam_pinsert(BPI_REPLACE) -> __bam_irep
  bt_rec.c __bam_rcuradj_recover-- rrecno (DB_RENUMBER) cursor adjust
                                   logged under a CHILD txn, then aborted
                                   (handler acts only on DB_TXN_ABORT)
  db_rec.c __db_ovref_recover   -- DB->truncate() of a btree with overflow
                                   items logs __db_ovref(-1) per ovfl page

recd_handlers.c builds each scenario and replays it under DB_RECOVER /
DB_RECOVER_FATAL (and txn abort for the undo paths), verifying DB
integrity after recovery.  Hard SIGALRM guard, self-cleaning home dir,
same shape as recd_compact.c.  Runs in ~9s.

Lift (driver alone, all four go 0 calls -> covered):
  __bam_root_recover    ~53% branch
  __bam_irep_recover    ~60% branch
  __bam_rcuradj_recover ~74% branch
  __db_ovref_recover    ~68% branch

Documented-but-uncovered: __db_cksum_recover.  Its __db_cksum marker
record is only written on a checksum error during a logged page-in;
recovery's redo re-reads the still-corrupt page and panics (pgin failed)
before reaching the marker, so the handler never runs.  Tcl recd016 has
the same limitation.
Run test/db/run_recd_handlers.sh alongside recd_compact in the
COV_BACKUP driver block (default on), and document the four newly-covered
recover handlers (and the one documented-uncovered __db_cksum_recover) in
the coverage README.
@github-actions

Copy link
Copy Markdown

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

@github-actions

Copy link
Copy Markdown

ABI diff vs v5.3.32 (libabigail — authoritative)

Removed exported symbols (nm -D, _NNNN version suffix normalized)

None.


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

@gburd

gburd commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by coverage/recd-handlers-final (rebased onto master; the stale db_join/db_method/fi_sweep copies from #90/#92 dropped, test-only now). Reopening.

@gburd gburd closed this Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant