func (s *Server) handleHandshake(conn *Conn, msg *protocol.Message) { handshake := msg.GetHandshake() conn.Peer = handshake.GetSender() s.peersLock.RLock() peer := s.Peers[conn.Peer.Id] s.peersLock.RUnlock() if peer != nil { s.Printf("Ignoring duplicate peer %s.", conn.PrettyID()) if err := conn.Close(); err != nil && err != io.EOF { s.Printf("ERR closing connection %s", err) } return } s.peersLock.Lock() s.Peers[conn.Peer.Id] = conn s.peersLock.Unlock() s.Print(color.GreenString("New peer %s", conn.PrettyID())) if !handshake.Response { if err := s.sendHandshake(conn, true); err != nil { s.Printf("ERR sendHandshake %s", err) } } else { if err := s.sendPeerRequest(conn); err != nil { s.Printf("ERR sendPeerRequest %s", err) } } go s.connHeartbeat(conn) }
// Request sends a message on a connection and waits for a response. // Returns error network.Timeout if no response in 10 seconds. func (c *Conn) Request(m *protocol.Message) (*protocol.Message, error) { m.Id = uint64(rand.Int63()) m.ResponseRequired = true if err := c.Send(m); err != nil { return nil, err } timeout := make(chan bool, 1) go func() { time.Sleep(10 * time.Second) timeout <- true }() resp := make(chan *protocol.Message, 1) c.expectedMessages[m.Id] = resp var msg *protocol.Message var err error select { case msg = <-resp: case <-timeout: err = Timeout } delete(c.expectedMessages, m.Id) return msg, err }
func (s *Server) handlePeerNotify(conn *Conn, msg *protocol.Message) { peers := msg.GetPeerNotify().Peers for _, peer := range peers { if _, ok := s.Peers[peer.Id]; !ok { s.Peers[peer.Id] = nil s.Connect(peer.Id) } } }
// Send a message on the specified connection. Consider Request. func (c *Conn) Send(m *protocol.Message) error { msg, err := m.Marshal() if err != nil { return err } packet := make([]byte, len(msg)+4) binary.BigEndian.PutUint32(packet, uint32(len(msg))) copy(packet[4:], msg) _, err = c.Conn.Write(packet) return err }
func (s *Server) handlePeerNotify(conn *Conn, msg *protocol.Message) { conn.peerRequest <- true s.Printf("PeerNotify %+v", conn) peers := msg.GetPeerNotify().Peers for _, peer := range peers { if _, ok := s.Peers[peer.Id]; !ok { s.Peers[peer.Id] = nil s.Connect(peer.Id) } } }
// Send a message to the specified connection. func (c *Conn) Send(m *protocol.Message) error { msg, err := m.Marshal() if err != nil { return err } packet := make([]byte, len(msg)+4) binary.BigEndian.PutUint32(packet, uint32(len(msg))) copy(packet[4:], msg) if _, err := c.Write(packet); err != nil { return err } c.server.Printf("Message: -> %s, %+v", c.PrettyID(), m.GetMessage()) return nil }
// Broadcast sends a message to all peers with that have the hash in their keyspace. func (s *Server) Broadcast(hash *uint64, msg *protocol.Message) error { alreadySentTo := make(map[uint64]bool) if msg.Gossip { for _, to := range msg.SentTo { alreadySentTo[to] = true } } sentTo := []uint64{murmur3.Sum64([]byte(s.LocalPeer().Id))} var toPeers []*Conn for _, peer := range s.Peers { peerHash := murmur3.Sum64([]byte(peer.Peer.Id)) if (hash == nil || peer.Peer.GetKeyspace().Includes(*hash)) && !alreadySentTo[peerHash] { sentTo = append(sentTo, peerHash) toPeers = append(toPeers, peer) } } if msg.Gossip { msg.SentTo = append(msg.SentTo, sentTo...) } for _, peer := range toPeers { s.Printf("Broadcasting to %s", peer.Peer.Id) if err := peer.Send(msg); err != nil { return err } } return nil }
func (s *server) handleQueryRequest(conn *network.Conn, msg *protocol.Message) { triples, err := s.ExecuteQuery(msg.GetQueryRequest()) resp := &protocol.Message{ Message: &protocol.Message_QueryResponse{ QueryResponse: &protocol.QueryResponse{ Triples: triples, }, }, } if err != nil { resp.Error = err.Error() } if err := conn.RespondTo(msg, resp); err != nil { s.Printf("ERR send QueryResponse %s", err) } }
func (s *Server) handleHandshake(conn *Conn, msg *protocol.Message) { handshake := msg.GetHandshake() conn.Peer = handshake.GetSender() s.Peers[conn.Peer.Id] = conn s.Printf("New peer %s", conn.Peer.Id) if !handshake.Response { if err := s.sendHandshake(conn, true); err != nil { log.Printf("ERR sendHandshake %s", err) } } else { msg := &protocol.Message{Message: &protocol.Message_PeerRequest{ PeerRequest: &protocol.PeerRequest{ Limit: -1, //Keyspace: s.LocalPeer().Keyspace, }}} if err := conn.Send(msg); err != nil { log.Printf("ERR sending PeerRequest: %s", err) } } }
func (s *Server) handlePeerNotify(conn *Conn, msg *protocol.Message) { conn.peerRequest <- true peers := msg.GetPeerNotify().Peers for _, peer := range peers { s.peersLock.RLock() _, ok := s.Peers[peer.Id] s.peersLock.RUnlock() if ok { continue } s.peersLock.Lock() s.Peers[peer.Id] = nil s.peersLock.Unlock() if err := s.Connect(peer.Id); err != nil { s.Printf("ERR failed to connect to peer %s", err) } } }
func (s *server) handleInsertTriples(conn *network.Conn, msg *protocol.Message) { triples := msg.GetInsertTriples().Triples localKS := s.network.LocalPeer().Keyspace var validTriples []*protocol.Triple idHashes := make(map[string]uint64) for _, triple := range triples { hash, ok := idHashes[triple.Subj] if !ok { hash = murmur3.Sum64([]byte(triple.Subj)) idHashes[triple.Subj] = hash } if !localKS.Includes(hash) { s.Printf("ERR insert triple dropped due to keyspace %#v from %#v", triple, conn.Peer) // TODO(d4l3k): Follow up on bad triple by reannouncing keyspace. continue } validTriples = append(validTriples, triple) } s.ts.Insert(validTriples) }
func (s *Server) handlePeerRequest(conn *Conn, msg *protocol.Message) { // TODO(d4l3k): Handle keyspace check. req := msg.GetPeerRequest() var peers []*protocol.Peer for id, v := range s.Peers { if conn.Peer.Id == id || v == nil { continue } peers = append(peers, v.Peer) if req.Limit > 0 && int32(len(peers)) >= req.Limit { break } } err := conn.Send(&protocol.Message{Message: &protocol.Message_PeerNotify{ PeerNotify: &protocol.PeerNotify{ Peers: peers, }}}) if err != nil { log.Printf("ERR sending PeerNotify: %s", err) } }
// RespondTo sends `resp` as a response to the request `to`. func (c *Conn) RespondTo(to *protocol.Message, resp *protocol.Message) error { resp.ResponseTo = to.Id return c.Send(resp) }
func (s *server) ExecuteQuery(q *protocol.QueryRequest) ([]*protocol.Triple, error) { var triples []*protocol.Triple switch q.Type { case protocol.BASIC: for i, step := range q.Steps { if i != 0 { var midTriples []*protocol.Triple for _, triple := range triples { midTriples = append(midTriples, &protocol.Triple{ Subj: triple.Obj, }) } step = &protocol.ArrayOp{ Arguments: []*protocol.ArrayOp{step}, Mode: protocol.AND, Triples: midTriples, } } // External request and is already sharded. if q.Sharded { return s.ts.QueryArrayOp(step, int(q.Limit)) } var wg sync.WaitGroup var triplesLock sync.RWMutex triples = nil shards := query.ShardQueryByHash(step) // Unrooted queries if arrayOp, ok := shards[0]; ok { // TODO localnode set := s.network.MinimumCoveringPeers() s.Printf("Minimum covering set %+v", set) _ = arrayOp wg.Add(len(set)) req := basicReq(arrayOp) var err error for _, conn := range set { conn := conn go func() { var msg *protocol.Message msg, err = conn.Request(req) if err != nil { return } triplesLock.Lock() // TODO(d4l3k): Deduplicate triples triples = append(triples, msg.GetQueryResponse().Triples...) triplesLock.Unlock() done := make(chan bool, 1) go func() { wg.Done() done <- true }() go func() { time.Sleep(10 * time.Second) done <- true }() <-done }() } wg.Wait() return triples, err } // Rooted queries for hash, arrayOp := range shards { if hash == 0 { return nil, query.ErrUnRooted } if s.network.LocalPeer().Keyspace.Includes(hash) { trips, err := s.ts.QueryArrayOp(arrayOp, int(q.Limit)) if err != nil { return nil, err } triples = append(triples, trips...) continue } Peers: for _, conn := range s.network.Peers { if conn == nil || conn.Peer == nil { continue } if conn.Peer.Keyspace.Includes(hash) { req := basicReq(arrayOp) // TODO(d4l3k) Parallelize msg, err := conn.Request(req) if err != nil { return nil, err } triples = append(triples, msg.GetQueryResponse().Triples...) break Peers } } } } //case protocol.GREMLIN: //case protocol.MQL: default: return nil, query.ErrNotImplemented } return triples, nil }