@cryptotaxi247 / kubo / commits / a114e9cd1

better query processing (runner)

Juan Batiz-Benet committed Sep 18, 2014 at 19:30 UTC a114e9cd12fea900bfbf10af1989573a17b4ad10
5 files changed +291 -170
routing/dht/dht.go
+16 -8
@@ -177,6 +177,9 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p *peer.Peer, pmes *Message
177 if err != nil {
178 return nil, err
179 }
180 + if rmes == nil {
181 + return nil, errors.New("no response to request")
182 + }
183
184 rtt := time.Since(start)
185 rmes.Peer().SetLatency(rtt)
@@ -218,19 +221,22 @@ func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p *peer.Peer,
221 return nil, nil, err
222 }
223
224 + u.POut("pmes.GetValue() %v\n", pmes.GetValue())
225 if value := pmes.GetValue(); value != nil {
226 // Success! We were given the value
227 + u.POut("getValueOrPeers: got value\n")
228 return value, nil, nil
229 }
230
231 // TODO decide on providers. This probably shouldn't be happening.
227 - // if prv := pmes.GetProviderPeers(); prv != nil && len(prv) > 0 {
228 - // val, err := dht.getFromPeerList(key, timeout,, level)
229 - // if err != nil {
230 - // return nil, nil, err
231 - // }
232 - // return val, nil, nil
233 - // }
232 + if prv := pmes.GetProviderPeers(); prv != nil && len(prv) > 0 {
233 + val, err := dht.getFromPeerList(ctx, key, prv, level)
234 + if err != nil {
235 + return nil, nil, err
236 + }
237 + u.POut("getValueOrPeers: get from providers\n")
238 + return val, nil, nil
239 + }
240
241 // Perhaps we were given closer peers
242 var peers []*peer.Peer
@@ -256,10 +262,12 @@ func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p *peer.Peer,
262 }
263
264 if len(peers) > 0 {
265 + u.POut("getValueOrPeers: peers\n")
266 return nil, peers, nil
267 }
268
262 - return nil, nil, errors.New("NotFound. did not get value or closer peers.")
269 + u.POut("getValueOrPeers: u.ErrNotFound\n")
270 + return nil, nil, u.ErrNotFound
271 }
272
273 // getValueSingle simply performs the get value RPC with the given parameters
routing/dht/ext_test.go
+43 -39
@@ -18,14 +18,23 @@ import (
18 "time"
19 )
20
21 +// mesHandleFunc is a function that takes in outgoing messages
22 +// and can respond to them, simulating other peers on the network.
23 +// returning nil will chose not to respond and pass the message onto the
24 +// next registered handler
25 +type mesHandleFunc func(msg.NetMessage) msg.NetMessage
26 +
27 // fauxNet is a standin for a swarm.Network in order to more easily recreate
28 // different testing scenarios
29 type fauxSender struct {
30 handlers []mesHandleFunc
31 }
32
27 -func (f *fauxSender) SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) {
33 +func (f *fauxSender) AddHandler(fn func(msg.NetMessage) msg.NetMessage) {
34 + f.handlers = append(f.handlers, fn)
35 +}
36
37 +func (f *fauxSender) SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) {
38 for _, h := range f.handlers {
39 reply := h(m)
40 if reply != nil {
@@ -33,7 +42,12 @@ func (f *fauxSender) SendRequest(ctx context.Context, m msg.NetMessage) (msg.Net
42 }
43 }
44
36 - return nil, nil
45 + // no reply? ok force a timeout
46 + select {
47 + case <-ctx.Done():
48 + }
49 +
50 + return nil, ctx.Err()
51 }
52
53 func (f *fauxSender) SendMessage(ctx context.Context, m msg.NetMessage) error {
@@ -49,17 +63,6 @@ func (f *fauxSender) SendMessage(ctx context.Context, m msg.NetMessage) error {
63 // fauxNet is a standin for a swarm.Network in order to more easily recreate
64 // different testing scenarios
65 type fauxNet struct {
52 - handlers []mesHandleFunc
53 -}
54 -
55 -// mesHandleFunc is a function that takes in outgoing messages
56 -// and can respond to them, simulating other peers on the network.
57 -// returning nil will chose not to respond and pass the message onto the
58 -// next registered handler
59 -type mesHandleFunc func(msg.NetMessage) msg.NetMessage
60 -
61 -func (f *fauxNet) AddHandler(fn func(msg.NetMessage) msg.NetMessage) {
62 - f.handlers = append(f.handlers, fn)
66 }
67
68 // DialPeer attempts to establish a connection to a given peer
@@ -98,25 +101,23 @@ func TestGetFailures(t *testing.T) {
101 local.ID = peer.ID("test_peer")
102
103 d := NewDHT(local, peerstore, fn, fs, ds.NewMapDatastore())
101 -
104 other := &peer.Peer{ID: peer.ID("other_peer")}
103 -
104 - d.Start()
105 -
105 d.Update(other)
106
107 // This one should time out
108 + // u.POut("Timout Test\n")
109 _, err := d.GetValue(u.Key("test"), time.Millisecond*10)
110 if err != nil {
111 - if err != u.ErrTimeout {
112 - t.Fatal("Got different error than we expected.")
111 + if err != context.DeadlineExceeded {
112 + t.Fatal("Got different error than we expected", err)
113 }
114 } else {
115 t.Fatal("Did not get expected error!")
116 }
117
118 + // u.POut("NotFound Test\n")
119 // Reply with failures to every message
119 - fn.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
120 + fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
121 pmes := new(Message)
122 err := proto.Unmarshal(mes.Data(), pmes)
123 if err != nil {
@@ -140,18 +141,7 @@ func TestGetFailures(t *testing.T) {
141 t.Fatal("expected error, got none.")
142 }
143
143 - success := make(chan struct{})
144 - fn.handlers = nil
145 - fn.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
146 - resp := new(Message)
147 - err := proto.Unmarshal(mes.Data(), resp)
148 - if err != nil {
149 - t.Fatal(err)
150 - }
151 - success <- struct{}{}
152 - return nil
153 - })
154 -
144 + fs.handlers = nil
145 // Now we test this DHT's handleGetValue failure
146 typ := Message_GET_VALUE
147 str := "hello"
@@ -161,17 +151,32 @@ func TestGetFailures(t *testing.T) {
151 Value: []byte{0},
152 }
153
154 + // u.POut("handleGetValue Test\n")
155 mes, err := msg.FromObject(other, &req)
156 if err != nil {
157 t.Error(err)
158 }
159
169 - mes, err = fs.SendRequest(ctx, mes)
160 + mes, err = d.HandleMessage(ctx, mes)
161 if err != nil {
162 t.Error(err)
163 }
164
174 - <-success
165 + pmes := new(Message)
166 + err = proto.Unmarshal(mes.Data(), pmes)
167 + if err != nil {
168 + t.Fatal(err)
169 + }
170 + if pmes.GetValue() != nil {
171 + t.Fatal("shouldnt have value")
172 + }
173 + if pmes.GetCloserPeers() != nil {
174 + t.Fatal("shouldnt have closer peers")
175 + }
176 + if pmes.GetProviderPeers() != nil {
177 + t.Fatal("shouldnt have provider peers")
178 + }
179 +
180 }
181
182 // TODO: Maybe put these in some sort of "ipfs_testutil" package
@@ -192,7 +197,6 @@ func TestNotFound(t *testing.T) {
197 peerstore := peer.NewPeerstore()
198
199 d := NewDHT(local, peerstore, fn, fs, ds.NewMapDatastore())
195 - d.Start()
200
201 var ps []*peer.Peer
202 for i := 0; i < 5; i++ {
@@ -201,7 +205,7 @@ func TestNotFound(t *testing.T) {
205 }
206
207 // Reply with random peers to every message
204 - fn.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
208 + fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
209 pmes := new(Message)
210 err := proto.Unmarshal(mes.Data(), pmes)
211 if err != nil {
@@ -228,7 +232,8 @@ func TestNotFound(t *testing.T) {
232
233 })
234
231 - _, err := d.GetValue(u.Key("hello"), time.Second*30)
235 + v, err := d.GetValue(u.Key("hello"), time.Second*5)
236 + u.POut("get value got %v\n", v)
237 if err != nil {
238 switch err {
239 case u.ErrNotFound:
@@ -254,7 +259,6 @@ func TestLessThanKResponses(t *testing.T) {
259 local.ID = peer.ID("test_peer")
260
261 d := NewDHT(local, peerstore, fn, fs, ds.NewMapDatastore())
257 - d.Start()
262
263 var ps []*peer.Peer
264 for i := 0; i < 5; i++ {
@@ -264,7 +268,7 @@ func TestLessThanKResponses(t *testing.T) {
268 other := _randPeer()
269
270 // Reply with random peers to every message
267 - fn.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
271 + fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
272 pmes := new(Message)
273 err := proto.Unmarshal(mes.Data(), pmes)
274 if err != nil {
routing/dht/handlers.go
+7 -9
@@ -58,7 +58,10 @@ func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *Message) (*Message, error
58 return nil, err
59 }
60
61 - // if we have the value, respond with it!
61 + // Note: changed the behavior here to return _as much_ info as possible
62 + // (potentially all of {value, closer peers, provider})
63 +
64 + // if we have the value, send it back
65 if err == nil {
66 u.DOut("handleGetValue success!\n")
67
@@ -68,7 +71,6 @@ func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *Message) (*Message, error
71 }
72
73 resp.Value = byts
71 - return resp, nil
74 }
75
76 // if we know any providers for the requested value, return those.
@@ -76,20 +78,16 @@ func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *Message) (*Message, error
78 if len(provs) > 0 {
79 u.DOut("handleGetValue returning %d provider[s]\n", len(provs))
80 resp.ProviderPeers = peersToPBPeers(provs)
79 - return resp, nil
81 }
82
83 // Find closest peer on given cluster to desired key and reply with that info
84 closer := dht.betterPeerToQuery(pmes)
84 - if closer == nil {
85 - u.DOut("handleGetValue could not find a closer node than myself.\n")
86 - resp.CloserPeers = nil
85 + if closer != nil {
86 + u.DOut("handleGetValue returning a closer peer: '%s'\n", closer.ID.Pretty())
87 + resp.CloserPeers = peersToPBPeers([]*peer.Peer{closer})
88 return resp, nil
89 }
90
90 - // we got a closer peer, it seems. return it.
91 - u.DOut("handleGetValue returning a closer peer: '%s'\n", closer.ID.Pretty())
92 - resp.CloserPeers = peersToPBPeers([]*peer.Peer{closer})
91 return resp, nil
92 }
93
routing/dht/query.go
+181 -50
@@ -1,19 +1,45 @@
1 package dht
2
3 import (
4 + "sync"
5 +
6 peer "github.com/jbenet/go-ipfs/peer"
7 queue "github.com/jbenet/go-ipfs/peer/queue"
8 + kb "github.com/jbenet/go-ipfs/routing/kbucket"
9 u "github.com/jbenet/go-ipfs/util"
10 + todoctr "github.com/jbenet/go-ipfs/util/todocounter"
11
12 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
13 )
14
15 +const maxQueryConcurrency = 5
16 +
17 type dhtQuery struct {
12 - // a PeerQueue
13 - peers queue.PeerQueue
18 + // the key we're querying for
19 + key u.Key
20
21 // the function to execute per peer
22 qfunc queryFunc
23 +
24 + // the concurrency parameter
25 + concurrency int
26 +}
27 +
28 +type dhtQueryResult struct {
29 + value []byte // GetValue
30 + peer *peer.Peer // FindPeer
31 + providerPeers []*peer.Peer // GetProviders
32 + closerPeers []*peer.Peer // *
33 + success bool
34 +}
35 +
36 +// constructs query
37 +func newQuery(k u.Key, f queryFunc) *dhtQuery {
38 + return &dhtQuery{
39 + key: k,
40 + qfunc: f,
41 + concurrency: maxQueryConcurrency,
42 + }
43 }
44
45 // QueryFunc is a function that runs a particular query with a given peer.
@@ -21,65 +47,170 @@ type dhtQuery struct {
47 // - the value
48 // - a list of peers potentially better able to serve the query
49 // - an error
24 -type queryFunc func(context.Context, *peer.Peer) (interface{}, []*peer.Peer, error)
50 +type queryFunc func(context.Context, *peer.Peer) (*dhtQueryResult, error)
51 +
52 +// Run runs the query at hand. pass in a list of peers to use first.
53 +func (q *dhtQuery) Run(ctx context.Context, peers []*peer.Peer) (*dhtQueryResult, error) {
54 + runner := newQueryRunner(ctx, q)
55 + return runner.Run(peers)
56 +}
57 +
58 +type dhtQueryRunner struct {
59 +
60 + // the query to run
61 + query *dhtQuery
62 +
63 + // peersToQuery is a list of peers remaining to query
64 + peersToQuery *queue.ChanQueue
65 +
66 + // peersSeen are all the peers queried. used to prevent querying same peer 2x
67 + peersSeen peer.Map
68
26 -func (q *dhtQuery) Run(ctx context.Context, concurrency int) (interface{}, error) {
27 - // get own cancel function to signal when we've found the value
69 + // rateLimit is a channel used to rate limit our processing (semaphore)
70 + rateLimit chan struct{}
71 +
72 + // peersRemaining is a counter of peers remaining (toQuery + processing)
73 + peersRemaining todoctr.Counter
74 +
75 + // context
76 + ctx context.Context
77 + cancel context.CancelFunc
78 +
79 + // result
80 + result *dhtQueryResult
81 +
82 + // result errors
83 + errs []error
84 +
85 + // lock for concurrent access to fields
86 + sync.RWMutex
87 +}
88 +
89 +func newQueryRunner(ctx context.Context, q *dhtQuery) *dhtQueryRunner {
90 ctx, cancel := context.WithCancel(ctx)
91
30 - // the variable waiting to be populated upon success
31 - var result interface{}
32 -
33 - // chanQueue is how workers receive their work
34 - chanQueue := queue.NewChanQueue(ctx, q.peers)
35 -
36 - // worker
37 - worker := func() {
38 - for {
39 - select {
40 - case p := <-chanQueue.DeqChan:
41 -
42 - val, closer, err := q.qfunc(ctx, p)
43 - if err != nil {
44 - u.PErr("error running query: %v\n", err)
45 - continue
46 - }
47 -
48 - if val != nil {
49 - result = val
50 - cancel() // signal we're done.
51 - return
52 - }
53 -
54 - if closer != nil {
55 - for _, p := range closer {
56 - select {
57 - case chanQueue.EnqChan <- p:
58 - case <-ctx.Done():
59 - return
60 - }
61 - }
62 - }
63 -
64 - case <-ctx.Done():
65 - return
66 - }
67 - }
92 + return &dhtQueryRunner{
93 + ctx: ctx,
94 + cancel: cancel,
95 + query: q,
96 + peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(q.key)),
97 + peersRemaining: todoctr.NewSyncCounter(),
98 + peersSeen: peer.Map{},
99 + rateLimit: make(chan struct{}, q.concurrency),
100 + }
101 +}
102 +
103 +func (r *dhtQueryRunner) Run(peers []*peer.Peer) (*dhtQueryResult, error) {
104 + // setup concurrency rate limiting
105 + for i := 0; i < r.query.concurrency; i++ {
106 + r.rateLimit <- struct{}{}
107 }
108
70 - // launch all workers
71 - for i := 0; i < concurrency; i++ {
72 - go worker()
109 + // add all the peers we got first.
110 + for _, p := range peers {
111 + r.addPeerToQuery(p, nil) // don't have access to self here...
112 }
113
114 // wait until we're done. yep.
115 select {
77 - case <-ctx.Done():
116 + case <-r.peersRemaining.Done():
117 + r.cancel() // ran all and nothing. cancel all outstanding workers.
118 +
119 + r.RLock()
120 + defer r.RUnlock()
121 +
122 + if len(r.errs) > 0 {
123 + return nil, r.errs[0]
124 + }
125 + return nil, u.ErrNotFound
126 +
127 + case <-r.ctx.Done():
128 + r.RLock()
129 + defer r.RUnlock()
130 +
131 + if r.result != nil && r.result.success {
132 + return r.result, nil
133 + }
134 + return nil, r.ctx.Err()
135 + }
136 +
137 +}
138 +
139 +func (r *dhtQueryRunner) addPeerToQuery(next *peer.Peer, benchmark *peer.Peer) {
140 + if next == nil {
141 + // wtf why are peers nil?!?
142 + u.PErr("Query getting nil peers!!!\n")
143 + return
144 + }
145 +
146 + // if new peer further away than whom we got it from, bother (loops)
147 + if benchmark != nil && kb.Closer(benchmark.ID, next.ID, r.query.key) {
148 + return
149 + }
150 +
151 + // if already seen, no need.
152 + r.Lock()
153 + _, found := r.peersSeen[next.Key()]
154 + if found {
155 + r.Unlock()
156 + return
157 + }
158 + r.peersSeen[next.Key()] = next
159 + r.Unlock()
160 +
161 + // do this after unlocking to prevent possible deadlocks.
162 + r.peersRemaining.Increment(1)
163 + select {
164 + case r.peersToQuery.EnqChan <- next:
165 + case <-r.ctx.Done():
166 }
167 +}
168 +
169 +func (r *dhtQueryRunner) spawnWorkers(p *peer.Peer) {
170 + for {
171 + select {
172 + case <-r.peersRemaining.Done():
173 + return
174 +
175 + case <-r.ctx.Done():
176 + return
177 +
178 + case p := <-r.peersToQuery.DeqChan:
179 + go r.queryPeer(p)
180 + }
181 + }
182 +}
183
80 - if result != nil {
81 - return result, nil
184 +func (r *dhtQueryRunner) queryPeer(p *peer.Peer) {
185 + // make sure we rate limit concurrency.
186 + select {
187 + case <-r.rateLimit:
188 + case <-r.ctx.Done():
189 + r.peersRemaining.Decrement(1)
190 + return
191 + }
192 +
193 + // finally, run the query against this peer
194 + res, err := r.query.qfunc(r.ctx, p)
195 +
196 + if err != nil {
197 + r.Lock()
198 + r.errs = append(r.errs, err)
199 + r.Unlock()
200 +
201 + } else if res.success {
202 + r.Lock()
203 + r.result = res
204 + r.Unlock()
205 + r.cancel() // signal to everyone that we're done.
206 +
207 + } else if res.closerPeers != nil {
208 + for _, next := range res.closerPeers {
209 + r.addPeerToQuery(next, p)
210 + }
211 }
212
84 - return nil, ctx.Err()
213 + // signal we're done proccessing peer p
214 + r.peersRemaining.Decrement(1)
215 + r.rateLimit <- struct{}{}
216 }
routing/dht/routing.go
+44 -64
@@ -3,14 +3,11 @@ package dht
3 import (
4 "bytes"
5 "encoding/json"
6 - "errors"
7 - "fmt"
6 "time"
7
8 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
9
10 peer "github.com/jbenet/go-ipfs/peer"
13 - queue "github.com/jbenet/go-ipfs/peer/queue"
11 kb "github.com/jbenet/go-ipfs/routing/kbucket"
12 u "github.com/jbenet/go-ipfs/util"
13 )
@@ -24,28 +21,23 @@ import (
21 func (dht *IpfsDHT) PutValue(key u.Key, value []byte) error {
22 ctx := context.TODO()
23
27 - query := &dhtQuery{}
28 - query.peers = queue.NewXORDistancePQ(key)
24 + peers := []*peer.Peer{}
25
26 // get the peers we need to announce to
27 for _, route := range dht.routingTables {
32 - peers := route.NearestPeers(kb.ConvertKey(key), KValue)
33 - for _, p := range peers {
34 - if p == nil {
35 - // this shouldn't be happening.
36 - panic("p should not be nil")
37 - }
38 -
39 - query.peers.Enqueue(p)
40 - }
28 + npeers := route.NearestPeers(kb.ConvertKey(key), KValue)
29 + peers = append(peers, npeers...)
30 }
31
43 - query.qfunc = func(ctx context.Context, p *peer.Peer) (interface{}, []*peer.Peer, error) {
44 - dht.putValueToNetwork(ctx, p, string(key), value)
45 - return nil, nil, nil
46 - }
32 + query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
33 + err := dht.putValueToNetwork(ctx, p, string(key), value)
34 + if err != nil {
35 + return nil, err
36 + }
37 + return &dhtQueryResult{success: true}, nil
38 + })
39
48 - _, err := query.Run(ctx, query.peers.Len())
40 + _, err := query.Run(ctx, peers)
41 return err
42 }
43
@@ -63,7 +55,6 @@ func (dht *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
55 val, err := dht.getLocal(key)
56 if err == nil {
57 ll.Success = true
66 - u.DOut("Found local, returning.\n")
58 return val, nil
59 }
60
@@ -74,30 +65,33 @@ func (dht *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
65 return nil, kb.ErrLookupFailure
66 }
67
77 - query := &dhtQuery{}
78 - query.peers = queue.NewXORDistancePQ(key)
68 + // setup the Query
69 + query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
70
80 - // get the peers we need to announce to
81 - for _, p := range closest {
82 - query.peers.Enqueue(p)
83 - }
71 + val, peers, err := dht.getValueOrPeers(ctx, p, key, routeLevel)
72 + if err != nil {
73 + return nil, err
74 + }
75
85 - // setup the Query Function
86 - query.qfunc = func(ctx context.Context, p *peer.Peer) (interface{}, []*peer.Peer, error) {
87 - return dht.getValueOrPeers(ctx, p, key, routeLevel)
88 - }
76 + res := &dhtQueryResult{value: val, closerPeers: peers}
77 + if val != nil {
78 + res.success = true
79 + }
80 +
81 + return res, nil
82 + })
83
84 // run it!
91 - result, err := query.Run(ctx, query.peers.Len())
85 + result, err := query.Run(ctx, closest)
86 if err != nil {
87 return nil, err
88 }
89
96 - byt, ok := result.([]byte)
97 - if !ok {
98 - return nil, fmt.Errorf("received non-byte slice value")
90 + if result.value == nil {
91 + return nil, u.ErrNotFound
92 }
100 - return byt, nil
93 +
94 + return result.value, nil
95 }
96
97 // Value provider layer of indirection.
@@ -278,25 +272,19 @@ func (dht *IpfsDHT) findPeerMultiple(id peer.ID, timeout time.Duration) (*peer.P
272 return p, nil
273 }
274
281 - query := &dhtQuery{}
282 - query.peers = queue.NewXORDistancePQ(u.Key(id))
283 -
275 // get the peers we need to announce to
276 routeLevel := 0
277 peers := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
278 if len(peers) == 0 {
279 return nil, kb.ErrLookupFailure
280 }
290 - for _, p := range peers {
291 - query.peers.Enqueue(p)
292 - }
281
282 // setup query function
295 - query.qfunc = func(ctx context.Context, p *peer.Peer) (interface{}, []*peer.Peer, error) {
283 + query := newQuery(u.Key(id), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
284 pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
285 if err != nil {
286 u.DErr("getPeer error: %v\n", err)
299 - return nil, nil, err
287 + return nil, err
288 }
289
290 plist := pmes.GetCloserPeers()
@@ -313,25 +301,24 @@ func (dht *IpfsDHT) findPeerMultiple(id peer.ID, timeout time.Duration) (*peer.P
301 }
302
303 if nxtp.ID.Equal(id) {
316 - return nxtp, nil, nil
304 + return &dhtQueryResult{peer: nxtp, success: true}, nil
305 }
306
307 nxtprs[i] = nxtp
308 }
309
322 - return nil, nxtprs, nil
323 - }
310 + return &dhtQueryResult{closerPeers: nxtprs}, nil
311 + })
312
325 - p5, err := query.Run(ctx, query.peers.Len())
313 + result, err := query.Run(ctx, peers)
314 if err != nil {
315 return nil, err
316 }
317
330 - p6, ok := p5.(*peer.Peer)
331 - if !ok {
332 - return nil, errors.New("received non peer object")
318 + if result.peer == nil {
319 + return nil, u.ErrNotFound
320 }
334 - return p6, nil
321 + return result.peer, nil
322 }
323
324 // Ping a peer, log the time it took
@@ -350,21 +337,14 @@ func (dht *IpfsDHT) getDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
337 ctx, _ := context.WithTimeout(context.TODO(), timeout)
338
339 u.DOut("Begin Diagnostic")
353 - query := &dhtQuery{}
354 - query.peers = queue.NewXORDistancePQ(u.Key(dht.self.ID))
355 -
356 - targets := dht.routingTables[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
357 - for _, p := range targets {
358 - query.peers.Enqueue(p)
359 - }
360 -
340 + peers := dht.routingTables[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
341 var out []*diagInfo
342
363 - query.qfunc = func(ctx context.Context, p *peer.Peer) (interface{}, []*peer.Peer, error) {
343 + query := newQuery(dht.self.Key(), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
344 pmes := newMessage(Message_DIAGNOSTIC, "", 0)
345 rpmes, err := dht.sendRequest(ctx, p, pmes)
346 if err != nil {
367 - return nil, nil, err
347 + return nil, err
348 }
349
350 dec := json.NewDecoder(bytes.NewBuffer(rpmes.GetValue()))
@@ -377,9 +357,9 @@ func (dht *IpfsDHT) getDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
357
358 out = append(out, di)
359 }
380 - return nil, nil, nil
381 - }
360 + return &dhtQueryResult{success: true}, nil
361 + })
362
383 - _, err := query.Run(ctx, query.peers.Len())
363 + _, err := query.Run(ctx, peers)
364 return out, err
365 }