Files
buzz/crates
Luke Tornquist f6d31d13e4 db: answer match-nothing event reads without taking a connection (#8663)
## Summary

A NIP-01 `limit: 0` REQ asks for no stored events: it is a live-only
subscription. The relay still acquired a pool connection for it, then
ran a `LIMIT 0` query. Desktop is moving live subscriptions to `limit:
0`, so these acquires add up during a reconnect burst.

The existing match-nothing shortcuts in `query_events_on` (an empty
`kinds`, `authors`, `ids` or `#e` list) had the same cost, because they
ran after the caller had already acquired a connection.

This PR moves the query validation and the match-nothing checks into one
function, `answer_without_db`. It adds a zero page (`limit: 0`, after
the page clamp) to those checks, and every entry point now calls the
function before it acquires a connection:

- `query_events_with_operation`, which covers `Db::query_events` and its
writer variants
- `Db::query_events_routed`
- `Db::query_events_routed_bounded`
- `query_events_on`, for the session (aux) path that already holds a
connection

Invalid queries still return the same errors, in the same order, and
match-nothing queries still return an empty page. What changes besides
the connection:

- A routed match-nothing read now returns before `route_read`, so it
emits no `buzz_db_route_decision` and runs no replica proof. As desktop
moves live subscriptions to `limit: 0`, writer/replica route-decision
ratios will shift. Fewer reads are routed; no read changes destination.
- During a pool outage, an invalid query now returns its `InvalidData`
error instead of the pool error.
- A zero page skips checks that only SQL applies, such as rejecting a
negative `offset`. Current callers only build non-negative offsets.

**Simpler?** Yes. The four separate early returns become one predicate,
and the page-limit clamp is computed in one place (`page_limit`), shared
by the shortcut and the SQL builder.

### Related issue
N/A. This is a follow-up from https://github.com/block/buzz/pull/8651.

### Testing
- New unit test,
`runtime::postgres_tests::match_nothing_reads_take_no_connection`. Both
pools point at a closed port, replica routing is on, and the fence is
forced open, so a routed read that reached `route_read` would try the
reader first. Each match-nothing shape (`limit: 0`, `max_limit: 0`, and
an empty `kinds`, `authors`, `ids` or `#e` list) must return an empty
page through the writer, routed and routed-bounded entry points. Invalid
queries that would also match nothing must return `InvalidData` through
each entry point. None of these may record a
`buzz_db_pool_acquire_attempts_total`. A `limit: 1` routed control must
fail after trying both the reader and the writer. The test runs in the
`cargo nextest run -p buzz-db --lib` unit lane.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Luke Tornquist <tornquist@squareup.com>
Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:21:08 -04:00
..