code: func (m *Memberlist) pushPull() {
  	// Get a random live node
  	m.nodeLock.RLock()
  	nodes := kRandomNodes(1, m.nodes, func(n *nodeState) bool {
  		return n.Name == m.config.Name ||
  			n.State != stateAlive
  	})
  	m.nodeLock.RUnlock()
  
  	// If no nodes, bail
  	if len(nodes) == 0 {
  		return
  	}
  	node := nodes[0]
  
  	// Attempt a push pull
  	if err := m.pushPullNode(node.Address(), false); err != nil {
  		m.logger.Printf("[ERR] memberlist: Push/Pull with %s failed: %s", node.Name, err)
  	}
  }
docs: // pushPull is invoked periodically to randomly perform a complete state
  // exchange. Used to ensure a high level of convergence, but is also
  // reasonably expensive as the entire state of this node is exchanged
  // with the other node.