// handleFetchData handles a request for the current nodes meta data func (r *rpc) handleFetchData(req *internal.FetchDataRequest) (*internal.FetchDataResponse, error) { var ( b []byte data *Data err error ) for { data = r.store.cachedData() if data.Index != req.GetIndex() { b, err = data.MarshalBinary() if err != nil { return nil, err } break } if !req.GetBlocking() { break } if err := r.store.WaitForDataChanged(); err != nil { return nil, err } } return &internal.FetchDataResponse{ Header: &internal.ResponseHeader{ OK: proto.Bool(true), }, Index: proto.Uint64(data.Index), Term: proto.Uint64(data.Term), Data: b}, nil }
// Ensure shards with deprecated "OwnerIDs" can be decoded. func TestShardInfo_UnmarshalBinary_OwnerIDs(t *testing.T) { // Encode deprecated form to bytes. buf, err := proto.Marshal(&internal.ShardInfo{ ID: proto.Uint64(1), OwnerIDs: []uint64{10, 20, 30}, }) if err != nil { t.Fatal(err) } // Decode deprecated form. var si meta.ShardInfo if err := si.UnmarshalBinary(buf); err != nil { t.Fatal(err) } // Verify data is migrated correctly. if !reflect.DeepEqual(si, meta.ShardInfo{ ID: 1, Owners: []meta.ShardOwner{ {NodeID: 10}, {NodeID: 20}, {NodeID: 30}, }, }) { t.Fatalf("unexpected shard info: %s", spew.Sdump(si)) } }
// handleJoinRequest handles a request to join the cluster func (r *rpc) handleJoinRequest(req *internal.JoinRequest) (*internal.JoinResponse, error) { r.traceCluster("join request from: %v", *req.Addr) node, err := func() (*NodeInfo, error) { // attempt to create the node node, err := r.store.CreateNode(*req.Addr) // if it exists, return the existing node if err == ErrNodeExists { node, err = r.store.NodeByHost(*req.Addr) if err != nil { return node, err } r.logger.Printf("existing node re-joined: id=%v addr=%v", node.ID, node.Host) } else if err != nil { return nil, fmt.Errorf("create node: %v", err) } peers, err := r.store.Peers() if err != nil { return nil, fmt.Errorf("list peers: %v", err) } // If we have less than 3 nodes, add them as raft peers if they are not // already a peer if len(peers) < MaxRaftNodes && !raft.PeerContained(peers, *req.Addr) { r.logger.Printf("adding new raft peer: nodeId=%v addr=%v", node.ID, *req.Addr) if err = r.store.AddPeer(*req.Addr); err != nil { return node, fmt.Errorf("add peer: %v", err) } } return node, err }() nodeID := uint64(0) if node != nil { nodeID = node.ID } if err != nil { return nil, err } // get the current raft peers peers, err := r.store.Peers() if err != nil { return nil, fmt.Errorf("list peers: %v", err) } return &internal.JoinResponse{ Header: &internal.ResponseHeader{ OK: proto.Bool(true), }, EnableRaft: proto.Bool(raft.PeerContained(peers, *req.Addr)), RaftNodes: peers, NodeID: proto.Uint64(nodeID), }, err }
// marshal serializes to a protobuf representation. func (si ShardInfo) marshal() *internal.ShardInfo { pb := &internal.ShardInfo{ ID: proto.Uint64(si.ID), } pb.OwnerIDs = make([]uint64, len(si.OwnerIDs)) copy(pb.OwnerIDs, si.OwnerIDs) return pb }
// fetchMetaData returns the latest copy of the meta store data from the current // leader. func (r *rpc) fetchMetaData(blocking bool) (*Data, error) { assert(r.store != nil, "store is nil") // Retrieve the current known leader. leader := r.store.Leader() if leader == "" { return nil, errors.New("no leader") } var index, term uint64 data := r.store.cachedData() if data != nil { index = data.Index term = data.Index } resp, err := r.call(leader, &internal.FetchDataRequest{ Index: proto.Uint64(index), Term: proto.Uint64(term), Blocking: proto.Bool(blocking), }) if err != nil { return nil, err } switch t := resp.(type) { case *internal.FetchDataResponse: // If data is nil, then the term and index we sent matches the leader if t.GetData() == nil { return nil, nil } ms := &Data{} if err := ms.UnmarshalBinary(t.GetData()); err != nil { return nil, fmt.Errorf("rpc unmarshal metadata: %v", err) } return ms, nil case *internal.ErrorResponse: return nil, fmt.Errorf("rpc failed: %s", t.GetHeader().GetError()) default: return nil, fmt.Errorf("rpc failed: unknown response type: %v", t.String()) } }
// marshal serializes to a protobuf representation. func (si ShardInfo) marshal() *internal.ShardInfo { pb := &internal.ShardInfo{ ID: proto.Uint64(si.ID), } pb.Owners = make([]*internal.ShardOwner, len(si.Owners)) for i := range si.Owners { pb.Owners[i] = si.Owners[i].marshal() } return pb }
// marshal serializes to a protobuf representation. func (data *Data) marshal() *internal.Data { pb := &internal.Data{ Term: proto.Uint64(data.Term), Index: proto.Uint64(data.Index), ClusterID: proto.Uint64(data.ClusterID), MaxNodeID: proto.Uint64(data.MaxNodeID), MaxShardGroupID: proto.Uint64(data.MaxShardGroupID), MaxShardID: proto.Uint64(data.MaxShardID), } pb.Nodes = make([]*internal.NodeInfo, len(data.Nodes)) for i := range data.Nodes { pb.Nodes[i] = data.Nodes[i].marshal() } pb.Databases = make([]*internal.DatabaseInfo, len(data.Databases)) for i := range data.Databases { pb.Databases[i] = data.Databases[i].marshal() } pb.Users = make([]*internal.UserInfo, len(data.Users)) for i := range data.Users { pb.Users[i] = data.Users[i].marshal() } return pb }
// marshal serializes to a protobuf representation. func (sgi *ShardGroupInfo) marshal() *internal.ShardGroupInfo { pb := &internal.ShardGroupInfo{ ID: proto.Uint64(sgi.ID), StartTime: proto.Int64(MarshalTime(sgi.StartTime)), EndTime: proto.Int64(MarshalTime(sgi.EndTime)), DeletedAt: proto.Int64(MarshalTime(sgi.DeletedAt)), } pb.Shards = make([]*internal.ShardInfo, len(sgi.Shards)) for i := range sgi.Shards { pb.Shards[i] = sgi.Shards[i].marshal() } return pb }
// unmarshal deserializes from a protobuf representation. func (si *ShardInfo) unmarshal(pb *internal.ShardInfo) { si.ID = pb.GetID() // If deprecated "OwnerIDs" exists then convert it to "Owners" format. if len(pb.GetOwnerIDs()) > 0 { si.Owners = make([]ShardOwner, len(pb.GetOwnerIDs())) for i, x := range pb.GetOwnerIDs() { si.Owners[i].unmarshal(&internal.ShardOwner{ NodeID: proto.Uint64(x), }) } } else if len(pb.GetOwners()) > 0 { si.Owners = make([]ShardOwner, len(pb.GetOwners())) for i, x := range pb.GetOwners() { si.Owners[i].unmarshal(x) } } }
// marshal serializes to a protobuf representation. func (ni NodeInfo) marshal() *internal.NodeInfo { pb := &internal.NodeInfo{} pb.ID = proto.Uint64(ni.ID) pb.Host = proto.String(ni.Host) return pb }
// marshal serializes to a protobuf representation. func (so ShardOwner) marshal() *internal.ShardOwner { return &internal.ShardOwner{ NodeID: proto.Uint64(so.NodeID), } }