tiered put/get implemented
Jeromy committed
Aug 9, 2014 at 22:28 UTC
67ddab1e4e7003a2a33bd9f9e38bc8aa0b5d9632
10 files changed
+287
-97
peer/peer.go
+3
-3
@@ -1,13 +1,13 @@
1
package peer
2
3
import (
4
- "time"
4
"sync"
5
+ "time"
6
7
+ b58 "github.com/jbenet/go-base58"
8
u "github.com/jbenet/go-ipfs/util"
9
ma "github.com/jbenet/go-multiaddr"
10
mh "github.com/jbenet/go-multihash"
10
- b58 "github.com/jbenet/go-base58"
11
12
"bytes"
13
)
@@ -33,7 +33,7 @@ type Peer struct {
33
ID ID
34
Addresses []*ma.Multiaddr
35
36
- latency time.Duration
36
+ latency time.Duration
37
latenLock sync.RWMutex
38
}
39
routing/dht/DHTMessage.go
+21
@@ -1,5 +1,9 @@
1
package dht
2
3
+import (
4
+ peer "github.com/jbenet/go-ipfs/peer"
5
+)
6
+
7
// A helper struct to make working with protbuf types easier
8
type DHTMessage struct {
9
Type PBDHTMessage_MessageType
@@ -8,6 +12,20 @@ type DHTMessage struct {
12
Response bool
13
Id uint64
14
Success bool
15
+ Peers []*peer.Peer
16
+}
17
+
18
+func peerInfo(p *peer.Peer) *PBDHTMessage_PBPeer {
19
+ pbp := new(PBDHTMessage_PBPeer)
20
+ addr, err := p.Addresses[0].String()
21
+ if err != nil {
22
+ //Temp: what situations could cause this?
23
+ panic(err)
24
+ }
25
+ pbp.Addr = &addr
26
+ pid := string(p.ID)
27
+ pbp.Id = &pid
28
+ return pbp
29
}
30
31
func (m *DHTMessage) ToProtobuf() *PBDHTMessage {
@@ -21,6 +39,9 @@ func (m *DHTMessage) ToProtobuf() *PBDHTMessage {
39
pmes.Response = &m.Response
40
pmes.Id = &m.Id
41
pmes.Success = &m.Success
42
+ for _, p := range m.Peers {
43
+ pmes.Peers = append(pmes.Peers, peerInfo(p))
44
+ }
45
46
return pmes
47
}
routing/dht/dht.go
+113
-24
@@ -8,9 +8,9 @@ import (
8
"time"
9
10
peer "github.com/jbenet/go-ipfs/peer"
11
+ kb "github.com/jbenet/go-ipfs/routing/kbucket"
12
swarm "github.com/jbenet/go-ipfs/swarm"
13
u "github.com/jbenet/go-ipfs/util"
13
- kb "github.com/jbenet/go-ipfs/routing/kbucket"
14
15
ma "github.com/jbenet/go-multiaddr"
16
@@ -37,7 +37,6 @@ type IpfsDHT struct {
37
datastore ds.Datastore
38
39
// Map keys to peers that can provide their value
40
- // TODO: implement a TTL on each of these keys
40
providers map[u.Key][]*providerInfo
41
providerLock sync.RWMutex
42
@@ -67,7 +66,7 @@ type listenInfo struct {
66
eol time.Time
67
}
68
70
-// Create a new DHT object with the given peer as the 'local' host
69
+// NewDHT creates a new DHT object with the given peer as the 'local' host
70
func NewDHT(p *peer.Peer) (*IpfsDHT, error) {
71
if p == nil {
72
return nil, errors.New("nil peer passed to NewDHT()")
@@ -111,7 +110,7 @@ func (dht *IpfsDHT) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
110
// NOTE: this should be done better...
111
err = dht.Ping(npeer, time.Second*2)
112
if err != nil {
114
- return nil, errors.New("Failed to ping newly connected peer.")
113
+ return nil, errors.New("failed to ping newly connected peer")
114
}
115
116
return npeer, nil
@@ -227,7 +226,7 @@ func (dht *IpfsDHT) cleanExpiredListeners() {
226
dht.listenLock.Unlock()
227
}
228
230
-func (dht *IpfsDHT) putValueToPeer(p *peer.Peer, key string, value []byte) error {
229
+func (dht *IpfsDHT) putValueToNetwork(p *peer.Peer, key string, value []byte) error {
230
pmes := DHTMessage{
231
Type: PBDHTMessage_PUT_VALUE,
232
Key: key,
@@ -242,26 +241,32 @@ func (dht *IpfsDHT) putValueToPeer(p *peer.Peer, key string, value []byte) error
241
242
func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *PBDHTMessage) {
243
dskey := ds.NewKey(pmes.GetKey())
245
- var resp *DHTMessage
246
- i_val, err := dht.datastore.Get(dskey)
244
+ resp := &DHTMessage{
245
+ Response: true,
246
+ Id: pmes.GetId(),
247
+ Key: pmes.GetKey(),
248
+ }
249
+ iVal, err := dht.datastore.Get(dskey)
250
if err == nil {
248
- resp = &DHTMessage{
249
- Response: true,
250
- Id: *pmes.Id,
251
- Key: *pmes.Key,
252
- Value: i_val.([]byte),
253
- Success: true,
254
- }
251
+ resp.Success = true
252
+ resp.Value = iVal.([]byte)
253
} else if err == ds.ErrNotFound {
256
- // Find closest peer(s) to desired key and reply with that info
257
- closer := dht.routes[0].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
258
- resp = &DHTMessage{
259
- Response: true,
260
- Id: *pmes.Id,
261
- Key: *pmes.Key,
262
- Value: closer.ID,
263
- Success: false,
254
+ // Check if we know any providers for the requested value
255
+ provs, ok := dht.providers[u.Key(pmes.GetKey())]
256
+ if ok && len(provs) > 0 {
257
+ for _, prov := range provs {
258
+ resp.Peers = append(resp.Peers, prov.Value)
259
+ }
260
+ resp.Success = true
261
+ } else {
262
+ // No providers?
263
+ // Find closest peer(s) to desired key and reply with that info
264
+ closer := dht.routes[0].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
265
+ resp.Peers = []*peer.Peer{closer}
266
}
267
+ } else {
268
+ //temp: what other errors can a datastore throw?
269
+ panic(err)
270
}
271
272
mes := swarm.NewMessage(p, resp.ToProtobuf())
@@ -397,6 +402,7 @@ func (dht *IpfsDHT) Unlisten(mesid uint64) {
402
close(list.resp)
403
}
404
405
+// Check whether or not the dht is currently listening for mesid
406
func (dht *IpfsDHT) IsListening(mesid uint64) bool {
407
dht.listenLock.RLock()
408
li, ok := dht.listeners[mesid]
@@ -424,6 +430,7 @@ func (dht *IpfsDHT) addProviderEntry(key u.Key, p *peer.Peer) {
430
dht.providerLock.Unlock()
431
}
432
433
+// NOTE: not yet finished, low priority
434
func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
435
dht.diaglock.Lock()
436
if dht.IsListening(pmes.GetId()) {
@@ -434,7 +441,7 @@ func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
441
dht.diaglock.Unlock()
442
443
seq := dht.routes[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
437
- listen_chan := dht.ListenFor(pmes.GetId(), len(seq), time.Second*30)
444
+ listenChan := dht.ListenFor(pmes.GetId(), len(seq), time.Second*30)
445
446
for _, ps := range seq {
447
mes := swarm.NewMessage(ps, pmes)
@@ -453,7 +460,7 @@ func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
460
case <-after:
461
//Timeout, return what we have
462
goto out
456
- case req_resp := <-listen_chan:
463
+ case req_resp := <-listenChan:
464
pmes_out := new(PBDHTMessage)
465
err := proto.Unmarshal(req_resp.Data, pmes_out)
466
if err != nil {
@@ -477,6 +484,77 @@ out:
484
dht.network.Chan.Outgoing <- mes
485
}
486
487
+func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duration) ([]byte, error) {
488
+ pmes := DHTMessage{
489
+ Type: PBDHTMessage_GET_VALUE,
490
+ Key: string(key),
491
+ Id: GenerateMessageID(),
492
+ }
493
+ response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
494
+
495
+ mes := swarm.NewMessage(p, pmes.ToProtobuf())
496
+ dht.network.Chan.Outgoing <- mes
497
+
498
+ // Wait for either the response or a timeout
499
+ timeup := time.After(timeout)
500
+ select {
501
+ case <-timeup:
502
+ dht.Unlisten(pmes.Id)
503
+ return nil, u.ErrTimeout
504
+ case resp, ok := <-response_chan:
505
+ if !ok {
506
+ u.PErr("response channel closed before timeout, please investigate.")
507
+ return nil, u.ErrTimeout
508
+ }
509
+ pmes_out := new(PBDHTMessage)
510
+ err := proto.Unmarshal(resp.Data, pmes_out)
511
+ if err != nil {
512
+ return nil, err
513
+ }
514
+ // TODO: debate moving this logic out of this function to be handled by the caller
515
+ if pmes_out.GetSuccess() {
516
+ if pmes_out.Value == nil {
517
+ // We were given provider[s]
518
+ return dht.getFromProviderList(key, timeout, pmes_out.GetPeers())
519
+ }
520
+ // We were given the value
521
+ return pmes_out.GetValue(), nil
522
+ } else {
523
+ return pmes_out.GetValue(), u.ErrSearchIncomplete
524
+ }
525
+ }
526
+}
527
+
528
+// TODO: Im not certain on this implementation, we get a list of providers from someone
529
+// what do we do with it? Connect to each of them? randomly pick one to get the value from?
530
+// Or just connect to one at a time until we get a successful connection and request the
531
+// value from it?
532
+func (dht *IpfsDHT) getFromProviderList(key u.Key, timeout time.Duration, provlist []*PBDHTMessage_PBPeer) ([]byte, error) {
533
+ for _, prov := range provlist {
534
+ prov_p, _ := dht.Find(peer.ID(prov.GetId()))
535
+ if prov_p == nil {
536
+ maddr, err := ma.NewMultiaddr(prov.GetAddr())
537
+ if err != nil {
538
+ u.PErr("getValue error: %s", err)
539
+ continue
540
+ }
541
+ prov_p, err = dht.Connect(maddr)
542
+ if err != nil {
543
+ u.PErr("getValue error: %s", err)
544
+ continue
545
+ }
546
+ }
547
+ data, err := dht.getValueSingle(prov_p, key, timeout)
548
+ if err != nil {
549
+ u.DErr("getFromProvs error: %s", err)
550
+ continue
551
+ }
552
+
553
+ return data, nil
554
+ }
555
+ return nil, u.ErrNotFound
556
+}
557
+
558
func (dht *IpfsDHT) GetLocal(key u.Key) ([]byte, error) {
559
v, err := dht.datastore.Get(ds.NewKey(string(key)))
560
if err != nil {
@@ -495,3 +573,14 @@ func (dht *IpfsDHT) Update(p *peer.Peer) {
573
dht.network.Drop(removed)
574
}
575
}
576
+
577
+// Look for a peer with a given ID connected to this dht
578
+func (dht *IpfsDHT) Find(id peer.ID) (*peer.Peer, *kb.RoutingTable) {
579
+ for _, table := range dht.routes {
580
+ p := table.Find(id)
581
+ if p != nil {
582
+ return p, table
583
+ }
584
+ }
585
+ return nil, nil
586
+}
routing/dht/dht_test.go
+80
-4
@@ -90,15 +90,21 @@ func TestValueGetSet(t *testing.T) {
90
dht_a.Start()
91
dht_b.Start()
92
93
+ go func() {
94
+ select {
95
+ case err := <-dht_a.network.Chan.Errors:
96
+ t.Fatal(err)
97
+ case err := <-dht_b.network.Chan.Errors:
98
+ t.Fatal(err)
99
+ }
100
+ }()
101
+
102
_, err = dht_a.Connect(addr_b)
103
if err != nil {
104
t.Fatal(err)
105
}
106
98
- err = dht_a.PutValue("hello", []byte("world"))
99
- if err != nil {
100
- t.Fatal(err)
101
- }
107
+ dht_a.PutValue("hello", []byte("world"))
108
109
val, err := dht_a.GetValue("hello", time.Second*2)
110
if err != nil {
@@ -179,3 +185,73 @@ func TestProvides(t *testing.T) {
185
dhts[i].Halt()
186
}
187
}
188
+
189
+func TestLayeredGet(t *testing.T) {
190
+ u.Debug = false
191
+ var addrs []*ma.Multiaddr
192
+ for i := 0; i < 4; i++ {
193
+ a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
194
+ if err != nil {
195
+ t.Fatal(err)
196
+ }
197
+ addrs = append(addrs, a)
198
+ }
199
+
200
+ var peers []*peer.Peer
201
+ for i := 0; i < 4; i++ {
202
+ p := new(peer.Peer)
203
+ p.AddAddress(addrs[i])
204
+ p.ID = peer.ID([]byte(fmt.Sprintf("peer_%d", i)))
205
+ peers = append(peers, p)
206
+ }
207
+
208
+ var dhts []*IpfsDHT
209
+ for i := 0; i < 4; i++ {
210
+ d, err := NewDHT(peers[i])
211
+ if err != nil {
212
+ t.Fatal(err)
213
+ }
214
+ dhts = append(dhts, d)
215
+ d.Start()
216
+ }
217
+
218
+ _, err := dhts[0].Connect(addrs[1])
219
+ if err != nil {
220
+ t.Fatal(err)
221
+ }
222
+
223
+ _, err = dhts[1].Connect(addrs[2])
224
+ if err != nil {
225
+ t.Fatal(err)
226
+ }
227
+
228
+ _, err = dhts[1].Connect(addrs[3])
229
+ if err != nil {
230
+ t.Fatal(err)
231
+ }
232
+
233
+ err = dhts[3].PutLocal(u.Key("hello"), []byte("world"))
234
+ if err != nil {
235
+ t.Fatal(err)
236
+ }
237
+
238
+ err = dhts[3].Provide(u.Key("hello"))
239
+ if err != nil {
240
+ t.Fatal(err)
241
+ }
242
+
243
+ time.Sleep(time.Millisecond * 60)
244
+
245
+ val, err := dhts[0].GetValue(u.Key("hello"), time.Second)
246
+ if err != nil {
247
+ t.Fatal(err)
248
+ }
249
+
250
+ if string(val) != "world" {
251
+ t.Fatal("Got incorrect value.")
252
+ }
253
+
254
+ for i := 0; i < 4; i++ {
255
+ dhts[i].Halt()
256
+ }
257
+}
routing/dht/diag.go
+5
-6
@@ -9,14 +9,14 @@ import (
9
10
type connDiagInfo struct {
11
Latency time.Duration
12
- Id peer.ID
12
+ Id peer.ID
13
}
14
15
type diagInfo struct {
16
- Id peer.ID
16
+ Id peer.ID
17
Connections []connDiagInfo
18
- Keys []string
19
- LifeSpan time.Duration
18
+ Keys []string
19
+ LifeSpan time.Duration
20
CodeVersion string
21
}
22
@@ -29,7 +29,6 @@ func (di *diagInfo) Marshal() []byte {
29
return b
30
}
31
32
-
32
func (dht *IpfsDHT) getDiagInfo() *diagInfo {
33
di := new(diagInfo)
34
di.CodeVersion = "github.com/jbenet/go-ipfs"
@@ -37,7 +36,7 @@ func (dht *IpfsDHT) getDiagInfo() *diagInfo {
36
di.LifeSpan = time.Since(dht.birth)
37
di.Keys = nil // Currently no way to query datastore
38
40
- for _,p := range dht.routes[0].Listpeers() {
39
+ for _, p := range dht.routes[0].Listpeers() {
40
di.Connections = append(di.Connections, connDiagInfo{p.GetLatency(), p.ID})
41
}
42
return di
routing/dht/routing.go
+39
-46
@@ -4,6 +4,7 @@ import (
4
"bytes"
5
"encoding/json"
6
"errors"
7
+ "fmt"
8
"math/rand"
9
"time"
10
@@ -32,58 +33,50 @@ func GenerateMessageID() uint64 {
33
34
// PutValue adds value corresponding to given Key.
35
// This is the top level "Store" operation of the DHT
35
-func (s *IpfsDHT) PutValue(key u.Key, value []byte) error {
36
- var p *peer.Peer
37
- p = s.routes[0].NearestPeer(kb.ConvertKey(key))
38
- if p == nil {
39
- return errors.New("Table returned nil peer!")
36
+func (s *IpfsDHT) PutValue(key u.Key, value []byte) {
37
+ complete := make(chan struct{})
38
+ for i, route := range s.routes {
39
+ p := route.NearestPeer(kb.ConvertKey(key))
40
+ if p == nil {
41
+ s.network.Chan.Errors <- fmt.Errorf("No peer found on level %d", i)
42
+ continue
43
+ go func() {
44
+ complete <- struct{}{}
45
+ }()
46
+ }
47
+ go func() {
48
+ err := s.putValueToNetwork(p, string(key), value)
49
+ if err != nil {
50
+ s.network.Chan.Errors <- err
51
+ }
52
+ complete <- struct{}{}
53
+ }()
54
+ }
55
+ for _, _ = range s.routes {
56
+ <-complete
57
}
41
-
42
- return s.putValueToPeer(p, string(key), value)
58
}
59
60
// GetValue searches for the value corresponding to given Key.
61
// If the search does not succeed, a multiaddr string of a closer peer is
62
// returned along with util.ErrSearchIncomplete
63
func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
49
- var p *peer.Peer
50
- p = s.routes[0].NearestPeer(kb.ConvertKey(key))
51
- if p == nil {
52
- return nil, errors.New("Table returned nil peer!")
53
- }
54
-
55
- pmes := DHTMessage{
56
- Type: PBDHTMessage_GET_VALUE,
57
- Key: string(key),
58
- Id: GenerateMessageID(),
59
- }
60
- response_chan := s.ListenFor(pmes.Id, 1, time.Minute)
61
-
62
- mes := swarm.NewMessage(p, pmes.ToProtobuf())
63
- s.network.Chan.Outgoing <- mes
64
+ for _, route := range s.routes {
65
+ var p *peer.Peer
66
+ p = route.NearestPeer(kb.ConvertKey(key))
67
+ if p == nil {
68
+ return nil, errors.New("Table returned nil peer!")
69
+ }
70
65
- // Wait for either the response or a timeout
66
- timeup := time.After(timeout)
67
- select {
68
- case <-timeup:
69
- s.Unlisten(pmes.Id)
70
- return nil, u.ErrTimeout
71
- case resp, ok := <-response_chan:
72
- if !ok {
73
- u.PErr("response channel closed before timeout, please investigate.")
74
- return nil, u.ErrTimeout
71
+ b, err := s.getValueSingle(p, key, timeout)
72
+ if err == nil {
73
+ return b, nil
74
}
76
- pmes_out := new(PBDHTMessage)
77
- err := proto.Unmarshal(resp.Data, pmes_out)
78
- if err != nil {
75
+ if err != u.ErrSearchIncomplete {
76
return nil, err
77
}
81
- if pmes_out.GetSuccess() {
82
- return pmes_out.GetValue(), nil
83
- } else {
84
- return pmes_out.GetValue(), u.ErrSearchIncomplete
85
- }
78
}
79
+ return nil, u.ErrNotFound
80
}
81
82
// Value provider layer of indirection.
@@ -121,7 +114,7 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
114
115
mes := swarm.NewMessage(p, pmes.ToProtobuf())
116
124
- listen_chan := s.ListenFor(pmes.Id, 1, time.Minute)
117
+ listenChan := s.ListenFor(pmes.Id, 1, time.Minute)
118
u.DOut("Find providers for: '%s'", key)
119
s.network.Chan.Outgoing <- mes
120
after := time.After(timeout)
@@ -129,7 +122,7 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
122
case <-after:
123
s.Unlisten(pmes.Id)
124
return nil, u.ErrTimeout
132
- case resp := <-listen_chan:
125
+ case resp := <-listenChan:
126
u.DOut("FindProviders: got response.")
127
pmes_out := new(PBDHTMessage)
128
err := proto.Unmarshal(resp.Data, pmes_out)
@@ -179,14 +172,14 @@ func (s *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, error
172
173
mes := swarm.NewMessage(p, pmes.ToProtobuf())
174
182
- listen_chan := s.ListenFor(pmes.Id, 1, time.Minute)
175
+ listenChan := s.ListenFor(pmes.Id, 1, time.Minute)
176
s.network.Chan.Outgoing <- mes
177
after := time.After(timeout)
178
select {
179
case <-after:
180
s.Unlisten(pmes.Id)
181
return nil, u.ErrTimeout
189
- case resp := <-listen_chan:
182
+ case resp := <-listenChan:
183
pmes_out := new(PBDHTMessage)
184
err := proto.Unmarshal(resp.Data, pmes_out)
185
if err != nil {
@@ -251,7 +244,7 @@ func (dht *IpfsDHT) GetDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
244
Id: GenerateMessageID(),
245
}
246
254
- listen_chan := dht.ListenFor(pmes.Id, len(targets), time.Minute*2)
247
+ listenChan := dht.ListenFor(pmes.Id, len(targets), time.Minute*2)
248
249
pbmes := pmes.ToProtobuf()
250
for _, p := range targets {
@@ -266,7 +259,7 @@ func (dht *IpfsDHT) GetDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
259
case <-after:
260
u.DOut("Diagnostic request timed out.")
261
return out, u.ErrTimeout
269
- case resp := <-listen_chan:
262
+ case resp := <-listenChan:
263
pmes_out := new(PBDHTMessage)
264
err := proto.Unmarshal(resp.Data, pmes_out)
265
if err != nil {
routing/kbucket/bucket.go
+1
@@ -5,6 +5,7 @@ import (
5
6
peer "github.com/jbenet/go-ipfs/peer"
7
)
8
+
9
// Bucket holds a list of peers.
10
type Bucket list.List
11
routing/kbucket/table.go
+23
-12
@@ -19,7 +19,7 @@ type RoutingTable struct {
19
tabLock sync.RWMutex
20
21
// kBuckets define all the fingers to other nodes.
22
- Buckets []*Bucket
22
+ Buckets []*Bucket
23
bucketsize int
24
}
25
@@ -52,7 +52,7 @@ func (rt *RoutingTable) Update(p *peer.Peer) *peer.Peer {
52
53
// Are we past the max bucket size?
54
if bucket.Len() > rt.bucketsize {
55
- if b_id == len(rt.Buckets) - 1 {
55
+ if b_id == len(rt.Buckets)-1 {
56
new_bucket := bucket.Split(b_id, rt.local)
57
rt.Buckets = append(rt.Buckets, new_bucket)
58
if new_bucket.Len() > rt.bucketsize {
@@ -81,25 +81,27 @@ func (rt *RoutingTable) Update(p *peer.Peer) *peer.Peer {
81
82
// A helper struct to sort peers by their distance to the local node
83
type peerDistance struct {
84
- p *peer.Peer
84
+ p *peer.Peer
85
distance ID
86
}
87
88
// peerSorterArr implements sort.Interface to sort peers by xor distance
89
type peerSorterArr []*peerDistance
90
-func (p peerSorterArr) Len() int {return len(p)}
91
-func (p peerSorterArr) Swap(a, b int) {p[a],p[b] = p[b],p[a]}
90
+
91
+func (p peerSorterArr) Len() int { return len(p) }
92
+func (p peerSorterArr) Swap(a, b int) { p[a], p[b] = p[b], p[a] }
93
func (p peerSorterArr) Less(a, b int) bool {
94
return p[a].distance.Less(p[b].distance)
95
}
96
+
97
//
98
99
func copyPeersFromList(target ID, peerArr peerSorterArr, peerList *list.List) peerSorterArr {
98
- for e := peerList.Front(); e != nil; e = e.Next() {
100
+ for e := peerList.Front(); e != nil; e = e.Next() {
101
p := e.Value.(*peer.Peer)
102
p_id := ConvertPeerID(p.ID)
103
pd := peerDistance{
102
- p: p,
104
+ p: p,
105
distance: xor(target, p_id),
106
}
107
peerArr = append(peerArr, &pd)
@@ -111,6 +113,15 @@ func copyPeersFromList(target ID, peerArr peerSorterArr, peerList *list.List) pe
113
return peerArr
114
}
115
116
+// Find a specific peer by ID or return nil
117
+func (rt *RoutingTable) Find(id peer.ID) *peer.Peer {
118
+ srch := rt.NearestPeers(ConvertPeerID(id), 1)
119
+ if len(srch) == 0 || !srch[0].ID.Equal(id) {
120
+ return nil
121
+ }
122
+ return srch[0]
123
+}
124
+
125
// Returns a single peer that is nearest to the given ID
126
func (rt *RoutingTable) NearestPeer(id ID) *peer.Peer {
127
peers := rt.NearestPeers(id, 1)
@@ -139,12 +150,12 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
150
// In the case of an unusual split, one bucket may be empty.
151
// if this happens, search both surrounding buckets for nearest peer
152
if cpl > 0 {
142
- plist := (*list.List)(rt.Buckets[cpl - 1])
153
+ plist := (*list.List)(rt.Buckets[cpl-1])
154
peerArr = copyPeersFromList(id, peerArr, plist)
155
}
156
146
- if cpl < len(rt.Buckets) - 1 {
147
- plist := (*list.List)(rt.Buckets[cpl + 1])
157
+ if cpl < len(rt.Buckets)-1 {
158
+ plist := (*list.List)(rt.Buckets[cpl+1])
159
peerArr = copyPeersFromList(id, peerArr, plist)
160
}
161
} else {
@@ -166,7 +177,7 @@ func (rt *RoutingTable) NearestPeers(id ID, count int) []*peer.Peer {
177
// Returns the total number of peers in the routing table
178
func (rt *RoutingTable) Size() int {
179
var tot int
169
- for _,buck := range rt.Buckets {
180
+ for _, buck := range rt.Buckets {
181
tot += buck.Len()
182
}
183
return tot
@@ -175,7 +186,7 @@ func (rt *RoutingTable) Size() int {
186
// NOTE: This is potentially unsafe... use at your own risk
187
func (rt *RoutingTable) Listpeers() []*peer.Peer {
188
var peers []*peer.Peer
178
- for _,buck := range rt.Buckets {
189
+ for _, buck := range rt.Buckets {
190
for e := buck.getIter(); e != nil; e = e.Next() {
191
peers = append(peers, e.Value.(*peer.Peer))
192
}
routing/kbucket/table_test.go
+1
-1
@@ -1,10 +1,10 @@
1
package dht
2
3
import (
4
+ "container/list"
5
crand "crypto/rand"
6
"crypto/sha256"
7
"math/rand"
7
- "container/list"
8
"testing"
9
10
peer "github.com/jbenet/go-ipfs/peer"
swarm/swarm_test.go
+1
-1
@@ -44,7 +44,7 @@ func TestSwarm(t *testing.T) {
44
45
swarm := NewSwarm(nil)
46
var peers []*peer.Peer
47
- var listeners []net.Listener
47
+ var listeners []net.Listener
48
peerNames := map[string]string{
49
"11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a30": "/ip4/127.0.0.1/tcp/1234",
50
"11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31": "/ip4/127.0.0.1/tcp/2345",