bucket.go 3.33 KB
Newer Older
1 2
//go:generate go run ./generate

3
package kbucket
4 5 6

import (
	"container/list"
7
	"time"
Jeromy's avatar
Jeromy committed
8

9
	"github.com/libp2p/go-libp2p-core/peer"
10 11
)

Aarsh Shah's avatar
Aarsh Shah committed
12 13
// PeerInfo holds all related information for a peer in the K-Bucket.
type PeerInfo struct {
14
	Id peer.ID
Aarsh Shah's avatar
Aarsh Shah committed
15 16 17 18 19 20 21 22

	// LastUsefulAt is the time instant at which the peer was last "useful" to us.
	// Please see the DHT docs for the definition of usefulness.
	LastUsefulAt time.Time

	// LastSuccessfulOutboundQueryAt is the time instant at which we last got a
	// successful query response from the peer.
	LastSuccessfulOutboundQueryAt time.Time
23 24 25

	// Id of the peer in the DHT XOR keyspace
	dhtId ID
26 27 28
}

// bucket holds a list of peers.
Aarsh Shah's avatar
Aarsh Shah committed
29 30 31 32
// we synchronize on the Routing Table lock for all access to the bucket
// and so do not need any locks in the bucket.
// if we want/need to avoid locking the table for accessing a bucket in the future,
// it WILL be the caller's responsibility to synchronize all access to a bucket.
33
type bucket struct {
34 35 36
	list *list.List
}

37 38
func newBucket() *bucket {
	b := new(bucket)
39 40 41
	b.list = list.New()
	return b
}
42

43
// returns all peers in the bucket
Aarsh Shah's avatar
Aarsh Shah committed
44
// it is safe for the caller to modify the returned objects as it is a defensive copy
Aarsh Shah's avatar
Aarsh Shah committed
45 46
func (b *bucket) peers() []PeerInfo {
	var ps []PeerInfo
47
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
48
		p := e.Value.(*PeerInfo)
Aarsh Shah's avatar
Aarsh Shah committed
49
		ps = append(ps, *p)
50 51 52 53 54 55
	}
	return ps
}

// return the Ids of all the peers in the bucket.
func (b *bucket) peerIds() []peer.ID {
56 57
	ps := make([]peer.ID, 0, b.list.Len())
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
58
		p := e.Value.(*PeerInfo)
59
		ps = append(ps, p.Id)
60 61 62 63
	}
	return ps
}

Aarsh Shah's avatar
Aarsh Shah committed
64 65
// returns the peer with the given Id if it exists
// returns nil if the peerId does not exist
Aarsh Shah's avatar
Aarsh Shah committed
66
func (b *bucket) getPeer(p peer.ID) *PeerInfo {
67
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
68 69
		if e.Value.(*PeerInfo).Id == p {
			return e.Value.(*PeerInfo)
70 71
		}
	}
Aarsh Shah's avatar
Aarsh Shah committed
72
	return nil
73 74
}

75 76 77
// removes the peer with the given Id from the bucket.
// returns true if successful, false otherwise.
func (b *bucket) remove(id peer.ID) bool {
78
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
79
		if e.Value.(*PeerInfo).Id == id {
80
			b.list.Remove(e)
81
			return true
82 83
		}
	}
84
	return false
85 86
}

87 88
func (b *bucket) moveToFront(id peer.ID) {

89
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
90
		if e.Value.(*PeerInfo).Id == id {
91 92 93
			b.list.MoveToFront(e)
		}
	}
94 95
}

Aarsh Shah's avatar
Aarsh Shah committed
96
func (b *bucket) pushFront(p *PeerInfo) {
97
	b.list.PushFront(p)
98 99
}

100
func (b *bucket) len() int {
101
	return b.list.Len()
102 103
}

104
// splits a buckets peers into two buckets, the methods receiver will have
105 106
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
107
func (b *bucket) split(cpl int, target ID) *bucket {
108
	out := list.New()
109
	newbuck := newBucket()
110 111
	newbuck.list = out
	e := b.list.Front()
112
	for e != nil {
Aarsh Shah's avatar
Aarsh Shah committed
113
		pDhtId := e.Value.(*PeerInfo).dhtId
114
		peerCPL := CommonPrefixLen(pDhtId, target)
115
		if peerCPL > cpl {
116 117 118
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
119
			b.list.Remove(cur)
120 121 122 123
			continue
		}
		e = e.Next()
	}
124
	return newbuck
125
}
126 127 128 129 130 131 132 133 134 135 136 137 138

// maxCommonPrefix returns the maximum common prefix length between any peer in
// the bucket with the target ID.
func (b *bucket) maxCommonPrefix(target ID) uint {
	maxCpl := uint(0)
	for e := b.list.Front(); e != nil; e = e.Next() {
		cpl := uint(CommonPrefixLen(e.Value.(*PeerInfo).dhtId, target))
		if cpl > maxCpl {
			maxCpl = cpl
		}
	}
	return maxCpl
}