Skip to content

Reduce Redis proxy replay backpressure#1146

Open
bootjp wants to merge 12 commits into
mainfrom
feature/redis-proxy-connections
Open

Reduce Redis proxy replay backpressure#1146
bootjp wants to merge 12 commits into
mainfrom
feature/redis-proxy-connections

Conversation

@bootjp

@bootjp bootjp commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • Increase Redis proxy ElasticKV backend connection defaults and blocking replay capacity.
  • Extend HLC renewal slack so Redis write load does not exhaust the physical ceiling during transient Raft proposal latency.
  • Optimize BZPOPMIN replay by popping from the ZSet score index instead of loading the whole sorted set.
  • Align the Redis server per-peer connection default with the larger proxy pool and update deployment docs.

Root cause

Production Redis proxy metrics showed the blocking replay queue filling while the ElasticKV go-redis pool had no pending requests. CPU profiling on the ElasticKV leader showed BZPOPMIN replay spending most CPU in ZSet type/probe scans and full sorted-set loading. Under this pressure, the previous 1s HLC renewal proposal timeout could miss renewals and cause write failures.

Validation

  • go test ./adapter -run 'TestRedisPeerLimiter|TestRedisLeaderClient|TestRedisBlockingLeaderClient|TestRedis_BZPopMin|TestRedis_BullMQ' -count=1
  • go test ./cmd/redis-proxy ./proxy ./kv -count=1
  • git diff --check

Operations

Temporarily updated the running proxy on 192.168.0.64 to pool 192, write concurrency 96, script concurrency 16, blocking replay concurrency 64, and blocking replay queue 8192. After the change, proxy metrics showed drop count 0, secondary write errors 0, queue depth 0, and no backend pool wait.

Summary by CodeRabbit

  • 機能改善

    • HLCリース更新の安定性を高め、更新処理の遅延時も継続的に動作するよう改善しました。
    • Redisプロキシの接続プールとセカンダリ書き込み再生の同時実行性能を向上しました。
    • BZPOPMINの候補選択を改善し、インデックス利用時の処理効率と互換性を高めました。
  • ドキュメント

    • HLCの更新間隔・安全ウィンドウ、Redisプロキシの推奨設定および監視方法を最新化しました。

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

HLCリース更新を非同期化し、提案タイムアウトと物理窓を更新しました。BZPOPMINの候補探索とscan計画を再構成し、Redisプロキシの接続上限・blocking replay並列度・関連文書を更新しました。

Changes

HLCリース更新

