// writeInitialState bootstraps a new Raft group (i.e. it is called when we // bootstrap a Range, or when setting up the right hand side of a split). // Its main task is to persist a consistent Raft (and associated Replica) state // which does not start from zero but presupposes a few entries already having // applied. // The supplied MVCCStats are used for the Stats field after adjusting for // persisting the state itself, and the updated stats are returned. func writeInitialState( ctx context.Context, eng engine.ReadWriter, ms enginepb.MVCCStats, desc roachpb.RangeDescriptor, ) (enginepb.MVCCStats, error) { var s storagebase.ReplicaState s.TruncatedState = &roachpb.RaftTruncatedState{ Term: raftInitialLogTerm, Index: raftInitialLogIndex, } s.RaftAppliedIndex = s.TruncatedState.Index s.Desc = &roachpb.RangeDescriptor{ RangeID: desc.RangeID, } s.Stats = ms newMS, err := saveState(ctx, eng, s) if err != nil { return enginepb.MVCCStats{}, err } oldHS, err := loadHardState(ctx, eng, desc.RangeID) if err != nil { return enginepb.MVCCStats{}, err } if err := synthesizeHardState(ctx, eng, s, oldHS); err != nil { return enginepb.MVCCStats{}, err } if err := setLastIndex(ctx, eng, desc.RangeID, s.TruncatedState.Index); err != nil { return enginepb.MVCCStats{}, err } return newMS, nil }
// writeInitialState bootstraps a new Raft group (i.e. it is called when we // bootstrap a Range, or when setting up the right hand side of a split). // Its main task is to persist a consistent Raft (and associated Replica) state // which does not start from zero but presupposes a few entries already having // applied. // The supplied MVCCStats are used for the Stats field after adjusting for // persisting the state itself, and the updated stats are returned. func writeInitialState( eng engine.ReadWriter, ms enginepb.MVCCStats, desc roachpb.RangeDescriptor, ) (enginepb.MVCCStats, error) { rangeID := desc.RangeID var s storagebase.ReplicaState s.TruncatedState = &roachpb.RaftTruncatedState{ Term: raftInitialLogTerm, Index: raftInitialLogIndex, } s.RaftAppliedIndex = s.TruncatedState.Index s.Desc = &roachpb.RangeDescriptor{ RangeID: rangeID, } s.Stats = ms newMS, err := saveState(eng, s) if err != nil { return enginepb.MVCCStats{}, err } if err := updateHardState(eng, s); err != nil { return enginepb.MVCCStats{}, err } if err := setLastIndex(eng, rangeID, s.TruncatedState.Index); err != nil { return enginepb.MVCCStats{}, err } return newMS, nil }
// writeInitialState bootstraps a new Raft group (i.e. it is called when we // bootstrap a Range, or when setting up the right hand side of a split). // Its main task is to persist a consistent Raft (and associated Replica) state // which does not start from zero but presupposes a few entries already having // applied. // The supplied MVCCStats are used for the Stats field after adjusting for // persisting the state itself, and the updated stats are returned. func writeInitialState( eng engine.ReadWriter, ms enginepb.MVCCStats, desc roachpb.RangeDescriptor, ) (enginepb.MVCCStats, error) { rangeID := desc.RangeID var s storagebase.ReplicaState s.TruncatedState = &roachpb.RaftTruncatedState{ Term: raftInitialLogTerm, Index: raftInitialLogIndex, } s.RaftAppliedIndex = s.TruncatedState.Index s.Desc = &roachpb.RangeDescriptor{ RangeID: rangeID, } s.Stats = ms newMS, err := saveState(eng, s) if err != nil { return enginepb.MVCCStats{}, err } // Load a potentially existing HardState as we may need to preserve // information about cast votes. For example, during a Split for which // another node's new right-hand side has contacted us before our left-hand // side called in here to create the group. oldHS, err := loadHardState(eng, rangeID) if err != nil { return enginepb.MVCCStats{}, err } newHS := raftpb.HardState{ Term: s.TruncatedState.Term, Commit: s.TruncatedState.Index, } if !raft.IsEmptyHardState(oldHS) { if oldHS.Commit > newHS.Commit { newHS.Commit = oldHS.Commit } if oldHS.Term > newHS.Term { newHS.Term = oldHS.Term } newHS.Vote = oldHS.Vote } if err := setHardState(eng, rangeID, newHS); err != nil { return enginepb.MVCCStats{}, err } if err := setLastIndex(eng, rangeID, s.TruncatedState.Index); err != nil { return enginepb.MVCCStats{}, err } return newMS, nil }
// loadState loads a ReplicaState from disk. The exception is the Desc field, // which is updated transactionally, and is populated from the supplied // RangeDescriptor under the convention that that is the latest committed // version. func loadState( ctx context.Context, reader engine.Reader, desc *roachpb.RangeDescriptor, ) (storagebase.ReplicaState, error) { var s storagebase.ReplicaState // TODO(tschottdorf): figure out whether this is always synchronous with // on-disk state (likely iffy during Split/ChangeReplica triggers). s.Desc = protoutil.Clone(desc).(*roachpb.RangeDescriptor) // Read the range lease. var err error if s.Lease, err = loadLease(ctx, reader, desc.RangeID); err != nil { return storagebase.ReplicaState{}, err } if s.Frozen, err = loadFrozenStatus(ctx, reader, desc.RangeID); err != nil { return storagebase.ReplicaState{}, err } if s.GCThreshold, err = loadGCThreshold(ctx, reader, desc.RangeID); err != nil { return storagebase.ReplicaState{}, err } if s.RaftAppliedIndex, s.LeaseAppliedIndex, err = loadAppliedIndex( ctx, reader, desc.RangeID, ); err != nil { return storagebase.ReplicaState{}, err } if s.Stats, err = loadMVCCStats(ctx, reader, desc.RangeID); err != nil { return storagebase.ReplicaState{}, err } // The truncated state should not be optional (i.e. the pointer is // pointless), but it is and the migration is not worth it. truncState, err := loadTruncatedState(ctx, reader, desc.RangeID) if err != nil { return storagebase.ReplicaState{}, err } s.TruncatedState = &truncState return s, nil }