@cryptotaxi247 / kubo / commits / 67ddab1e4

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",