go.etcd.io/etcd@v3.3.27+incompatible/raft/rafttest/node.go (about) 1 // Copyright 2015 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 15 package rafttest 16 17 import ( 18 "context" 19 "log" 20 "sync" 21 "time" 22 23 "github.com/coreos/etcd/raft" 24 "github.com/coreos/etcd/raft/raftpb" 25 ) 26 27 type node struct { 28 raft.Node 29 id uint64 30 iface iface 31 stopc chan struct{} 32 pausec chan bool 33 34 // stable 35 storage *raft.MemoryStorage 36 37 mu sync.Mutex // guards state 38 state raftpb.HardState 39 } 40 41 func startNode(id uint64, peers []raft.Peer, iface iface) *node { 42 st := raft.NewMemoryStorage() 43 c := &raft.Config{ 44 ID: id, 45 ElectionTick: 10, 46 HeartbeatTick: 1, 47 Storage: st, 48 MaxSizePerMsg: 1024 * 1024, 49 MaxInflightMsgs: 256, 50 } 51 rn := raft.StartNode(c, peers) 52 n := &node{ 53 Node: rn, 54 id: id, 55 storage: st, 56 iface: iface, 57 pausec: make(chan bool), 58 } 59 n.start() 60 return n 61 } 62 63 func (n *node) start() { 64 n.stopc = make(chan struct{}) 65 ticker := time.Tick(5 * time.Millisecond) 66 67 go func() { 68 for { 69 select { 70 case <-ticker: 71 n.Tick() 72 case rd := <-n.Ready(): 73 if !raft.IsEmptyHardState(rd.HardState) { 74 n.mu.Lock() 75 n.state = rd.HardState 76 n.mu.Unlock() 77 n.storage.SetHardState(n.state) 78 } 79 n.storage.Append(rd.Entries) 80 time.Sleep(time.Millisecond) 81 // TODO: make send async, more like real world... 82 for _, m := range rd.Messages { 83 n.iface.send(m) 84 } 85 n.Advance() 86 case m := <-n.iface.recv(): 87 go n.Step(context.TODO(), m) 88 case <-n.stopc: 89 n.Stop() 90 log.Printf("raft.%d: stop", n.id) 91 n.Node = nil 92 close(n.stopc) 93 return 94 case p := <-n.pausec: 95 recvms := make([]raftpb.Message, 0) 96 for p { 97 select { 98 case m := <-n.iface.recv(): 99 recvms = append(recvms, m) 100 case p = <-n.pausec: 101 } 102 } 103 // step all pending messages 104 for _, m := range recvms { 105 n.Step(context.TODO(), m) 106 } 107 } 108 } 109 }() 110 } 111 112 // stop stops the node. stop a stopped node might panic. 113 // All in memory state of node is discarded. 114 // All stable MUST be unchanged. 115 func (n *node) stop() { 116 n.iface.disconnect() 117 n.stopc <- struct{}{} 118 // wait for the shutdown 119 <-n.stopc 120 } 121 122 // restart restarts the node. restart a started node 123 // blocks and might affect the future stop operation. 124 func (n *node) restart() { 125 // wait for the shutdown 126 <-n.stopc 127 c := &raft.Config{ 128 ID: n.id, 129 ElectionTick: 10, 130 HeartbeatTick: 1, 131 Storage: n.storage, 132 MaxSizePerMsg: 1024 * 1024, 133 MaxInflightMsgs: 256, 134 } 135 n.Node = raft.RestartNode(c) 136 n.start() 137 n.iface.connect() 138 } 139 140 // pause pauses the node. 141 // The paused node buffers the received messages and replies 142 // all of them when it resumes. 143 func (n *node) pause() { 144 n.pausec <- true 145 } 146 147 // resume resumes the paused node. 148 func (n *node) resume() { 149 n.pausec <- false 150 }