// NewNode generates a new Raft node func NewNode(opts NodeOptions) *Node { cfg := opts.Config if cfg == nil { cfg = DefaultNodeConfig() } if opts.TickInterval == 0 { opts.TickInterval = time.Second } if opts.SendTimeout == 0 { opts.SendTimeout = 2 * time.Second } raftStore := raft.NewMemoryStorage() n := &Node{ cluster: membership.NewCluster(2 * cfg.ElectionTick), raftStore: raftStore, opts: opts, Config: &raft.Config{ ElectionTick: cfg.ElectionTick, HeartbeatTick: cfg.HeartbeatTick, Storage: raftStore, MaxSizePerMsg: cfg.MaxSizePerMsg, MaxInflightMsgs: cfg.MaxInflightMsgs, Logger: cfg.Logger, }, doneCh: make(chan struct{}), removeRaftCh: make(chan struct{}), stopped: make(chan struct{}), leadershipBroadcast: watch.NewQueue(), lastSendToMember: make(map[uint64]chan struct{}), keyRotator: opts.KeyRotator, } n.memoryStore = store.NewMemoryStore(n) if opts.ClockSource == nil { n.ticker = clock.NewClock().NewTicker(opts.TickInterval) } else { n.ticker = opts.ClockSource.NewTicker(opts.TickInterval) } n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) n.wait = newWait() n.removeRaftFunc = func(n *Node) func() { var removeRaftOnce sync.Once return func() { removeRaftOnce.Do(func() { close(n.removeRaftCh) }) } }(n) return n }
// NewNode generates a new Raft node func NewNode(ctx context.Context, opts NewNodeOptions) *Node { cfg := opts.Config if cfg == nil { cfg = DefaultNodeConfig() } if opts.TickInterval == 0 { opts.TickInterval = time.Second } raftStore := raft.NewMemoryStorage() ctx, cancel := context.WithCancel(ctx) n := &Node{ Ctx: ctx, cancel: cancel, cluster: membership.NewCluster(), tlsCredentials: opts.TLSCredentials, raftStore: raftStore, Address: opts.Addr, opts: opts, Config: &raft.Config{ ElectionTick: cfg.ElectionTick, HeartbeatTick: cfg.HeartbeatTick, Storage: raftStore, MaxSizePerMsg: cfg.MaxSizePerMsg, MaxInflightMsgs: cfg.MaxInflightMsgs, Logger: cfg.Logger, }, forceNewCluster: opts.ForceNewCluster, stopCh: make(chan struct{}), doneCh: make(chan struct{}), removeRaftCh: make(chan struct{}), StateDir: opts.StateDir, joinAddr: opts.JoinAddr, sendTimeout: 2 * time.Second, leadershipBroadcast: events.NewBroadcaster(), } n.memoryStore = store.NewMemoryStore(n) if opts.ClockSource == nil { n.ticker = clock.NewClock().NewTicker(opts.TickInterval) } else { n.ticker = opts.ClockSource.NewTicker(opts.TickInterval) } if opts.SendTimeout != 0 { n.sendTimeout = opts.SendTimeout } n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) n.wait = newWait() return n }
func newTestCluster(members []*membership.Member, removed []*membership.Member) *membership.Cluster { c := membership.NewCluster() for _, m := range members { c.AddMember(m) } for _, m := range removed { c.AddMember(m) c.RemoveMember(m.RaftID) } return c }
func TestMembers(t *testing.T) { cls := membership.NewCluster() defer cls.Clear() cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 1}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 5}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 20}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 50}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 10}}) assert.Len(t, cls.Members(), 5) }
func TestMembers(t *testing.T) { w := map[uint64]*membership.Member{ 1: {RaftMember: &api.RaftMember{RaftID: 1}}, 20: {RaftMember: &api.RaftMember{RaftID: 20}}, 10: {RaftMember: &api.RaftMember{RaftID: 10}}, 5: {RaftMember: &api.RaftMember{RaftID: 5}}, 50: {RaftMember: &api.RaftMember{RaftID: 50}}, } cls := membership.NewCluster() cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 1}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 5}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 20}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 50}}) cls.AddMember(&membership.Member{RaftMember: &api.RaftMember{RaftID: 10}}) assert.Equal(t, cls.Members(), w) }
// NewNode generates a new Raft node func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) { cfg := opts.Config if cfg == nil { cfg = DefaultNodeConfig() } if opts.TickInterval == 0 { opts.TickInterval = time.Second } raftID, err := identity.ParseNodeID(opts.ID) if err != nil { return nil, err } raftStore := raft.NewMemoryStorage() ctx, cancel := context.WithCancel(ctx) n := &Node{ Ctx: ctx, cancel: cancel, cluster: membership.NewCluster(), tlsCredentials: opts.TLSCredentials, raftStore: raftStore, Address: opts.Addr, Config: &raft.Config{ ElectionTick: cfg.ElectionTick, HeartbeatTick: cfg.HeartbeatTick, Storage: raftStore, MaxSizePerMsg: cfg.MaxSizePerMsg, MaxInflightMsgs: cfg.MaxInflightMsgs, Logger: cfg.Logger, ID: raftID, }, forceNewCluster: opts.ForceNewCluster, stopCh: make(chan struct{}), doneCh: make(chan struct{}), StateDir: opts.StateDir, joinAddr: opts.JoinAddr, sendTimeout: 2 * time.Second, leadershipBroadcast: events.NewBroadcaster(), } n.memoryStore = store.NewMemoryStore(n) if opts.ClockSource == nil { n.ticker = clock.NewClock().NewTicker(opts.TickInterval) } else { n.ticker = opts.ClockSource.NewTicker(opts.TickInterval) } if opts.SendTimeout != 0 { n.sendTimeout = opts.SendTimeout } if err := n.loadAndStart(ctx, opts.ForceNewCluster); err != nil { n.ticker.Stop() return nil, err } snapshot, err := raftStore.Snapshot() // Snapshot never returns an error if err != nil { panic("could not get snapshot of raft store") } n.confState = snapshot.Metadata.ConfState n.appliedIndex = snapshot.Metadata.Index n.snapshotIndex = snapshot.Metadata.Index n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) n.wait = newWait() if n.startNodePeers != nil { if n.joinAddr != "" { c, err := n.ConnectToMember(n.joinAddr, 10*time.Second) if err != nil { return nil, err } defer func() { _ = c.Conn.Close() }() ctx, cancel := context.WithTimeout(n.Ctx, 10*time.Second) defer cancel() resp, err := c.Join(ctx, &api.JoinRequest{ Addr: n.Address, }) if err != nil { return nil, err } n.Node = raft.StartNode(n.Config, []raft.Peer{}) if err := n.registerNodes(resp.Members); err != nil { return nil, err } } else { n.Node = raft.StartNode(n.Config, n.startNodePeers) if err := n.Campaign(n.Ctx); err != nil { return nil, err } } return n, nil } if n.joinAddr != "" { n.Config.Logger.Warning("ignoring request to join cluster, because raft state already exists") } n.Node = raft.RestartNode(n.Config) return n, nil }