WIP: Implement NodeState as an attribute of *Node

NodeState is shared among nodes in the cluster (via gossip
in a gossip implementation) and cached locally in Cluster.Nodes
in order to be available to the /status endpoint.
This commit is contained in:
Travis 2017-04-21 18:27:46 -05:00
parent 6fe8e2b8ab
commit 74bf4731f5
No known key found for this signature in database
GPG key ID: 7F08008DFD9314C9
7 changed files with 305 additions and 96 deletions

View file

@ -3,6 +3,8 @@ package pilosa
import (
"encoding/binary"
"hash/fnv"
"github.com/pilosa/pilosa/internal"
)
const (
@ -12,15 +14,30 @@ const (
// DefaultReplicaN is the default number of replicas per partition.
DefaultReplicaN = 1
// HealthStatus is the return value of the /health endpoint for a node in the cluster.
HealthStatusUp = "UP"
HealthStatusDown = "DOWN"
// NodeState represents node state returned in /status endpoint for a node in the cluster.
NodeStateUp = "UP"
NodeStateDown = "DOWN"
)
// Node represents a node in the cluster.
type Node struct {
Host string `json:"host"`
InternalHost string `json:"internalHost"`
status *internal.NodeStatus `json:"state"`
}
// SetStatus sets the NodeStatus.
func (n *Node) SetStatus(s *internal.NodeStatus) {
n.status = s
}
// SetState sets the Node.status.state.
func (n *Node) SetState(s string) {
if n.status == nil {
n.status = &internal.NodeStatus{}
}
n.status.State = s
}
// Nodes represents a list of nodes.
@ -120,21 +137,37 @@ func (c *Cluster) NodeSetHosts() []string {
return a
}
// Health returns a map of nodes in the cluster with each node's state (UP/DOWN) as the value.
func (c *Cluster) Health() map[string]string {
// NodeStates returns a map of nodes in the cluster with each node's state (UP/DOWN) as the value.
func (c *Cluster) NodeStates() map[string]string {
h := make(map[string]string)
for _, n := range c.Nodes {
h[n.Host] = HealthStatusDown
h[n.Host] = NodeStateDown
}
// we are assuming that NodeSetHosts is a subset of c.Nodes
for _, m := range c.NodeSetHosts() {
if _, ok := h[m]; ok {
h[m] = HealthStatusUp
h[m] = NodeStateUp
}
}
return h
}
// State returns the internal ClusterState representation.
func (c *Cluster) Status() *internal.ClusterStatus {
return &internal.ClusterStatus{
Nodes: encodeClusterStatus(c.Nodes),
}
}
// encodeClusterStatus converts a into its internal representation.
func encodeClusterStatus(a []*Node) []*internal.NodeStatus {
other := make([]*internal.NodeStatus, len(a))
for i := range a {
other[i] = a[i].status
}
return other
}
// NodeByHost returns a node reference by host.
func (c *Cluster) NodeByHost(host string) *Node {
for _, n := range c.Nodes {

View file

@ -89,7 +89,7 @@ func TestCluster_NodeSetHosts(t *testing.T) {
}
// Ensure cluster can compare its Nodes and Members
func TestCluster_Health(t *testing.T) {
func TestCluster_NodeStates(t *testing.T) {
c := pilosa.Cluster{
Nodes: []*pilosa.Node{
{Host: "serverA:1000"},
@ -109,12 +109,12 @@ func TestCluster_Health(t *testing.T) {
}
// Verify a DOWN node is reported, and extraneous nodes are ignored
if a := c.Health(); !reflect.DeepEqual(a, map[string]string{
"serverA:1000": pilosa.HealthStatusUp,
"serverB:1000": pilosa.HealthStatusDown,
"serverC:1000": pilosa.HealthStatusUp,
if a := c.NodeStates(); !reflect.DeepEqual(a, map[string]string{
"serverA:1000": pilosa.NodeStateUp,
"serverB:1000": pilosa.NodeStateDown,
"serverC:1000": pilosa.NodeStateUp,
}) {
t.Fatalf("unexpected health: %s", spew.Sdump(a))
t.Fatalf("unexpected node state: %s", spew.Sdump(a))
}
}

View file

@ -14,14 +14,6 @@ import (
"github.com/pilosa/pilosa/internal"
)
// StateHandler specifies two methods which an object must implement to share
// state in the cluster. These are used by the GossipNodeSet to implement the
// LocalState and MergeRemoteState methods of memberlist.Delegate
type StateHandler interface {
LocalState() (proto.Message, error)
HandleRemoteState(proto.Message) error
}
// GossipNodeSet represents a gossip implementation of NodeSet using memberlist
// GossipNodeSet also represents a gossip implementation of pilosa.Broadcaster
// GossipNodeSet also represents an implementation of memberlist.Delegate
@ -31,8 +23,8 @@ type GossipNodeSet struct {
broadcasts *memberlist.TransmitLimitedQueue
stateHandler StateHandler
config *GossipConfig
statusHandler pilosa.StatusHandler
config *GossipConfig
// The writer for any logging.
LogOutput io.Writer
@ -89,7 +81,7 @@ type GossipConfig struct {
}
// NewGossipNodeSet returns a new instance of GossipNodeSet.
func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, sh StateHandler) *GossipNodeSet {
func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, sh pilosa.StatusHandler) *GossipNodeSet {
g := &GossipNodeSet{
LogOutput: os.Stderr,
}
@ -106,7 +98,7 @@ func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed
g.config.memberlistConfig.AdvertisePort = gossipPort
g.config.memberlistConfig.Delegate = g
g.stateHandler = sh
g.statusHandler = sh
return g
}
@ -176,7 +168,7 @@ func (g *GossipNodeSet) GetBroadcasts(overhead, limit int) [][]byte {
}
func (g *GossipNodeSet) LocalState(join bool) []byte {
pb, err := g.stateHandler.LocalState()
pb, err := g.statusHandler.LocalStatus()
if err != nil {
g.logger().Printf("error getting local state, err=%s", err)
return []byte{}
@ -193,12 +185,12 @@ func (g *GossipNodeSet) LocalState(join bool) []byte {
func (g *GossipNodeSet) MergeRemoteState(buf []byte, join bool) {
// Unmarshal nodestate data.
var pb internal.NodeState
var pb internal.NodeStatus
if err := proto.Unmarshal(buf, &pb); err != nil {
g.logger().Printf("error unmarshalling nodestate data, err=%s", err)
return
}
err := g.stateHandler.HandleRemoteState(&pb)
err := g.statusHandler.HandleRemoteStatus(&pb)
if err != nil {
g.logger().Printf("merge state error: %s", err)
}

View file

@ -27,8 +27,9 @@ import (
// Handler represents an HTTP handler.
type Handler struct {
Holder *Holder
Broadcaster Broadcaster
Holder *Holder
Broadcaster Broadcaster
StatusHandler StatusHandler
// Local hostname & cluster configuration.
Host string
@ -85,6 +86,7 @@ func NewRouter(handler *Handler) *mux.Router {
router.HandleFunc("/nodes", handler.handleGetNodes).Methods("GET")
router.HandleFunc("/schema", handler.handleGetSchema).Methods("GET")
router.HandleFunc("/slices/max", handler.handleGetSliceMax).Methods("GET")
router.HandleFunc("/status", handler.handleGetStatus).Methods("GET")
router.HandleFunc("/version", handler.handleGetVersion).Methods("GET")
// TODO: Apply MethodNotAllowed statuses to all endpoints.
@ -116,8 +118,13 @@ func (h *Handler) handleGetSchema(w http.ResponseWriter, r *http.Request) {
// handleGetStatus handles GET /status requests.
func (h *Handler) handleGetStatus(w http.ResponseWriter, r *http.Request) {
status, err := h.StatusHandler.ClusterStatus()
if err != nil {
h.logger().Printf("cluster status error: %s", err)
return
}
if err := json.NewEncoder(w).Encode(getStatusResponse{
Health: h.Cluster.Health(),
Status: status,
}); err != nil {
h.logger().Printf("write status response error: %s", err)
}
@ -128,7 +135,7 @@ type getSchemaResponse struct {
}
type getStatusResponse struct {
Health map[string]string `json:"health"`
Status proto.Message `json:"status"`
}
// handlePostQuery handles /query requests.

View file

@ -23,7 +23,8 @@
DeleteFrameMessage
Frame
Index
NodeState
NodeStatus
ClusterStatus
*/
package internal
@ -231,24 +232,40 @@ func (m *Index) GetFrames() []*Frame {
return nil
}
type NodeState struct {
type NodeStatus struct {
Host string `protobuf:"bytes,1,opt,name=Host,proto3" json:"Host,omitempty"`
State string `protobuf:"bytes,2,opt,name=State,proto3" json:"State,omitempty"`
Indexes []*Index `protobuf:"bytes,3,rep,name=Indexes" json:"Indexes,omitempty"`
}
func (m *NodeState) Reset() { *m = NodeState{} }
func (m *NodeState) String() string { return proto.CompactTextString(m) }
func (*NodeState) ProtoMessage() {}
func (*NodeState) Descriptor() ([]byte, []int) { return fileDescriptorPrivate, []int{14} }
func (m *NodeStatus) Reset() { *m = NodeStatus{} }
func (m *NodeStatus) String() string { return proto.CompactTextString(m) }
func (*NodeStatus) ProtoMessage() {}
func (*NodeStatus) Descriptor() ([]byte, []int) { return fileDescriptorPrivate, []int{14} }
func (m *NodeState) GetIndexes() []*Index {
func (m *NodeStatus) GetIndexes() []*Index {
if m != nil {
return m.Indexes
}
return nil
}
type ClusterStatus struct {
Nodes []*NodeStatus `protobuf:"bytes,1,rep,name=Nodes" json:"Nodes,omitempty"`
}
func (m *ClusterStatus) Reset() { *m = ClusterStatus{} }
func (m *ClusterStatus) String() string { return proto.CompactTextString(m) }
func (*ClusterStatus) ProtoMessage() {}
func (*ClusterStatus) Descriptor() ([]byte, []int) { return fileDescriptorPrivate, []int{15} }
func (m *ClusterStatus) GetNodes() []*NodeStatus {
if m != nil {
return m.Nodes
}
return nil
}
func init() {
proto.RegisterType((*IndexMeta)(nil), "internal.IndexMeta")
proto.RegisterType((*FrameMeta)(nil), "internal.FrameMeta")
@ -264,7 +281,8 @@ func init() {
proto.RegisterType((*DeleteFrameMessage)(nil), "internal.DeleteFrameMessage")
proto.RegisterType((*Frame)(nil), "internal.Frame")
proto.RegisterType((*Index)(nil), "internal.Index")
proto.RegisterType((*NodeState)(nil), "internal.NodeState")
proto.RegisterType((*NodeStatus)(nil), "internal.NodeStatus")
proto.RegisterType((*ClusterStatus)(nil), "internal.ClusterStatus")
}
func (m *IndexMeta) Marshal() (dAtA []byte, err error) {
size := m.Size()
@ -780,7 +798,7 @@ func (m *Index) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *NodeState) Marshal() (dAtA []byte, err error) {
func (m *NodeStatus) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
@ -790,7 +808,7 @@ func (m *NodeState) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
func (m *NodeState) MarshalTo(dAtA []byte) (int, error) {
func (m *NodeStatus) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
@ -822,6 +840,36 @@ func (m *NodeState) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *ClusterStatus) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ClusterStatus) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Nodes) > 0 {
for _, msg := range m.Nodes {
dAtA[i] = 0xa
i++
i = encodeVarintPrivate(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
func encodeFixed64Private(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
@ -1074,7 +1122,7 @@ func (m *Index) Size() (n int) {
return n
}
func (m *NodeState) Size() (n int) {
func (m *NodeStatus) Size() (n int) {
var l int
_ = l
l = len(m.Host)
@ -1094,6 +1142,18 @@ func (m *NodeState) Size() (n int) {
return n
}
func (m *ClusterStatus) Size() (n int) {
var l int
_ = l
if len(m.Nodes) > 0 {
for _, e := range m.Nodes {
l = e.Size()
n += 1 + l + sovPrivate(uint64(l))
}
}
return n
}
func sovPrivate(x uint64) (n int) {
for {
n++
@ -2899,7 +2959,7 @@ func (m *Index) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *NodeState) Unmarshal(dAtA []byte) error {
func (m *NodeStatus) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@ -2922,10 +2982,10 @@ func (m *NodeState) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: NodeState: wiretype end group for non-group")
return fmt.Errorf("proto: NodeStatus: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: NodeState: illegal tag %d (wire type %d)", fieldNum, wire)
return fmt.Errorf("proto: NodeStatus: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
@ -3038,6 +3098,87 @@ func (m *NodeState) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ClusterStatus) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPrivate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ClusterStatus: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ClusterStatus: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Nodes", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPrivate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthPrivate
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Nodes = append(m.Nodes, &NodeStatus{})
if err := m.Nodes[len(m.Nodes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPrivate(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPrivate
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipPrivate(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
@ -3146,43 +3287,44 @@ var (
func init() { proto.RegisterFile("private.proto", fileDescriptorPrivate) }
var fileDescriptorPrivate = []byte{
// 594 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x4c,
0x10, 0xfe, 0x9d, 0xb8, 0xfd, 0xe3, 0x89, 0x1a, 0xd2, 0x05, 0x21, 0x53, 0xa1, 0x28, 0xda, 0x03,
0x0d, 0x3d, 0xe4, 0x50, 0x2e, 0x08, 0x71, 0xa8, 0x9a, 0x04, 0x35, 0x12, 0x29, 0x62, 0x53, 0x71,
0x66, 0x93, 0x8c, 0xc0, 0x8a, 0x63, 0x07, 0x7b, 0x93, 0x34, 0x1c, 0xb8, 0xf3, 0x06, 0x48, 0x3c,
0x03, 0xef, 0xc1, 0x91, 0x47, 0x40, 0xe1, 0x45, 0xd0, 0x8e, 0xd7, 0x76, 0x70, 0x29, 0x15, 0xdc,
0x76, 0xbe, 0x99, 0x9d, 0xef, 0x9b, 0xcf, 0xb3, 0x86, 0xbd, 0x79, 0xe4, 0x2d, 0xa5, 0xc2, 0xf6,
0x3c, 0x0a, 0x55, 0xc8, 0x2a, 0x5e, 0xa0, 0x30, 0x0a, 0xa4, 0xcf, 0x5f, 0x80, 0xd3, 0x0f, 0x26,
0x78, 0x39, 0x40, 0x25, 0x59, 0x13, 0xaa, 0x9d, 0xd0, 0x5f, 0xcc, 0x82, 0xe7, 0x72, 0x84, 0xbe,
0x6b, 0x35, 0xad, 0x96, 0x23, 0xb6, 0x21, 0x5d, 0x71, 0xe1, 0xcd, 0xf0, 0xe5, 0x42, 0x06, 0x6a,
0x31, 0x73, 0x4b, 0x49, 0xc5, 0x16, 0xc4, 0xbf, 0x58, 0xe0, 0x3c, 0x8b, 0xe4, 0x0c, 0xa9, 0xe3,
0x01, 0x54, 0x44, 0xb8, 0xda, 0x6e, 0x97, 0xc5, 0xec, 0x01, 0xd4, 0xfa, 0xc1, 0x12, 0xa3, 0x18,
0x7b, 0x81, 0x1c, 0xf9, 0x38, 0xa1, 0x76, 0x15, 0x51, 0x40, 0xd9, 0x7d, 0x70, 0x3a, 0x72, 0xfc,
0x16, 0x2f, 0xd6, 0x73, 0x74, 0xcb, 0xd4, 0x24, 0x07, 0xb2, 0xec, 0xd0, 0x7b, 0x8f, 0xae, 0xdd,
0xb4, 0x5a, 0x7b, 0x22, 0x07, 0x8a, 0x7a, 0x77, 0xae, 0xea, 0xe5, 0x50, 0xeb, 0xcf, 0xe6, 0x61,
0xa4, 0x04, 0xc6, 0xf3, 0x30, 0x88, 0x91, 0xd5, 0xa1, 0xdc, 0x8b, 0x22, 0x23, 0x57, 0x1f, 0xf9,
0x07, 0xa8, 0x9f, 0xfa, 0xe1, 0x78, 0xda, 0x95, 0x4a, 0x0a, 0x7c, 0xb7, 0xc0, 0x58, 0xb1, 0x3b,
0xb0, 0x43, 0xc6, 0x99, 0xba, 0x24, 0xd0, 0x28, 0x0d, 0x6f, 0x9c, 0x49, 0x02, 0x8d, 0xd2, 0x7d,
0x52, 0x6f, 0x8b, 0x24, 0xd0, 0xe8, 0xd0, 0xf7, 0xc6, 0x89, 0x6a, 0x5b, 0x24, 0x01, 0x63, 0x60,
0xbf, 0xf2, 0x70, 0x65, 0xa4, 0xd2, 0x99, 0xf7, 0x61, 0x7f, 0x8b, 0xdf, 0xc8, 0xbc, 0x0b, 0xbb,
0x22, 0x5c, 0xf5, 0xbb, 0xb1, 0x6b, 0x35, 0xcb, 0x2d, 0x5b, 0x98, 0x88, 0x0c, 0xa1, 0x2f, 0xa6,
0x53, 0x25, 0x4a, 0xe5, 0x00, 0xbf, 0x07, 0x3b, 0xe4, 0x8e, 0x9e, 0x32, 0xbf, 0xab, 0x8f, 0xfc,
0xb3, 0x05, 0xfb, 0x03, 0x79, 0x49, 0x32, 0xe2, 0x8c, 0xe6, 0x0c, 0x9c, 0x0c, 0xa4, 0xea, 0xea,
0xf1, 0x51, 0x3b, 0x5d, 0x9f, 0xf6, 0x95, 0xfa, 0x1c, 0xe9, 0x05, 0x2a, 0x5a, 0x8b, 0xfc, 0xf2,
0xc1, 0x53, 0xa8, 0xfd, 0x9a, 0xd4, 0x1a, 0xa6, 0xb8, 0x4e, 0x9d, 0x9e, 0xe2, 0x5a, 0x7b, 0xb2,
0x94, 0xfe, 0x22, 0xf1, 0xcf, 0x16, 0x49, 0xf0, 0xa4, 0xf4, 0xd8, 0xe2, 0x27, 0xc0, 0x3a, 0x11,
0x4a, 0x85, 0xd4, 0x60, 0x80, 0x71, 0x2c, 0xdf, 0xe0, 0xf5, 0x5f, 0x21, 0x71, 0xb6, 0xb4, 0xe5,
0x2c, 0x3f, 0x02, 0xd6, 0x45, 0x1f, 0x15, 0x9a, 0x85, 0xff, 0x43, 0x07, 0x3e, 0x4c, 0xd9, 0x6e,
0xae, 0x65, 0x87, 0x60, 0xeb, 0x5d, 0x27, 0xb2, 0xea, 0xf1, 0xed, 0xdc, 0x9c, 0xec, 0x61, 0x09,
0x2a, 0xe0, 0x5e, 0xda, 0xd4, 0xbc, 0x8f, 0x1b, 0x46, 0xf8, 0xcd, 0x22, 0xa5, 0x54, 0xe5, 0x22,
0x55, 0xf6, 0xe2, 0x0c, 0xd5, 0x49, 0x3a, 0xeb, 0xbf, 0x52, 0xf1, 0xae, 0x41, 0xf5, 0x42, 0x9e,
0xeb, 0x6c, 0x72, 0x87, 0xce, 0xd7, 0x8f, 0x5c, 0xd4, 0xf1, 0xd1, 0x32, 0x94, 0x7f, 0xd7, 0xa6,
0xe0, 0x9c, 0xfe, 0x8d, 0xa4, 0xab, 0x63, 0xde, 0x50, 0x16, 0xb3, 0x43, 0xd8, 0x25, 0xd6, 0xd8,
0xb5, 0x69, 0x3b, 0x6f, 0x15, 0xd4, 0x08, 0x93, 0xe6, 0xaf, 0xc1, 0x39, 0x0f, 0x27, 0x38, 0x54,
0x52, 0xd1, 0x54, 0x67, 0x61, 0xac, 0x52, 0x39, 0xfa, 0x4c, 0x6b, 0xa3, 0x93, 0xa9, 0x11, 0x49,
0xe5, 0x43, 0xf8, 0x9f, 0xe4, 0x60, 0xec, 0x96, 0x8b, 0x04, 0x94, 0x10, 0x69, 0xfe, 0xb4, 0xfe,
0x75, 0xd3, 0xb0, 0xbe, 0x6d, 0x1a, 0xd6, 0xf7, 0x4d, 0xc3, 0xfa, 0xf4, 0xa3, 0xf1, 0xdf, 0x68,
0x97, 0xfe, 0xb7, 0x8f, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0xc6, 0x68, 0xdc, 0x63, 0x80, 0x05,
0x00, 0x00,
// 617 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
0x10, 0xc5, 0x89, 0x53, 0x9a, 0xa9, 0x5a, 0xda, 0xa5, 0x42, 0xa6, 0x42, 0x51, 0xb4, 0x07, 0x5a,
0x7a, 0xe8, 0xa1, 0x5c, 0x10, 0x70, 0xa8, 0x9a, 0x04, 0x35, 0x12, 0x29, 0x62, 0x53, 0x71, 0xdf,
0x24, 0x23, 0xb0, 0xe2, 0xd8, 0xc1, 0xbb, 0x4e, 0x1a, 0x0e, 0xdc, 0xf9, 0x03, 0x24, 0xbe, 0x81,
0xff, 0xe0, 0xc8, 0x27, 0xa0, 0xf0, 0x23, 0x68, 0xc7, 0x6b, 0x3b, 0xb8, 0x94, 0x0a, 0x6e, 0x3b,
0x6f, 0x66, 0xe7, 0xbd, 0x7d, 0x9e, 0x31, 0x6c, 0x4e, 0x63, 0x7f, 0x26, 0x35, 0x1e, 0x4d, 0xe3,
0x48, 0x47, 0x6c, 0xdd, 0x0f, 0x35, 0xc6, 0xa1, 0x0c, 0xf8, 0x2b, 0xa8, 0x77, 0xc3, 0x11, 0x5e,
0xf6, 0x50, 0x4b, 0xd6, 0x84, 0x8d, 0x56, 0x14, 0x24, 0x93, 0xf0, 0xa5, 0x1c, 0x60, 0xe0, 0x39,
0x4d, 0xe7, 0xa0, 0x2e, 0x56, 0x21, 0x53, 0x71, 0xe1, 0x4f, 0xf0, 0x75, 0x22, 0x43, 0x9d, 0x4c,
0xbc, 0x4a, 0x5a, 0xb1, 0x02, 0xf1, 0xaf, 0x0e, 0xd4, 0x5f, 0xc4, 0x72, 0x82, 0xd4, 0x71, 0x0f,
0xd6, 0x45, 0x34, 0x5f, 0x6d, 0x97, 0xc7, 0xec, 0x21, 0x6c, 0x75, 0xc3, 0x19, 0xc6, 0x0a, 0x3b,
0xa1, 0x1c, 0x04, 0x38, 0xa2, 0x76, 0xeb, 0xa2, 0x84, 0xb2, 0x07, 0x50, 0x6f, 0xc9, 0xe1, 0x3b,
0xbc, 0x58, 0x4c, 0xd1, 0xab, 0x52, 0x93, 0x02, 0xc8, 0xb3, 0x7d, 0xff, 0x03, 0x7a, 0x6e, 0xd3,
0x39, 0xd8, 0x14, 0x05, 0x50, 0xd6, 0x5b, 0xbb, 0xaa, 0x97, 0xc3, 0x56, 0x77, 0x32, 0x8d, 0x62,
0x2d, 0x50, 0x4d, 0xa3, 0x50, 0x21, 0xdb, 0x86, 0x6a, 0x27, 0x8e, 0xad, 0x5c, 0x73, 0xe4, 0x1f,
0x61, 0xfb, 0x34, 0x88, 0x86, 0xe3, 0xb6, 0xd4, 0x52, 0xe0, 0xfb, 0x04, 0x95, 0x66, 0xbb, 0x50,
0x23, 0xe3, 0x6c, 0x5d, 0x1a, 0x18, 0x94, 0x1e, 0x6f, 0x9d, 0x49, 0x03, 0x83, 0xd2, 0x7d, 0x52,
0xef, 0x8a, 0x34, 0x30, 0x68, 0x3f, 0xf0, 0x87, 0xa9, 0x6a, 0x57, 0xa4, 0x01, 0x63, 0xe0, 0xbe,
0xf1, 0x71, 0x6e, 0xa5, 0xd2, 0x99, 0x77, 0x61, 0x67, 0x85, 0xdf, 0xca, 0xbc, 0x07, 0x6b, 0x22,
0x9a, 0x77, 0xdb, 0xca, 0x73, 0x9a, 0xd5, 0x03, 0x57, 0xd8, 0x88, 0x0c, 0xa1, 0x2f, 0x66, 0x52,
0x15, 0x4a, 0x15, 0x00, 0xbf, 0x0f, 0x35, 0x72, 0xc7, 0xbc, 0xb2, 0xb8, 0x6b, 0x8e, 0xfc, 0x8b,
0x03, 0x3b, 0x3d, 0x79, 0x49, 0x32, 0x54, 0x4e, 0x73, 0x06, 0xf5, 0x1c, 0xa4, 0xea, 0x8d, 0xe3,
0xc3, 0xa3, 0x6c, 0x7c, 0x8e, 0xae, 0xd4, 0x17, 0x48, 0x27, 0xd4, 0xf1, 0x42, 0x14, 0x97, 0xf7,
0x9e, 0xc3, 0xd6, 0xef, 0x49, 0xa3, 0x61, 0x8c, 0x8b, 0xcc, 0xe9, 0x31, 0x2e, 0x8c, 0x27, 0x33,
0x19, 0x24, 0xa9, 0x7f, 0xae, 0x48, 0x83, 0xa7, 0x95, 0x27, 0x0e, 0x3f, 0x01, 0xd6, 0x8a, 0x51,
0x6a, 0xa4, 0x06, 0x3d, 0x54, 0x4a, 0xbe, 0xc5, 0xeb, 0xbf, 0x42, 0xea, 0x6c, 0x65, 0xc5, 0x59,
0x7e, 0x08, 0xac, 0x8d, 0x01, 0x6a, 0xb4, 0x03, 0xff, 0x97, 0x0e, 0xbc, 0x9f, 0xb1, 0xdd, 0x5c,
0xcb, 0xf6, 0xc1, 0x35, 0xb3, 0x4e, 0x64, 0x1b, 0xc7, 0x77, 0x0b, 0x73, 0xf2, 0xc5, 0x12, 0x54,
0xc0, 0xfd, 0xac, 0xa9, 0xdd, 0x8f, 0x1b, 0x9e, 0xf0, 0x87, 0x41, 0xca, 0xa8, 0xaa, 0x65, 0xaa,
0x7c, 0xe3, 0x2c, 0xd5, 0x49, 0xf6, 0xd6, 0xff, 0xa5, 0xe2, 0x6d, 0x8b, 0x9a, 0x81, 0x3c, 0x37,
0xd9, 0xf4, 0x0e, 0x9d, 0xaf, 0x7f, 0x72, 0x59, 0xc7, 0x27, 0xc7, 0x52, 0xfe, 0x5b, 0x9b, 0x92,
0x73, 0xe6, 0x37, 0x92, 0x8d, 0x8e, 0xdd, 0xa1, 0x3c, 0x66, 0xfb, 0xb0, 0x46, 0xac, 0xca, 0x73,
0x69, 0x3a, 0xef, 0x94, 0xd4, 0x08, 0x9b, 0xe6, 0x12, 0xe0, 0x3c, 0x1a, 0x61, 0x5f, 0x4b, 0x9d,
0x28, 0xa3, 0xe7, 0x2c, 0x52, 0x3a, 0xd3, 0x63, 0xce, 0x34, 0x37, 0x5a, 0xea, 0xdc, 0x09, 0x0a,
0xd8, 0x23, 0xb8, 0x4d, 0x7a, 0x50, 0x79, 0xd5, 0x32, 0x03, 0x25, 0x44, 0x96, 0xe7, 0xcf, 0x60,
0xb3, 0x15, 0x24, 0x4a, 0x63, 0x6c, 0x59, 0x0e, 0xa1, 0x66, 0x38, 0xb3, 0xcd, 0xd9, 0x2d, 0x6e,
0x16, 0x52, 0x44, 0x5a, 0x72, 0xba, 0xfd, 0x6d, 0xd9, 0x70, 0xbe, 0x2f, 0x1b, 0xce, 0x8f, 0x65,
0xc3, 0xf9, 0xfc, 0xb3, 0x71, 0x6b, 0xb0, 0x46, 0x7f, 0xeb, 0xc7, 0xbf, 0x02, 0x00, 0x00, 0xff,
0xff, 0x77, 0x02, 0x29, 0xbb, 0xbe, 0x05, 0x00, 0x00,
}

View file

@ -77,8 +77,12 @@ message Index {
repeated Frame Frames = 4;
}
message NodeState {
message NodeStatus {
string Host = 1;
string State = 2;
repeated Index Indexes = 3;
}
message ClusterStatus {
repeated NodeStatus Nodes = 1;
}

View file

@ -118,6 +118,7 @@ func (s *Server) Open() error {
// Initialize HTTP handler.
s.Handler.Broadcaster = s.Broadcaster
s.Handler.StatusHandler = s
s.Handler.Host = s.Host
s.Handler.Cluster = s.Cluster
s.Handler.Executor = e
@ -271,28 +272,49 @@ func (s *Server) ReceiveMessage(pb proto.Message) error {
return nil
}
// Server implements gossip.StateHandler.
// LocalState returns the state of the local node as well as the
// Server implements StatusHandler.
// LocalStatus returns the state of the local node as well as the
// holder (indexes/frames) according to the local node.
// In a gossip implementation, memberlist.Delegate.LocalState() uses this.
func (s *Server) LocalState() (proto.Message, error) {
func (s *Server) LocalStatus() (proto.Message, error) {
if s.Holder == nil {
return nil, errors.New("Server.Holder is nil.")
}
return &internal.NodeState{
return &internal.NodeStatus{
Host: s.Host,
State: "OK", // TODO: make this work, pull from s.Cluster.Node
State: NodeStateUp,
Indexes: encodeIndexes(s.Holder.Indexes()),
}, nil
}
// HandleRemoteState receives incoming NodeState from remote nodes.
func (s *Server) HandleRemoteState(pb proto.Message) error {
return s.mergeRemoteState(pb.(*internal.NodeState))
// ClusterStatus returns the NodeState for all nodes in the cluster.
func (s *Server) ClusterStatus() (proto.Message, error) {
// Update local Node.state.
ns, err := s.LocalStatus()
if err != nil {
return nil, err
}
node := s.Cluster.NodeByHost(s.Host)
node.SetStatus(ns.(*internal.NodeStatus))
// Update NodeState for all nodes.
for host, nodeState := range s.Cluster.NodeStates() {
node := s.Cluster.NodeByHost(host)
node.SetState(nodeState)
}
return s.Cluster.Status(), nil
}
func (s *Server) mergeRemoteState(ns *internal.NodeState) error {
// TODO: update some node state value in the cluster (it should be in cluster.node i guess)
// HandleRemoteStatus receives incoming NodeState from remote nodes.
func (s *Server) HandleRemoteStatus(pb proto.Message) error {
return s.mergeRemoteStatus(pb.(*internal.NodeStatus))
}
func (s *Server) mergeRemoteStatus(ns *internal.NodeStatus) error {
// Update Node.state.
node := s.Cluster.NodeByHost(ns.Host)
node.SetStatus(ns)
// Create indexes that don't exist.
for _, index := range ns.Indexes {
@ -364,3 +386,12 @@ func checkMaxSlices(hostport string) (map[string]uint64, error) {
return pb.MaxSlices, nil
}
// StatusHandler specifies two methods which an object must implement to share
// state in the cluster. These are used by the GossipNodeSet to implement the
// LocalState and MergeRemoteState methods of memberlist.Delegate
type StatusHandler interface {
LocalStatus() (proto.Message, error)
ClusterStatus() (proto.Message, error)
HandleRemoteStatus(proto.Message) error
}