func (s *consulSnapshot) persistTombstones(sink raft.SnapshotSink, encoder *codec.Encoder) error { streamCh := make(chan interface{}, 256) errorCh := make(chan error) go func() { if err := s.state.TombstoneDump(streamCh); err != nil { errorCh <- err } }() for { select { case raw := <-streamCh: if raw == nil { return nil } sink.Write([]byte{byte(structs.TombstoneRequestType)}) if err := encoder.Encode(raw); err != nil { return err } case err := <-errorCh: return err } } }
func (s *consulSnapshot) persistACLs(sink raft.SnapshotSink, encoder *codec.Encoder) error { acls, err := s.state.ACLList() if err != nil { return err } for _, s := range acls { sink.Write([]byte{byte(structs.ACLRequestType)}) if err := encoder.Encode(s); err != nil { return err } } return nil }
func (s *consulSnapshot) persistSessions(sink raft.SnapshotSink, encoder *codec.Encoder) error { sessions, err := s.state.SessionList() if err != nil { return err } for _, s := range sessions { sink.Write([]byte{byte(structs.SessionRequestType)}) if err := encoder.Encode(s); err != nil { return err } } return nil }
func (s *consulSnapshot) persistNodes(sink raft.SnapshotSink, encoder *codec.Encoder) error { // Get all the nodes nodes := s.state.Nodes() // Register each node var req structs.RegisterRequest for i := 0; i < len(nodes); i++ { req = structs.RegisterRequest{ Node: nodes[i].Node, Address: nodes[i].Address, } // Register the node itself sink.Write([]byte{byte(structs.RegisterRequestType)}) if err := encoder.Encode(&req); err != nil { return err } // Register each service this node has services := s.state.NodeServices(nodes[i].Node) for _, srv := range services.Services { req.Service = srv sink.Write([]byte{byte(structs.RegisterRequestType)}) if err := encoder.Encode(&req); err != nil { return err } } // Register each check this node has req.Service = nil checks := s.state.NodeChecks(nodes[i].Node) for _, check := range checks { req.Check = check sink.Write([]byte{byte(structs.RegisterRequestType)}) if err := encoder.Encode(&req); err != nil { return err } } } return nil }
// handleCommand is used to decode and dispatch a single command func (n *NetworkTransport) handleCommand(r *bufio.Reader, dec *codec.Decoder, enc *codec.Encoder) error { // Get the rpc type rpcType, err := r.ReadByte() if err != nil { return err } // Create the RPC object respCh := make(chan RPCResponse, 1) rpc := RPC{ RespChan: respCh, } // Decode the command isHeartbeat := false switch rpcType { case rpcAppendEntries: var req AppendEntriesRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req // Check if this is a heartbeat if req.Term != 0 && req.Leader != nil && req.PrevLogEntry == 0 && req.PrevLogTerm == 0 && len(req.Entries) == 0 && req.LeaderCommitIndex == 0 { isHeartbeat = true } case rpcRequestVote: var req RequestVoteRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req case rpcInstallSnapshot: var req InstallSnapshotRequest if err := dec.Decode(&req); err != nil { return err } rpc.Command = &req rpc.Reader = io.LimitReader(r, req.Size) default: return fmt.Errorf("unknown rpc type %d", rpcType) } // Check for heartbeat fast-path if isHeartbeat { n.heartbeatFnLock.Lock() fn := n.heartbeatFn n.heartbeatFnLock.Unlock() if fn != nil { fn(rpc) goto RESP } } // Dispatch the RPC select { case n.consumeCh <- rpc: case <-n.shutdownCh: return ErrTransportShutdown } // Wait for response RESP: select { case resp := <-respCh: // Send the error first respErr := "" if resp.Error != nil { respErr = resp.Error.Error() } if err := enc.Encode(respErr); err != nil { return err } // Send the response if err := enc.Encode(resp.Response); err != nil { return err } case <-n.shutdownCh: return ErrTransportShutdown } return nil }