Skip to content

Unify entity-store full scans behind a bounded paged primitive#873

Merged
phinze merged 1 commit into
mainfrom
phinze/mir-1272-unify-entity-store-full-scans-behind-a-bounded-paged
Jun 30, 2026
Merged

Unify entity-store full scans behind a bounded paged primitive#873
phinze merged 1 commit into
mainfrom
phinze/mir-1272-unify-entity-store-full-scans-behind-a-bounded-paged

Conversation

@phinze

@phinze phinze commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Follow-on cleanup to #871 and #872, which fixed a coordinator parking in starting entity migration for ~7.5h after a restart. The startup maintenance phase reads the whole entity keyspace before the edge listener binds, and on a bloated etcd that unbounded read stalled indefinitely. #871 added a 2-minute timeout (the net) and #872 paginated two of the reads (the fix).

The catch is that #872's paging helper only covered two of the five full-keyspace reads in the startup path; the other three (the short-id unique-key set, ListAllEntityIDs, and reindex's stale-cleanup scan) still open-coded their own Get(WithPrefix()). So instead of leaving bounding as something each call site has to remember, we promote the helper to one primitive every read shares. listEntitiesPaged becomes scanPaged with keys-only and page-size options plus a thin EtcdStore method, and all five scans now route through a single paging loop.

While in here, we also untangled the timeout nesting. Reindex had its own inner 5-minute deadline, but it was derived from #871's outer 2-minute ceiling, so it could only ever clamp down to whatever was left of the 2 minutes. It never granted reindex anything. We dropped it and let reindex share the single 2-minute bound, which is the real guarantee anyway; an unfinished reindex is hash-gated to retry on the next boot.

Closes MIR-1272

@phinze phinze requested a review from a team as a code owner June 29, 2026 22:13
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e0ed93f-d902-471b-8ab0-5ec8f5004842

📥 Commits

Reviewing files that changed from the base of the PR and between 411262c and 63ed275.

📒 Files selected for processing (7)
  • components/coordinate/coordinate.go
  • pkg/entity/migrate.go
  • pkg/entity/reindex.go
  • pkg/entity/scan.go
  • pkg/entity/scan_test.go
  • pkg/entity/shortid_migrate.go
  • pkg/entity/store.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/entity/shortid_migrate.go
  • pkg/entity/migrate.go
  • pkg/entity/store.go
  • pkg/entity/reindex.go
  • pkg/entity/scan_test.go
  • components/coordinate/coordinate.go
  • pkg/entity/scan.go

📝 Walkthrough

Walkthrough

pkg/entity/scan.go adds a new scanPaged helper with configurable page size and keys-only support, plus an EtcdStore.scanPaged wrapper. MigrateEntityStore, Reindex, MigrateShortIds, and ListAllEntityIDs now use that helper. pkg/entity/scan_test.go adds coverage for paging, keys-only reads, and empty prefixes. checkAndReindex no longer creates a dedicated 5-minute timeout for store.Reindex and uses the caller context directly.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/entity/scan.go (1)

60-75: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Pin the etcd revision across pages.
scanPaged issues each page at the current revision, so concurrent writes can make a full scan miss or duplicate keys between requests. Capture resp.Header.Revision on the first page and pass clientv3.WithRev(...) on the rest so these list operations keep snapshot semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/entity/scan.go` around lines 60 - 75, The scanPaged loop currently
reissues each etcd page without fixing the revision, which can make results
inconsistent across concurrent writes. In scan.go, update scanPaged to capture
resp.Header.Revision from the first successful client.Get call and reuse it for
subsequent requests by adding clientv3.WithRev(...) to getOpts after the first
page. Keep the existing cursor advancement logic, but ensure all later pages are
fetched from the same snapshot revision so the full scan remains stable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/entity/scan.go`:
- Around line 60-75: The scanPaged loop currently reissues each etcd page
without fixing the revision, which can make results inconsistent across
concurrent writes. In scan.go, update scanPaged to capture resp.Header.Revision
from the first successful client.Get call and reuse it for subsequent requests
by adding clientv3.WithRev(...) to getOpts after the first page. Keep the
existing cursor advancement logic, but ensure all later pages are fetched from
the same snapshot revision so the full scan remains stable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1f835e2-27e0-4376-97ab-a50c73218c9f

📥 Commits

Reviewing files that changed from the base of the PR and between 64b9043 and 411262c.

📒 Files selected for processing (7)
  • components/coordinate/coordinate.go
  • pkg/entity/migrate.go
  • pkg/entity/reindex.go
  • pkg/entity/scan.go
  • pkg/entity/scan_test.go
  • pkg/entity/shortid_migrate.go
  • pkg/entity/store.go

#872 added listEntitiesPaged to bound two startup scans, but the
principled home is one primitive every full-keyspace read shares.
Rename it scanPaged, give it keys-only and page-size options plus an
EtcdStore method, and route the three reads #872 missed through it:
the short-id unique-key set, ListAllEntityIDs, and reindex's
stale-cleanup scan. No startup scan open-codes Get(WithPrefix()) now.

Also collapse the reindex timeout nesting from #871. checkAndReindex's
inner 5-min budget always clamped to whatever was left of the 2-min
startup ceiling, so it was dead. Drop it and let reindex share the
single 2-min bound that keeps the coordinator off the edge listener's
back; an unfinished reindex retries on the next boot.
@phinze phinze force-pushed the phinze/mir-1272-unify-entity-store-full-scans-behind-a-bounded-paged branch from 411262c to 63ed275 Compare June 29, 2026 22:27
@phinze phinze merged commit 95cf5db into main Jun 30, 2026
17 checks passed
@phinze phinze deleted the phinze/mir-1272-unify-entity-store-full-scans-behind-a-bounded-paged branch June 30, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants