github.com/micro/go-micro/v2@v2.9.1/network/node.go (about)

     1  package network
     2  
     3  import (
     4  	"container/list"
     5  	"errors"
     6  	"sync"
     7  	"time"
     8  
     9  	pb "github.com/micro/go-micro/v2/network/service/proto"
    10  )
    11  
    12  var (
    13  	// MaxDepth defines max depth of peer topology
    14  	MaxDepth uint = 3
    15  )
    16  
    17  var (
    18  	// ErrPeerExists is returned when adding a peer which already exists
    19  	ErrPeerExists = errors.New("peer already exists")
    20  	// ErrPeerNotFound is returned when a peer could not be found in node topology
    21  	ErrPeerNotFound = errors.New("peer not found")
    22  )
    23  
    24  // nodeError tracks node errors
    25  type nodeError struct {
    26  	sync.RWMutex
    27  	count int
    28  	msg   error
    29  }
    30  
    31  // Increment increments node error count
    32  func (e *nodeError) Update(err error) {
    33  	e.Lock()
    34  	defer e.Unlock()
    35  
    36  	e.count++
    37  	e.msg = err
    38  }
    39  
    40  // Count returns node error count
    41  func (e *nodeError) Count() int {
    42  	e.RLock()
    43  	defer e.RUnlock()
    44  
    45  	return e.count
    46  }
    47  
    48  func (e *nodeError) Msg() string {
    49  	e.RLock()
    50  	defer e.RUnlock()
    51  
    52  	if e.msg != nil {
    53  		return e.msg.Error()
    54  	}
    55  
    56  	return ""
    57  }
    58  
    59  // status returns node status
    60  type status struct {
    61  	sync.RWMutex
    62  	err *nodeError
    63  }
    64  
    65  // newStatus creates
    66  func newStatus() *status {
    67  	return &status{
    68  		err: new(nodeError),
    69  	}
    70  }
    71  
    72  func newPeerStatus(peer *pb.Peer) *status {
    73  	status := &status{
    74  		err: new(nodeError),
    75  	}
    76  
    77  	// if Node.Status is nil, return empty status
    78  	if peer.Node.Status == nil {
    79  		return status
    80  	}
    81  
    82  	// if peer.Node.Status.Error is NOT nil, update status fields
    83  	if err := peer.Node.Status.GetError(); err != nil {
    84  		status.err.count = int(peer.Node.Status.Error.Count)
    85  		status.err.msg = errors.New(peer.Node.Status.Error.Msg)
    86  	}
    87  
    88  	return status
    89  }
    90  
    91  func (s *status) Error() Error {
    92  	s.RLock()
    93  	defer s.RUnlock()
    94  
    95  	return &nodeError{
    96  		count: s.err.count,
    97  		msg:   s.err.msg,
    98  	}
    99  }
   100  
   101  // node is network node
   102  type node struct {
   103  	sync.RWMutex
   104  	// id is node id
   105  	id string
   106  	// address is node address
   107  	address string
   108  	// link on which we communicate with the peer
   109  	link string
   110  	// peers are nodes with direct link to this node
   111  	peers map[string]*node
   112  	// network returns the node network
   113  	network Network
   114  	// lastSeen keeps track of node lifetime and updates
   115  	lastSeen time.Time
   116  	// lastSync keeps track of node last sync request
   117  	lastSync time.Time
   118  	// err tracks node status
   119  	status *status
   120  }
   121  
   122  // Id is node ide
   123  func (n *node) Id() string {
   124  	return n.id
   125  }
   126  
   127  // Address returns node address
   128  func (n *node) Address() string {
   129  	return n.address
   130  }
   131  
   132  // Network returns node network
   133  func (n *node) Network() Network {
   134  	return n.network
   135  }
   136  
   137  // Status returns node status
   138  func (n *node) Status() Status {
   139  	n.RLock()
   140  	defer n.RUnlock()
   141  
   142  	return &status{
   143  		err: &nodeError{
   144  			count: n.status.err.count,
   145  			msg:   n.status.err.msg,
   146  		},
   147  	}
   148  }
   149  
   150  // walk walks the node graph until some condition is met
   151  func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node {
   152  	// track the visited nodes
   153  	visited := make(map[string]*node)
   154  	// queue of the nodes to visit
   155  	queue := list.New()
   156  
   157  	// push node to the back of queue
   158  	queue.PushBack(n)
   159  	// mark the node as visited
   160  	visited[n.id] = n
   161  
   162  	// keep iterating over the queue until its empty
   163  	for queue.Len() > 0 {
   164  		// pop the node from the front of the queue
   165  		qnode := queue.Front()
   166  		if until(qnode.Value.(*node)) {
   167  			return visited
   168  		}
   169  		// iterate through all of the node peers
   170  		// mark the visited nodes; enqueue the non-visted
   171  		for id, peer := range qnode.Value.(*node).peers {
   172  			action(qnode.Value.(*node), peer)
   173  			if _, ok := visited[id]; !ok {
   174  				visited[id] = peer
   175  				queue.PushBack(peer)
   176  			}
   177  		}
   178  		// remove the node from the queue
   179  		queue.Remove(qnode)
   180  	}
   181  
   182  	return visited
   183  }
   184  
   185  // AddPeer adds a new peer to node topology
   186  // It returns false if the peer already exists
   187  func (n *node) AddPeer(peer *node) error {
   188  	n.Lock()
   189  	defer n.Unlock()
   190  
   191  	// get node topology: we need to check if the peer
   192  	// we are trying to add is already in our graph
   193  	top := n.getTopology(MaxDepth)
   194  
   195  	untilFoundPeer := func(n *node) bool {
   196  		return n.id == peer.id
   197  	}
   198  
   199  	justWalk := func(paent, node *node) {}
   200  
   201  	visited := top.walk(untilFoundPeer, justWalk)
   202  
   203  	peerNode, inTop := visited[peer.id]
   204  
   205  	if _, ok := n.peers[peer.id]; !ok {
   206  		if inTop {
   207  			// just create a new edge to the existing peer
   208  			// but make sure you update the peer link
   209  			peerNode.link = peer.link
   210  			n.peers[peer.id] = peerNode
   211  			return nil
   212  		}
   213  		n.peers[peer.id] = peer
   214  		return nil
   215  	}
   216  
   217  	return ErrPeerExists
   218  }
   219  
   220  // DeletePeer deletes a peer from node peers
   221  // It returns true if the peer has been deleted
   222  func (n *node) DeletePeer(id string) bool {
   223  	n.Lock()
   224  	defer n.Unlock()
   225  
   226  	delete(n.peers, id)
   227  
   228  	return true
   229  }
   230  
   231  // UpdatePeer updates a peer if it already exists
   232  // It returns error if the peer does not exist
   233  func (n *node) UpdatePeer(peer *node) error {
   234  	n.Lock()
   235  	defer n.Unlock()
   236  
   237  	if _, ok := n.peers[peer.id]; ok {
   238  		n.peers[peer.id] = peer
   239  		return nil
   240  	}
   241  
   242  	return ErrPeerNotFound
   243  }
   244  
   245  // RefreshPeer updates node last seen timestamp
   246  // It returns false if the peer has not been found.
   247  func (n *node) RefreshPeer(id, link string, now time.Time) error {
   248  	n.Lock()
   249  	defer n.Unlock()
   250  
   251  	peer, ok := n.peers[id]
   252  	if !ok {
   253  		return ErrPeerNotFound
   254  	}
   255  
   256  	// set peer link
   257  	peer.link = link
   258  	// set last seen
   259  	peer.lastSeen = now
   260  
   261  	return nil
   262  }
   263  
   264  // RefreshSync refreshes nodes sync time
   265  func (n *node) RefreshSync(now time.Time) error {
   266  	n.Lock()
   267  	defer n.Unlock()
   268  
   269  	n.lastSync = now
   270  
   271  	return nil
   272  }
   273  
   274  // Nodes returns a slice of all nodes in the whole node topology
   275  func (n *node) Nodes() []Node {
   276  	// we need to freeze the network graph here
   277  	// otherwise we might get inconsisten results
   278  	n.RLock()
   279  	defer n.RUnlock()
   280  
   281  	// NOTE: this should never be true
   282  	untilNoMorePeers := func(node *node) bool {
   283  		return node == nil
   284  	}
   285  	justWalk := func(parent, node *node) {}
   286  
   287  	visited := n.walk(untilNoMorePeers, justWalk)
   288  
   289  	nodes := make([]Node, 0, len(visited))
   290  	// collect all the nodes and return them
   291  	for _, node := range visited {
   292  		nodes = append(nodes, node)
   293  	}
   294  
   295  	return nodes
   296  }
   297  
   298  // GetPeerNode returns a node from node MaxDepth topology
   299  // It returns nil if the peer was not found
   300  func (n *node) GetPeerNode(id string) *node {
   301  	// get node topology up to MaxDepth
   302  	top := n.Topology(MaxDepth)
   303  
   304  	untilFoundPeer := func(n *node) bool {
   305  		return n.id == id
   306  	}
   307  	justWalk := func(paent, node *node) {}
   308  
   309  	visited := top.walk(untilFoundPeer, justWalk)
   310  
   311  	peerNode, ok := visited[id]
   312  	if !ok {
   313  		return nil
   314  	}
   315  
   316  	return peerNode
   317  }
   318  
   319  // DeletePeerNode removes peer node from node topology
   320  func (n *node) DeletePeerNode(id string) error {
   321  	n.Lock()
   322  	defer n.Unlock()
   323  
   324  	untilNoMorePeers := func(node *node) bool {
   325  		return node == nil
   326  	}
   327  
   328  	deleted := make(map[string]*node)
   329  	deletePeer := func(parent, node *node) {
   330  		if node.id != n.id && node.id == id {
   331  			delete(parent.peers, node.id)
   332  			deleted[node.id] = node
   333  		}
   334  	}
   335  
   336  	n.walk(untilNoMorePeers, deletePeer)
   337  
   338  	if _, ok := deleted[id]; !ok {
   339  		return ErrPeerNotFound
   340  	}
   341  
   342  	return nil
   343  }
   344  
   345  // PrunePeer prunes the peers with the given id
   346  func (n *node) PrunePeer(id string) {
   347  	n.Lock()
   348  	defer n.Unlock()
   349  
   350  	untilNoMorePeers := func(node *node) bool {
   351  		return node == nil
   352  	}
   353  
   354  	prunePeer := func(parent, node *node) {
   355  		if node.id != n.id && node.id == id {
   356  			delete(parent.peers, node.id)
   357  		}
   358  	}
   359  
   360  	n.walk(untilNoMorePeers, prunePeer)
   361  }
   362  
   363  // PruneStalePeerNodes prunes the peers that have not been seen for longer than pruneTime
   364  // It returns a map of the the nodes that got pruned
   365  func (n *node) PruneStalePeers(pruneTime time.Duration) map[string]*node {
   366  	n.Lock()
   367  	defer n.Unlock()
   368  
   369  	untilNoMorePeers := func(node *node) bool {
   370  		return node == nil
   371  	}
   372  
   373  	pruned := make(map[string]*node)
   374  	pruneStalePeer := func(parent, node *node) {
   375  		if node.id != n.id && time.Since(node.lastSeen) > PruneTime {
   376  			delete(parent.peers, node.id)
   377  			pruned[node.id] = node
   378  		}
   379  	}
   380  
   381  	n.walk(untilNoMorePeers, pruneStalePeer)
   382  
   383  	return pruned
   384  }
   385  
   386  // getTopology traverses node graph and builds node topology
   387  // NOTE: this function is not thread safe
   388  func (n *node) getTopology(depth uint) *node {
   389  	// make a copy of yourself
   390  	node := &node{
   391  		id:       n.id,
   392  		address:  n.address,
   393  		peers:    make(map[string]*node),
   394  		network:  n.network,
   395  		status:   n.status,
   396  		lastSeen: n.lastSeen,
   397  	}
   398  
   399  	// return if we reach requested depth or we have no more peers
   400  	if depth == 0 || len(n.peers) == 0 {
   401  		return node
   402  	}
   403  
   404  	// decrement the depth
   405  	depth--
   406  
   407  	// iterate through our peers and update the node peers
   408  	for _, peer := range n.peers {
   409  		nodePeer := peer.getTopology(depth)
   410  		if _, ok := node.peers[nodePeer.id]; !ok {
   411  			node.peers[nodePeer.id] = nodePeer
   412  		}
   413  	}
   414  
   415  	return node
   416  }
   417  
   418  // Topology returns a copy of the node topology down to given depth
   419  // NOTE: the returned node is a node graph - not a single node
   420  func (n *node) Topology(depth uint) *node {
   421  	n.RLock()
   422  	defer n.RUnlock()
   423  
   424  	return n.getTopology(depth)
   425  }
   426  
   427  // Peers returns node peers up to MaxDepth
   428  func (n *node) Peers() []Node {
   429  	n.RLock()
   430  	defer n.RUnlock()
   431  
   432  	peers := make([]Node, 0, len(n.peers))
   433  	for _, nodePeer := range n.peers {
   434  		peer := nodePeer.getTopology(MaxDepth)
   435  		peers = append(peers, peer)
   436  	}
   437  
   438  	return peers
   439  }
   440  
   441  // UnpackPeerTopology unpacks pb.Peer into node topology of given depth
   442  func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node {
   443  	peerNode := &node{
   444  		id:       pbPeer.Node.Id,
   445  		address:  pbPeer.Node.Address,
   446  		peers:    make(map[string]*node),
   447  		status:   newPeerStatus(pbPeer),
   448  		lastSeen: lastSeen,
   449  	}
   450  
   451  	// return if have either reached the depth or have no more peers
   452  	if depth == 0 || len(pbPeer.Peers) == 0 {
   453  		return peerNode
   454  	}
   455  
   456  	// decrement the depth
   457  	depth--
   458  
   459  	peers := make(map[string]*node)
   460  	for _, pbPeer := range pbPeer.Peers {
   461  		peer := UnpackPeerTopology(pbPeer, lastSeen, depth)
   462  		peers[pbPeer.Node.Id] = peer
   463  	}
   464  
   465  	peerNode.peers = peers
   466  
   467  	return peerNode
   468  }
   469  
   470  func peerProtoTopology(peer Node, depth uint) *pb.Peer {
   471  	node := &pb.Node{
   472  		Id:      peer.Id(),
   473  		Address: peer.Address(),
   474  		Status: &pb.Status{
   475  			Error: &pb.Error{
   476  				Count: uint32(peer.Status().Error().Count()),
   477  				Msg:   peer.Status().Error().Msg(),
   478  			},
   479  		},
   480  	}
   481  
   482  	// set the network name if network is not nil
   483  	if peer.Network() != nil {
   484  		node.Network = peer.Network().Name()
   485  	}
   486  
   487  	pbPeers := &pb.Peer{
   488  		Node:  node,
   489  		Peers: make([]*pb.Peer, 0),
   490  	}
   491  
   492  	// return if we reached the end of topology or depth
   493  	if depth == 0 || len(peer.Peers()) == 0 {
   494  		return pbPeers
   495  	}
   496  
   497  	// decrement the depth
   498  	depth--
   499  
   500  	// iterate through peers of peers aka pops
   501  	for _, pop := range peer.Peers() {
   502  		peer := peerProtoTopology(pop, depth)
   503  		pbPeers.Peers = append(pbPeers.Peers, peer)
   504  	}
   505  
   506  	return pbPeers
   507  }
   508  
   509  // PeersToProto returns node peers graph encoded into protobuf
   510  func PeersToProto(node Node, depth uint) *pb.Peer {
   511  	// network node aka root node
   512  	pbNode := &pb.Node{
   513  		Id:      node.Id(),
   514  		Address: node.Address(),
   515  		Status: &pb.Status{
   516  			Error: &pb.Error{
   517  				Count: uint32(node.Status().Error().Count()),
   518  				Msg:   node.Status().Error().Msg(),
   519  			},
   520  		},
   521  	}
   522  
   523  	// set the network name if network is not nil
   524  	if node.Network() != nil {
   525  		pbNode.Network = node.Network().Name()
   526  	}
   527  
   528  	// we will build proto topology into this
   529  	pbPeers := &pb.Peer{
   530  		Node:  pbNode,
   531  		Peers: make([]*pb.Peer, 0),
   532  	}
   533  
   534  	for _, peer := range node.Peers() {
   535  		pbPeer := peerProtoTopology(peer, depth)
   536  		pbPeers.Peers = append(pbPeers.Peers, pbPeer)
   537  	}
   538  
   539  	return pbPeers
   540  }