routing/kbucket: cleaner "public" interface for bucket
Juan Batiz-Benet committed
Feb 5, 2015 at 06:22 UTC
e92a33f442a00a2d7d12afc6cdc637efcb8e08c2
3 files changed
+51
-49
routing/kbucket/bucket.go
+14
-10
@@ -30,18 +30,18 @@ func (b *Bucket) Peers() []peer.ID {
30
return ps
31
}
32
33
-func (b *Bucket) find(id peer.ID) *list.Element {
33
+func (b *Bucket) Has(id peer.ID) bool {
34
b.lk.RLock()
35
defer b.lk.RUnlock()
36
for e := b.list.Front(); e != nil; e = e.Next() {
37
if e.Value.(peer.ID) == id {
38
- return e
38
+ return true
39
}
40
}
41
- return nil
41
+ return false
42
}
43
44
-func (b *Bucket) remove(id peer.ID) {
44
+func (b *Bucket) Remove(id peer.ID) {
45
b.lk.Lock()
46
defer b.lk.Unlock()
47
for e := b.list.Front(); e != nil; e = e.Next() {
@@ -51,19 +51,23 @@ func (b *Bucket) remove(id peer.ID) {
51
}
52
}
53
54
-func (b *Bucket) moveToFront(e *list.Element) {
54
+func (b *Bucket) MoveToFront(id peer.ID) {
55
b.lk.Lock()
56
- b.list.MoveToFront(e)
57
- b.lk.Unlock()
56
+ defer b.lk.Unlock()
57
+ for e := b.list.Front(); e != nil; e = e.Next() {
58
+ if e.Value.(peer.ID) == id {
59
+ b.list.MoveToFront(e)
60
+ }
61
+ }
62
}
63
60
-func (b *Bucket) pushFront(p peer.ID) {
64
+func (b *Bucket) PushFront(p peer.ID) {
65
b.lk.Lock()
66
b.list.PushFront(p)
67
b.lk.Unlock()
68
}
69
66
-func (b *Bucket) popBack() peer.ID {
70
+func (b *Bucket) PopBack() peer.ID {
71
b.lk.Lock()
72
defer b.lk.Unlock()
73
last := b.list.Back()
@@ -71,7 +75,7 @@ func (b *Bucket) popBack() peer.ID {
75
return last.Value.(peer.ID)
76
}
77
74
-func (b *Bucket) len() int {
78
+func (b *Bucket) Len() int {
79
b.lk.RLock()
80
defer b.lk.RUnlock()
81
return b.list.Len()
routing/kbucket/table.go
+34
-32
@@ -46,7 +46,7 @@ func NewRoutingTable(bucketsize int, localID ID, latency time.Duration, m peer.M
46
47
// Update adds or moves the given peer to the front of its respective bucket
48
// If a peer gets removed from a bucket, it is returned
49
-func (rt *RoutingTable) Update(p peer.ID) peer.ID {
49
+func (rt *RoutingTable) Update(p peer.ID) {
50
rt.tabLock.Lock()
51
defer rt.tabLock.Unlock()
52
peerID := ConvertPeerID(p)
@@ -58,33 +58,35 @@ func (rt *RoutingTable) Update(p peer.ID) peer.ID {
58
}
59
60
bucket := rt.Buckets[bucketID]
61
- e := bucket.find(p)
62
- if e == nil {
63
- // New peer, add to bucket
64
- if rt.metrics.LatencyEWMA(p) > rt.maxLatency {
65
- // Connection doesnt meet requirements, skip!
66
- return ""
67
- }
68
- bucket.pushFront(p)
69
-
70
- // Are we past the max bucket size?
71
- if bucket.len() > rt.bucketsize {
72
- // If this bucket is the rightmost bucket, and its full
73
- // we need to split it and create a new bucket
74
- if bucketID == len(rt.Buckets)-1 {
75
- return rt.nextBucket()
76
- } else {
77
- // If the bucket cant split kick out least active node
78
- return bucket.popBack()
79
- }
61
+ if bucket.Has(p) {
62
+ // If the peer is already in the table, move it to the front.
63
+ // This signifies that it it "more active" and the less active nodes
64
+ // Will as a result tend towards the back of the list
65
+ bucket.MoveToFront(p)
66
+ return
67
+ }
68
+
69
+ if rt.metrics.LatencyEWMA(p) > rt.maxLatency {
70
+ // Connection doesnt meet requirements, skip!
71
+ return
72
+ }
73
+
74
+ // New peer, add to bucket
75
+ bucket.PushFront(p)
76
+
77
+ // Are we past the max bucket size?
78
+ if bucket.Len() > rt.bucketsize {
79
+ // If this bucket is the rightmost bucket, and its full
80
+ // we need to split it and create a new bucket
81
+ if bucketID == len(rt.Buckets)-1 {
82
+ rt.nextBucket()
83
+ return
84
+ } else {
85
+ // If the bucket cant split kick out least active node
86
+ bucket.PopBack()
87
+ return
88
}
81
- return ""
89
}
83
- // If the peer is already in the table, move it to the front.
84
- // This signifies that it it "more active" and the less active nodes
85
- // Will as a result tend towards the back of the list
86
- bucket.moveToFront(e)
87
- return ""
90
}
91
92
// Remove deletes a peer from the routing table. This is to be used
@@ -101,20 +103,20 @@ func (rt *RoutingTable) Remove(p peer.ID) {
103
}
104
105
bucket := rt.Buckets[bucketID]
104
- bucket.remove(p)
106
+ bucket.Remove(p)
107
}
108
109
func (rt *RoutingTable) nextBucket() peer.ID {
110
bucket := rt.Buckets[len(rt.Buckets)-1]
111
newBucket := bucket.Split(len(rt.Buckets)-1, rt.local)
112
rt.Buckets = append(rt.Buckets, newBucket)
111
- if newBucket.len() > rt.bucketsize {
113
+ if newBucket.Len() > rt.bucketsize {
114
return rt.nextBucket()
115
}
116
117
// If all elements were on left side of split...
116
- if bucket.len() > rt.bucketsize {
117
- return bucket.popBack()
118
+ if bucket.Len() > rt.bucketsize {
119
+ return bucket.PopBack()
120
}
121
return ""
122
}
@@ -153,7 +155,7 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.ID {
155
bucket = rt.Buckets[cpl]
156
157
var peerArr peerSorterArr
156
- if bucket.len() == 0 {
158
+ if bucket.Len() == 0 {
159
// In the case of an unusual split, one bucket may be empty.
160
// if this happens, search both surrounding buckets for nearest peer
161
if cpl > 0 {
@@ -184,7 +186,7 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.ID {
186
func (rt *RoutingTable) Size() int {
187
var tot int
188
for _, buck := range rt.Buckets {
187
- tot += buck.len()
189
+ tot += buck.Len()
190
}
191
return tot
192
}
routing/kbucket/table_test.go
+3
-7
@@ -17,15 +17,14 @@ func TestBucket(t *testing.T) {
17
peers := make([]peer.ID, 100)
18
for i := 0; i < 100; i++ {
19
peers[i] = tu.RandPeerIDFatal(t)
20
- b.pushFront(peers[i])
20
+ b.PushFront(peers[i])
21
}
22
23
local := tu.RandPeerIDFatal(t)
24
localID := ConvertPeerID(local)
25
26
i := rand.Intn(len(peers))
27
- e := b.find(peers[i])
28
- if e == nil {
27
+ if !b.Has(peers[i]) {
28
t.Errorf("Failed to find peer: %v", peers[i])
29
}
30
@@ -62,10 +61,7 @@ func TestTableUpdate(t *testing.T) {
61
62
// Testing Update
63
for i := 0; i < 10000; i++ {
65
- p := rt.Update(peers[rand.Intn(len(peers))])
66
- if p != "" {
67
- //t.Log("evicted peer.")
68
- }
64
+ rt.Update(peers[rand.Intn(len(peers))])
65
}
66
67
for i := 0; i < 100; i++ {