Skip to content

Native timer exceeds the 1s lateness bound under MariaDB qualification load #714

Closed

Description

@rmcdaniel

Finding

The native Server timer path can exceed the existing one-second canonical-lateness bound under MariaDB-family qualification load.

Two hosted observations on October 23, 2026 establish that this is repeated evidence rather than a one-off assertion:

PR #708 changes only the JavaScript operator-metrics contract and tests; its failed cell ran the main native binary. This finding is therefore not caused by #708 and should not be fixed by weakening that PR or broadening its contract.

Required investigation

  1. Reproduce with controlled declared CPU load on MariaDB 10.11, recording fire_at, wake/poll times, persisted event time, runner load and scheduler/poller cadence.
  2. Run the same bounded probe on SQLite, PostgreSQL, MySQL 8.0/8.4 and MariaDB to separate database-family behavior from shared-runner starvation.
  3. Attribute the excess latency to the timer query/wake path, database scheduling, worker polling, executor contention or measurement boundary.
  4. Correct the causal path and rerun the original hosted cell. Preserve the 1.000-second maximum; do not turn a repeated miss into a pass by widening the tolerance.
  5. Retain exact before/after observations and cleanup receipts.

This issue owns the reliability follow-through. It is independent of #708 source acceptance and does not authorize publication or native/shared edits outside the existing Rust Server ownership.

Activity

  1. rmcdaniel commented on Oct 23, 2026

    @rmcdaniel
    MemberAuthor

    Cause found; fix in #717. The 1.000 s bound is unchanged.

    Reproduction (disposable 4-vCPU VM, unchanged codec-deadline-health cell on main f67f2816e):

    • MariaDB 10.11 failed 2 of 8 cells (timers 1.228 s and 1.213 s late).
    • MySQL 8.0 and 8.4 failed 3 of 8.
    • PostgreSQL 17 and SQLite passed 8 of 8, at most 171 ms late.

    Attribution (temporary local-only instrumentation, never pushed):

    1. Timer path. Every late timer waited behind the global transition lock. In the 1.228 s case, the timer came due just after the scheduler tick began. The tick's activity-deadline sweep waited 543 ms behind a workflow completion holding the lock 690 ms, then held it 407 ms itself. The timer then waited 145 ms more.
    2. Database. Not slow. MariaDB's full statement log shows those transactions spent a median of 5 ms in the database (p90 9 ms) over 30 to 48 statements, while holding the lock 0.3 to 1 s. Only the lock acquisition statement itself was ever slow.
    3. Executor and CPU. Not starved. Async-task and OS-thread wake-up probes rarely saw a 50 ms delay. Giving native 2 CPUs instead of 1 left the holds unchanged, and MariaDB's own CPU averaged about 30%, like PostgreSQL's.
    4. Measurement boundary. Not the cause. The same per-statement stall appears in hold times measured inside native.
    5. The stall. Timestamps on each statement inside the transactions showed 40 to 100 ms gaps spread over ordinary statements, many near 58 ms. That is Nagle's algorithm waiting for a delayed ACK. sqlx-mysql 0.9.0 sends replyless COM_STMT_CLOSE packets in their own writes (on cache eviction, after an uncached execute, and in a flush before draining results), so the next statement waits about 40 ms. SQLx sets no TCP_NODELAY; PHP's mysqlnd does. PostgreSQL's driver batches its closes, which is why only the MySQL family fails.

    Fix (#717, vendored driver only): queue statement closes so they leave in the same write as the next command. A proxy-recorded regression test fails with the published driver and passes with the fix on MySQL 8.0 and MariaDB.

    Before and after. Clean release builds, same cell, interleaved:

    main #717
    MariaDB 10.11 2/4 passed, worst 1738 ms 4/4, worst 55 ms
    MySQL 8.0 3/4, worst 307 ms 4/4, worst 235 ms
    MySQL 8.4 1/4, worst 1672 ms 4/4, worst 292 ms
    PostgreSQL 17 4/4 4/4
    SQLite 4/4 4/4

    Full table and local test receipts: #717 (comment). The hosted MariaDB/MySQL cells rerun on #717's own CI.

    Cleanup. VM dw-rs325-20261023T212416 ran 21:24–22:51 UTC (about $0.10). Instance and temporary SSH key were deleted and verified absent. No other instances were touched. The local instrumentation branch was never pushed and is being deleted.

  2. added a commit that references this issue on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions