Skip to content

perf(db): stop the events recent pass at a ceiling for regular-kind reads - #9157

Merged
TheSentinel454 merged 2 commits into
mainfrom
events-recent-ceiling
Nov 6, 2026
Merged

TheSentinel454 merged 2 commits into
mainfrom
events-recent-ceiling

Conversation

@TheSentinel454

@TheSentinel454 TheSentinel454 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The recent pass of a split newest-first events read now has an upper bound when every requested kind is a regular kind. Postgres stops planning the empty monthlies made ahead of time and the open-ended catch-all. Results are unchanged.

Why. #9091 gave the recent pass a floor (created_at >= <start of previous month>) but no ceiling, and its "Not covered" section names that gap. The partition manager keeps 6 empty monthlies ahead of the current month, plus an open-ended catch-all, so the recent pass still planned and locked about 9 partitions, each with its full index set. That is far past a backend's 16 fast-path lock slots.

What changes. For a regular-kinds-only read, the recent pass reads floor <= created_at < ceiling. The ceiling is a SQL literal at 00:00 UTC on the first day of the month after now + 1 h, so the pass plans the previous and current monthlies, plus the next one during the last hour of a month. The older pass is unchanged.

Why no row is lost. Ingest rejects events more than 900 s ahead of the relay's clock (MAX_TIMESTAMP_DRIFT_SECS). Every regular-kind event the relay signs itself is stamped with its clock. The extra margin up to 1 h covers clock differences between relay processes. I audited every writer of events rows for this.

Why only regular kinds. The relay stamps its own replacements of some replaceable and addressable rows at max(previous + 1 s, now): group discovery (39000–39002), the NIP-43 membership list, the archived list, DM visibility and verified profiles. A coordinate replaced faster than once a second can therefore run ahead of the clock. A read that may match those kinds (no kinds, or any replaceable/addressable kind) keeps the open recent pass from #9091.

No protocol, schema, index or client change.

Related issue

Follow-up to #9091 (its "Not covered" upper bound).

Testing

  • recent_pass::tests: ceiling arithmetic (month and year wraps, and either side of the 1 h margin). Predicate literals with and without a ceiling. The eligibility table now records not split / ceiled / open per read shape, including mixed regular and latest-state kinds. The in-memory exactness test runs both the ceiled and the open split.
  • split_passes_bound_created_at_with_a_literal: SQL shape. The recent pass is bounded on both sides, on e. and m. for #p. The older pass and unsplit reads carry no ceiling.
  • postgres_tests::recent_pass_locks_only_the_partitions_below_its_ceiling (new): runs partition maintenance to get the layout a running relay keeps, then runs the recent pass under plan_cache_mode = force_generic_plan inside a transaction and reads the backend's pg_locks. The ceiled pass locks exactly the partitions holding rows at the floor, now, and one second below the ceiling. The open pass locks strictly more.
  • split_page_reads_match_the_unsplit_read: now matches the recent pass by its exact floor and ceiling literals.
  • Fixture fix (test-only): the perf(db): split newest-first events reads at a month floor so Postgres prunes partitions #9091 snapshot fixtures waited for any ungranted pg_locks row on a partition's OID. pg_locks covers every database, and the per-test databases are clones that share OIDs, so a wait in another test's database could release the fixture early. That likely caused one CI failure of split_read_passes_share_one_snapshot, which I couldn't reproduce on Blox. Both lock checks now match only the current database, as several advisory-lock waits in other fixtures already do.

Mutation-checked on Blox. Each of these fails the new Postgres test or the unit tests: dropping the ceiling from the predicate, applying it to every split read, and widening it.

What got simpler

Nothing got simpler. The change adds one optional bound to the existing Split/Range types in store/recent_pass.rs and no new concept. floor_for became split_for, and it returns the floor and the ceiling together.

Identified, out of scope: unsplit reads whose since is a bind parameter (live REQs with a recent since) still lock every partition under a cached generic plan on PG 16. Postgres prunes bind-parameter bounds only at execution, after it has taken the locks.

🤖 Generated with Claude Code

The recent pass of a split newest-first read had only a floor, so Postgres
still planned and locked the empty monthlies made ahead of time and the
open-ended last partition: about nine partitions, each with its index set.

A read of regular kinds only now also bounds the recent pass below the start
of the month after now + 1 h, as a literal, so it locks the previous and
current monthlies (and the next one in the last hour of a month). Ingest
rejects regular events more than 900 s ahead, and the relay stamps its own
regular events with its clock, so no such row sits at or above the ceiling.

Replaceable and addressable rows have no such bound: the relay stamps its
own replacements one second past the live row, so a coordinate replaced
faster than once a second runs ahead of the clock. A read that may match
them keeps the open recent pass.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Luke Tornquist <[email protected]>
@TheSentinel454
TheSentinel454 marked this pull request as ready for review November 6, 2026 00:06
@TheSentinel454
TheSentinel454 requested a review from a team as a code owner November 6, 2026 00:06
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 6, 2026
@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated, security-focused review generated by Codex.
Use it as a supplement to human review; false positives are possible.

Scope

  • Exact PR diff: 133c883b8ca1221d82d17c94249809844d2b80b3...fd63c8194e90936b7a9081238f809c5b9efe54c9
  • Model: gpt-6.1-sol

