-
Notifications
You must be signed in to change notification settings - Fork 36
/
bucket.go
165 lines (140 loc) · 4.18 KB
/
bucket.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//go:generate go run ./generate
package kbucket
import (
"container/list"
"time"
"github.com/libp2p/go-libp2p/core/peer"
)
// PeerInfo holds all related information for a peer in the K-Bucket.
type PeerInfo struct {
Id peer.ID
// 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
// AddedAt is the time this peer was added to the routing table.
AddedAt time.Time
// Id of the peer in the DHT XOR keyspace
dhtId ID
// if a bucket is full, this peer can be replaced to make space for a new peer.
replaceable bool
}
// bucket holds a list of peers.
// 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.
type bucket struct {
list *list.List
}
func newBucket() *bucket {
b := new(bucket)
b.list = list.New()
return b
}
// returns all peers in the bucket
// it is safe for the caller to modify the returned objects as it is a defensive copy
func (b *bucket) peers() []PeerInfo {
ps := make([]PeerInfo, 0, b.len())
for e := b.list.Front(); e != nil; e = e.Next() {
p := e.Value.(*PeerInfo)
ps = append(ps, *p)
}
return ps
}
// returns the "minimum" peer in the bucket based on the `lessThan` comparator passed to it.
// It is NOT safe for the comparator to mutate the given `PeerInfo`
// as we pass in a pointer to it.
// It is NOT safe to modify the returned value.
func (b *bucket) min(lessThan func(p1 *PeerInfo, p2 *PeerInfo) bool) *PeerInfo {
if b.list.Len() == 0 {
return nil
}
minVal := b.list.Front().Value.(*PeerInfo)
for e := b.list.Front().Next(); e != nil; e = e.Next() {
val := e.Value.(*PeerInfo)
if lessThan(val, minVal) {
minVal = val
}
}
return minVal
}
// updateAllWith updates all the peers in the bucket by applying the given update function.
func (b *bucket) updateAllWith(updateFnc func(p *PeerInfo)) {
for e := b.list.Front(); e != nil; e = e.Next() {
val := e.Value.(*PeerInfo)
updateFnc(val)
}
}
// return the Ids of all the peers in the bucket.
func (b *bucket) peerIds() []peer.ID {
ps := make([]peer.ID, 0, b.list.Len())
for e := b.list.Front(); e != nil; e = e.Next() {
p := e.Value.(*PeerInfo)
ps = append(ps, p.Id)
}
return ps
}
// returns the peer with the given Id if it exists
// returns nil if the peerId does not exist
func (b *bucket) getPeer(p peer.ID) *PeerInfo {
for e := b.list.Front(); e != nil; e = e.Next() {
if e.Value.(*PeerInfo).Id == p {
return e.Value.(*PeerInfo)
}
}
return nil
}
// removes the peer with the given Id from the bucket.
// returns true if successful, false otherwise.
func (b *bucket) remove(id peer.ID) bool {
for e := b.list.Front(); e != nil; e = e.Next() {
if e.Value.(*PeerInfo).Id == id {
b.list.Remove(e)
return true
}
}
return false
}
func (b *bucket) pushFront(p *PeerInfo) {
b.list.PushFront(p)
}
func (b *bucket) len() int {
return b.list.Len()
}
// splits a buckets peers into two buckets, the methods receiver will have
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
func (b *bucket) split(cpl int, target ID) *bucket {
out := list.New()
newbuck := newBucket()
newbuck.list = out
e := b.list.Front()
for e != nil {
pDhtId := e.Value.(*PeerInfo).dhtId
peerCPL := CommonPrefixLen(pDhtId, target)
if peerCPL > cpl {
cur := e
out.PushBack(e.Value)
e = e.Next()
b.list.Remove(cur)
continue
}
e = e.Next()
}
return newbuck
}
// 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
}