Merge pull request #209 from Arceliar/switch-tune

Adjust switch parent selection behavior
This commit is contained in:
Neil Alexander 2018-11-24 23:21:45 +00:00 committed by GitHub
commit 5a7c2b250c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -21,6 +21,7 @@ import (
const switch_timeout = time.Minute
const switch_updateInterval = switch_timeout / 2
const switch_throttle = switch_updateInterval / 2
const switch_max_time = time.Hour
// The switch locator represents the topology and network state dependent info about a node, minus the signatures that go with it.
// Nodes will pick the best root they see, provided that the root continues to push out updates with new timestamps.
@ -390,39 +391,55 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort) {
}
return true
}()
// Get the time we've known about the sender (or old parent's) current coords, up to a maximum of `switch_max_time`.
sTime := now.Sub(sender.firstSeen)
pTime := oldParent.time.Sub(oldParent.firstSeen) + switch_timeout
if sTime > switch_max_time {
sTime = switch_max_time
}
pTime := now.Sub(oldParent.firstSeen)
if pTime > switch_max_time {
pTime = switch_max_time
}
// Really want to compare sLen/sTime and pLen/pTime
// Cross multiplied to avoid divide-by-zero
cost := len(sender.locator.coords) * int(pTime.Seconds())
pCost := len(t.data.locator.coords) * int(sTime.Seconds())
cost := float64(len(sender.locator.coords)) * pTime.Seconds()
pCost := float64(len(t.data.locator.coords)) * sTime.Seconds()
dropTstamp, isIn := t.drop[sender.locator.root]
// Here be dragons
switch {
case !noLoop: // do nothing
case isIn && dropTstamp >= sender.locator.tstamp: // do nothing
case !noLoop:
// This route loops, so we can't use the sender as our parent.
case isIn && dropTstamp >= sender.locator.tstamp:
// This is a known root with a timestamp older than a known timeout, so we can't trust it to be a new announcement.
case firstIsBetter(&sender.locator.root, &t.data.locator.root):
// This is a better root than what we're currently using, so we should update.
updateRoot = true
case t.data.locator.root != sender.locator.root: // do nothing
case t.data.locator.tstamp > sender.locator.tstamp: // do nothing
case t.data.locator.root != sender.locator.root:
// This is not the same root, and it's apparently not better (from the above), so we should ignore it.
case t.data.locator.tstamp > sender.locator.tstamp:
// This timetsamp is older than the most recently seen one from this root, so we should ignore it.
case noParent:
// We currently have no working parent, and at this point in the switch statement, anything is better than nothing.
updateRoot = true
case cost < pCost:
// The sender has a better combination of path length and reliability than the current parent.
updateRoot = true
case sender.port != t.parent: // do nothing
case sender.port != t.parent:
// Ignore further cases if the sender isn't our parent.
case !equiv(&sender.locator, &t.data.locator):
// Special case
// If coords changed, then this may now be a worse parent than before
// Re-parent the node (de-parent and reprocess the message)
// Then reprocess *all* messages to look for a better parent
// This is so we don't keep using this node as our parent if there's something better
// Special case:
// If coords changed, then this may now be a worse parent than before.
// Re-parent the node (de-parent and reprocess the message).
// Then reprocess *all* messages to look for a better parent.
// This is so we don't keep using this node as our parent if there's something better.
t.parent = 0
t.unlockedHandleMsg(msg, fromPort)
for _, info := range t.data.peers {
t.unlockedHandleMsg(&info.msg, info.port)
}
case now.Sub(t.time) < switch_throttle: // do nothing
case now.Sub(t.time) < switch_throttle:
// We've already gotten an update from this root recently, so ignore this one to avoid flooding.
case sender.locator.tstamp > t.data.locator.tstamp:
// The timestamp was updated, so we need to update locally and send to our peers.
updateRoot = true
}
if updateRoot {