Ejemplo n.º 1
0
// 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
}