// start starts the node by registering the storage instance for the // RPC service "Node" and initializing stores for each specified // engine. Launches periodic store gossiping in a goroutine. func (n *Node) start(rpcServer *rpc.Server, engines []engine.Engine, attrs proto.Attributes, stopper *util.Stopper) error { n.initDescriptor(rpcServer.Addr(), attrs) if err := rpcServer.RegisterName("Node", (*nodeServer)(n)); err != nil { log.Fatalf("unable to register node service with RPC server: %s", err) } // Start status monitor. n.status.StartMonitorFeed(n.ctx.EventFeed) stopper.AddCloser(n.ctx.EventFeed) // Initialize stores, including bootstrapping new ones. if err := n.initStores(engines, stopper); err != nil { return err } n.startedAt = n.ctx.Clock.Now().WallTime // Initialize publisher for Node Events. This requires the NodeID, which is // initialized by initStores(); because of this, some Store initialization // events will precede the StartNodeEvent on the feed. n.feed = status.NewNodeEventFeed(n.Descriptor.NodeID, n.ctx.EventFeed) n.feed.StartNode(n.Descriptor, n.startedAt) n.startStoresScanner(stopper) n.startPublishStatuses(stopper) n.startGossip(stopper) log.Infoc(n.context(), "Started node with %v engine(s) and attributes %v", engines, attrs.Attrs) return nil }
// start starts the node by registering the storage instance for the // RPC service "Node" and initializing stores for each specified // engine. Launches periodic store gossiping in a goroutine. func (n *Node) start(rpcServer *rpc.Server, engines []engine.Engine, attrs proto.Attributes, stopper *util.Stopper) error { n.initDescriptor(rpcServer.Addr(), attrs) if err := rpcServer.RegisterName("Node", (*nodeServer)(n)); err != nil { log.Fatalf("unable to register node service with RPC server: %s", err) } // Start status monitor. n.status.StartMonitorFeed(n.ctx.EventFeed) stopper.AddCloser(n.ctx.EventFeed) // Initialize stores, including bootstrapping new ones. if err := n.initStores(engines, stopper); err != nil { return err } // Pass NodeID to status monitor - this value is initialized in initStores, // but the StatusMonitor must be active before initStores. n.status.SetNodeID(n.Descriptor.NodeID) // Initialize publisher for Node Events. n.feed = status.NewNodeEventFeed(n.Descriptor.NodeID, n.ctx.EventFeed) n.startedAt = n.ctx.Clock.Now().WallTime n.startStoresScanner(stopper) n.startPublishStatuses(stopper) n.startGossip(stopper) log.Infoc(n.context(), "Started node with %v engine(s) and attributes %v", engines, attrs.Attrs) return nil }
// NewMultiRaft creates a MultiRaft object. func NewMultiRaft(nodeID proto.RaftNodeID, config *Config, stopper *util.Stopper) (*MultiRaft, error) { if nodeID == 0 { return nil, util.Error("Invalid RaftNodeID") } if err := config.validate(); err != nil { return nil, err } if config.Ticker == nil { config.Ticker = newTicker(config.TickInterval) stopper.AddCloser(config.Ticker) } if config.EntryFormatter != nil { // Wrap the EntryFormatter to strip off the command id. ef := config.EntryFormatter config.EntryFormatter = func(data []byte) string { if len(data) == 0 { return "[empty]" } id, cmd := decodeCommand(data) formatted := ef(cmd) return fmt.Sprintf("%x: %s", id, formatted) } } m := &MultiRaft{ Config: *config, stopper: stopper, multiNode: raft.StartMultiNode(uint64(nodeID)), nodeID: nodeID, // Output channel. Events: make(chan interface{}, config.EventBufferSize), // Input channels. reqChan: make(chan *RaftMessageRequest), createGroupChan: make(chan *createGroupOp), removeGroupChan: make(chan *removeGroupOp), proposalChan: make(chan *proposal), callbackChan: make(chan func()), } if err := m.Transport.Listen(nodeID, (*multiraftServer)(m)); err != nil { return nil, err } return m, nil }
func newTestCluster(transport Transport, size int, stopper *util.Stopper, t *testing.T) *testCluster { if transport == nil { transport = NewLocalRPCTransport() } stopper.AddCloser(transport) cluster := &testCluster{ t: t, transport: transport, groups: map[proto.RaftID][]int{}, } for i := 0; i < size; i++ { ticker := newManualTicker() storage := &BlockableStorage{storage: NewMemoryStorage()} config := &Config{ Transport: transport, Storage: storage, Ticker: ticker, ElectionTimeoutTicks: 2, HeartbeatIntervalTicks: 1, TickInterval: time.Hour, // not in use } mr, err := NewMultiRaft(proto.RaftNodeID(i+1), config, stopper) if err != nil { t.Fatal(err) } state := newState(mr) demux := newEventDemux(state.Events) demux.start(stopper) cluster.nodes = append(cluster.nodes, state) cluster.tickers = append(cluster.tickers, ticker) cluster.events = append(cluster.events, demux) cluster.storages = append(cluster.storages, storage) } cluster.start() return cluster }