Skip to content

perf(channels): coalesce concurrent GetChannels/GetEncryptedChannels cache misses #109

Closed

Description

@dborup

Upstream source

Evaluate and port the behaviour from Kpa-clawbot/CoreScope#2059: coalesce concurrent cache misses for GetChannels and GetEncryptedChannels so one cold/expired key causes one SQLite query rather than one query per request.

Why this is still relevant here

Current fork master still has no channel-query singleflight. GetChannels uses a 60-second cache, but concurrent callers can all miss before the first result is stored. GetEncryptedChannels follows a separate query path.

This fork has diverged from upstream:

Do not cherry-pick blindly. Preserve those behaviours and adapt request coalescing to the current cache contract.

Acceptance criteria

  • Concurrent misses for the same normalized region execute at most one real GetChannels query.
  • Concurrent misses for the same normalized region execute at most one real GetEncryptedChannels query.
  • Different region keys are never coalesced together and cannot receive each other's result.
  • Errors are shared only within the in-flight call and are not cached as successful data.
  • A second cache check occurs inside the singleflight winner.
  • Existing index-pinning/fallback behaviour from perf(db): pin GetChannels and CountFloodAdvertsForNode to their indexes (issue #100) #107 remains intact.
  • Existing cache-slice protection from fix(server): avoid mutating the cached channels slice on includeEncrypted #98 remains intact.
  • Deterministic tests count actual query executions; timing alone is not sufficient.
  • Run the relevant Go tests with -race and measure cold concurrent behaviour before and after.

No deploy is part of this issue.

Activity

  1. dborup commented on Sep 28, 2026

    @dborup
    OwnerAuthor

    Additional scope found in upstream Kpa-clawbot#1936

    The selective cache work in Kpa-clawbot/CoreScope#1936 reinforces this issue but should not be ported wholesale.

    Current fork findings:

    Recommended extension to this issue: use keyed caches plus per-key singleflight for normalized-region channel and encrypted-channel queries. Benchmark message-page caching as a separate decision, and require an immutable/copy-on-read contract before adding it.

  2. dborup commented on Sep 29, 2026

    @dborup
    OwnerAuthor

    Draft PR #138 klar til review: CI grøn (Go Build & Test, Playwright E2E, Docker build). GetChannels og GetEncryptedChannels bruger nu en begrænset cache pr. normaliseret region med singleflight og et ekstra cache-tjek inde i flighten. #107 og #98 er bevaret. Der er ingen message-page-cache og intet nyt indeks. 16 samtidige kolde kald giver 2 queries (master: 16).


    Generated by Claude Code

  3. dborup commented on Sep 30, 2026

    @dborup
    OwnerAuthor

    Fixed by #138 (merged as e829d1ea). The list cache is per normalized region, concurrent misses share one query, rows.Err() is checked, and keys over 256 bytes are stored as a digest while the query still gets the full region. Review note, not blocking: TTL expiry itself has no dedicated test.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions