func tryRaftLogEntry(kv engine.MVCCKeyValue) (string, error) { var ent raftpb.Entry if err := maybeUnmarshalInline(kv.Value, &ent); err != nil { return "", err } if ent.Type == raftpb.EntryNormal { if len(ent.Data) > 0 { _, cmdData := storage.DecodeRaftCommand(ent.Data) var cmd storagebase.RaftCommand if err := cmd.Unmarshal(cmdData); err != nil { return "", err } ent.Data = nil return fmt.Sprintf("%s by %v\n%s\n%s\n", &ent, cmd.OriginReplica, cmd.BatchRequest, &cmd), nil } return fmt.Sprintf("%s: EMPTY\n", &ent), nil } else if ent.Type == raftpb.EntryConfChange { var cc raftpb.ConfChange if err := cc.Unmarshal(ent.Data); err != nil { return "", err } var ctx storage.ConfChangeContext if err := ctx.Unmarshal(cc.Context); err != nil { return "", err } var cmd storagebase.ReplicatedEvalResult if err := cmd.Unmarshal(ctx.Payload); err != nil { return "", err } ent.Data = nil return fmt.Sprintf("%s\n%s\n", &ent, &cmd), nil } return "", fmt.Errorf("unknown log entry type: %s", &ent) }
func (r *Replica) handleReplicatedEvalResult( ctx context.Context, rResult storagebase.ReplicatedEvalResult, ) (shouldAssert bool) { // Fields for which no action is taken in this method are zeroed so that // they don't trigger an assertion at the end of the method (which checks // that all fields were handled). { rResult.IsLeaseRequest = false rResult.IsConsistencyRelated = false rResult.IsFreeze = false rResult.Timestamp = hlc.ZeroTimestamp } if rResult.BlockReads { r.readOnlyCmdMu.Lock() defer r.readOnlyCmdMu.Unlock() rResult.BlockReads = false } // Update MVCC stats and Raft portion of ReplicaState. r.mu.Lock() r.mu.state.Stats.Add(rResult.Delta) if rResult.State.RaftAppliedIndex != 0 { r.mu.state.RaftAppliedIndex = rResult.State.RaftAppliedIndex } if rResult.State.LeaseAppliedIndex != 0 { r.mu.state.LeaseAppliedIndex = rResult.State.LeaseAppliedIndex } needsSplitBySize := r.needsSplitBySizeLocked() r.mu.Unlock() r.store.metrics.addMVCCStats(rResult.Delta) rResult.Delta = enginepb.MVCCStats{} const raftLogCheckFrequency = 1 + RaftLogQueueStaleThreshold/4 if rResult.State.RaftAppliedIndex%raftLogCheckFrequency == 1 { r.store.raftLogQueue.MaybeAdd(r, r.store.Clock().Now()) } if needsSplitBySize { r.store.splitQueue.MaybeAdd(r, r.store.Clock().Now()) } rResult.State.Stats = enginepb.MVCCStats{} rResult.State.LeaseAppliedIndex = 0 rResult.State.RaftAppliedIndex = 0 // The above are always present, so we assert only if there are // "nontrivial" actions below. shouldAssert = (rResult != storagebase.ReplicatedEvalResult{}) // Process Split or Merge. This needs to happen after stats update because // of the ContainsEstimates hack. if rResult.Split != nil { // TODO(tschottdorf): We want to let the usual MVCCStats-delta // machinery update our stats for the left-hand side. But there is no // way to pass up an MVCCStats object that will clear out the // ContainsEstimates flag. We should introduce one, but the migration // makes this worth a separate effort (ContainsEstimates would need to // have three possible values, 'UNCHANGED', 'NO', and 'YES'). // Until then, we're left with this rather crude hack. { r.mu.Lock() r.mu.state.Stats.ContainsEstimates = false stats := r.mu.state.Stats r.mu.Unlock() if err := setMVCCStats(ctx, r.store.Engine(), r.RangeID, stats); err != nil { log.Fatal(ctx, errors.Wrap(err, "unable to write MVCC stats")) } } splitPostApply( r.AnnotateCtx(ctx), rResult.Split.RHSDelta, &rResult.Split.SplitTrigger, r, ) rResult.Split = nil } if rResult.Merge != nil { if err := r.store.MergeRange(ctx, r, rResult.Merge.LeftDesc.EndKey, rResult.Merge.RightDesc.RangeID, ); err != nil { // Our in-memory state has diverged from the on-disk state. log.Fatalf(ctx, "failed to update store after merging range: %s", err) } rResult.Merge = nil } // Update the remaining ReplicaState. if rResult.State.Frozen != storagebase.ReplicaState_FROZEN_UNSPECIFIED { r.mu.Lock() r.mu.state.Frozen = rResult.State.Frozen r.mu.Unlock() } rResult.State.Frozen = storagebase.ReplicaState_FROZEN_UNSPECIFIED if newDesc := rResult.State.Desc; newDesc != nil { if err := r.setDesc(newDesc); err != nil { // Log the error. There's not much we can do because the commit may // have already occurred at this point. log.Fatalf( ctx, "failed to update range descriptor to %+v: %s", newDesc, err, ) } rResult.State.Desc = nil } if change := rResult.ChangeReplicas; change != nil { if change.ChangeType == roachpb.REMOVE_REPLICA && r.store.StoreID() == change.Replica.StoreID { // This wants to run as late as possible, maximizing the chances // that the other nodes have finished this command as well (since // processing the removal from the queue looks up the Range at the // lease holder, being too early here turns this into a no-op). if _, err := r.store.replicaGCQueue.Add(r, replicaGCPriorityRemoved); err != nil { // Log the error; the range should still be GC'd eventually. log.Errorf(ctx, "unable to add to replica GC queue: %s", err) } } rResult.ChangeReplicas = nil } if newLease := rResult.State.Lease; newLease != nil { rResult.State.Lease = nil // for assertion r.mu.Lock() replicaID := r.mu.replicaID prevLease := r.mu.state.Lease r.mu.state.Lease = newLease r.mu.Unlock() r.leasePostApply(ctx, newLease, replicaID, prevLease) } if newTruncState := rResult.State.TruncatedState; newTruncState != nil { rResult.State.TruncatedState = nil // for assertion r.mu.Lock() r.mu.state.TruncatedState = newTruncState r.mu.Unlock() // Clear any entries in the Raft log entry cache for this range up // to and including the most recently truncated index. r.store.raftEntryCache.clearTo(r.RangeID, newTruncState.Index+1) } if newThresh := rResult.State.GCThreshold; newThresh != hlc.ZeroTimestamp { r.mu.Lock() r.mu.state.GCThreshold = newThresh r.mu.Unlock() rResult.State.GCThreshold = hlc.ZeroTimestamp } if newThresh := rResult.State.TxnSpanGCThreshold; newThresh != hlc.ZeroTimestamp { r.mu.Lock() r.mu.state.TxnSpanGCThreshold = newThresh r.mu.Unlock() rResult.State.TxnSpanGCThreshold = hlc.ZeroTimestamp } if rResult.ComputeChecksum != nil { r.computeChecksumPostApply(ctx, *rResult.ComputeChecksum) rResult.ComputeChecksum = nil } if rResult.RaftLogDelta != nil { r.mu.Lock() r.mu.raftLogSize += *rResult.RaftLogDelta if r.mu.raftLogSize < 0 { // Ensure raftLogSize is not negative since it isn't persisted between // server restarts. r.mu.raftLogSize = 0 } r.mu.Unlock() rResult.RaftLogDelta = nil } if (rResult != storagebase.ReplicatedEvalResult{}) { log.Fatalf(ctx, "unhandled field in ReplicatedEvalResult: %s", pretty.Diff(rResult, storagebase.ReplicatedEvalResult{})) } return shouldAssert }