Skip to content

tso: add dedicated ceiling fsm#1095

Open
bootjp wants to merge 3 commits into
mainfrom
design/dedicated-tso-fsm
Open

tso: add dedicated ceiling fsm#1095
bootjp wants to merge 3 commits into
mainfrom
design/dedicated-tso-fsm

Conversation

@bootjp

@bootjp bootjp commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add a minimal dedicated TSO state machine that accepts only HLC lease entries.
  • Snapshot and restore the physical ceiling as 8-byte big-endian state, and classify full lease entries as volatile-only.
  • Update the centralized TSO design doc status and remaining runtime wiring.

Validation

  • go test ./kv -run 'TestTSOStateMachine|TestLocalTSOAllocator|TestBatchAllocator|TestShardedCoordinator.*Timestamp|TestCoordinateUsesTSOAllocator' -count=1 -timeout=180s
  • go test ./kv -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./kv --timeout=5m
  • git diff --check
  • go test ./adapter -run '^TestMilestone1SplitRange_RestartReloadsCatalog$' -count=1 -timeout=180s
  • go test ./... -count=1 -timeout=600s (adapter package timed out at 600s; other packages completed)

Notes

  • This adds the dedicated FSM implementation and tests. Runtime bootstrap wiring for groupID = 0 remains a follow-up until the TSO leader redirect path exists.

Author: bootjp

Summary by CodeRabbit

  • 新機能
    • 専用TSOグループで、時刻の上限と割り当て基準値を管理できるようになりました。
    • スナップショットの保存・復元に対応し、従来形式のデータも互換的に復元できます。
  • 改善
    • 専用TSOグループでは暗号化変更操作を安全に拒否し、時刻サービスを継続できるようになりました。
    • グループ構築時のエラー処理とリソース解放を改善しました。
  • ドキュメント
    • TSO移行の進捗、互換性、今後の対応範囲を更新しました。

@bootjp

bootjp commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@bootjp, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b995d8ab-9990-4a29-8802-3112e5a66146

📥 Commits

Reviewing files that changed from the base of the PR and between 97a42ba and aa94f4e.

