// Update adds or moves the given peer to the front of its respective bucket // If a peer gets removed from a bucket, it is returned func (rt *RoutingTable) Update(p *peer.Peer) *peer.Peer { rt.tabLock.Lock() defer rt.tabLock.Unlock() peerID := ConvertPeerID(p.ID) cpl := xor(peerID, rt.local).commonPrefixLen() bucketID := cpl if bucketID >= len(rt.Buckets) { bucketID = len(rt.Buckets) - 1 } bucket := rt.Buckets[bucketID] e := bucket.find(p.ID) if e == nil { // New peer, add to bucket if p.GetLatency() > rt.maxLatency { // Connection doesnt meet requirements, skip! return nil } bucket.pushFront(p) // Are we past the max bucket size? if bucket.len() > rt.bucketsize { if bucketID == len(rt.Buckets)-1 { newBucket := bucket.Split(bucketID, rt.local) rt.Buckets = append(rt.Buckets, newBucket) if newBucket.len() > rt.bucketsize { // TODO: This is a very rare and annoying case panic("Case not handled.") } // If all elements were on left side of split... if bucket.len() > rt.bucketsize { return bucket.popBack() } } else { // If the bucket cant split kick out least active node return bucket.popBack() } } return nil } // If the peer is already in the table, move it to the front. // This signifies that it it "more active" and the less active nodes // Will as a result tend towards the back of the list bucket.moveToFront(e) return nil }