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 }