mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	exponential dht throttle backoff, and make it based on when packets were sent as part of bootstrapping/maintenance, not when arbitrary packets were received
This commit is contained in:
		
							parent
							
								
									909b48f2f2
								
							
						
					
					
						commit
						359af66d0d
					
				
					 1 changed files with 44 additions and 20 deletions
				
			
		| 
						 | 
					@ -41,10 +41,11 @@ type dhtInfo struct {
 | 
				
			||||||
	nodeID_hidden *NodeID
 | 
						nodeID_hidden *NodeID
 | 
				
			||||||
	key           boxPubKey
 | 
						key           boxPubKey
 | 
				
			||||||
	coords        []byte
 | 
						coords        []byte
 | 
				
			||||||
	send          time.Time // When we last sent a message
 | 
						send          time.Time     // When we last sent a message
 | 
				
			||||||
	recv          time.Time // When we last received a message
 | 
						recv          time.Time     // When we last received a message
 | 
				
			||||||
	pings         int       // Decide when to drop
 | 
						pings         int           // Decide when to drop
 | 
				
			||||||
	throttle      uint8     // Number of seconds to wait before pinging a node to bootstrap buckets, gradually increases up to 1 minute
 | 
						throttle      time.Duration // Time to wait before pinging a node to bootstrap buckets, increases exponentially from 1 second to 1 minute
 | 
				
			||||||
 | 
						bootstrapSend time.Time     // The time checked/updated as part of throttle checks
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times.
 | 
					// Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times.
 | 
				
			||||||
| 
						 | 
					@ -141,12 +142,14 @@ func (t *dht) handleRes(res *dhtRes) {
 | 
				
			||||||
	if !isIn {
 | 
						if !isIn {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						now := time.Now()
 | 
				
			||||||
	rinfo := dhtInfo{
 | 
						rinfo := dhtInfo{
 | 
				
			||||||
		key:      res.Key,
 | 
							key:           res.Key,
 | 
				
			||||||
		coords:   res.Coords,
 | 
							coords:        res.Coords,
 | 
				
			||||||
		send:     time.Now(), // Technically wrong but should be OK...
 | 
							send:          now, // Technically wrong but should be OK...
 | 
				
			||||||
		recv:     time.Now(),
 | 
							recv:          now,
 | 
				
			||||||
		throttle: 1,
 | 
							throttle:      time.Second,
 | 
				
			||||||
 | 
							bootstrapSend: now,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// If they're already in the table, then keep the correct send time
 | 
						// If they're already in the table, then keep the correct send time
 | 
				
			||||||
	bidx, isOK := t.getBucketIndex(rinfo.getNodeID())
 | 
						bidx, isOK := t.getBucketIndex(rinfo.getNodeID())
 | 
				
			||||||
| 
						 | 
					@ -157,13 +160,15 @@ func (t *dht) handleRes(res *dhtRes) {
 | 
				
			||||||
	for _, oldinfo := range b.peers {
 | 
						for _, oldinfo := range b.peers {
 | 
				
			||||||
		if oldinfo.key == rinfo.key {
 | 
							if oldinfo.key == rinfo.key {
 | 
				
			||||||
			rinfo.send = oldinfo.send
 | 
								rinfo.send = oldinfo.send
 | 
				
			||||||
			rinfo.throttle += oldinfo.throttle
 | 
								rinfo.throttle = oldinfo.throttle
 | 
				
			||||||
 | 
								rinfo.bootstrapSend = oldinfo.bootstrapSend
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, oldinfo := range b.other {
 | 
						for _, oldinfo := range b.other {
 | 
				
			||||||
		if oldinfo.key == rinfo.key {
 | 
							if oldinfo.key == rinfo.key {
 | 
				
			||||||
			rinfo.send = oldinfo.send
 | 
								rinfo.send = oldinfo.send
 | 
				
			||||||
			rinfo.throttle += oldinfo.throttle
 | 
								rinfo.throttle = oldinfo.throttle
 | 
				
			||||||
 | 
								rinfo.bootstrapSend = oldinfo.bootstrapSend
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Insert into table
 | 
						// Insert into table
 | 
				
			||||||
| 
						 | 
					@ -266,8 +271,8 @@ func (t *dht) insert(info *dhtInfo, isPeer bool) {
 | 
				
			||||||
		// This speeds up bootstrapping
 | 
							// This speeds up bootstrapping
 | 
				
			||||||
		info.recv = info.recv.Add(-time.Hour)
 | 
							info.recv = info.recv.Add(-time.Hour)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if isPeer || info.throttle > 60 {
 | 
						if isPeer || info.throttle > time.Minute {
 | 
				
			||||||
		info.throttle = 60
 | 
							info.throttle = time.Minute
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// First drop any existing entry from the bucket
 | 
						// First drop any existing entry from the bucket
 | 
				
			||||||
	b.drop(&info.key)
 | 
						b.drop(&info.key)
 | 
				
			||||||
| 
						 | 
					@ -512,20 +517,39 @@ func (t *dht) doMaintenance() {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if oldest != nil && time.Since(oldest.recv) > time.Minute {
 | 
							if oldest != nil && time.Since(oldest.recv) > time.Minute {
 | 
				
			||||||
 | 
								// Ping the oldest node in the DHT, but don't ping nodes that have been checked within the last minute
 | 
				
			||||||
			t.addToMill(oldest, nil)
 | 
								t.addToMill(oldest, nil)
 | 
				
			||||||
		} // if the DHT isn't empty
 | 
							}
 | 
				
			||||||
		// Refresh buckets
 | 
							// Refresh buckets
 | 
				
			||||||
		if t.offset > last {
 | 
							if t.offset > last {
 | 
				
			||||||
			t.offset = 0
 | 
								t.offset = 0
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		target := t.getTarget(t.offset)
 | 
							target := t.getTarget(t.offset)
 | 
				
			||||||
		for _, info := range t.lookup(target, true) {
 | 
							func() {
 | 
				
			||||||
			if time.Since(info.recv) > time.Duration(info.throttle)*time.Second {
 | 
								closer := t.lookup(target, false)
 | 
				
			||||||
				t.addToMill(info, target)
 | 
								for _, info := range closer {
 | 
				
			||||||
				t.offset++
 | 
									// Throttled ping of a node that's closer to the destination
 | 
				
			||||||
				break
 | 
									if time.Since(info.recv) > info.throttle {
 | 
				
			||||||
 | 
										t.addToMill(info, target)
 | 
				
			||||||
 | 
										t.offset++
 | 
				
			||||||
 | 
										info.bootstrapSend = time.Now()
 | 
				
			||||||
 | 
										info.throttle *= 2
 | 
				
			||||||
 | 
										if info.throttle > time.Minute {
 | 
				
			||||||
 | 
											info.throttle = time.Minute
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
								if len(closer) == 0 {
 | 
				
			||||||
 | 
									// If we don't know of anyone closer at all, then there's a hole in our dht
 | 
				
			||||||
 | 
									// Ping the closest node we know and ignore the throttle, to try to fill it
 | 
				
			||||||
 | 
									for _, info := range t.lookup(target, true) {
 | 
				
			||||||
 | 
										t.addToMill(info, target)
 | 
				
			||||||
 | 
										t.offset++
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
		//t.offset++
 | 
							//t.offset++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for len(t.rumorMill) > 0 {
 | 
						for len(t.rumorMill) > 0 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue