github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discv5/topic.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:44</date> 10 //</624342657799294976> 11 12 13 package discv5 14 15 import ( 16 "container/heap" 17 "fmt" 18 "math" 19 "math/rand" 20 "time" 21 22 "github.com/ethereum/go-ethereum/common/mclock" 23 "github.com/ethereum/go-ethereum/log" 24 ) 25 26 const ( 27 maxEntries = 10000 28 maxEntriesPerTopic = 50 29 30 fallbackRegistrationExpiry = 1 * time.Hour 31 ) 32 33 type Topic string 34 35 type topicEntry struct { 36 topic Topic 37 fifoIdx uint64 38 node *Node 39 expire mclock.AbsTime 40 } 41 42 type topicInfo struct { 43 entries map[uint64]*topicEntry 44 fifoHead, fifoTail uint64 45 rqItem *topicRequestQueueItem 46 wcl waitControlLoop 47 } 48 49 //从FIFO中删除尾部元素 50 func (t *topicInfo) getFifoTail() *topicEntry { 51 for t.entries[t.fifoTail] == nil { 52 t.fifoTail++ 53 } 54 tail := t.entries[t.fifoTail] 55 t.fifoTail++ 56 return tail 57 } 58 59 type nodeInfo struct { 60 entries map[Topic]*topicEntry 61 lastIssuedTicket, lastUsedTicket uint32 62 //您不能在noreguntil(绝对时间)之前注册比lastusedticket更新的票据。 63 noRegUntil mclock.AbsTime 64 } 65 66 type topicTable struct { 67 db *nodeDB 68 self *Node 69 nodes map[*Node]*nodeInfo 70 topics map[Topic]*topicInfo 71 globalEntries uint64 72 requested topicRequestQueue 73 requestCnt uint64 74 lastGarbageCollection mclock.AbsTime 75 } 76 77 func newTopicTable(db *nodeDB, self *Node) *topicTable { 78 if printTestImgLogs { 79 fmt.Printf("*N %016x\n", self.sha[:8]) 80 } 81 return &topicTable{ 82 db: db, 83 nodes: make(map[*Node]*nodeInfo), 84 topics: make(map[Topic]*topicInfo), 85 self: self, 86 } 87 } 88 89 func (t *topicTable) getOrNewTopic(topic Topic) *topicInfo { 90 ti := t.topics[topic] 91 if ti == nil { 92 rqItem := &topicRequestQueueItem{ 93 topic: topic, 94 priority: t.requestCnt, 95 } 96 ti = &topicInfo{ 97 entries: make(map[uint64]*topicEntry), 98 rqItem: rqItem, 99 } 100 t.topics[topic] = ti 101 heap.Push(&t.requested, rqItem) 102 } 103 return ti 104 } 105 106 func (t *topicTable) checkDeleteTopic(topic Topic) { 107 ti := t.topics[topic] 108 if ti == nil { 109 return 110 } 111 if len(ti.entries) == 0 && ti.wcl.hasMinimumWaitPeriod() { 112 delete(t.topics, topic) 113 heap.Remove(&t.requested, ti.rqItem.index) 114 } 115 } 116 117 func (t *topicTable) getOrNewNode(node *Node) *nodeInfo { 118 n := t.nodes[node] 119 if n == nil { 120 //fmt.printf(“newnode%016x%016x\n”,t.self.sha[:8],node.sha[:8]) 121 var issued, used uint32 122 if t.db != nil { 123 issued, used = t.db.fetchTopicRegTickets(node.ID) 124 } 125 n = &nodeInfo{ 126 entries: make(map[Topic]*topicEntry), 127 lastIssuedTicket: issued, 128 lastUsedTicket: used, 129 } 130 t.nodes[node] = n 131 } 132 return n 133 } 134 135 func (t *topicTable) checkDeleteNode(node *Node) { 136 if n, ok := t.nodes[node]; ok && len(n.entries) == 0 && n.noRegUntil < mclock.Now() { 137 //fmt.printf(“删除节点%016x%016x\n”,t.self.sha[:8],节点.sha[:8]) 138 delete(t.nodes, node) 139 } 140 } 141 142 func (t *topicTable) storeTicketCounters(node *Node) { 143 n := t.getOrNewNode(node) 144 if t.db != nil { 145 t.db.updateTopicRegTickets(node.ID, n.lastIssuedTicket, n.lastUsedTicket) 146 } 147 } 148 149 func (t *topicTable) getEntries(topic Topic) []*Node { 150 t.collectGarbage() 151 152 te := t.topics[topic] 153 if te == nil { 154 return nil 155 } 156 nodes := make([]*Node, len(te.entries)) 157 i := 0 158 for _, e := range te.entries { 159 nodes[i] = e.node 160 i++ 161 } 162 t.requestCnt++ 163 t.requested.update(te.rqItem, t.requestCnt) 164 return nodes 165 } 166 167 func (t *topicTable) addEntry(node *Node, topic Topic) { 168 n := t.getOrNewNode(node) 169 //按同一节点清除以前的条目 170 for _, e := range n.entries { 171 t.deleteEntry(e) 172 } 173 //*** 174 n = t.getOrNewNode(node) 175 176 tm := mclock.Now() 177 te := t.getOrNewTopic(topic) 178 179 if len(te.entries) == maxEntriesPerTopic { 180 t.deleteEntry(te.getFifoTail()) 181 } 182 183 if t.globalEntries == maxEntries { 184 t.deleteEntry(t.leastRequested()) //不是空的,不需要检查零 185 } 186 187 fifoIdx := te.fifoHead 188 te.fifoHead++ 189 entry := &topicEntry{ 190 topic: topic, 191 fifoIdx: fifoIdx, 192 node: node, 193 expire: tm + mclock.AbsTime(fallbackRegistrationExpiry), 194 } 195 if printTestImgLogs { 196 fmt.Printf("*+ %d %v %016x %016x\n", tm/1000000, topic, t.self.sha[:8], node.sha[:8]) 197 } 198 te.entries[fifoIdx] = entry 199 n.entries[topic] = entry 200 t.globalEntries++ 201 te.wcl.registered(tm) 202 } 203 204 //从FIFO中删除请求最少的元素 205 func (t *topicTable) leastRequested() *topicEntry { 206 for t.requested.Len() > 0 && t.topics[t.requested[0].topic] == nil { 207 heap.Pop(&t.requested) 208 } 209 if t.requested.Len() == 0 { 210 return nil 211 } 212 return t.topics[t.requested[0].topic].getFifoTail() 213 } 214 215 //条目应该存在 216 func (t *topicTable) deleteEntry(e *topicEntry) { 217 if printTestImgLogs { 218 fmt.Printf("*- %d %v %016x %016x\n", mclock.Now()/1000000, e.topic, t.self.sha[:8], e.node.sha[:8]) 219 } 220 ne := t.nodes[e.node].entries 221 delete(ne, e.topic) 222 if len(ne) == 0 { 223 t.checkDeleteNode(e.node) 224 } 225 te := t.topics[e.topic] 226 delete(te.entries, e.fifoIdx) 227 if len(te.entries) == 0 { 228 t.checkDeleteTopic(e.topic) 229 } 230 t.globalEntries-- 231 } 232 233 //假设主题和等待期的长度相同。 234 func (t *topicTable) useTicket(node *Node, serialNo uint32, topics []Topic, idx int, issueTime uint64, waitPeriods []uint32) (registered bool) { 235 log.Trace("Using discovery ticket", "serial", serialNo, "topics", topics, "waits", waitPeriods) 236 //fmt.println(“useticket”,serialno,topics,waitperiods) 237 t.collectGarbage() 238 239 n := t.getOrNewNode(node) 240 if serialNo < n.lastUsedTicket { 241 return false 242 } 243 244 tm := mclock.Now() 245 if serialNo > n.lastUsedTicket && tm < n.noRegUntil { 246 return false 247 } 248 if serialNo != n.lastUsedTicket { 249 n.lastUsedTicket = serialNo 250 n.noRegUntil = tm + mclock.AbsTime(noRegTimeout()) 251 t.storeTicketCounters(node) 252 } 253 254 currTime := uint64(tm / mclock.AbsTime(time.Second)) 255 regTime := issueTime + uint64(waitPeriods[idx]) 256 relTime := int64(currTime - regTime) 257 if relTime >= -1 && relTime <= regTimeWindow+1 { //在两端给客户一点安全边际 258 if e := n.entries[topics[idx]]; e == nil { 259 t.addEntry(node, topics[idx]) 260 } else { 261 //如果有活动条目,不要移动到FIFO的前面,而是延长过期时间 262 e.expire = tm + mclock.AbsTime(fallbackRegistrationExpiry) 263 } 264 return true 265 } 266 267 return false 268 } 269 270 func (t *topicTable) getTicket(node *Node, topics []Topic) *ticket { 271 t.collectGarbage() 272 273 now := mclock.Now() 274 n := t.getOrNewNode(node) 275 n.lastIssuedTicket++ 276 t.storeTicketCounters(node) 277 278 tic := &ticket{ 279 issueTime: now, 280 topics: topics, 281 serial: n.lastIssuedTicket, 282 regTime: make([]mclock.AbsTime, len(topics)), 283 } 284 for i, topic := range topics { 285 var waitPeriod time.Duration 286 if topic := t.topics[topic]; topic != nil { 287 waitPeriod = topic.wcl.waitPeriod 288 } else { 289 waitPeriod = minWaitPeriod 290 } 291 292 tic.regTime[i] = now + mclock.AbsTime(waitPeriod) 293 } 294 return tic 295 } 296 297 const gcInterval = time.Minute 298 299 func (t *topicTable) collectGarbage() { 300 tm := mclock.Now() 301 if time.Duration(tm-t.lastGarbageCollection) < gcInterval { 302 return 303 } 304 t.lastGarbageCollection = tm 305 306 for node, n := range t.nodes { 307 for _, e := range n.entries { 308 if e.expire <= tm { 309 t.deleteEntry(e) 310 } 311 } 312 313 t.checkDeleteNode(node) 314 } 315 316 for topic := range t.topics { 317 t.checkDeleteTopic(topic) 318 } 319 } 320 321 const ( 322 minWaitPeriod = time.Minute 323 regTimeWindow = 10 //秒 324 avgnoRegTimeout = time.Minute * 10 325 //两个传入AD请求之间的目标平均间隔 326 wcTargetRegInterval = time.Minute * 10 / maxEntriesPerTopic 327 // 328 wcTimeConst = time.Minute * 10 329 ) 330 331 //不需要初始化,将在首次注册时设置为minwaitperiod 332 type waitControlLoop struct { 333 lastIncoming mclock.AbsTime 334 waitPeriod time.Duration 335 } 336 337 func (w *waitControlLoop) registered(tm mclock.AbsTime) { 338 w.waitPeriod = w.nextWaitPeriod(tm) 339 w.lastIncoming = tm 340 } 341 342 func (w *waitControlLoop) nextWaitPeriod(tm mclock.AbsTime) time.Duration { 343 period := tm - w.lastIncoming 344 wp := time.Duration(float64(w.waitPeriod) * math.Exp((float64(wcTargetRegInterval)-float64(period))/float64(wcTimeConst))) 345 if wp < minWaitPeriod { 346 wp = minWaitPeriod 347 } 348 return wp 349 } 350 351 func (w *waitControlLoop) hasMinimumWaitPeriod() bool { 352 return w.nextWaitPeriod(mclock.Now()) == minWaitPeriod 353 } 354 355 func noRegTimeout() time.Duration { 356 e := rand.ExpFloat64() 357 if e > 100 { 358 e = 100 359 } 360 return time.Duration(float64(avgnoRegTimeout) * e) 361 } 362 363 type topicRequestQueueItem struct { 364 topic Topic 365 priority uint64 366 index int 367 } 368 369 //TopicRequestQueue实现heap.interface并保存TopicRequestQueueitems。 370 type topicRequestQueue []*topicRequestQueueItem 371 372 func (tq topicRequestQueue) Len() int { return len(tq) } 373 374 func (tq topicRequestQueue) Less(i, j int) bool { 375 return tq[i].priority < tq[j].priority 376 } 377 378 func (tq topicRequestQueue) Swap(i, j int) { 379 tq[i], tq[j] = tq[j], tq[i] 380 tq[i].index = i 381 tq[j].index = j 382 } 383 384 func (tq *topicRequestQueue) Push(x interface{}) { 385 n := len(*tq) 386 item := x.(*topicRequestQueueItem) 387 item.index = n 388 *tq = append(*tq, item) 389 } 390 391 func (tq *topicRequestQueue) Pop() interface{} { 392 old := *tq 393 n := len(old) 394 item := old[n-1] 395 item.index = -1 396 *tq = old[0 : n-1] 397 return item 398 } 399 400 func (tq *topicRequestQueue) update(item *topicRequestQueueItem, priority uint64) { 401 item.priority = priority 402 heap.Fix(tq, item.index) 403 } 404