💡 Click "edited" above to see earlier reviews for this PR.


Review Summary

Overall Risk: NONE

No concrete security, correctness, or reliability regressions found in the authorized PR range.

Findings

No concrete security, correctness, or reliability findings were identified.

Notes

  • Review used read-only source and history inspection. Builds and tests were not run, as requested.

Generated by Codex Security Review |
Requested by: @TheSentinel454 |
Workflow run

`pg_locks` lists locks in every database, and the per-test databases are
clones of one source, so a partition has the same OID in all of them. The
snapshot fixtures waited for any ungranted lock on that OID, so a test in
another database waiting on its own copy of the partition released the
fixture before its read reached the older pass. The replacement then
committed before the read's snapshot, and the page showed it.

Match only waits in the current database, as the advisory-lock waits in
the other fixtures already do.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Luke Tornquist <[email protected]>
@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 6, 2026
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 6, 2026

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 LGTM. Checked the one claim the ceiling depends on: that no regular-kind row is stored with created_at past now + 1h. Client events, including the HTTP bridge, go through ingest_event, which rejects anything more than 900 s off the relay clock. The relay-signed regular kinds I traced (workflow stream messages, huddle lifecycle events) are stamped at signing time, and moderation notices reuse a past outbox timestamp. Keeping the open pass for any read that can match replaceable or addressable kinds covers the max(previous + 1 s, now) restamps. The pg_locks test pins the pruning behaviour under generic plans, and the database filter added to the snapshot fixtures fixes a real cross-database false positive.

@TheSentinel454
TheSentinel454 merged commit 8ae35c5 into main Nov 6, 2026
90 checks passed
@TheSentinel454
TheSentinel454 deleted the events-recent-ceiling branch November 6, 2026 01:23
TheSentinel454 added a commit that referenced this pull request Nov 6, 2026
…al (#9197)

## Summary

A newest-first `events` read whose own `since` is at or above the
recent-pass floor now runs as a single recent pass. Postgres prunes it
to the recent monthlies at plan time instead of locking every partition.
Results are unchanged.

**Why.** `split_for` skipped any read whose `since` was at or above the
floor (`since_prunes`), on the theory that its `since` already prunes.
It does, but only as a bind parameter. Once a prepared statement
switches to a cached generic plan, Postgres prunes bind-parameter bounds
at execution, after `AcquireExecutorLocks` has already locked every
`events` partition and its indexes. Live REQs with a recent `since` are
this shape, for example `#p` mention reads from reconnecting agents.
Under load they spill past the 16 fast-path lock slots and contend on
`LWLock:LockManager`. The ceiling PR (#9157) named this gap as
identified debt.

**What changes.** Such a read now gets the same `Split` as other recent
reads, so the recent pass carries the floor literal (plus the ceiling
literal for regular-kind reads) on `e.created_at` and on
`m.event_created_at` for `#p`. `Split` gains `older: bool`. It is false
when the read's own `since` is at or above the floor, because no row
below the floor can match, so no older pass follows a short recent pass.
A read whose `until` falls below the floor stays unsplit, as before.

No protocol, schema, index or client change.

### Related issue

Follow-up to #9157 (its identified debt: bind-parameter `since` reads).

### Testing

- `recent_pass::tests::split_eligibility`: the table now records not
split / ceiled / open and whether an older pass follows. New rows:
`since` at the floor, a recent `since` with regular, any and
addressable-only kinds, and a recent `since` with `until` below the
floor.
- `recent_pass::tests` in-memory exactness: adds a `since`-at-floor
split that runs exactly one pass and returns the rows at or above the
floor.
-
`postgres_tests::since_bounded_mention_read_locks_only_recent_partitions`
(new): runs partition maintenance, inserts `#p` rows at the floor, now,
one second below the ceiling and one day below the floor, then reads
with `since = floor`. The production path returns the three recent rows
through the mention join. Under `plan_cache_mode = force_generic_plan`
the recent pass locks only the partitions holding those rows. The
unsplit read locks every partition.
- The partition-lock helper from #9157's test is now shared by both lock
tests.
- Diagnostic on Postgres 17.11 with the 19-partition layout partition
maintenance keeps, for a `#p` read with `since` at the floor (not
committed):

| | `events` partitions locked | Relation locks | Non-fast-path locks |
  |---|---|---|---|
| Before (bind-only `since`, generic plan after five runs) | 19 | 26 |
10 |
  | After (floor and ceiling literals) | 2 | 9 | 0 |

`EXPLAIN (GENERIC_PLAN)` before appends all 19 partitions. After, it
appends only the previous and current monthlies.

Mutation-checked on Blox. Each of these fails the new Postgres test or
the unit tests: removing the `since_prunes` split, ignoring `older`, and
dropping the `e.` literal.

## What got simpler

Nothing got simpler. The change adds one flag to the existing `Split`
type and no new concept. The duplicated partition-lock reader in the
#9157 test became one shared helper.

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

---------

Signed-off-by: Luke Tornquist <[email protected]>
Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <[email protected]>

This branch was previously deployed

1 inactive deployment
codex-review — fd63c819 Deployed Nov 6, 2026 by TheSentinel454 via Run Codex Security Review #13286
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex-security-review-current The posted Codex security review matches its recorded range.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants