Skip to content

stateloader: untangle SynthesizeRaftState #147469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

pav-kv
Copy link
Collaborator

@pav-kv pav-kv commented May 28, 2025

This PR starts untangling the opaque code in SynthesizeHardState and SynthesizeRaftState, with the goals of (a) making it simple, (b) decoupling log and state machine reads/writes. Right now, these funcs are used in exactly 2 cases:

  1. during cluster bootstrap, for creating the initial set of ranges
  2. when applying a split trigger, for initializing the RHS (which is uninitialized and only possibly can have a HardState)

In both cases, the replica's state machine and log are initialized at RaftInitialLogIndex/Term. This means that everything these funcs generate is mostly based on constants (modulo the HardState in case 2). But it is really hard to tell by reading it. After this PR, case (1) is decoupled into its own WriteInitialRaftState func, and directly produces the right output. The "synthesize" funcs are now only used by splits, and can be further simplified in follow-up PRs.

The first half of this PR adds a datadriven test for WriteInitialRangeState showing the state of a typical replica created at cluster bootstrap. The printout only includes RangeID-local state, and no user space keys. The test helps ensuring that subsequent commits are no-ops.

Epic: CRDB-49111

@pav-kv pav-kv requested a review from arulajmani May 28, 2025 22:09
@pav-kv pav-kv requested a review from a team as a code owner May 28, 2025 22:09
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@pav-kv
Copy link
Collaborator Author

pav-kv commented May 28, 2025

@arulajmani apologies if this overlaps with your split work stream too much. This untangles cluster bootstrap code from splits. I left a couple of TODOs in the code from where the splits stuff can be continued.

pav-kv added 5 commits May 28, 2025 23:16
Epic: none
Release note: none
Epic: none
Release note: none
Epic: none
Release note: none
@pav-kv pav-kv changed the title stateloader: echo test for WriteInitialRangeState stateloader: untangle SynthesizeRaftState May 28, 2025
@pav-kv pav-kv requested a review from tbg May 28, 2025 22:25
const replicaID = roachpb.ReplicaID(1)
// Use PreviousRelease so that we don't have to update this test on every
// version gate addition.
cv := clusterversion.ClusterVersion{Version: clusterversion.PreviousRelease.Version()}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

TODO: find a version handle that doesn't change or get removed. Or maybe just use zero.

Copy link
Member

Choose a reason for hiding this comment

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

Another thing you could do is s/.(*RangeVersion.*: )(.*)/\1VERSION/ on the output.


eng := storage.NewDefaultInMemForTesting()
defer eng.Close()
b := eng.NewBatch() // TODO(pav-kv): make it write-only batch
Copy link
Member

Choose a reason for hiding this comment

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

TODO

const replicaID = roachpb.ReplicaID(1)
// Use PreviousRelease so that we don't have to update this test on every
// version gate addition.
cv := clusterversion.ClusterVersion{Version: clusterversion.PreviousRelease.Version()}
Copy link
Member

Choose a reason for hiding this comment

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

Another thing you could do is s/.(*RangeVersion.*: )(.*)/\1VERSION/ on the output.


str, err := print.DecodeWriteBatch(b.Repr())
require.NoError(t, err)
str = strings.ReplaceAll(str, "\n\n", "\n")
Copy link
Member

Choose a reason for hiding this comment

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

optional tangent: is there something we could tweak in DecodeWriteBatch or do the double newlines make sense in other situations?

@@ -0,0 +1,10 @@
echo
----
Put: 0,0 /Local/RangeID/5/u/RaftTruncatedState (0x01698d757266747400): index:10 term:5
Copy link
Member

Choose a reason for hiding this comment

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

It makes sense for these results to be out of order given how the test is written - this lists the contents of a write batch after all - but it took me a second to realize (was wondering why u and r keys were interleaved). It is probably not worth committing the batch and then re-reading it. Maybe a comment?

@@ -694,6 +694,8 @@ func SendEmptySnapshot(
return err
}

// TODO(review): this now doesn't write RaftTruncatedState, is this fine? It's
// a snapshot, so it will not load unreplicated state.
Copy link
Member

Choose a reason for hiding this comment

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

This should be fine (better, actually). The snapshot is sent through the usual channels, so the receiver should really be managing their own raft state (via applySnapshotRaftMuLocked). TestResetQuorum exercises this btw, and I'm assuming it passes.

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.

4 participants