interaction_env_handler_process_ready.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2019 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package rafttest
  15. import (
  16. "testing"
  17. "github.com/cockroachdb/datadriven"
  18. "go.etcd.io/etcd/raft"
  19. "go.etcd.io/etcd/raft/quorum"
  20. "go.etcd.io/etcd/raft/raftpb"
  21. )
  22. func (env *InteractionEnv) handleProcessReady(t *testing.T, d datadriven.TestData) error {
  23. idx := firstAsNodeIdx(t, d)
  24. return env.ProcessReady(idx)
  25. }
  26. // ProcessReady runs Ready handling on the node with the given index.
  27. func (env *InteractionEnv) ProcessReady(idx int) error {
  28. // TODO(tbg): Allow simulating crashes here.
  29. rn, s := env.Nodes[idx].RawNode, env.Nodes[idx].Storage
  30. rd := rn.Ready()
  31. // TODO(tbg): the order of operations here is not necessarily safe. See:
  32. // https://github.com/etcd-io/etcd/pull/10861
  33. if !raft.IsEmptyHardState(rd.HardState) {
  34. if err := s.SetHardState(rd.HardState); err != nil {
  35. return err
  36. }
  37. }
  38. if err := s.Append(rd.Entries); err != nil {
  39. return err
  40. }
  41. if !raft.IsEmptySnap(rd.Snapshot) {
  42. if err := s.ApplySnapshot(rd.Snapshot); err != nil {
  43. return err
  44. }
  45. }
  46. for _, ent := range rd.CommittedEntries {
  47. var update []byte
  48. switch ent.Type {
  49. case raftpb.EntryConfChange:
  50. var cc raftpb.ConfChange
  51. if err := cc.Unmarshal(ent.Data); err != nil {
  52. return err
  53. }
  54. update = cc.Context
  55. rn.ApplyConfChange(cc)
  56. case raftpb.EntryConfChangeV2:
  57. var cc raftpb.ConfChangeV2
  58. if err := cc.Unmarshal(ent.Data); err != nil {
  59. return err
  60. }
  61. rn.ApplyConfChange(cc)
  62. update = cc.Context
  63. default:
  64. update = ent.Data
  65. }
  66. // Record the new state by starting with the current state and applying
  67. // the command.
  68. lastSnap := env.Nodes[idx].History[len(env.Nodes[idx].History)-1]
  69. var snap raftpb.Snapshot
  70. snap.Data = append(snap.Data, lastSnap.Data...)
  71. // NB: this hard-codes an "appender" state machine.
  72. snap.Data = append(snap.Data, update...)
  73. snap.Metadata.Index = ent.Index
  74. snap.Metadata.Term = ent.Term
  75. cfg := rn.Status().Config
  76. snap.Metadata.ConfState = raftpb.ConfState{
  77. Voters: cfg.Voters[0].Slice(),
  78. VotersOutgoing: cfg.Voters[1].Slice(),
  79. Learners: quorum.MajorityConfig(cfg.Learners).Slice(),
  80. LearnersNext: quorum.MajorityConfig(cfg.LearnersNext).Slice(),
  81. }
  82. env.Nodes[idx].History = append(env.Nodes[idx].History, snap)
  83. }
  84. for _, msg := range rd.Messages {
  85. env.Messages = append(env.Messages, msg)
  86. }
  87. rn.Advance(rd)
  88. env.Output.WriteString(raft.DescribeReady(rd, defaultEntryFormatter))
  89. return nil
  90. }