// raftTruncatedStateLocked returns metadata about the log that preceded the // first current entry. This includes both entries that have been compacted away // and the dummy entries that make up the starting point of an empty log. // raftTruncatedStateLocked requires that the replica lock be held. func (r *Replica) raftTruncatedStateLocked() (roachpb.RaftTruncatedState, error) { if r.mu.truncatedState != nil { return *r.mu.truncatedState, nil } ts := roachpb.RaftTruncatedState{} ok, err := engine.MVCCGetProto(r.store.Engine(), keys.RaftTruncatedStateKey(r.RangeID), roachpb.ZeroTimestamp, true, nil, &ts) if err != nil { return ts, err } if !ok { if r.isInitializedLocked() { // If we created this range, set the initial log index/term. ts.Index = raftInitialLogIndex ts.Term = raftInitialLogTerm } else { // This is a new range we are receiving from another node. Start // from zero so we will receive a snapshot. ts.Index = 0 ts.Term = 0 } } if ts.Index != 0 { r.mu.truncatedState = &ts } return ts, nil }
// InternalTruncateLog discards a prefix of the raft log. func (r *Range) InternalTruncateLog(batch engine.Engine, ms *engine.MVCCStats, args *proto.InternalTruncateLogRequest, reply *proto.InternalTruncateLogResponse) { // args.Index is the first index to keep. term, err := r.Term(args.Index - 1) if err != nil { reply.SetGoError(err) return } start := keys.RaftLogKey(r.Desc().RaftID, 0) end := keys.RaftLogKey(r.Desc().RaftID, args.Index) err = batch.Iterate(engine.MVCCEncodeKey(start), engine.MVCCEncodeKey(end), func(kv proto.RawKeyValue) (bool, error) { err := batch.Clear(kv.Key) return false, err }) if err != nil { reply.SetGoError(err) return } ts := proto.RaftTruncatedState{ Index: args.Index - 1, Term: term, } err = engine.MVCCPutProto(batch, ms, keys.RaftTruncatedStateKey(r.Desc().RaftID), proto.ZeroTimestamp, nil, &ts) reply.SetGoError(err) }
// raftTruncatedState returns metadata about the log that preceded the first // current entry. This includes both entries that have been compacted away // and the dummy entries that make up the starting point of an empty log. func (r *Replica) raftTruncatedState() (proto.RaftTruncatedState, error) { if ts := r.getCachedTruncatedState(); ts != nil { return *ts, nil } ts := proto.RaftTruncatedState{} ok, err := engine.MVCCGetProto(r.rm.Engine(), keys.RaftTruncatedStateKey(r.Desc().RangeID), proto.ZeroTimestamp, true, nil, &ts) if err != nil { return ts, err } if !ok { if r.isInitialized() { // If we created this range, set the initial log index/term. ts.Index = raftInitialLogIndex ts.Term = raftInitialLogTerm } else { // This is a new range we are receiving from another node. Start // from zero so we will receive a snapshot. ts.Index = 0 ts.Term = 0 } } if ts.Index != 0 { r.setCachedTruncatedState(&ts) } return ts, nil }
func raftTruncatedState( eng engine.Reader, rangeID roachpb.RangeID, ) (roachpb.RaftTruncatedState, error) { ts := roachpb.RaftTruncatedState{} _, err := engine.MVCCGetProto(context.Background(), eng, keys.RaftTruncatedStateKey(rangeID), hlc.ZeroTimestamp, true, nil, &ts) return ts /* zero if not found */, err }
func setTruncatedState( eng engine.ReadWriter, ms *enginepb.MVCCStats, rangeID roachpb.RangeID, truncState roachpb.RaftTruncatedState, ) error { return engine.MVCCPutProto(context.Background(), eng, ms, keys.RaftTruncatedStateKey(rangeID), hlc.ZeroTimestamp, nil, &truncState) }
func loadTruncatedState( ctx context.Context, reader engine.Reader, rangeID roachpb.RangeID, ) (roachpb.RaftTruncatedState, error) { var truncState roachpb.RaftTruncatedState if _, err := engine.MVCCGetProto(ctx, reader, keys.RaftTruncatedStateKey(rangeID), hlc.ZeroTimestamp, true, nil, &truncState); err != nil { return roachpb.RaftTruncatedState{}, err } return truncState, nil }
// createRangeData creates sample range data in all possible areas of // the key space. Returns a slice of the encoded keys of all created // data. func createRangeData(t *testing.T, r *Replica) []engine.MVCCKey { ts0 := hlc.ZeroTimestamp ts := hlc.Timestamp{WallTime: 1} desc := r.Desc() keyTSs := []struct { key roachpb.Key ts hlc.Timestamp }{ {keys.AbortCacheKey(r.RangeID, testTxnID), ts0}, {keys.AbortCacheKey(r.RangeID, testTxnID2), ts0}, {keys.RangeFrozenStatusKey(r.RangeID), ts0}, {keys.RangeLastGCKey(r.RangeID), ts0}, {keys.RaftAppliedIndexKey(r.RangeID), ts0}, {keys.RaftTruncatedStateKey(r.RangeID), ts0}, {keys.LeaseAppliedIndexKey(r.RangeID), ts0}, {keys.RangeStatsKey(r.RangeID), ts0}, {keys.RaftHardStateKey(r.RangeID), ts0}, {keys.RaftLastIndexKey(r.RangeID), ts0}, {keys.RaftLogKey(r.RangeID, 1), ts0}, {keys.RaftLogKey(r.RangeID, 2), ts0}, {keys.RangeLastReplicaGCTimestampKey(r.RangeID), ts0}, {keys.RangeLastVerificationTimestampKey(r.RangeID), ts0}, {keys.RangeDescriptorKey(desc.StartKey), ts}, {keys.TransactionKey(roachpb.Key(desc.StartKey), uuid.NewV4()), ts0}, {keys.TransactionKey(roachpb.Key(desc.StartKey.Next()), uuid.NewV4()), ts0}, {keys.TransactionKey(fakePrevKey(desc.EndKey), uuid.NewV4()), ts0}, // TODO(bdarnell): KeyMin.Next() results in a key in the reserved system-local space. // Once we have resolved https://github.com/cockroachdb/cockroach/issues/437, // replace this with something that reliably generates the first valid key in the range. //{r.Desc().StartKey.Next(), ts}, // The following line is similar to StartKey.Next() but adds more to the key to // avoid falling into the system-local space. {append(append([]byte{}, desc.StartKey...), '\x02'), ts}, {fakePrevKey(r.Desc().EndKey), ts}, } keys := []engine.MVCCKey{} for _, keyTS := range keyTSs { if err := engine.MVCCPut(context.Background(), r.store.Engine(), nil, keyTS.key, keyTS.ts, roachpb.MakeValueFromString("value"), nil); err != nil { t.Fatal(err) } keys = append(keys, engine.MVCCKey{Key: keyTS.key, Timestamp: keyTS.ts}) } return keys }
func raftTruncatedState(eng engine.Engine, rangeID roachpb.RangeID, isInitialized bool) (roachpb.RaftTruncatedState, error) { ts := roachpb.RaftTruncatedState{} ok, err := engine.MVCCGetProto(context.Background(), eng, keys.RaftTruncatedStateKey(rangeID), roachpb.ZeroTimestamp, true, nil, &ts) if err != nil { return ts, err } if !ok { if isInitialized { // If we created this range, set the initial log index/term. ts.Index = raftInitialLogIndex ts.Term = raftInitialLogTerm } else { // This is a new range we are receiving from another node. Start // from zero so we will receive a snapshot. ts.Index = 0 ts.Term = 0 } } return ts, nil }