Skip to content

distribution: add split job management RPCs#1092

Open
bootjp wants to merge 15 commits into
design/hotspot-split-m2-target-readinessfrom
design/hotspot-split-m2-job-rpc
Open

distribution: add split job management RPCs#1092
bootjp wants to merge 15 commits into
design/hotspot-split-m2-target-readinessfrom
design/hotspot-split-m2-job-rpc

Conversation

@bootjp

@bootjp bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • add durable split job retry and abandon lifecycle transitions
  • implement GetSplitJob, ListSplitJobs, RetrySplitJob, and AbandonSplitJob on the distribution server
  • keep StartSplitMigration fail-closed until the migration capability gate is available
  • route mutating job RPCs through coordinator-backed CAS transactions

Tests

  • go test ./distribution -run 'TestCatalogStore(RetrySplitJob|BeginSplitJobAbandon)'\n- go test ./adapter -run 'TestDistributionServer(StartSplitMigration|SplitJob|RetrySplitJob|AbandonSplitJob)'\n- go test ./adapter -run '^(TestDistributionServer|TestBuildCatalogSplitOps|TestMilestone1SplitRange)' -timeout=3m\n- go test -run '^$' ./...\n- GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./distribution ./adapter --timeout=5m\n- git diff --check\n\nNote: go test ./distribution ./adapter timed out after 10m in the existing full adapter integration suite; the focused adapter server coverage above passed.\n\nAuthor: bootjp\n

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d66d043d-4513-4ff3-8642-8935866fafb0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Implemented split job management RPCs and coordinator-backed lifecycle transitions.

@codex review

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (b93f5b9):

  • distribution/split_job_catalog.go
  • distribution/split_job_catalog_test.go
  • distribution/split_job_lifecycle.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

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

Copy link
Copy Markdown
Contributor

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 adds new gRPC endpoints to DistributionServer for managing split migrations and split jobs, alongside a new split_job_lifecycle.go file to handle job state transitions and corresponding unit tests. The review feedback recommends exporting the splitJobsEquivalent helper function from the distribution package as SplitJobsEquivalent and reusing it within the adapter package to eliminate the duplicated splitJobsEqualByEncoding helper.

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 adapter/distribution_server.go Outdated
if err != nil {
return splitJobCatalogStatusError(err)
}
if splitJobsEqualByEncoding(expected, next) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Use the exported distribution.SplitJobsEquivalent helper instead of the duplicated local splitJobsEqualByEncoding function to improve maintainability.

