interaction_env_handler_add_nodes.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. "errors"
  17. "fmt"
  18. "reflect"
  19. "testing"
  20. "github.com/cockroachdb/datadriven"
  21. "go.etcd.io/etcd/raft"
  22. pb "go.etcd.io/etcd/raft/raftpb"
  23. )
  24. func (env *InteractionEnv) handleAddNodes(t *testing.T, d datadriven.TestData) error {
  25. n := firstAsInt(t, d)
  26. var snap pb.Snapshot
  27. for _, arg := range d.CmdArgs[1:] {
  28. for i := range arg.Vals {
  29. switch arg.Key {
  30. case "voters":
  31. var id uint64
  32. arg.Scan(t, i, &id)
  33. snap.Metadata.ConfState.Voters = append(snap.Metadata.ConfState.Voters, id)
  34. case "learners":
  35. var id uint64
  36. arg.Scan(t, i, &id)
  37. snap.Metadata.ConfState.Learners = append(snap.Metadata.ConfState.Learners, id)
  38. case "index":
  39. arg.Scan(t, i, &snap.Metadata.Index)
  40. case "content":
  41. arg.Scan(t, i, &snap.Data)
  42. }
  43. }
  44. }
  45. return env.AddNodes(n, snap)
  46. }
  47. type snapOverrideStorage struct {
  48. Storage
  49. snapshotOverride func() (pb.Snapshot, error)
  50. }
  51. func (s snapOverrideStorage) Snapshot() (pb.Snapshot, error) {
  52. if s.snapshotOverride != nil {
  53. return s.snapshotOverride()
  54. }
  55. return s.Storage.Snapshot()
  56. }
  57. var _ raft.Storage = snapOverrideStorage{}
  58. // AddNodes adds n new nodes initializes from the given snapshot (which may be
  59. // empty). They will be assigned consecutive IDs.
  60. func (env *InteractionEnv) AddNodes(n int, snap pb.Snapshot) error {
  61. bootstrap := !reflect.DeepEqual(snap, pb.Snapshot{})
  62. for i := 0; i < n; i++ {
  63. id := uint64(1 + len(env.Nodes))
  64. s := snapOverrideStorage{
  65. Storage: raft.NewMemoryStorage(),
  66. // When you ask for a snapshot, you get the most recent snapshot.
  67. //
  68. // TODO(tbg): this is sort of clunky, but MemoryStorage itself will
  69. // give you some fixed snapshot and also the snapshot changes
  70. // whenever you compact the logs and vice versa, so it's all a bit
  71. // awkward to use.
  72. snapshotOverride: func() (pb.Snapshot, error) {
  73. snaps := env.Nodes[int(id-1)].History
  74. return snaps[len(snaps)-1], nil
  75. },
  76. }
  77. if bootstrap {
  78. // NB: we could make this work with 1, but MemoryStorage just
  79. // doesn't play well with that and it's not a loss of generality.
  80. if snap.Metadata.Index <= 1 {
  81. return errors.New("index must be specified as > 1 due to bootstrap")
  82. }
  83. snap.Metadata.Term = 1
  84. if err := s.ApplySnapshot(snap); err != nil {
  85. return err
  86. }
  87. fi, err := s.FirstIndex()
  88. if err != nil {
  89. return err
  90. }
  91. // At the time of writing and for *MemoryStorage, applying a
  92. // snapshot also truncates appropriately, but this would change with
  93. // other storage engines potentially.
  94. if exp := snap.Metadata.Index + 1; fi != exp {
  95. return fmt.Errorf("failed to establish first index %d; got %d", exp, fi)
  96. }
  97. }
  98. cfg := defaultRaftConfig(id, snap.Metadata.Index, s)
  99. if env.Options.OnConfig != nil {
  100. env.Options.OnConfig(cfg)
  101. if cfg.ID != id {
  102. // This could be supported but then we need to do more work
  103. // translating back and forth -- not worth it.
  104. return errors.New("OnConfig must not change the ID")
  105. }
  106. }
  107. if cfg.Logger != nil {
  108. return errors.New("OnConfig must not set Logger")
  109. }
  110. cfg.Logger = env.Output
  111. rn, err := raft.NewRawNode(cfg)
  112. if err != nil {
  113. return err
  114. }
  115. node := Node{
  116. RawNode: rn,
  117. // TODO(tbg): allow a more general Storage, as long as it also allows
  118. // us to apply snapshots, append entries, and update the HardState.
  119. Storage: s,
  120. Config: cfg,
  121. History: []pb.Snapshot{snap},
  122. }
  123. env.Nodes = append(env.Nodes, node)
  124. }
  125. return nil
  126. }