Layer / File(s) Summary
HLC更新制御
kv/coordinator.go, kv/sharded_coordinator.go
HLC更新間隔と物理窓の既定値を変更し、提案ごとのタイムアウトを導入しました。更新提案のin-flight抑制を削除し、重複提案を許可しました。
HLC前提とテストの整合
kv/*_test.go, README.md, docs/architecture_overview.md, docs/design/*
提案deadline、更新重複、物理窓の余裕を検証するテストを追加し、関連文書の数値前提を2秒・20秒へ更新しました。

BZPOPMIN候補選択

Layer / File(s) Summary
候補探索と結果永続化
adapter/redis_zset_cmds.go, adapter/redis_bzpopmin_wake_test.go
スコアインデックス、メンバー行、レガシーblobの候補選択を分離し、候補情報に基づく永続化とScanAt計画のテストを追加しました。

Redisプロキシ容量設定

Layer / File(s) Summary
容量と並列度の既定値
internal/redislimits/limits.go, proxy/*, adapter/redis_peer_limiter*, cmd/redis-proxy/main_test.go
共有接続上限64を導入し、ElasticKVプール、per-peer上限、blocking replay上限と関連テストを更新しました。
デプロイ設定と運用記述
README.md, docs/design/2026_04_24_implemented_workload_isolation.md, docs/redis-proxy-deployment.md
dual-writeの起動例、接続上限の説明、blocking replay設定、メトリクス、運用手順を更新しました。

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

Sequence Diagram(s)

sequenceDiagram
  participant RunHLCLeaseRenewal
  participant renewHLCLeaseAsync
  participant ProposeHLCLease
  RunHLCLeaseRenewal->>renewHLCLeaseAsync: 更新提案を非同期投入
  renewHLCLeaseAsync->>ProposeHLCLease: タイムアウト付きで提案
  ProposeHLCLease-->>renewHLCLeaseAsync: 提案結果
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Redis proxy の replay/backpressure 問題に対処する変更内容を簡潔に要約しており、主な変更点と一致しています。
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@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 (eaf5701):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 22, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@bootjp
bootjp marked this pull request as ready for review July 22, 2026 17:22
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@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 (eaf5701):

  • kv/coordinator.go
  • kv/sharded_coordinator.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.

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
adapter/redis_peer_limiter_test.go (1)

13-20: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

proxy poolとの一致を実際に検証してください。

このテストはdefaultRedisPerPeerConnectionCapとリテラル64の一致しか確認しておらず、DefaultElasticKVBackendOptions().PoolSizeとの不一致は検出できません。共有定数を単一ソースにするか、依存方向を壊さない統合テストで両方の既定値を比較してください。

🤖 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 `@adapter/redis_peer_limiter_test.go` around lines 13 - 20, Update
TestRedisPeerLimiterDefaultMatchesProxyPool to compare server.peerLimiter.limit
with DefaultElasticKVBackendOptions().PoolSize, removing the literal 64
assertion. Ensure the test verifies both defaults remain equal without
introducing a dependency that violates package direction; use a shared constant
instead if that is the established design.
adapter/redis_zset_cmds.go (1)

1170-1170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

マジックナンバー 2//nolint:mnd を付与せず、名前付き定数化を検討してください。

コーディングガイドラインでは //nolint の追加は極力避け、リファクタリングを優先するよう定められています。2bzpopminScoreScanLimit のような定数として切り出せば、.golangci.yamlmnd linter を無効化せずに済みます。

As per coding guidelines, "Avoid using //nolint directives; refactor instead in Go code".

♻️ 提案する修正
+// bzpopminScoreScanLimit fetches the first score-index entry plus a
+// last-entry sentinel so isLast can be determined without a full scan.
+const bzpopminScoreScanLimit = 2
+
 func (r *RedisServer) bzpopminWideScoreCandidateAt(ctx context.Context, key []byte, readTS uint64) (*bzpopminCandidate, error) {
 	scorePrefix := store.ZSetScoreScanPrefix(key)
 	scoreEnd := store.PrefixScanEnd(scorePrefix)
-	scoreKVs, err := r.store.ScanAt(ctx, scorePrefix, scoreEnd, 2, readTS) //nolint:mnd // first entry plus last-entry sentinel
+	scoreKVs, err := r.store.ScanAt(ctx, scorePrefix, scoreEnd, bzpopminScoreScanLimit, readTS)
🤖 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 `@adapter/redis_zset_cmds.go` at line 1170, Replace the literal scan limit 2
and its //nolint:mnd directive in the ScanAt call with a clearly named constant
such as bzpopminScoreScanLimit, preserving the existing behavior of scanning the
first entry plus the last-entry sentinel.

Source: Coding guidelines

adapter/redis_bzpopmin_wake_test.go (1)

30-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

候補選択の他の分岐(isLast=true、member-only/legacyフォールバック)がテストされていません。

現在のテストは wide-score-index かつ isLast=false の1ケースのみです。特に isLast=truedeleteLogicalKeyElems による全体削除に分岐する重要なパスなので、table-driven形式で以下も追加することを推奨します。

  • スコアエントリが1件のみ(isLast=true)
  • スコアインデックスなし・member-onlyのみ存在
  • スコア/member両方なし・legacy blobのみ存在

As per coding guidelines, "Unit tests should be co-located with packages in *_test.go files; prefer table-driven test cases."

🤖 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 `@adapter/redis_bzpopmin_wake_test.go` around lines 30 - 54, Expand
TestRedis_BZPopMinCandidateUsesScoreIndex into table-driven cases covering the
existing wide-score-index path, a single score entry that produces isLast=true,
member-only fallback without a score index, and legacy-blob fallback when
neither score nor member entries exist. For each case, construct the appropriate
store state and assert the candidate selection and deletion-path flags,
especially isLast=true for the single-entry case.
🤖 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.

Inline comments:
In `@docs/architecture_overview.md`:
- Line 173: Update the architecture diagram’s “every hlcRenewalInterval” label
to explicitly state the operational 2-second renewal interval while retaining
the under-30-second physical-window constraint, using wording such as “=2s;
<30s”.

In `@docs/design/2026_06_12_proposed_scaling_roadmap.md`:
- Around line 88-89: HLC更新主体の説明を現行実装に合わせ、`ProposeHLCLease` と
`hlcPhysicalWindowMs`/`hlcRenewalInterval` の更新をdefault-group leader限定ではなく各shard
group単位のrenewalとして記述してください。続くWAN依存モデルおよびper-group
renewalの説明も同じ契約に統一し、更新間隔の値は維持してください。

In `@kv/coordinator.go`:
- Around line 44-46: hlcRenewalInterval
の値だけを根拠にHLC窓の失効が防止されるような定義・コメントにせず、提案処理の最大時間、スケジューラ停止、連続更新失敗を含む安全余裕を明示的に反映してください。hlcRenewalInterval
と hlcPhysicalWindowMs の関係を、その余裕を満たすことまで検証できる形に更新し、将来の値変更で誤った安全性判断が生じないようにしてください。

In `@README.md`:
- Line 17:
README.md:17のHLC説明を条件付き表現に変更し、新リーダーが重複タイムスタンプを発行しないことを実装済み保証として断定しない。docs/design/2026_06_11_implemented_leader_balance_scheduler.md:192のリーダー移動時の安全性説明にも、論理カウンタ引き継ぎとceiling
expiry時のfail-closed
fencingが実装されていることを前提条件として明記する。両文書の記述を、これらの安全機構が実装されるまで保証ではなく必要条件として整合させる。

---

Nitpick comments:
In `@adapter/redis_bzpopmin_wake_test.go`:
- Around line 30-54: Expand TestRedis_BZPopMinCandidateUsesScoreIndex into
table-driven cases covering the existing wide-score-index path, a single score
entry that produces isLast=true, member-only fallback without a score index, and
legacy-blob fallback when neither score nor member entries exist. For each case,
construct the appropriate store state and assert the candidate selection and
deletion-path flags, especially isLast=true for the single-entry case.

In `@adapter/redis_peer_limiter_test.go`:
- Around line 13-20: Update TestRedisPeerLimiterDefaultMatchesProxyPool to
compare server.peerLimiter.limit with DefaultElasticKVBackendOptions().PoolSize,
removing the literal 64 assertion. Ensure the test verifies both defaults remain
equal without introducing a dependency that violates package direction; use a
shared constant instead if that is the established design.

In `@adapter/redis_zset_cmds.go`:
- Line 1170: Replace the literal scan limit 2 and its //nolint:mnd directive in
the ScanAt call with a clearly named constant such as bzpopminScoreScanLimit,
preserving the existing behavior of scanning the first entry plus the last-entry
sentinel.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3ee592f7-7d7c-4bda-8e99-5d8617f10bb2

📥 Commits

Reviewing files that changed from the base of the PR and between 5d4c5ca and eaf5701.

📒 Files selected for processing (21)
  • README.md
  • adapter/redis_bzpopmin_wake_test.go
  • adapter/redis_peer_limiter.go
  • adapter/redis_peer_limiter_test.go
  • adapter/redis_zset_cmds.go
  • cmd/redis-proxy/main_test.go
  • deploy/redis-proxy/docker-compose.ha.yml
  • docs/architecture_overview.md
  • docs/design/2026_04_24_implemented_workload_isolation.md
  • docs/design/2026_05_28_implemented_tla_safety_spec.md
  • docs/design/2026_06_02_implemented_idempotent_snapshot_restore.md
  • docs/design/2026_06_11_implemented_leader_balance_scheduler.md
  • docs/design/2026_06_12_proposed_scaling_roadmap.md
  • docs/redis-proxy-deployment.md
  • kv/coordinator.go
  • kv/lease_read_test.go
  • kv/lease_warmup_test.go
  • kv/sharded_coordinator.go
  • proxy/backend.go
  • proxy/dualwrite.go
  • proxy/proxy_test.go

Comment thread docs/architecture_overview.md Outdated
Comment thread docs/design/2026_06_12_proposed_scaling_roadmap.md Outdated
Comment thread kv/coordinator.go
Comment thread README.md Outdated
@bootjp

bootjp commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@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 (c174055):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 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: c1740550db

ℹ️ 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/redis_zset_cmds.go Outdated
Comment on lines +1159 to +1163
candidate, err := r.bzpopminWideScoreCandidateAt(ctx, key, readTS)
if err != nil || candidate != nil {
return candidate, err
}
candidate, err = r.bzpopminMemberOnlyCandidateAt(ctx, key, readTS)

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 BZPOPMIN from skipping member-only zset entries

When a zset still has member-only wide rows from the older layout and a later ZADD/ZINCRBY touches only some members, only those touched members get !zs|scr| score-index rows. This score-first branch then treats any partial score index as authoritative, so BZPOPMIN can pop a higher-scored indexed member while lower-scored unindexed members remain; if there is only one indexed member, isLast is set and persistBZPopMinResult deletes the whole logical key, dropping the unindexed members. Please fall back to the member scan/load path unless the score index is known to cover the full zset, or migrate all member rows before using the score index.

Useful? React with 👍 / 👎.

bootjp added 3 commits July 23, 2026 20:24
# Conflicts:
#	adapter/redis_peer_limiter.go
#	adapter/redis_peer_limiter_test.go
#	docs/redis-proxy-deployment.md
#	kv/lease_read_test.go
#	proxy/backend.go
#	proxy/proxy_test.go
# Conflicts:
#	adapter/redis_peer_limiter_test.go
#	docs/redis-proxy-deployment.md
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

@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 (64e97df):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 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: 64e97dfc1a

ℹ️ 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/redis_zset_cmds.go Outdated
return &bzpopminCandidate{
entry: redisZSetEntry{Member: string(member), Score: score},
isWide: true,
isLast: len(scoreKVs) == 1,

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 Do not mark indexed candidates as last by index count

When a wide ZSET is in a mixed upgrade state (member rows exist but only the newly written lowest member has a score-index row), this sets isLast from the score-index scan count rather than the member-row count. bzpopminCandidateAt can then pick this lower score candidate, and persistBZPopMinResult treats it as the last entry and calls deleteLogicalKeyElems, deleting the remaining unindexed members instead of popping only the returned member.

Useful? React with 👍 / 👎.

Comment thread adapter/redis_peer_limiter.go Outdated
redisPeerLimitError = "ERR max connections per client exceeded"
unknownRedisPeer = "unknown"
redisPerPeerLimitEnv = "ELASTICKV_REDIS_PER_PEER_CONNECTIONS"
defaultRedisPerPeerConnectionCap = redislimits.DefaultElasticKVRedisConnections

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 headroom for dedicated Pub/Sub sockets

With the new default, the adapter per-peer cap equals the proxy's default ElasticKV command pool size (64). In modes where the proxy also opens ElasticKV Pub/Sub/shadow Pub/Sub connections, those sockets are dedicated outside the go-redis command pool, so a busy proxy host can fill all 64 pooled command connections and then have the Pub/Sub connection rejected by this limiter; the previous dedicated headroom avoided that user-visible failure.

Useful? React with 👍 / 👎.

Comment thread proxy/dualwrite.go
Comment thread adapter/redis_zset_cmds.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 (a3ed3ec):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 added 2 commits July 23, 2026 21:11
…onnections

# Conflicts:
#	adapter/redis_peer_limiter_test.go
#	docs/redis-proxy-deployment.md
#	proxy/backend.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 (c14b20c):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 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: c14b20c3c8

ℹ️ 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/redis_zset_cmds.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 (9193b0b):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 23, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@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: 9193b0bbf1

ℹ️ 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/redis_zset_cmds.go Outdated
Comment on lines +1213 to +1217
return &bzpopminCandidate{
entry: redisZSetEntry{Member: string(member), Score: score},
isWide: true,
isLast: scoreIndexComplete && metaLen == 1,
}, scoreIndexComplete, 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 Preserve tie ordering before popping from the score index

When BZPOPMIN runs on the Pebble-backed store and the minimum-score bucket has members whose names are prefix-related, such as a and aa, returning the first raw score-index scan row can pop the wrong member. Pebble orders encoded MVCC keys as userKey || invertedTS, so ...aa... can sort before ...a<ts>... even though Redis sorted sets break equal-score ties by member lexicographic order; the existing range fast path avoids this by falling back on duplicate scores. This path should either sort/verify all tied minimum-score rows or fall back to the member loader when the score scan shows a tie before deleting the candidate.

Useful? React with 👍 / 👎.

Comment thread kv/coordinator.go Outdated
// ceiling = now + window, and renews before the window expires. A new leader
// inherits the committed ceiling so it never issues timestamps that collide
// with the previous leader's window.
const hlcPhysicalWindowMs int64 = 30_000

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 the HLC window below txn lock TTL

With this window set to 30s, a normal renewal makes NextFenced allocate prepare startTS values around now+30s, but txnLockExpireAt still sets the default lock expiry to wall now+defaultTxnLockTTLms, also 30s. For a two-phase/cross-shard transaction prepared soon after a renewal, the lock's ExpireAt is therefore at or only milliseconds above its own startTS, and the MVCC visibility check treats ExpireAt <= readTS as expired, so later transactions stop seeing the lock after the next renewal instead of after the intended 30s. Either keep the window comfortably below the default lock TTL or compute lock expiry from the HLC start timestamp.

Useful? React with 👍 / 👎.

Comment on lines 27 to 28
close hooks. Default cap is 64 per peer IP and is configurable via
`ELASTICKV_REDIS_PER_PEER_CONNECTIONS` /

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Document the actual per-peer default

This updated status says the Redis adapter's per-peer cap defaults to 64, but the implementation now derives defaultRedisPerPeerConnectionCap as the 64-connection ElasticKV pool plus 64 dedicated headroom, i.e. 128. Operators following this doc may set ELASTICKV_REDIS_PER_PEER_CONNECTIONS to only the proxy pool size and lose the intended room for Pub/Sub/detached sockets, recreating the connection rejects this change is trying to avoid.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

@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 (47ebe6e):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 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: 47ebe6ea70

ℹ️ 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 docs/design/2026_04_24_implemented_workload_isolation.md Outdated
Comment thread docs/design/2026_06_12_proposed_scaling_roadmap.md Outdated
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Evidence for current HEAD cfd495d:

Addressed the latest documentation findings:

  • Workload isolation doc now uses the implemented/default per-peer Redis cap N=128 consistently with the status section and defaultRedisPerPeerConnectionCap.
  • Scaling roadmap now describes stretched HLC renewal as depending on each route's shard group quorum, matching per-led-group renewal.

Validation:

  • rg confirmed the stale default N=64 and default group's quorum wording is gone from the touched docs.
  • git diff --check
  • commit signature verified locally for bootjp contact@bootjp.me

@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 (cfd495d):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 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: cfd495d75b

ℹ️ 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/redis_zset_cmds.go Outdated
if metaLen >= int64(maxWideScanLimit) {
return maxWideScanLimit
}
return int(metaLen) + 1

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 BZPOPMIN score scans bounded

For normal wide zsets with metadata, this sets the ScanAt limit to metaLen + 1 (capped at 100001), so a hot BZPOPMIN on a 50k-member sorted set still reads essentially the entire score index before popping one member. That preserves much of the O(N) replay cost this change is trying to remove; the score-index fast path should keep the initial scan bounded to the first couple of score rows and only fall back to the full member load when the bounded probe cannot be trusted (e.g. ties or incomplete-index detection).

Useful? React with 👍 / 👎.

Comment thread kv/coordinator.go
(iii) makes the ceiling-fence behaviour normative: a leader
partitioned from the default group's quorum for longer than
`hlcPhysicalWindowMs` (currently 3s) cannot serve any persistence
`hlcPhysicalWindowMs` (currently 20s) cannot serve any persistence

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Refresh the HLC availability failure model

This updated 20s risk item still describes HLC outage as partition from the default group's quorum and says the current implementation silently keeps issuing timestamps, but the code now renews HLC leases for led shard groups and persistence allocation goes through NextFenced/RecoverHLCLease. Operators reading the implemented TLA spec will use the wrong quorum/fail-closed model when evaluating partitions, so this section should be updated to match per-group renewal and fenced timestamp allocation.

Useful? React with 👍 / 👎.

@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 (073aee6):

  • kv/coordinator.go
  • kv/sharded_coordinator.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 23, 2026

Copy link
Copy Markdown
Owner Author

Addressed the latest-head review items in 073aee6.

  • BZPOPMIN score-index probing now uses the bounded bzpopminScoreScanLimit instead of metaLen + 1, while preserving the existing member/legacy fallback paths for ties or incomplete indexes.
  • HLC lease renewal now schedules by tick launch and allows bounded overlapping proposals, so one slow renewal cannot monopolize logical counter headroom.
  • The TLA safety doc now describes per-shard-group HLC renewal and fail-closed NextFenced / RecoverHLCLease behavior instead of the stale default-group/silent-issuance model.

Validation:

  • go test ./adapter -run 'TestRedis_BZPopMin(CandidateSelection)?' -count=1\n- go test ./kv -run 'Test(Coordinate_RenewHLCLeaseAsync_OverlapsSlowProposal|ShardedCoordinator_RenewHLCLeases_(OverlapsInFlightGroup|SlowGroupDoesNotBlockPeers|UsesProposalTimeoutBeyondCadence)|HLCLeaseRenewalTimingHasPhysicalWindowMargin)' -count=1\n- git diff --check\n\n@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.

Caution

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

⚠️ Outside diff range comments (3)
docs/redis-proxy-deployment.md (1)

38-38: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

peer capの説明をコード側の前提に合わせてください。

Line [38] の「ELASTICKV_REDIS_PER_PEER_CONNECTIONS 以下」は、同文書の Line [447] および proxy/backend.go Lines [76-81] の「プールより大きい上限を設定し、Pub/Sub・detached socket用の余裕を残す」という説明と矛盾します。上限とpool sizeを同値にすると専用接続分の余裕がなくなるため、headroomを明示してください。

修正例
-| `-elastickv-pool-size` | `64` | ElasticKV backend connection pool size; keep this at or below `ELASTICKV_REDIS_PER_PEER_CONNECTIONS` on the cluster |
+| `-elastickv-pool-size` | `64` | ElasticKV backend connection pool size; configure `ELASTICKV_REDIS_PER_PEER_CONNECTIONS` above this value to leave headroom for dedicated and detached sockets |
🤖 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 `@docs/redis-proxy-deployment.md` at line 38, Update the -elastickv-pool-size
description to match the backend connection logic: state that
ELASTICKV_REDIS_PER_PEER_CONNECTIONS must be greater than the pool size, leaving
headroom for Pub/Sub and detached-socket connections. Keep the existing
configuration key and pool-size guidance unchanged.
kv/sharded_coordinator.go (2)

2446-2456: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

遅い最初のグループで recovery 全体を直列化しないでください。

Line 2449 の提案が rctx の期限まで遅延すると、後続の正常な target に一度も提案されません。全 target を並行起動して結果を集約し、遅延 target と即時成功 target の組合せを回帰テストしてください。

🤖 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/sharded_coordinator.go` around lines 2446 - 2456, Update
recoverHLCLeaseTargets to launch proposeHLCLeaseForGroup concurrently for every
target instead of processing targets serially, then wait for all attempts and
combine their errors using the existing recovery error aggregation. Preserve the
ceiling-expiry check and hlcRecoveryFailedError behavior, and add a regression
test covering a delayed target alongside an immediately successful target.

2459-2471: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

errors.CombineErrorsgithub.com/cockroachdb/errors v1.14.0 に存在し、このコードではコンパイルできません。

import "github.com/pkg/errors" を追加・置換するか、この箇所でも github.com/cockroachdb/errors の集約 API を一貫して使用してください。現状のままではこの関数でビルド失敗します。

🤖 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/sharded_coordinator.go` around lines 2459 - 2471, Update
combineHLCRecoveryErrors and hlcRecoveryFailedError to use the imported errors
package consistently with the repository’s dependency version. Replace the
unsupported errors.CombineErrors calls with the supported aggregation API, or
switch the import to github.com/pkg/errors if that is the established usage,
while preserving the existing wrapped error messages and nil-handling behavior.

Source: Coding guidelines

🧹 Nitpick comments (2)
cmd/redis-proxy/main_test.go (1)

75-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

本番デフォルトの入力値を共有定数から参照してください。

Line [75] の 64 は、proxy/backend.go が使用する redislimits.DefaultElasticKVRedisConnections と重複しています。このままだと既定値が変更されても、production defaultを検証するテストが古い64を使ったまま通過します。

修正例
-			elasticKVPoolSize:       64,
+			elasticKVPoolSize:       redislimits.DefaultElasticKVRedisConnections,
🤖 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 `@cmd/redis-proxy/main_test.go` around lines 75 - 78, Update the test case
around elasticKVPoolSize to use the shared production default constant
redislimits.DefaultElasticKVRedisConnections instead of the literal 64, ensuring
the expected value stays synchronized with proxy/backend.go.
kv/lease_read_test.go (1)

195-204: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

//nolint を値検証に置き換えてください。

kv/lease_read_test.go:201 の入力は生バイト列なので、binary.BigEndian.Uint64(data[1:])int64 に変換する前に uint64(math.MaxInt64) 以下であることを検証してください。こうすれば Suppress directive 不要で、無効な HLC 上限も明示的に扱えます。

修正案
+	rawCeilingMs := binary.BigEndian.Uint64(data[1:])
+	if rawCeilingMs > uint64(math.MaxInt64) {
+		t.Error("invalid HLC lease ceiling")
+		return
+	}
-	ceilingMs := int64(binary.BigEndian.Uint64(data[1:])) //nolint:gosec // encoded from a positive Unix ms timestamp.
-	clock.SetPhysicalCeiling(ceilingMs)
+	clock.SetPhysicalCeiling(int64(rawCeilingMs))
🤖 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/lease_read_test.go` around lines 195 - 204, In applyHLCLeaseEntryToClock,
validate that the decoded uint64 value is at most uint64(math.MaxInt64) before
converting it to int64. Return without updating the clock for out-of-range
values, then remove the nolint directive from the conversion.

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.

Outside diff comments:
In `@docs/redis-proxy-deployment.md`:
- Line 38: Update the -elastickv-pool-size description to match the backend
connection logic: state that ELASTICKV_REDIS_PER_PEER_CONNECTIONS must be
greater than the pool size, leaving headroom for Pub/Sub and detached-socket
connections. Keep the existing configuration key and pool-size guidance
unchanged.

In `@kv/sharded_coordinator.go`:
- Around line 2446-2456: Update recoverHLCLeaseTargets to launch
proposeHLCLeaseForGroup concurrently for every target instead of processing
targets serially, then wait for all attempts and combine their errors using the
existing recovery error aggregation. Preserve the ceiling-expiry check and
hlcRecoveryFailedError behavior, and add a regression test covering a delayed
target alongside an immediately successful target.
- Around line 2459-2471: Update combineHLCRecoveryErrors and
hlcRecoveryFailedError to use the imported errors package consistently with the
repository’s dependency version. Replace the unsupported errors.CombineErrors
calls with the supported aggregation API, or switch the import to
github.com/pkg/errors if that is the established usage, while preserving the
existing wrapped error messages and nil-handling behavior.

---

Nitpick comments:
In `@cmd/redis-proxy/main_test.go`:
- Around line 75-78: Update the test case around elasticKVPoolSize to use the
shared production default constant redislimits.DefaultElasticKVRedisConnections
instead of the literal 64, ensuring the expected value stays synchronized with
proxy/backend.go.

In `@kv/lease_read_test.go`:
- Around line 195-204: In applyHLCLeaseEntryToClock, validate that the decoded
uint64 value is at most uint64(math.MaxInt64) before converting it to int64.
Return without updating the clock for out-of-range values, then remove the
nolint directive from the conversion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb5a7d1c-9464-4162-a33c-e35f78696728

📥 Commits

Reviewing files that changed from the base of the PR and between eaf5701 and 073aee6.

📒 Files selected for processing (20)
  • README.md
  • adapter/redis_bzpopmin_wake_test.go
  • adapter/redis_peer_limiter.go
  • adapter/redis_peer_limiter_test.go
  • adapter/redis_zset_cmds.go
  • cmd/redis-proxy/main_test.go
  • docs/architecture_overview.md
  • docs/design/2026_04_24_implemented_workload_isolation.md
  • docs/design/2026_05_28_implemented_tla_safety_spec.md
  • docs/design/2026_06_11_implemented_leader_balance_scheduler.md
  • docs/design/2026_06_12_proposed_scaling_roadmap.md
  • docs/redis-proxy-deployment.md
  • internal/redislimits/limits.go
  • kv/coordinator.go
  • kv/lease_read_test.go
  • kv/lease_warmup_test.go
  • kv/sharded_coordinator.go
  • proxy/backend.go
  • proxy/dualwrite.go
  • proxy/proxy_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • README.md
  • adapter/redis_peer_limiter.go
  • proxy/dualwrite.go
  • adapter/redis_zset_cmds.go

@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: 073aee6110

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

return nil, false, nil
}
if candidate != nil {
scoreIndexComplete := metaExists && metaLen > 0 && int64(len(scoreKVs)) == metaLen

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 Avoid full member scans for large BZPOPMIN zsets

When a live wide-column zset has more than two members, scoreKVs is capped by bzpopminScoreScanLimit (2), so this completeness check is always false for metaLen > 2. That makes bzpopminCandidateAt fall through to bzpopminMemberOnlyCandidateAt, which calls loadZSetMembersAt and scans/sorts the whole zset before every pop; for the large blocking queues this change is meant to protect, the score-index path therefore still pays the old O(N) member load (plus the new score probes) instead of relieving replay backpressure.

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