Skip to content

test(coverage): cover os_aio backends + os_method via a direct C driver - #78

Merged
gburd merged 1 commit into
masterfrom
agent/osaio-dst
Jul 29, 2026
Merged

test(coverage): cover os_aio backends + os_method via a direct C driver#78
gburd merged 1 commit into
masterfrom
agent/osaio-dst

Conversation

@gburd

@gburd gburd commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

What

Raises coverage of libdb's async-I/O backends (all at 0%) and the DB_ENV
os-method setters via one bounded, single-process C driver.

New files:

  • test/os/os_aio_direct.c -- links internal libdb symbols and drives the
    os_aio abstraction and each backend directly.
  • test/os/run_os_aio.sh -- compiles + runs it under a timeout (mirrors
    test/xa/run_xa_direct.sh); wired into the COV_XA_UPG block of
    test/coverage/run_coverage.sh.

How AIO is enabled / selected (findings)

  • Gated, off by default. The buffer pool creates an AIO context only when
    DB_ENV->set_flags(DB_MPOOL_AIO) is set (mp_region.c); otherwise writeback
    is synchronous. The flag is public (DB_MPOOL_AIO, api_flags) and also
    settable from a DB_CONFIG set_flags db_mpool_aio line.
  • Single runtime backend. __os_aio_create (os_aio.c) probes backends in
    preference order and installs the first that initializes: io_uring >
    IOCP > kqueue+aio > POSIX aio > thread-pool
    . On this nix Linux env
    configure enables HAVE_IO_URING (flake liburing), HAVE_AIO_POSIX
    (librt), and HAVE_AIO_THREADPOOL (pthread) -- so io_uring always wins
    and no Tcl workload can ever reach the pool or posix backends.
  • Only path to os_aio is the mp_sync writeback (checkpoint / cache flush
    / trickle): __memp_bhwrite_async -> __os_aio_submit -> __memp_aio_drain
    -> __os_aio_reap. DB_MPOOL_AIO is not wired into the Tcl set_flags
    binding, confirming the DST/Tcl suite does not exercise os_aio (matches
    DESIGN.md's "os_aio* hooks remain follow-ups").

The driver therefore forces each backend's __os_aio_*_init in turn to cover
all of them in one run, then also runs a genuine DB_MPOOL_AIO checkpoint
workload so the production integration path (io_uring) runs too.

Which backend actually executed

threadpool, posixaio, io_uring, auto (io_uring), and sync-fallback
all ran and round-tripped 40 pages each (write -> reap -> read -> verify). The
real DB_MPOOL_AIO workload ran through io_uring (the auto-selected
backend on Linux).

Coverage: before -> after (measured, gcov)

file before after
os/os_aio.c 0% ~84%
os/os_aio_pool.c 0% ~73%
os/os_aio_posix.c 0% ~84%
os/os_aio_uring.c 0% ~81%
common/os_method.c 0% 100%
mp/mp_bh.c (async path) -- ~54%
mp/mp_sync.c (async path) -- ~54%

os_aio_iocp.c (Windows) and os_aio_kqueue.c (BSD) stay 0%: on Linux they
compile only their #else init stub -- unreachable without their target OS.

Bugs

None. Async writeback + reap ordering round-trips correctly across every
backend; no engine code was touched.

Validation

nix dev shell, --enable-debug --enable-test, run twice: all backends PASS,
deterministic, no hang (SIGALRM guard), no cores/orphans, clean home.

The async-I/O abstraction (src/os/os_aio.c) and its backends
(os_aio_pool.c, os_aio_posix.c, os_aio_uring.c) plus the DB_ENV
os-method setters (src/common/os_method.c) were all at 0%.

The buffer pool reaches os_aio ONLY via DB_ENV->set_flags(DB_MPOOL_AIO)
(off by default) and then probes a SINGLE backend at runtime in
preference order (io_uring > IOCP > kqueue+aio > POSIX aio >
thread-pool).  On a Linux box with liburing a normal Tcl workload can
therefore only ever exercise io_uring -- the pool + posix backends stay
dark, and os_aio is unreachable at all without the flag.

test/os/os_aio_direct.c links the internal libdb symbols and drives each
configured backend directly (submit N writes, reap, read back, verify
the round-trip), then exercises __os_aio_create's automatic selection
and the synchronous fallback, and finally runs a real DB_MPOOL_AIO
checkpoint workload so the production mp_sync -> __memp_bhwrite_async ->
backend -> __memp_aio_drain path runs too.  It also sets/clears every
DB_ENV os-method function.  Runs single-process under a SIGALRM guard so
the blocking reap loop can never hang the coverage run.

test/os/run_os_aio.sh compiles it against the just-built .so and runs it
under a timeout, mirroring test/xa/run_xa_direct.sh; it is wired into the
COV_XA_UPG driver block of run_coverage.sh.

Coverage lift (measured, gcov):
  os_aio.c           0% -> ~84%
  os_aio_pool.c      0% -> ~73%
  os_aio_posix.c     0% -> ~84%
  os_aio_uring.c     0% -> ~81%
  common/os_method.c 0% -> 100%
  (mp_bh.c / mp_sync.c async writeback path also newly exercised.)

os_aio_iocp.c (Windows) and os_aio_kqueue.c (BSD) stay 0%: on Linux they
compile only their #else init stub and need their target OS to be
reachable.

No engine code changed; async writeback + reap ordering round-trips
correctly across all backends (no bug surfaced).
@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.31 (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 merged commit 94a7769 into master Jul 29, 2026
45 of 47 checks passed
@gburd
gburd deleted the agent/osaio-dst branch July 29, 2026 12:05
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