Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/elastickv-list-routes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// table-route keys on the expected Raft groups before any workload
// op runs.
//
// Per the design doc (docs/design/2026_06_02_proposed_composed1_m5_jepsen_route_shuffle.md
// Per the design doc (docs/design/2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md
// §3.3), the Jepsen client's setup! shells out to this tool rather
// than re-implementing the gRPC client in Clojure: a JSON contract is
// stable across versions and a future ListRoutes schema change shows
Expand Down
2 changes: 1 addition & 1 deletion cmd/elastickv-route-key/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// elastickv-route-key prints the byte-string of a DynamoDB
// table-route key for a given table name. Used by the Composed-1
// M5 launch script (`scripts/run-jepsen-local.sh`) and OQ-7
// (docs/design/2026_06_02_proposed_composed1_m5_jepsen_route_shuffle.md)
// (docs/design/2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md)
// to compute `--shardRanges` boundary keys without inlining the
// base64-encoding logic in shell — the encoding is part of the
// routing surface and any drift would silently mis-route.
Expand Down
2 changes: 1 addition & 1 deletion cmd/elastickv-split/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// elastickv-split is a single-shot CLI that invokes the
// Distribution.SplitRange RPC on a running elastickv cluster. Per
// the Composed-1 M5 design doc
// (docs/design/2026_06_02_proposed_composed1_m5_jepsen_route_shuffle.md
// (docs/design/2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md
// §3.1), the Jepsen route-shuffle nemesis shells out to this tool
// rather than re-implementing the gRPC client in Clojure: keeping
// the request construction and the SplitRangeRequest field
Expand Down
2 changes: 1 addition & 1 deletion distribution/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Engine struct {
ts atomic.Uint64
hotspotThreshold uint64
// history is the M2 versioned-snapshot ring for Composed-1
// (docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// (docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M2). Keyed by catalogVersion; populated on every successful
// ApplySnapshot and seeded by NewEngineWithDefaultRoute so a
// transaction that observed catalogVersion = 0 (the engine's
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Composed-1 — cross-group commit-time ownership guard

Status: Proposed
Status: Partial — M1–M4 shipped via PR #900; M5a shipped via PRs #911 / #916 / #924 / #925; M5b (route-shuffle nemesis) still open. See companion doc `2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md` for the detailed M5 design and per-milestone state.
Author: bootjp
Date: 2026-05-29
Date: 2026-05-29 (renamed *_proposed_* → *_partial_* on 2026-06-04)

> **Forward-looking proposal.** Today's implementation is vacuously
> safe with respect to Composed-1 because `SplitRange` is the only
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
# Composed-1 M5 — Jepsen route-shuffle workload

Status: Proposed
Status: Partial. M5a shipped:
- PR #911 — `cmd/elastickv-split` + `cmd/elastickv-route-key` CLI helpers
- PR #916 — `dynamodb-append-multi-table-workload` (Clojure)
- PR #925 — `cmd/elastickv-list-routes` + setup-hook
`verify-multi-group-routing!`
- PR #924 — `scripts/run-jepsen-m5-local.sh` single-process
two-group launcher (with cross-PR integration to #925)
- PR #926 (separate) — `--host 127.0.0.1` fix discovered during
M5a E2E

M5b (route-shuffle nemesis) is still open. Plus one known follow-up
issue from M5a E2E: workers report `ResourceNotFoundException` for
every txn despite `create-all-tables!` reporting success and ListRoutes
showing the expected two-group catalog — likely a CreateTable
race / sync issue under 5-parallel client setup; tracked separately.

Author: bootjp
Date: 2026-06-02
Date: 2026-06-02 (renamed *_proposed_* → *_partial_* on 2026-06-04)
Parent design:
[`2026_05_29_proposed_composed1_cross_group_commit_guard.md`](2026_05_29_proposed_composed1_cross_group_commit_guard.md)
[`2026_05_29_partial_composed1_cross_group_commit_guard.md`](2026_05_29_partial_composed1_cross_group_commit_guard.md)
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 Update stale references after renaming design docs

Because this commit removes the old *_proposed_* filenames, the remaining repo references now point at missing files; I checked with rg "2026_05_29_proposed_composed1|2026_06_02_proposed_composed1" and found stale paths in implementation comments and scripts such as cmd/elastickv-route-key/main.go, kv/fsm.go, jepsen/src/elastickv/dynamodb_multi_table_workload.clj, and scripts/run-jepsen-m5-local.sh. Anyone following those design-doc pointers from the code will land on nonexistent files unless the references are updated along with this link.

Useful? React with 👍 / 👎.


> **Forward-looking proposal, same posture as the parent doc.**
> Today's `SplitRange` is same-group only (per CLAUDE.md and
Expand Down
2 changes: 1 addition & 1 deletion jepsen/src/elastickv/dynamodb_multi_table_workload.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"Composed-1 M5a multi-table variant of the DynamoDB list-append workload.

Why a separate workload exists (see
docs/design/2026_06_02_proposed_composed1_m5_jepsen_route_shuffle.md §3.3):
docs/design/2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md §3.3):
the single-table elastickv.dynamodb-workload cannot exercise the 2PC
path because kv/shard_key.go normalises every DynamoDB table-meta,
item, and GSI key for one table to a single per-table route key
Expand Down
2 changes: 1 addition & 1 deletion kv/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ func elemToMutation(req *Elem[OP]) *pb.Mutation {
// was captured at — flows into pb.Request.ObservedRouteVersion so the M3
// Composed-1 FSM apply-time gate can re-validate ownership against the
// route catalog snapshot at txn-begin (M1 plumbing, see
// docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md).
// docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md).
// Zero is the legacy "unpinned" sentinel.
func onePhaseTxnRequestWithPrevCommit(startTS, commitTS, prevCommitTS uint64, primaryKey []byte, reqs []*Elem[OP], readKeys [][]byte, observedRouteVersion uint64) *pb.Request {
muts := make([]*pb.Mutation, 0, len(reqs)+1)
Expand Down
2 changes: 1 addition & 1 deletion kv/coordinator_txn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestCoordinateDispatchTxn_PassesReadKeysToRaftEntry(t *testing.T) {
// through the dispatchTxn boundary into pb.Request.ObservedRouteVersion.
//
// This is the M1 round-trip witness for the Composed-1 plumbing per
// docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M1: at this milestone the FSM ignores the field, so the only assertion
// is that the value survives the encoder. M3 will add the FSM apply-time
// gate that *uses* this value.
Expand Down
6 changes: 3 additions & 3 deletions kv/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type kvFSM struct {
// short-circuit as "unpinned" (no Composed-1 enforcement) —
// matching the pre-feature behaviour byte-for-byte. Concrete
// production type is *distribution.Engine. See
// docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §4.2 prerequisite block + §M2.
routes RouteHistory
// shardGroupID is the Raft group ID this FSM serves. Used by
Expand Down Expand Up @@ -171,7 +171,7 @@ func WithCutoverSource(src CutoverSource) FSMOption {
// historical owner-of-key resolution. Zero is reserved for the
// not-wired case.
//
// See docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// See docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M2 + §4.2 prerequisite block.
func WithRouteHistory(routes RouteHistory, shardGroupID uint64) FSMOption {
return func(f *kvFSM) {
Expand Down Expand Up @@ -551,7 +551,7 @@ func (f *kvFSM) handleTxnRequest(ctx context.Context, r *pb.Request, commitTS ui
}

// verifyComposed1 is the M3 apply-time Composed-1 gate per
// docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §4.2(a) + §4.4. Runs two checks before the txn's writes land:
//
// (a) Observed-version owner — the txn's read-set was captured
Expand Down
2 changes: 1 addition & 1 deletion kv/route_history.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
// kv.RouteHistory bypass the wrapper entirely and implement the kv
// interface directly.
//
// See docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// See docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M2.
func WrapDistributionEngine(e *distribution.Engine) RouteHistory {
if e == nil {
Expand Down
2 changes: 1 addition & 1 deletion kv/sharded_coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ func (c *ShardedCoordinator) Dispatch(ctx context.Context, reqs *OperationGroup[

// dispatchTxnWithComposed1Retry runs the M4 Composed-1 retry loop
// (design doc
// docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M4). Pins reqs.ObservedRouteVersion to the engine's current
// catalog version on the FIRST attempt when the caller left it at the
// zero sentinel — every txn that flows through ShardedCoordinator
Expand Down
2 changes: 1 addition & 1 deletion kv/transcoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type OperationGroup[T OP] struct {
// "unpinned" — every existing caller leaves it at zero so this
// is behaviour-neutral on the M1 plumbing PR. M3 of the
// Composed-1 design
// (docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md)
// (docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md)
// will gate the FSM apply path on this version so a route shift
// between BeginTxn and Commit is caught before it can produce a
// G1c anomaly across a cross-group MoveRange / SplitRange.
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ func buildShardGroups(
// verifyComposed1 apply-time gate can resolve the
// observed-version owner-of-key without further plumbing
// work. At M2 the FSM stores both but does not consult them;
// see docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md
// see docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md
// §M2.
sm := kv.NewKvFSMWithHLC(st, clock,
kv.WithEncryption(applier),
Expand Down
2 changes: 1 addition & 1 deletion proto/internal.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion proto/internal.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ message Request {
// transaction's read set was captured at (set on BeginTxn from
// distribution.Engine.Version()). Zero means "unpinned" (legacy
// callers + read-only paths). M3 of the Composed-1 design
// (docs/design/2026_05_29_proposed_composed1_cross_group_commit_guard.md)
// (docs/design/2026_05_29_partial_composed1_cross_group_commit_guard.md)
// will gate the FSM apply path on it; M1 (this field's introduction)
// is plumbing only — the FSM ignores the value, so all existing
// callers see no behaviour change.
Expand Down
2 changes: 1 addition & 1 deletion scripts/run-jepsen-m5-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Why this script exists separately from run-jepsen-local.sh: the M5
# workload requires a multi-Raft-group cluster topology that the
# existing 3-node single-group layout cannot provide. Per the design
# doc (docs/design/2026_06_02_proposed_composed1_m5_jepsen_route_shuffle.md
# doc (docs/design/2026_06_02_partial_composed1_m5_jepsen_route_shuffle.md
# §3.3), today's `validateShardRanges` / `buildShardGroups` only
# support a "single process hosts all groups" model — separate
# processes per group fail validation or race on Raft listeners.
Expand Down
2 changes: 1 addition & 1 deletion tla/composed/Composed.tla
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ VARIABLES
\* observed-version check and the apply-time
\* current-version cross-version-read fence
\* (Composed-1a; see docs/design/
\* 2026_05_29_proposed_composed1_cross_group_commit_guard.md
\* 2026_05_29_partial_composed1_cross_group_commit_guard.md
\* §4.4 and §5).
opCount

Expand Down
Loading