Suggested change
if splitJobsEqualByEncoding(expected, next) {
if distribution.SplitJobsEquivalent(expected, next) {
References
  1. Centralize common complex logic, such as retry/backoff mechanisms, into shared helper functions to avoid code duplication and improve maintainability.

Comment thread adapter/distribution_server.go Outdated
Comment on lines +658 to +662
func splitJobsEqualByEncoding(left, right distribution.SplitJob) bool {
leftRaw, leftErr := distribution.EncodeSplitJob(left)
rightRaw, rightErr := distribution.EncodeSplitJob(right)
return leftErr == nil && rightErr == nil && bytes.Equal(leftRaw, rightRaw)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This helper function can be removed entirely since we can now use the exported distribution.SplitJobsEquivalent function.

References
  1. Centralize common complex logic, such as retry/backoff mechanisms, into shared helper functions to avoid code duplication and improve maintainability.

Comment thread distribution/split_job_lifecycle.go Outdated
if err != nil {
return SplitJob{}, err
}
if splitJobsEquivalent(expected, next) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Update this call to use the exported SplitJobsEquivalent function.

Suggested change
if splitJobsEquivalent(expected, next) {
if SplitJobsEquivalent(expected, next) {

Comment thread distribution/split_job_lifecycle.go Outdated
return false
}

func splitJobsEquivalent(left, right SplitJob) bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The helper function splitJobsEquivalent is identical in behavior to splitJobsEqualByEncoding in the adapter package. To avoid code duplication and improve maintainability, we should export splitJobsEquivalent as SplitJobsEquivalent so that it can be reused directly by the adapter package.

Suggested change
func splitJobsEquivalent(left, right SplitJob) bool {
// SplitJobsEquivalent returns true if the two SplitJobs have the same encoded representation.
func SplitJobsEquivalent(left, right SplitJob) bool {
References
  1. Centralize common complex logic, such as retry/backoff mechanisms, into shared helper functions to avoid code duplication and improve maintainability.

@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: b93f5b9d47

ℹ️ 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 adapter/distribution_server.go Outdated
Comment on lines +223 to +229
resp := &pb.ListSplitJobsResponse{}
for _, job := range jobs {
if !splitJobPassesListFilter(job, req.GetSinceTerminalAtMs(), phaseFilter) {
continue
}
resp.Jobs = append(resp.Jobs, distribution.SplitJobToProto(job))
}

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 Honor ListSplitJobs pagination

When there are more than the designed default page of split jobs/history records, this implementation appends every matching job and never consumes page_cursor or sets next_page_cursor. The design for ListSplitJobs explicitly calls for live+history with a default cap of 200 newest and cursor-based paging (docs/design/2026_06_11_proposed_hotspot_split_milestone2_migration.md), so an operator with a large history gets an unbounded response and has no way to page through results.

Useful? React with 👍 / 👎.

Comment thread adapter/distribution_server.go Outdated
Comment on lines +684 to +685
case errors.Is(err, kv.ErrLeaderNotFound):
return grpcStatusError(codes.FailedPrecondition, errDistributionNotLeader.Error())

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 Map split-job leadership loss as not-leader

If this node loses catalog leadership after verifyCatalogLeader but before/during coordinator.Dispatch, kv.Coordinate.Dispatch can still surface transient leader errors such as raft ErrNotLeader, leadership lost, or forwarded not leader strings after its retry budget (kv/coordinator.go:isTransientLeaderError). This switch only recognizes kv.ErrLeaderNotFound, so those split-job retry/abandon calls are reported as Internal instead of the not-leader/failed-precondition response clients can retry against.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated in 58c2128:

  • capped ListSplitJobs responses at 200 entries with opaque cursor paging and newest history ordering.
  • reused distribution.SplitJobsEquivalent and removed the duplicate adapter helper.
  • mapped split-job Dispatch leadership loss to not-leader / FailedPrecondition.

Validation:

  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./adapter -run 'TestDistributionServer(SplitJobRPCs|ListSplitJobs|RetrySplitJob|AbandonSplitJob)' -count=1 -timeout=120s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./distribution -run 'TestCatalogStore.*SplitJob|TestSplitJob' -count=1 -timeout=120s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./adapter ./distribution --timeout=5m
  • git diff --check

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (58c2128):

  • distribution/split_job_catalog.go
  • distribution/split_job_catalog_test.go
  • distribution/split_job_lifecycle.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 58c212801a

ℹ️ 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".

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

Current head 58c2128 has green CI and no current-head inline blockers found in the latest check. Requesting current-head review.\n\n@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 58c212801a

ℹ️ 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".

bootjp added 7 commits July 14, 2026 10:21
## Summary
- keep StartSplitMigration fail-closed until an explicit migration
capability gate succeeds
- create planned SplitJob records through the catalog coordinator when
the gate is open
- reject reserved migration/control ranges and enforce the one-live-job
limit before writing migration state

## Tests
- go test ./adapter -run
'TestDistributionServer(StartSplitMigration|SplitJobRPCs)' -count=1
- go test ./distribution -count=1
- golangci-lint --config=.golangci.yaml run ./adapter ./distribution
--timeout=5m

Note: a broader go test ./adapter ./distribution -count=1 run previously
timed out in adapter after 10m during wider raft/gRPC tests; the
targeted DistributionServer tests and distribution package pass.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (aff2a9f):

  • distribution/split_job_catalog.go
  • distribution/split_job_catalog_test.go
  • distribution/split_job_lifecycle.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Latest head has green CI and no current-head top-level inline findings from the review-comments API. Requesting a fresh review for the current head.

@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: aff2a9f037

ℹ️ 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 main.go
…eadiness' into design/hotspot-split-m2-job-rpc

# Conflicts:
#	adapter/distribution_server_test.go
@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (9994ec7):

  • distribution/split_job_catalog.go
  • distribution/split_job_catalog_test.go
  • distribution/split_job_lifecycle.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

Updated in 9994ec7.

Changes:

  • merged latest target-readiness base to resolve the PR conflict.
  • gated AbandonSplitJob and RetrySplitJob during startup rotation, matching StartSplitMigration and other durable mutators.

Validation:

  • GOCACHE=/tmp/elastickv-gocache-1092 go test . -run TestStartupPublicKVGate_BlocksMutatorsUntilReady -count=1 -timeout=120s
  • GOCACHE=/tmp/elastickv-gocache-1092 go test ./adapter -run 'TestDistributionServer(StartSplitMigration|RetrySplitJob|AbandonSplitJob|ListSplitJobs)' -count=1 -timeout=180s\n- GOCACHE=/tmp/elastickv-gocache-1092 go test ./distribution -run 'TestCatalogStore.*SplitJob|TestSplitJob' -count=1 -timeout=180s\n- golangci-lint --config=.golangci.yaml run --fix (commit hook, 0 issues)\n- git diff --check\n\n@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 9994ec77cc

ℹ️ 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".

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.

1 participant