github.com/klaytn/klaytn@v1.12.1/networks/p2p/discover/discover_storage_simple.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discover
    18  
    19  import (
    20  	"math/rand"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/klaytn/klaytn/common"
    25  	"github.com/klaytn/klaytn/common/math"
    26  	"github.com/klaytn/klaytn/log"
    27  	"github.com/klaytn/klaytn/networks/p2p/netutil"
    28  )
    29  
    30  type simpleStorage struct {
    31  	tab         *Table
    32  	targetType  NodeType
    33  	nodes       []*Node
    34  	noDiscover  bool // if noDiscover is true, don't lookup new node.
    35  	nodesMutex  sync.Mutex
    36  	max         int
    37  	rand        *rand.Rand
    38  	localLogger log.Logger
    39  
    40  	lock               sync.RWMutex
    41  	hasAuthorizedNodes bool
    42  	authorizedNodes    map[NodeID]*Node
    43  }
    44  
    45  func NewSimpleStorage(nodeType NodeType, noDiscover bool, max int, authorizedNodes []*Node) *simpleStorage {
    46  	storage := &simpleStorage{targetType: nodeType, noDiscover: noDiscover, max: max}
    47  	storage.authorizedNodes = make(map[NodeID]*Node)
    48  	for _, node := range authorizedNodes {
    49  		if node.NType == nodeType {
    50  			storage.putAuthorizedNode(node)
    51  		}
    52  	}
    53  	return storage
    54  }
    55  
    56  func (s *simpleStorage) init() {
    57  	// TODO
    58  	s.localLogger = logger.NewWith("Discover", "Simple")
    59  	now := time.Now().UnixNano()
    60  	s.rand = rand.New(rand.NewSource(now))
    61  }
    62  
    63  func (s *simpleStorage) lookup(targetID NodeID, refreshIfEmpty bool, targetType NodeType) []*Node {
    64  	// check exist alive bn
    65  	var seeds []*Node
    66  	s.nodesMutex.Lock()
    67  	for _, n := range s.nodes {
    68  		if n.NType == NodeTypeBN {
    69  			seeds = append(seeds, n)
    70  		}
    71  	}
    72  	s.nodesMutex.Unlock()
    73  
    74  	if len(seeds) == 0 {
    75  		seeds = append([]*Node{}, s.tab.nursery...)
    76  		seeds = s.tab.bondall(seeds)
    77  		for _, n := range seeds {
    78  			s.add(n)
    79  		}
    80  	}
    81  	s.localLogger.Debug("lookup", "StorageName", s.name(), "targetId", targetID, "targetType", nodeTypeName(targetType))
    82  	return s.tab.findNewNode(&nodesByDistance{entries: seeds}, targetID, targetType, false, s.max)
    83  }
    84  
    85  func (s *simpleStorage) shuffle(vals []*Node) []*Node {
    86  	if len(vals) == 0 {
    87  		return vals
    88  	}
    89  	ret := make([]*Node, len(vals))
    90  	perm := s.rand.Perm(len(vals))
    91  	for i, randIndex := range perm {
    92  		ret[i] = vals[randIndex]
    93  	}
    94  	return ret
    95  }
    96  
    97  func (s *simpleStorage) getNodes(max int) []*Node {
    98  	s.nodesMutex.Lock()
    99  	nodes := s.shuffle(s.nodes)
   100  
   101  	var ret []*Node
   102  	for _, nd := range nodes {
   103  		if nd.NType == s.targetType {
   104  			ret = append(ret, nd)
   105  		}
   106  		if len(ret) >= max {
   107  			break
   108  		}
   109  	}
   110  	s.nodesMutex.Unlock()
   111  
   112  	if len(ret) < max {
   113  		ret = s.lookup(NodeID{}, true, s.targetType)
   114  	}
   115  
   116  	if len(ret) < max {
   117  		return ret
   118  	} else {
   119  		return ret[:max]
   120  	}
   121  }
   122  
   123  func (s *simpleStorage) doRevalidate() {
   124  	s.nodesMutex.Lock()
   125  	defer s.nodesMutex.Unlock()
   126  
   127  	if len(s.nodes) == 0 {
   128  		return
   129  	}
   130  
   131  	oldest := s.nodes[len(s.nodes)-1]
   132  
   133  	holdingTime := s.tab.db.bondTime(oldest.ID).Add(10 * time.Second) // TODO-Klaytn-Node Make sleep time as configurable
   134  	if time.Now().Before(holdingTime) {
   135  		return
   136  	}
   137  
   138  	err := s.tab.ping(oldest.ID, oldest.addr())
   139  	if err != nil {
   140  		s.localLogger.Info("Removed the node without any response", "StorageName", s.name(), "NodeID", oldest.ID, "NodeType", nodeTypeName(oldest.NType))
   141  		s.deleteWithoutLock(oldest)
   142  		return
   143  	}
   144  	copy(s.nodes[1:], s.nodes[:len(s.nodes)-1])
   145  	s.nodes[0] = oldest
   146  }
   147  
   148  func (s *simpleStorage) setTargetNodeType(tType NodeType) {
   149  	s.targetType = tType
   150  }
   151  
   152  func (s *simpleStorage) doRefresh() {
   153  	if s.noDiscover {
   154  		return
   155  	}
   156  	s.lookup(s.tab.self.ID, false, s.targetType)
   157  }
   158  
   159  func (s *simpleStorage) nodeAll() []*Node {
   160  	s.nodesMutex.Lock()
   161  	defer s.nodesMutex.Unlock()
   162  	return s.nodes
   163  }
   164  
   165  func (s *simpleStorage) len() (n int) {
   166  	s.nodesMutex.Lock()
   167  	defer s.nodesMutex.Unlock()
   168  	return len(s.nodes)
   169  }
   170  
   171  func (s *simpleStorage) copyBondedNodes() {
   172  	s.nodesMutex.Lock()
   173  	defer s.nodesMutex.Unlock()
   174  	for _, n := range s.nodes {
   175  		s.tab.db.updateNode(n)
   176  	}
   177  }
   178  
   179  func (s *simpleStorage) getBucketEntries() []*Node {
   180  	s.nodesMutex.Lock()
   181  	defer s.nodesMutex.Unlock()
   182  
   183  	var ret []*Node
   184  	for _, n := range s.nodes {
   185  		ret = append(ret, n)
   186  	}
   187  	return ret
   188  }
   189  
   190  // The caller must not hold tab.mutex.
   191  func (s *simpleStorage) stuff(nodes []*Node) {
   192  	panic("implement me")
   193  }
   194  
   195  // The caller must hold s.nodesMutex.
   196  func (s *simpleStorage) delete(n *Node) {
   197  	s.deleteWithLock(n)
   198  }
   199  
   200  func (s *simpleStorage) deleteWithLock(n *Node) {
   201  	s.nodesMutex.Lock()
   202  	defer s.nodesMutex.Unlock()
   203  	s.deleteWithoutLock(n)
   204  }
   205  
   206  func (s *simpleStorage) deleteWithoutLock(n *Node) {
   207  	s.nodes = deleteNode(s.nodes, n)
   208  
   209  	s.tab.db.deleteNode(n.ID)
   210  	if netutil.IsLAN(n.IP) {
   211  		return
   212  	}
   213  	s.tab.ips.Remove(n.IP)
   214  }
   215  
   216  func (s *simpleStorage) closest(target common.Hash, nresults int) *nodesByDistance {
   217  	s.nodesMutex.Lock()
   218  	defer s.nodesMutex.Unlock()
   219  	// TODO-Klaytn-Node nodesByDistance is not suitable for SimpleStorage. Because there is no concept for distance
   220  	// in the SimpleStorage. Change it
   221  	cNodes := &nodesByDistance{target: target}
   222  	nodes := s.shuffle(s.nodes)
   223  	if len(nodes) > s.max {
   224  		cNodes.entries = nodes[:s.max]
   225  	} else {
   226  		cNodes.entries = nodes
   227  	}
   228  	return cNodes
   229  }
   230  
   231  func (s *simpleStorage) setTable(t *Table) {
   232  	s.tab = t
   233  }
   234  
   235  func (s *simpleStorage) readRandomNodes(buf []*Node) (n int) {
   236  	panic("implement me")
   237  }
   238  
   239  func (s *simpleStorage) add(n *Node) {
   240  	s.nodesMutex.Lock()
   241  	s.bumpOrAdd(n)
   242  	s.nodesMutex.Unlock()
   243  }
   244  
   245  // The caller must hold s.nodesMutex.
   246  func (s *simpleStorage) bumpOrAdd(n *Node) bool {
   247  	if s.bump(n) {
   248  		s.localLogger.Trace("Add(Bumped)", "StorageName", s.name(), "node", n)
   249  		return true
   250  	}
   251  
   252  	s.localLogger.Trace("Add(New)", "StorageName", s.name(), "node", n)
   253  	s.nodes, _ = pushNode(s.nodes, n, math.MaxInt64) // TODO-Klaytn-Node Change Max value for more reasonable one.
   254  	n.addedAt = time.Now()
   255  	if s.tab.nodeAddedHook != nil {
   256  		s.tab.nodeAddedHook(n)
   257  	}
   258  	return true
   259  }
   260  
   261  // The caller must hold s.nodesMutex.
   262  func (s *simpleStorage) bump(n *Node) bool {
   263  	for i := range s.nodes {
   264  		if s.nodes[i].ID == n.ID {
   265  			// move it to the front
   266  			copy(s.nodes[1:], s.nodes[:i])
   267  			s.nodes[0] = n
   268  			return true
   269  		}
   270  	}
   271  	return false
   272  }
   273  
   274  func (s *simpleStorage) name() string {
   275  	return nodeTypeName(s.targetType)
   276  }
   277  
   278  func (s *simpleStorage) isAuthorized(id NodeID) bool {
   279  	s.lock.RLock()
   280  	defer s.lock.RUnlock()
   281  	if !s.hasAuthorizedNodes {
   282  		return true
   283  	}
   284  	for _, n := range s.authorizedNodes {
   285  		if n.ID == id {
   286  			return true
   287  		}
   288  	}
   289  	return false
   290  }
   291  
   292  func (s *simpleStorage) getAuthorizedNodes() []*Node {
   293  	s.lock.RLock()
   294  	defer s.lock.RUnlock()
   295  	var ret []*Node
   296  	for _, val := range s.authorizedNodes {
   297  		ret = append(ret, val)
   298  	}
   299  	return ret
   300  }
   301  
   302  func (s *simpleStorage) putAuthorizedNode(node *Node) {
   303  	if node.NType != s.targetType {
   304  		return
   305  	}
   306  	s.lock.Lock()
   307  	defer s.lock.Unlock()
   308  	s.authorizedNodes[node.ID] = node
   309  	s.hasAuthorizedNodes = true
   310  }
   311  
   312  func (s *simpleStorage) deleteAuthorizedNode(id NodeID) {
   313  	s.lock.Lock()
   314  	defer s.lock.Unlock()
   315  	if _, ok := s.authorizedNodes[id]; ok {
   316  		delete(s.authorizedNodes, id)
   317  		s.hasAuthorizedNodes = len(s.authorizedNodes) != 0
   318  	} else {
   319  		logger.Debug("No node to be removed", "nodeid", id)
   320  	}
   321  }