// handleExecConn reads a command from the connection and executes it. func (s *Store) handleExecConn(conn net.Conn) { defer s.wg.Done() // Read and execute command. err := func() error { // Read marker message. b := make([]byte, 4) if _, err := io.ReadFull(conn, b); err != nil { return fmt.Errorf("read magic: %s", err) } else if string(b) != ExecMagic { return fmt.Errorf("invalid exec magic: %q", string(b)) } // Read command size. var sz uint64 if err := binary.Read(conn, binary.BigEndian, &sz); err != nil { return fmt.Errorf("read size: %s", err) } // Read command. buf := make([]byte, sz) if _, err := io.ReadFull(conn, buf); err != nil { return fmt.Errorf("read command: %s", err) } // Ensure command can be deserialized before applying. if err := proto.Unmarshal(buf, &internal.Command{}); err != nil { return fmt.Errorf("unable to unmarshal command: %s", err) } // Apply against the raft log. if err := s.apply(buf); err != nil { return fmt.Errorf("apply: %s", err) } return nil }() // Build response message. var resp internal.Response resp.OK = proto.Bool(err == nil) resp.Index = proto.Uint64(s.raft.LastIndex()) if err != nil { resp.Error = proto.String(err.Error()) } // Encode response back to connection. if b, err := proto.Marshal(&resp); err != nil { panic(err) } else if err = binary.Write(conn, binary.BigEndian, uint64(len(b))); err != nil { s.Logger.Printf("unable to write exec response size: %s", err) } else if _, err = conn.Write(b); err != nil { s.Logger.Printf("unable to write exec response: %s", err) } conn.Close() }
// remoteExec sends an encoded command to the remote leader. func (s *Store) remoteExec(b []byte) error { // Retrieve the current known leader. leader := s.raft.Leader() if leader == "" { return errors.New("no leader") } // Create a connection to the leader. conn, err := net.DialTimeout("tcp", leader, 10*time.Second) if err != nil { return err } defer conn.Close() // Write a marker byte for exec messages. _, err = conn.Write([]byte{MuxExecHeader}) if err != nil { return err } // Write a marker message. _, err = conn.Write([]byte(ExecMagic)) if err != nil { return err } // Write command size & bytes. if err := binary.Write(conn, binary.BigEndian, uint64(len(b))); err != nil { return fmt.Errorf("write command size: %s", err) } else if _, err := conn.Write(b); err != nil { return fmt.Errorf("write command: %s", err) } // Read response bytes. var sz uint64 if err := binary.Read(conn, binary.BigEndian, &sz); err != nil { return fmt.Errorf("read response size: %s", err) } buf := make([]byte, sz) if _, err := io.ReadFull(conn, buf); err != nil { return fmt.Errorf("read response: %s", err) } // Unmarshal response. var resp internal.Response if err := proto.Unmarshal(buf, &resp); err != nil { return fmt.Errorf("unmarshal response: %s", err) } else if !resp.GetOK() { return fmt.Errorf("exec failed: %s", resp.GetError()) } // Wait for local FSM to sync to index. if err := s.sync(resp.GetIndex(), 5*time.Second); err != nil { return fmt.Errorf("sync: %s", err) } return nil }