Skip to content

db: flag slow transactions, add opt-in commit ledger - #729

Closed
Roasbeef wants to merge 2 commits into
vtxo-listing-leversfrom
db-txn-observability
Closed

db: flag slow transactions, add opt-in commit ledger#729
Roasbeef wants to merge 2 commits into
vtxo-listing-leversfrom
db-txn-observability

Conversation

@Roasbeef

Copy link
Copy Markdown
Member

In this PR, we add two opt-in observability hooks to the db package, both
born during the OOR benchmarking campaign and both having already paid for
themselves in bugs found.

The first flags long-held transactions and stalled begins: any transaction
held past a threshold, or a begin that waits too long on the writer lock,
gets a warning with the caller attributed via the existing
execTxCallerHint frame walk. This is what caught the operator-side
ingress fold holding the writer lock across synchronous handler work
(32-58s begin stalls) during development; without it that regression read
as a generic throughput collapse.

The second is a per-call-site commit ledger: when armed
(EnableTxnAccounting), every successful commit is attributed to its
first non-db caller frame and bucketed by read/write. The cost when
disabled is a single atomic load per commit. The motivating result: an
audit had estimated ~27 write commits per payment; the ledger measured
77.9, and named the bucket every estimate had missed (the connection
actors' AckState cursor checkpoints, ~21/payment). Every subsequent
write-reduction lever in the train was driven by ledger deltas instead of
estimates. The stress harness arms it via --txn-accounting and dumps a
txn_ledger.txt into the run artifacts (darepo side).

This PR builds on #728 and is part of the OOR optimization train.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces transaction monitoring and accounting to track slow database transactions and record commit counts by domain call site. It adds warnings for transactions that stall during initiation or are held longer than a threshold, integrates with Go's runtime tracing, and provides a global ledger for transaction statistics. The review feedback suggests improving the robustness of the stack-walking logic in execTxCallerHint by reducing the hardcoded skip count in runtime.Callers to prevent fragility against compiler inlining or call-stack changes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread db/interfaces.go
// a flagged transaction. Only invoked on the slow path.
func execTxCallerHint() string {
pcs := make([]uintptr, 16)
n := runtime.Callers(3, pcs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a hardcoded skip count of 3 in runtime.Callers is fragile because it assumes a specific call depth. If execTxCallerHint or recordTxnCommit are ever inlined by the compiler, or if the call path changes, the skip count of 3 can skip past the actual caller frame.

Since the loop already filters out any frames containing "darepo-client/db", we can safely use a smaller skip count like 1 (or 2 to skip only runtime.Callers and execTxCallerHint). The package-path filtering will then reliably stop at the first frame outside the db package, making the caller attribution completely robust against compiler optimizations and call-stack refactoring.

Suggested change
n := runtime.Callers(3, pcs)
n := runtime.Callers(1, pcs)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3bac84871

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread db/interfaces.go
Comment on lines +423 to +424
if txnAccountingEnabled.Load() {
recordTxnCommit(txOptions.ReadOnly())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Count commits made by actor-owned transactions

When a store call runs under a durable-actor transaction, actor.TxFromContext returns at the top of ExecTx, so this newly added accounting hook is never reached. I checked baselib/actor/durable_actor.go and db/actordelivery/store_impl.go: actor message processing opens and commits its outer transaction in TxAwareActorDeliveryStore.ExecTx, then store methods invoked by the behavior join that transaction through the context. In actor-driven workloads, EnableTxnAccounting will therefore undercount write commits and omit the call sites that often dominate production transaction volume, making the benchmark ledger misleading.

Useful? React with 👍 / 👎.

@Roasbeef
Roasbeef force-pushed the vtxo-listing-levers branch from 897b8f4 to bb9bb3b Compare June 10, 2026 17:34
@Roasbeef
Roasbeef force-pushed the db-txn-observability branch from d3bac84 to 610448a Compare June 10, 2026 17:34
@Roasbeef
Roasbeef force-pushed the vtxo-listing-levers branch 3 times, most recently from b9242ad to 5a4b20d Compare June 15, 2026 04:25
@Roasbeef
Roasbeef force-pushed the db-txn-observability branch 2 times, most recently from 2f8f9fe to 4f4b261 Compare June 15, 2026 04:27
@Roasbeef
Roasbeef force-pushed the vtxo-listing-levers branch from 5a4b20d to 811adab Compare June 15, 2026 04:53
Roasbeef added 2 commits June 14, 2026 23:54
The stress workload intermittently surfaces SQLITE_BUSY on the send
path even though busy_timeout is confirmed armed at 30s, which means
some transaction occasionally holds the single-writer lock for tens of
seconds. The CPU and block profiles cannot attribute that: the holder
is waiting, not spinning, and database/sql pool waits hide the owning
call site.

In this commit, we teach ExecTx to identify both sides of a stall. A
transaction whose body+commit exceeds one second logs a warning with
the owning call site (the first caller frame outside the db packages,
resolved only on the slow path), and a begin that waits longer than a
second logs the victim side. When a runtime trace is active (the
arktest --trace runs), every transaction also opens a trace region
tagged with the same call site, so go tool trace shows exactly which
goroutine sat inside a transaction across a stall window. The fast
path cost is two clock reads and one IsEnabled check.
To pick the next write-amplification lever empirically instead of from
the estimated commit audit, ExecTx can now attribute every committed
transaction to the first caller frame outside the db packages, split by
the read-only flag. The ledger is disabled by default and costs one
atomic load per commit until a benchmark or test arms it, mirroring the
slow-transaction telemetry's gating approach.

The stress harness arms the ledger for the payment phase and divides
the totals by attempted payments, validating the ~27-commits-per-
payment audit and naming the dominant remaining buckets.
@Roasbeef
Roasbeef force-pushed the db-txn-observability branch from 4f4b261 to cfab0af Compare June 15, 2026 04:54
@levmi levmi added the P2 Priority 2 — medium label Jun 15, 2026
@Roasbeef Roasbeef closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Priority 2 — medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants