5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-26 07:11:40 +00: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:
Arceliar 2018-06-12 03:16:10 -05:00
parent 909b48f2f2
commit 359af66d0d

View File

@ -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 {