⛔ Files ignored due to path filters (2)
  • proto/distribution.pb.go is excluded by !**/*.pb.go
  • proto/service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (18)
  • adapter/distribution_server.go
  • adapter/distribution_server_test.go
  • adapter/grpc.go
  • adapter/grpc_test.go
  • docs/design/2026_04_16_partial_centralized_tso.md
  • kv/leader_routed_store_test.go
  • kv/shard_store.go
  • kv/sharded_coordinator.go
  • kv/tso.go
  • kv/tso_floor_test.go
  • kv/tso_fsm.go
  • kv/tso_fsm_test.go
  • kv/tso_raft.go
  • kv/tso_raft_test.go
  • main.go
  • main_tso_routing_test.go
  • proto/distribution.proto
  • proto/service.proto
📝 Walkthrough

Walkthrough

専用TSO用Raftステートマシンを追加し、leaseとallocation floorの適用、スナップショット互換復元、group-0 runtime構築、EncryptionAdminのmutator制御を実装した。関連する設計文書と検証テストも更新した。

Changes

専用TSO FSM

Layer / File(s) Summary
TSO状態の適用と入力検証
kv/tso_fsm.go, kv/tso_fsm_test.go, docs/design/...
TSOStateMachineがHLC leaseとallocation floorをatomicに保持・適用し、不正エントリをhalt付きで拒否する。レガシー暗号制御エントリは状態を変更せず拒否する。
スナップショットと旧形式復元
kv/tso_fsm.go, kv/tso_fsm_test.go, docs/design/...
ceilingとallocation floorを16バイトのv2形式で保存し、旧8バイト形式およびkvFSM由来スナップショットからfloorを導出して復元する。
group-0 runtimeと管理配線
main.go, main_encryption_admin.go, main_encryption_admin_test.go, multiraft_runtime_test.go, docs/design/...
専用TSO groupの構築と既存ストア保持を整理し、group-0ではmutatorを無効化しつつLeaderViewを配線する。失敗時のruntime解放とレガシー暗号エントリ後の継続処理を検証する。

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RaftRuntime
  participant TSOStateMachine
  participant HLC
  participant EncryptionAdmin
  RaftRuntime->>TSOStateMachine: group-0のlease/floorエントリをApply
  TSOStateMachine->>HLC: ceilingまたはallocation floorを反映
  TSOStateMachine-->>RaftRuntime: 更新結果または拒否結果
  RaftRuntime->>EncryptionAdmin: group単位の管理配線を登録
  EncryptionAdmin-->>RaftRuntime: group-0のmutator要求をFailedPreconditionで拒否
Loading

Possibly related PRs

  • bootjp/elastickv#748: TSO FSMが扱うレガシー暗号制御エントリのwire opcodeとデコード処理に関連する。
  • bootjp/elastickv#760: registerEncryptionAdminServerの登録経路とEncryptionAdmin配線に関連する。
  • bootjp/elastickv#1064: 専用TSOのgroup-0予約とTSO固有のruntime配線に関連する。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 専用TSO用のFSM追加という主要変更を簡潔に表しており、変更内容と整合しています。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

@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 implements the TSOStateMachine, a minimal state machine for the dedicated timestamp group that handles HLC lease-renewal entries, along with its snapshotting, restoration, and volatile entry classification logic. It also updates the design documentation to reflect this progress and adds comprehensive unit tests for the new state machine. There are no review comments to evaluate, and I have no additional feedback to provide.

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.

@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

| M6 — partial | Dedicated TSO Raft group (`groupID = 0`) is reserved/bootstrap-capable and warmed by the HLC renewal bridge; TSO-leader-only timestamp issuance and the minimal `TSOStateMachine` remain open | Low |

P3 Badge Update stale M6 status row

This milestone row still says the minimal TSOStateMachine remains open, but this same change marks it implemented in §1.0 and adds kv/tso_fsm.go. Readers using this design doc to plan M6 will incorrectly think the FSM work is still pending, so please update the row to match the new runtime-wiring-only remaining status.

ℹ️ 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 kv/tso_fsm.go Outdated
}
ceilingMs := int64(binary.BigEndian.Uint64(data[1:])) //nolint:gosec // value is a Unix ms timestamp encoded as uint64.
if f != nil && f.hlc != nil && ceilingMs > 0 {
f.hlc.SetPhysicalCeiling(ceilingMs)

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 Advance the TSO HLC floor on lease apply

When this FSM is used for the dedicated TSO group, applying a lease only updates physicalCeiling while leaving HLC.last at zero on followers/restarted nodes. If the current TSO leader has handed out timestamps under a future ceilingMs and then fails before the wall clock reaches it, the new leader has applied the same lease but has not observed any of those allocations, so its first NextBatchFenced can return (ceilingMs<<16)|0 again and duplicate timestamps. The TSO path needs to persist/observe an allocation floor or force a fresh higher lease before serving after leadership changes.

Useful? React with 👍 / 👎.

Comment thread kv/tso_fsm.go Outdated

func (f *TSOStateMachine) Apply(data []byte) any {
if len(data) != hlcLeaseEntryLen {
return errors.Wrapf(ErrTSOStateMachineInvalidEntry, "expected %d bytes, got %d", hlcLeaseEntryLen, len(data))

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 Return a halting response for invalid TSO entries

If a malformed payload is ever committed to the dedicated TSO group, returning a bare error here does not actually reject it at the raft apply layer: applyNormalCommitted only stops before setApplied for responses implementing HaltApply() error, while plain error responses are still marked applied and only delivered back to the proposer. In a misrouted group-0 proposal or mixed-version entry scenario, the invalid entry would be permanently advanced past instead of failing closed, violating the FSM's “accepts only HLC lease entries” contract.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated commit: 4e49dfbe7f31f084fc98bb5bec47a0e1458c4c24

Addressed current-head review findings:

  • TSOStateMachine now observes a derived allocation floor for each applied/restored HLC lease ceiling, preventing a restarted or newly elected TSO leader from reissuing the previous leader's logical slots.
  • Invalid TSO FSM entries now return a HaltApply response instead of a plain error, so malformed group-0 entries fail closed without advancing applied index.
  • The centralized TSO design doc M6/status text now matches the implemented FSM and remaining runtime-wiring work.

Caller/semantic audit:

  • NewTSOStateMachine remains only used by the new tests in this branch; runtime group-0 wiring is still a documented follow-up.
  • The HLC floor change is limited to the dedicated TSO FSM path and does not change kvFSM HLC lease apply behavior.

Validation:

  • go test ./kv -run 'TestTSOStateMachine|TestLocalTSOAllocator|TestBatchAllocator|TestShardedCoordinator.*Timestamp|TestCoordinateUsesTSOAllocator' -count=1 -timeout=180s
  • go test ./kv -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./kv --timeout=5m
  • git diff --check
  • git verify-commit 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: 4e49dfbea8

ℹ️ 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 kv/tso_fsm.go Outdated
return
}
hlc.SetPhysicalCeiling(ceilingMs)
hlc.Observe(tsoLeaseAllocationFloor(ceilingMs))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Persist the post-lease allocation floor

When the dedicated TSO FSM is wired, applying/restoring a lease with this Observe only records ceilingMs|maxLogical in memory while snapshots/WAL entries still persist just ceilingMs. If a leader applies ceiling C, serves one timestamp, NextBatchFenced returns (C+1,0) because the floor is already C|maxLogical; after a restart or re-election with only the same lease entry/snapshot, applyTSOLeaseToHLC recreates the same floor and can serve (C+1,0) again. This means the new floor does not actually prevent reissuing timestamps unless the allocation floor/current HLC is made durable or allocation is blocked until a higher ceiling is committed.

Useful? React with 👍 / 👎.

Comment thread kv/tso_fsm.go Outdated
Comment on lines +72 to +73
if hlc == nil || ceilingMs <= 0 {
return

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 Reject non-positive TSO lease ceilings

When a full HLC-lease entry encodes 0 or a high-bit value that decodes negative, this branch returns without error, so Apply returns nil and the engine advances the applied index. Renewals only generate positive Unix-ms ceilings, so these are malformed group-0 lease entries; accepting them masks the bad proposal instead of using the new fail-closed HaltApply path. Please reject non-positive ceilings in Apply while keeping snapshot restore's empty-state handling separate if needed.

Useful? React with 👍 / 👎.

Comment thread kv/tso_fsm.go Outdated
if f != nil {
hlc = f.hlc
}
return &tsoFSMSnapshot{ceilingMs: hlcCeilingFromHLC(hlc)}, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep snapshots sourced from TSO-applied leases

When group 0 is wired during the documented bridge, this FSM is likely to share the process HLC that shard FSMs also advance; then Snapshot can serialize a ceiling raised by some data-group lease even if the TSO group never committed that lease. If a shard renewal succeeds while the group-0 proposal fails or lags, installing/restoring the group-0 snapshot advances dedicated TSO state beyond its own consensus log. Keep a TSO-FSM-owned ceiling field updated only from this FSM's Apply/Restore path and snapshot that value instead.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated commit: 44e6c18

Addressed current-head review findings:

  • TSOStateMachine now keeps TSO-owned ceiling and allocation-floor state, and snapshots those fields instead of reading the shared HLC mirror. This prevents data-group lease renewals from contaminating group-0 snapshots.
  • HLC lease entries now advance only the physical ceiling; allocation-floor advancement is an explicit TSO FSM entry and is persisted through the FSM snapshot format.
  • Non-positive HLC lease ceilings and malformed allocation-floor entries now halt apply through ErrTSOStateMachineInvalidEntry.
  • The design doc now reflects the ceiling/floor snapshot contract and the remaining runtime group-0 wiring work.

Caller/semantic audit:

  • NewTSOStateMachine is still referenced only by this branch's TSO FSM tests; runtime group-0 wiring remains documented as a follow-up.
  • kvFSM HLC lease behavior is unchanged; the new allocation-floor opcode is TSO-FSM-local and intentionally uses a byte that data-group kvFSM already routes through the fail-closed reserved range.

Validation:

  • go test ./kv -run 'TestTSOStateMachine|TestLocalTSOAllocator|TestBatchAllocator|TestShardedCoordinator.*Timestamp|TestCoordinateUsesTSOAllocator' -count=1 -timeout=180s
  • go test ./kv -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./kv --timeout=5m
  • git diff --check
  • git verify-commit HEAD

Additional check:

  • go test ./... -count=1 -timeout=600s was attempted; all completed packages reported ok, but adapter timed out at 600s in long-running gRPC/SQS adapter tests. This is outside the changed kv/doc surface.

@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: 44e6c1852b

ℹ️ 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 kv/tso_fsm.go
Comment on lines +104 to +105
case tsoSnapshotV1Len:
ceilingMs = int64(binary.BigEndian.Uint64(payload[:hlcLeasePayloadLen])) //nolint:gosec // legacy snapshot value.

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 Derive the floor when restoring legacy TSO snapshots

When this restores an 8-byte snapshot emitted by the previous TSO FSM format, allocationFloor remains 0. Those legacy snapshots were produced by code that also observed tsoLeaseAllocationFloor(ceilingMs) on apply/restore to prevent a restarted or newly elected TSO leader from handing out logical slots from the old ceiling millisecond. After upgrading from such a snapshot, the HLC mirror has only the ceiling, so the next NextBatchFenced can start at ceiling<<16|0 and overlap timestamps already covered by the prior floor; derive the legacy floor from the decoded ceiling before calling restoreSnapshotState.

Useful? React with 👍 / 👎.

Comment thread kv/tso_fsm.go Outdated
Comment on lines +150 to +151
f.ceilingMs.Store(ceilingMs)
f.allocationFloor.Store(allocationFloor)

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 Keep TSO-owned fields monotonic during restore

When Restore is called on an FSM that has already applied a higher ceiling/floor (the monotonic-restore test exercises this shape), these unconditional stores regress the FSM-owned state even though the HLC mirror remains high via its monotonic setters. Because Snapshot() now serializes f.ceilingMs and f.allocationFloor rather than the HLC, the next snapshot from that FSM can persist the lower values and lose the higher applied TSO floor/ceiling; restore should max these fields the same way apply does.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated commit: 5b6fd30

Addressed current-head P2 findings:

  • Restoring a legacy 8-byte TSO FSM snapshot now derives the allocation floor from the restored ceiling, preserving the previous format's floor behavior across upgrade/restart.
  • Restore now updates TSO-owned ceiling/floor fields monotonically instead of unconditionally storing lower snapshot values; the HLC mirror and subsequent snapshots stay at the highest applied TSO state.
  • The design doc Restore example now reflects the 8-byte legacy and 16-byte current snapshot handling.

Caller/semantic audit:

  • NewTSOStateMachine remains referenced only by this branch's TSO FSM tests; runtime group-0 wiring remains a documented follow-up.
  • The restore semantic change is limited to TSOStateMachine and matches the monotonic apply path.

Validation:

  • go test ./kv -run 'TestTSOStateMachine|TestLocalTSOAllocator|TestBatchAllocator|TestShardedCoordinator.*Timestamp|TestCoordinateUsesTSOAllocator' -count=1 -timeout=180s
  • go test ./kv -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./kv --timeout=5m
  • git diff --check
  • git verify-commit HEAD

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 5b6fd30121

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

Base automatically changed from design/dedicated-tso-group to main July 19, 2026 06:07

@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: 46be7a832f

ℹ️ 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 Outdated
Comment on lines +1195 to +1196
sg := &kv.ShardGroup{Engine: runtime.engine}
sg.Txn = kv.NewLeaderProxyForShardGroup(sg, kv.WithProposalObserver(proposalObserver))

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 Don't count the TSO group in raft-envelope cutover scope

When group 0 is configured alongside a single data group, this returned ShardGroup is added to encWiring.attachRaftEnvelopeGroup in buildShardGroups. I checked adapter/encryption_admin.go's EnableRaftEnvelope path and main_raft_envelope_wiring.go's ValidateCutoverScope: the cutover precheck rejects unless exactly one group is attached, so enabling the dedicated TSO group turns a previously valid single-data-group raft-envelope rollout into FailedPrecondition (got 2) even though group 0 holds no user data. Exclude group 0 from that scope check or handle its cutover separately.

Useful? React with 👍 / 👎.

Comment thread kv/tso_fsm.go
Comment on lines +181 to +183
legacy, err := hasLegacyKVFSMSnapshotHeader(br)
if err != nil || !legacy {
return legacy, err

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 Preserve headerless legacy group-0 snapshots

When upgrading a reserved group-0 log that previously ran kvFSM from a version that emitted the supported headerless snapshot format, this probe returns legacy=false, so Restore falls through to readTSOSnapshotState and accepts only exactly 8 or 16 bytes. ReadSnapshotHeader deliberately leaves non-magic/headerless snapshots unconsumed for the inner store restore path, and those raw store payloads are not constrained to the TSO lengths, so affected nodes can fail to restore or misparse a 16-byte store payload instead of draining the legacy MVCC snapshot. Detect and drain headerless kvFSM snapshots before trying the raw TSO format.

Useful? React with 👍 / 👎.

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

ℹ️ 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_encryption_admin.go Outdated
Comment thread kv/tso_fsm.go Outdated
@bootjp
bootjp force-pushed the design/dedicated-tso-fsm branch from e701cb2 to 97a42ba Compare July 19, 2026 12:17
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Evidence for current HEAD 97a42ba72c18205fcb84a43ad4ca0cedc48efa31:

  • Dedicated TSO encryption-admin wiring keeps mutators disabled but retains LeaderView; ResyncSidecar now rejects group-0 followers.
  • Allocation-floor proposals use a versioned TSO envelope. Bare/future encryption-reserved entries cannot be decoded as TSO state and halt fail-closed.
  • Semantic audit: the sole production encryptionAdminWiringForGroup caller was checked; data-group mutator behavior is unchanged. Allocation-floor encoding remains TSO-FSM-local in this PR and all apply/classifier/test consumers use the same envelope.
  • TLA audit: make tla-check matched all safe and expected-gap model outcomes.
  • The design remains Partial until the full dependency stack is clear.

History sanitation:

  • Rebuilt on current origin/main 915bc77795d940644e09ce3ee521626e64e2f442.
  • PR-visible history is one commit, authored and committed by bootjp <contact@bootjp.me>.
  • GitHub signature verification is verified: true.
  • Desired tree hash before and after rebuild: 5d4fd0dccfb27bf859311df68cdf9a119fcb33bc.

Validation:

  • go test ./kv . -count=1
  • go test -race ./kv . -run "TestTSOStateMachine|TestEncryptionAdmin_(DedicatedTSOGroup|DataGroup)|TestRegisterEncryptionAdminServer" -count=1
  • golangci-lint run ./... --timeout=5m --allow-parallel-runners (0 issues)
  • make tla-check
  • git diff --check origin/main..HEAD

@codex review

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

🧹 Nitpick comments (1)
kv/tso_fsm.go (1)

94-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

//nolint:gosec の抑制は境界チェックへの置き換えを検討してください。

コーディングガイドラインでは //nolint の追加を避け、リファクタリングを優先することが求められています。タイムスタンプの uint64int64 変換については、変換前に math.MaxInt64 との境界チェックを行う小さなヘルパー(例: func unixMillisToInt64(v uint64) (int64, error))を導入することで、複数箇所の //nolint:gosec を排除できます。既存コードで許容される慣例であれば据え置きで構いませんが、新規追加分については抑制の集約を推奨します。

As per coding guidelines: "Avoid adding //nolint unless absolutely required; prefer refactoring."

Also applies to: 165-167, 197-197, 325-325

🤖 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 `@kv/tso_fsm.go` at line 94, Replace the new `//nolint:gosec` suppressions
around the `ceilingMs` conversion and the corresponding conversions at the other
referenced sites with a shared checked conversion helper, such as
`unixMillisToInt64`. Have the helper validate against `math.MaxInt64` before
converting and return an error for overflow, then propagate or handle that error
at each caller while preserving existing timestamp behavior.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@kv/tso_fsm.go`:
- Line 94: Replace the new `//nolint:gosec` suppressions around the `ceilingMs`
conversion and the corresponding conversions at the other referenced sites with
a shared checked conversion helper, such as `unixMillisToInt64`. Have the helper
validate against `math.MaxInt64` before converting and return an error for
overflow, then propagate or handle that error at each caller while preserving
existing timestamp behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 378b480f-a7cd-42e8-a4ec-e03b8e9fa899

📥 Commits

Reviewing files that changed from the base of the PR and between 915bc77 and 97a42ba.

📒 Files selected for processing (7)
  • docs/design/2026_04_16_partial_centralized_tso.md
  • kv/tso_fsm.go
  • kv/tso_fsm_test.go
  • main.go
  • main_encryption_admin.go
  • main_encryption_admin_test.go
  • multiraft_runtime_test.go

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 97a42ba72c

ℹ️ 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 2 commits July 19, 2026 22:58
## Summary
- route dedicated group-0 timestamp requests to the current TSO leader
- commit every returned window end and fence each leader term above
authoritative data-group commit floors
- add synchronous fail-closed shadow migration and a durable one-way
cutover marker
- preserve rolling compatibility by rejecting legacy timestamp responses
without durable reservation metadata
- update the centralized TSO design status through M6

## Migration safety
- shadow candidates are serialized through group 0 before the legacy
value is returned
- overlapping legacy candidates are discarded and retried
- cutover commits the marker before the first production window
- group-0, shadow, and cutover failures stop timestamp issuance instead
of falling back

## Validation
- `go test ./kv -count=1 -timeout=10m`
- `go test . -count=1 -timeout=10m`
- `go test ./adapter -run
'Test(DistributionServerGetTimestamp|GRPCServer_RawLatestCommitTS_EmptyKeyReturnsGlobalWatermark)'
-count=1 -timeout=5m`
- `go test ./... -run '^$' -count=1 -timeout=10m`
- `go test -race ./kv -run
'Test(RaftTSOAllocator|LeaderRoutedTSOAllocator|ShadowTimestampAllocator|ShardStoreGlobalCommittedTimestampFloor)'
-count=1 -timeout=10m`
- `golangci-lint --config=.golangci.yaml run ./kv ./adapter .
--timeout=5m`
- `make gen
BREAKING_AGAINST='../.git#subdir=proto,branch=design/dedicated-tso-runtime'`

## Stack
Base: #1103

Author: bootjp

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

ℹ️ 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 kv/tso_raft.go
Comment on lines +131 to +132
if min == ^uint64(0) {
return empty, errors.WithStack(ErrTxnCommitTSRequired)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject near-overflow TSO minimums

When ReserveBatchAfter is called with n > 1 and a minimum close to MaxUint64 (for example Distribution.GetTimestamp{count:2, min_timestamp:MaxUint64-1}), this guard lets the request through; a.clock.Observe(min) then causes NextBatchFenced to wrap the reserved base to 0 and the HLC current value to 1 before the later response validation can fail, and commitAllocationFloor can persist that regressed floor. Reject any min that cannot fit the requested window before observing it.

Useful? React with 👍 / 👎.

Comment thread main.go
cfg.engine,
distCatalog,
adapter.WithDistributionCoordinator(coordinate),
adapter.WithDistributionTimestampAllocator(tsoWiring.serverAllocator),

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 Gate mutating timestamp RPCs during startup rotation

When a client can reach the raft gRPC listener during startup rotation, this wiring makes Distribution.GetTimestamp call the dedicated allocator and commit group-0 allocation/cutover entries, but startupRotationGatedMethod only gates Distribution.SplitRange plus the RawKV/Transactional/Internal/Admin mutators. That lets timestamp proposals bypass the same startup mutator fence before waitRotateOnStartup completes and before public traffic is marked ready; include GetTimestamp in the gate or delay exposing the allocator until the gate opens.

Useful? React with 👍 / 👎.

return &pb.GetTimestampResponse{Timestamp: s.engine.NextTimestamp()}, nil
}

reservation, err := s.allocateTimestampReservation(ctx, count, minTimestamp, activateCutover)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate TSO cutover activation

When group 0 is configured for Phase A/B but this node was not started with --tsoEnabled, any caller that can reach Distribution.GetTimestamp can set activate_cutover=true; this line forwards that untrusted request bit into the allocator, which commits the one-way cutover marker. Since main wires the server allocator even before production cutover, this bypasses the operator flag and the all-nodes-shadow rollout precondition, so keep activation tied to local/internal configuration rather than the public RPC field.

Useful? React with 👍 / 👎.

Comment thread kv/shard_store.go
return 0, errors.Wrapf(ErrTSOCommitFloorUnavailable,
"data group %d is not led by this node", groupID)
}
if _, err := linearizableReadEngineCtx(nonNilTSOContext(ctx), engine); err != nil {

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 Bound local floor ReadIndex calls

When the TSO leader also leads a data group and the incoming timestamp request has no deadline, this local LinearizableRead inherits an unbounded context, unlike verifyLeaderEngineCtx and the remote floor RPC timeout. If that ReadIndex stalls, ReserveBatchAfter is still holding the allocator mutex while initializing the term floor, so one stuck local floor probe can wedge all subsequent TSO allocations; wrap this path in a bounded context.

Useful? React with 👍 / 👎.

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