gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/network/node.go (about)

     1  package network
     2  
     3  import (
     4  	"container/list"
     5  	"errors"
     6  	"sync"
     7  	"time"
     8  
     9  	pb "gitee.com/liuxuezhan/go-micro-v1.18.0/network/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  // node is network node
    25  type node struct {
    26  	sync.RWMutex
    27  	// id is node id
    28  	id string
    29  	// address is node address
    30  	address string
    31  	// peers are nodes with direct link to this node
    32  	peers map[string]*node
    33  	// network returns the node network
    34  	network Network
    35  	// lastSeen keeps track of node lifetime and updates
    36  	lastSeen time.Time
    37  }
    38  
    39  // Id is node ide
    40  func (n *node) Id() string {
    41  	return n.id
    42  }
    43  
    44  // Address returns node address
    45  func (n *node) Address() string {
    46  	return n.address
    47  }
    48  
    49  // Network returns node network
    50  func (n *node) Network() Network {
    51  	return n.network
    52  }
    53  
    54  // walk walks the node graph until some condition is met
    55  func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node {
    56  	// track the visited nodes
    57  	visited := make(map[string]*node)
    58  	// queue of the nodes to visit
    59  	queue := list.New()
    60  
    61  	// push node to the back of queue
    62  	queue.PushBack(n)
    63  	// mark the node as visited
    64  	visited[n.id] = n
    65  
    66  	// keep iterating over the queue until its empty
    67  	for queue.Len() > 0 {
    68  		// pop the node from the front of the queue
    69  		qnode := queue.Front()
    70  		if until(qnode.Value.(*node)) {
    71  			return visited
    72  		}
    73  		// iterate through all of the node peers
    74  		// mark the visited nodes; enqueue the non-visted
    75  		for id, peer := range qnode.Value.(*node).peers {
    76  			if _, ok := visited[id]; !ok {
    77  				visited[id] = peer
    78  				action(qnode.Value.(*node), peer)
    79  				queue.PushBack(peer)
    80  			}
    81  		}
    82  		// remove the node from the queue
    83  		queue.Remove(qnode)
    84  	}
    85  
    86  	return visited
    87  }
    88  
    89  // AddPeer adds a new peer to node topology
    90  // It returns false if the peer already exists
    91  func (n *node) AddPeer(peer *node) error {
    92  	n.Lock()
    93  	defer n.Unlock()
    94  
    95  	if _, ok := n.peers[peer.id]; !ok {
    96  		n.peers[peer.id] = peer
    97  		return nil
    98  	}
    99  
   100  	return ErrPeerExists
   101  }
   102  
   103  // DeletePeer deletes a peer from node peers
   104  // It returns true if the peer has been deleted
   105  func (n *node) DeletePeer(id string) bool {
   106  	n.Lock()
   107  	defer n.Unlock()
   108  
   109  	delete(n.peers, id)
   110  
   111  	return true
   112  }
   113  
   114  // UpdatePeer updates a peer if it already exists
   115  // It returns error if the peer does not exist
   116  func (n *node) UpdatePeer(peer *node) error {
   117  	n.Lock()
   118  	defer n.Unlock()
   119  
   120  	if _, ok := n.peers[peer.id]; ok {
   121  		n.peers[peer.id] = peer
   122  		return nil
   123  	}
   124  
   125  	return ErrPeerNotFound
   126  }
   127  
   128  // RefreshPeer updates node timestamp
   129  // It returns false if the peer has not been found.
   130  func (n *node) RefreshPeer(id string, now time.Time) error {
   131  	n.Lock()
   132  	defer n.Unlock()
   133  
   134  	peer, ok := n.peers[id]
   135  	if !ok {
   136  		return ErrPeerNotFound
   137  	}
   138  
   139  	if peer.lastSeen.Before(now) {
   140  		peer.lastSeen = now
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  // Nodes returns a slice of all nodes in the whole node topology
   147  func (n *node) Nodes() []Node {
   148  	// we need to freeze the network graph here
   149  	// otherwise we might get inconsisten results
   150  	n.RLock()
   151  	defer n.RUnlock()
   152  
   153  	// NOTE: this should never be true
   154  	untilNoMorePeers := func(node *node) bool {
   155  		return node == nil
   156  	}
   157  	justWalk := func(parent, node *node) {}
   158  
   159  	visited := n.walk(untilNoMorePeers, justWalk)
   160  
   161  	nodes := make([]Node, 0, len(visited))
   162  	// collect all the nodes and return them
   163  	for _, node := range visited {
   164  		nodes = append(nodes, node)
   165  	}
   166  
   167  	return nodes
   168  }
   169  
   170  // GetPeerNode returns a node from node MaxDepth topology
   171  // It returns nil if the peer was not found
   172  func (n *node) GetPeerNode(id string) *node {
   173  	// get node topology up to MaxDepth
   174  	top := n.Topology(MaxDepth)
   175  
   176  	untilFoundPeer := func(n *node) bool {
   177  		return n.id == id
   178  	}
   179  	justWalk := func(paent, node *node) {}
   180  
   181  	visited := top.walk(untilFoundPeer, justWalk)
   182  
   183  	peerNode, ok := visited[id]
   184  	if !ok {
   185  		return nil
   186  	}
   187  
   188  	return peerNode
   189  }
   190  
   191  // DeletePeerNode removes peer node from node topology
   192  func (n *node) DeletePeerNode(id string) error {
   193  	n.Lock()
   194  	defer n.Unlock()
   195  
   196  	untilNoMorePeers := func(node *node) bool {
   197  		return node == nil
   198  	}
   199  
   200  	deleted := make(map[string]*node)
   201  	deletePeer := func(parent, node *node) {
   202  		if node.id != n.id && node.id == id {
   203  			delete(parent.peers, node.id)
   204  			deleted[node.id] = node
   205  		}
   206  	}
   207  
   208  	n.walk(untilNoMorePeers, deletePeer)
   209  
   210  	if _, ok := deleted[id]; !ok {
   211  		return ErrPeerNotFound
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  // PruneStalePeerNodes prune the peers that have not been seen for longer than given time
   218  // It returns a map of the the nodes that got pruned
   219  func (n *node) PruneStalePeers(pruneTime time.Duration) map[string]*node {
   220  	n.Lock()
   221  	defer n.Unlock()
   222  
   223  	untilNoMorePeers := func(node *node) bool {
   224  		return node == nil
   225  	}
   226  
   227  	pruned := make(map[string]*node)
   228  	pruneStalePeer := func(parent, node *node) {
   229  		if node.id != n.id && time.Since(node.lastSeen) > PruneTime {
   230  			delete(parent.peers, node.id)
   231  			pruned[node.id] = node
   232  		}
   233  	}
   234  
   235  	n.walk(untilNoMorePeers, pruneStalePeer)
   236  
   237  	return pruned
   238  }
   239  
   240  // getTopology traverses node graph and builds node topology
   241  // NOTE: this function is not thread safe
   242  func (n *node) getTopology(depth uint) *node {
   243  	// make a copy of yourself
   244  	node := &node{
   245  		id:       n.id,
   246  		address:  n.address,
   247  		peers:    make(map[string]*node),
   248  		network:  n.network,
   249  		lastSeen: n.lastSeen,
   250  	}
   251  
   252  	// return if we reach requested depth or we have no more peers
   253  	if depth == 0 || len(n.peers) == 0 {
   254  		return node
   255  	}
   256  
   257  	// decrement the depth
   258  	depth--
   259  
   260  	// iterate through our peers and update the node peers
   261  	for _, peer := range n.peers {
   262  		nodePeer := peer.getTopology(depth)
   263  		if _, ok := node.peers[nodePeer.id]; !ok {
   264  			node.peers[nodePeer.id] = nodePeer
   265  		}
   266  	}
   267  
   268  	return node
   269  }
   270  
   271  // Topology returns a copy of the node topology down to given depth
   272  // NOTE: the returned node is a node graph - not a single node
   273  func (n *node) Topology(depth uint) *node {
   274  	n.RLock()
   275  	defer n.RUnlock()
   276  
   277  	return n.getTopology(depth)
   278  }
   279  
   280  // Peers returns node peers up to MaxDepth
   281  func (n *node) Peers() []Node {
   282  	n.RLock()
   283  	defer n.RUnlock()
   284  
   285  	peers := make([]Node, 0, len(n.peers))
   286  	for _, nodePeer := range n.peers {
   287  		peer := nodePeer.getTopology(MaxDepth)
   288  		peers = append(peers, peer)
   289  	}
   290  
   291  	return peers
   292  }
   293  
   294  // UnpackPeerTopology unpacks pb.Peer into node topology of given depth
   295  func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node {
   296  	peerNode := &node{
   297  		id:       pbPeer.Node.Id,
   298  		address:  pbPeer.Node.Address,
   299  		peers:    make(map[string]*node),
   300  		lastSeen: lastSeen,
   301  	}
   302  
   303  	// return if have either reached the depth or have no more peers
   304  	if depth == 0 || len(pbPeer.Peers) == 0 {
   305  		return peerNode
   306  	}
   307  
   308  	// decrement the depth
   309  	depth--
   310  
   311  	peers := make(map[string]*node)
   312  	for _, pbPeer := range pbPeer.Peers {
   313  		peer := UnpackPeerTopology(pbPeer, lastSeen, depth)
   314  		peers[pbPeer.Node.Id] = peer
   315  	}
   316  
   317  	peerNode.peers = peers
   318  
   319  	return peerNode
   320  }
   321  
   322  func peerProtoTopology(peer Node, depth uint) *pb.Peer {
   323  	node := &pb.Node{
   324  		Id:      peer.Id(),
   325  		Address: peer.Address(),
   326  	}
   327  
   328  	// set the network name if network is not nil
   329  	if peer.Network() != nil {
   330  		node.Network = peer.Network().Name()
   331  	}
   332  
   333  	pbPeers := &pb.Peer{
   334  		Node:  node,
   335  		Peers: make([]*pb.Peer, 0),
   336  	}
   337  
   338  	// return if we reached the end of topology or depth
   339  	if depth == 0 || len(peer.Peers()) == 0 {
   340  		return pbPeers
   341  	}
   342  
   343  	// decrement the depth
   344  	depth--
   345  
   346  	// iterate through peers of peers aka pops
   347  	for _, pop := range peer.Peers() {
   348  		peer := peerProtoTopology(pop, depth)
   349  		pbPeers.Peers = append(pbPeers.Peers, peer)
   350  	}
   351  
   352  	return pbPeers
   353  }
   354  
   355  // PeersToProto returns node peers graph encoded into protobuf
   356  func PeersToProto(node Node, depth uint) *pb.Peer {
   357  	// network node aka root node
   358  	pbNode := &pb.Node{
   359  		Id:      node.Id(),
   360  		Address: node.Address(),
   361  	}
   362  
   363  	// set the network name if network is not nil
   364  	if node.Network() != nil {
   365  		pbNode.Network = node.Network().Name()
   366  	}
   367  
   368  	// we will build proto topology into this
   369  	pbPeers := &pb.Peer{
   370  		Node:  pbNode,
   371  		Peers: make([]*pb.Peer, 0),
   372  	}
   373  
   374  	for _, peer := range node.Peers() {
   375  		pbPeer := peerProtoTopology(peer, depth)
   376  		pbPeers.Peers = append(pbPeers.Peers, pbPeer)
   377  	}
   378  
   379  	return pbPeers
   380  }