-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce Routing Table churn #90
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,15 +132,15 @@ func (rt *RoutingTable) NPeersForCpl(cpl uint) int { | |
// the boolean value will ALWAYS be false i.e. the peer wont be added to the Routing Table it it's not already there. | ||
// | ||
// A return value of false with error=nil indicates that the peer ALREADY exists in the Routing Table. | ||
func (rt *RoutingTable) TryAddPeer(p peer.ID, queryPeer bool) (bool, error) { | ||
func (rt *RoutingTable) TryAddPeer(p peer.ID, queryPeer bool, isReplaceable bool) (bool, error) { | ||
rt.tabLock.Lock() | ||
defer rt.tabLock.Unlock() | ||
|
||
return rt.addPeer(p, queryPeer) | ||
return rt.addPeer(p, queryPeer, isReplaceable) | ||
} | ||
|
||
// locking is the responsibility of the caller | ||
func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) { | ||
func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool, isReplaceable bool) (bool, error) { | ||
bucketID := rt.bucketIdForPeer(p) | ||
bucket := rt.buckets[bucketID] | ||
|
||
|
@@ -183,6 +183,7 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) { | |
LastSuccessfulOutboundQueryAt: now, | ||
AddedAt: now, | ||
dhtId: ConvertPeerID(p), | ||
replaceable: isReplaceable, | ||
}) | ||
rt.PeerAdded(p) | ||
return true, nil | ||
|
@@ -203,27 +204,31 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) { | |
LastSuccessfulOutboundQueryAt: now, | ||
AddedAt: now, | ||
dhtId: ConvertPeerID(p), | ||
replaceable: isReplaceable, | ||
}) | ||
rt.PeerAdded(p) | ||
return true, nil | ||
} | ||
} | ||
|
||
// the bucket to which the peer belongs is full. Let's try to find a peer | ||
// in that bucket with a LastSuccessfulOutboundQuery value above the maximum threshold and replace it. | ||
minLast := bucket.min(func(first *PeerInfo, second *PeerInfo) bool { | ||
return first.LastUsefulAt.Before(second.LastUsefulAt) | ||
// in that bucket which is replaceable. | ||
// we don't really need a stable sort here as it dosen't matter which peer we evict | ||
// as long as it's a replaceable peer. | ||
replaceablePeer := bucket.min(func(p1 *PeerInfo, p2 *PeerInfo) bool { | ||
return p1.replaceable | ||
}) | ||
|
||
if time.Since(minLast.LastUsefulAt) > rt.usefulnessGracePeriod { | ||
if replaceablePeer != nil && replaceablePeer.replaceable { | ||
// let's evict it and add the new peer | ||
if rt.removePeer(minLast.Id) { | ||
if rt.removePeer(replaceablePeer.Id) { | ||
bucket.pushFront(&PeerInfo{ | ||
Id: p, | ||
LastUsefulAt: lastUsefulAt, | ||
LastSuccessfulOutboundQueryAt: now, | ||
AddedAt: now, | ||
dhtId: ConvertPeerID(p), | ||
replaceable: isReplaceable, | ||
}) | ||
rt.PeerAdded(p) | ||
return true, nil | ||
|
@@ -237,6 +242,21 @@ func (rt *RoutingTable) addPeer(p peer.ID, queryPeer bool) (bool, error) { | |
return false, ErrPeerRejectedNoCapacity | ||
} | ||
|
||
// MarkAllPeersIrreplaceable marks all peers in the routing table as irreplaceable | ||
// This means that we will never replace an existing peer in the table to make space for a new peer. | ||
// However, they can still be removed by calling the `RemovePeer` API. | ||
func (rt *RoutingTable) MarkAllPeersIrreplaceable() { | ||
Comment on lines
+245
to
+248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels like a function just waiting to get deprecated, as opposed to basically exposing the
Comment on lines
+245
to
+248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to see how this is used in the DHT PR to ensure we don't run into race conditions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The PR is up and I think we can keep this for now. Let me know what you think. |
||
rt.tabLock.Lock() | ||
defer rt.tabLock.Unlock() | ||
|
||
for i := range rt.buckets { | ||
b := rt.buckets[i] | ||
b.updateAllWith(func(p *PeerInfo) { | ||
p.replaceable = false | ||
}) | ||
} | ||
} | ||
|
||
// GetPeerInfos returns the peer information that we've stored in the buckets | ||
func (rt *RoutingTable) GetPeerInfos() []PeerInfo { | ||
rt.tabLock.RLock() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add a comment here about us not needing a stable sort here just to call it out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.