rewrite message response listening framework
Jeromy committed
Aug 15, 2014 at 22:37 UTC
8a1fdbb83d648e419a8e789e9125aa2abb2a0988
3 files changed
+57
-137
routing/dht/dht.go
+15
-102
@@ -39,10 +39,6 @@ type IpfsDHT struct {
39
providers map[u.Key][]*providerInfo
40
providerLock sync.RWMutex
41
42
- // map of channels waiting for reply messages
43
- listeners map[uint64]*listenInfo
44
- listenLock sync.RWMutex
45
-
42
// Signal to shutdown dht
43
shutdown chan struct{}
44
@@ -51,18 +47,9 @@ type IpfsDHT struct {
47
48
//lock to make diagnostics work better
49
diaglock sync.Mutex
54
-}
55
-
56
-// The listen info struct holds information about a message that is being waited for
57
-type listenInfo struct {
58
- // Responses matching the listen ID will be sent through resp
59
- resp chan *swarm.Message
60
-
61
- // count is the number of responses to listen for
62
- count int
50
64
- // eol is the time at which this listener will expire
65
- eol time.Time
51
+ // listener is a server to register to listen for responses to messages
52
+ listener *MesListener
53
}
54
55
// NewDHT creates a new DHT object with the given peer as the 'local' host
@@ -71,7 +58,6 @@ func NewDHT(p *peer.Peer, net swarm.Network) *IpfsDHT {
58
dht.network = net
59
dht.datastore = ds.NewMapDatastore()
60
dht.self = p
74
- dht.listeners = make(map[uint64]*listenInfo)
61
dht.providers = make(map[u.Key][]*providerInfo)
62
dht.shutdown = make(chan struct{})
63
@@ -80,6 +66,7 @@ func NewDHT(p *peer.Peer, net swarm.Network) *IpfsDHT {
66
dht.routes[1] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Millisecond*100)
67
dht.routes[2] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Hour)
68
69
+ dht.listener = NewMesListener()
70
dht.birth = time.Now()
71
return dht
72
}
@@ -135,25 +122,7 @@ func (dht *IpfsDHT) handleMessages() {
122
123
// Note: not sure if this is the correct place for this
124
if pmes.GetResponse() {
138
- dht.listenLock.RLock()
139
- list, ok := dht.listeners[pmes.GetId()]
140
- dht.listenLock.RUnlock()
141
- if time.Now().After(list.eol) {
142
- dht.Unlisten(pmes.GetId())
143
- ok = false
144
- }
145
- if list.count > 1 {
146
- list.count--
147
- }
148
- if ok {
149
- list.resp <- mes
150
- if list.count == 1 {
151
- dht.Unlisten(pmes.GetId())
152
- }
153
- } else {
154
- u.DOut("Received response with nobody listening...")
155
- }
156
-
125
+ dht.listener.Respond(pmes.GetId(), mes)
126
continue
127
}
128
//
@@ -187,7 +156,6 @@ func (dht *IpfsDHT) handleMessages() {
156
case <-checkTimeouts.C:
157
// Time to collect some garbage!
158
dht.cleanExpiredProviders()
190
- dht.cleanExpiredListeners()
159
}
160
}
161
}
@@ -206,21 +174,6 @@ func (dht *IpfsDHT) cleanExpiredProviders() {
174
dht.providerLock.Unlock()
175
}
176
209
-func (dht *IpfsDHT) cleanExpiredListeners() {
210
- dht.listenLock.Lock()
211
- var remove []uint64
212
- now := time.Now()
213
- for k, v := range dht.listeners {
214
- if now.After(v.eol) {
215
- remove = append(remove, k)
216
- }
217
- }
218
- for _, k := range remove {
219
- delete(dht.listeners, k)
220
- }
221
- dht.listenLock.Unlock()
222
-}
223
-
177
func (dht *IpfsDHT) putValueToNetwork(p *peer.Peer, key string, value []byte) error {
178
pmes := DHTMessage{
179
Type: PBDHTMessage_PUT_VALUE,
@@ -393,41 +346,6 @@ func (dht *IpfsDHT) handleAddProvider(p *peer.Peer, pmes *PBDHTMessage) {
346
dht.addProviderEntry(key, p)
347
}
348
396
-// Register a handler for a specific message ID, used for getting replies
397
-// to certain messages (i.e. response to a GET_VALUE message)
398
-func (dht *IpfsDHT) ListenFor(mesid uint64, count int, timeout time.Duration) <-chan *swarm.Message {
399
- lchan := make(chan *swarm.Message)
400
- dht.listenLock.Lock()
401
- dht.listeners[mesid] = &listenInfo{lchan, count, time.Now().Add(timeout)}
402
- dht.listenLock.Unlock()
403
- return lchan
404
-}
405
-
406
-// Unregister the given message id from the listener map
407
-func (dht *IpfsDHT) Unlisten(mesid uint64) {
408
- dht.listenLock.Lock()
409
- list, ok := dht.listeners[mesid]
410
- if ok {
411
- delete(dht.listeners, mesid)
412
- }
413
- dht.listenLock.Unlock()
414
- close(list.resp)
415
-}
416
-
417
-// Check whether or not the dht is currently listening for mesid
418
-func (dht *IpfsDHT) IsListening(mesid uint64) bool {
419
- dht.listenLock.RLock()
420
- li, ok := dht.listeners[mesid]
421
- dht.listenLock.RUnlock()
422
- if time.Now().After(li.eol) {
423
- dht.listenLock.Lock()
424
- delete(dht.listeners, mesid)
425
- dht.listenLock.Unlock()
426
- return false
427
- }
428
- return ok
429
-}
430
-
349
// Stop all communications from this peer and shut down
350
func (dht *IpfsDHT) Halt() {
351
dht.shutdown <- struct{}{}
@@ -444,16 +362,8 @@ func (dht *IpfsDHT) addProviderEntry(key u.Key, p *peer.Peer) {
362
363
// NOTE: not yet finished, low priority
364
func (dht *IpfsDHT) handleDiagnostic(p *peer.Peer, pmes *PBDHTMessage) {
447
- dht.diaglock.Lock()
448
- if dht.IsListening(pmes.GetId()) {
449
- //TODO: ehhh..........
450
- dht.diaglock.Unlock()
451
- return
452
- }
453
- dht.diaglock.Unlock()
454
-
365
seq := dht.routes[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
456
- listenChan := dht.ListenFor(pmes.GetId(), len(seq), time.Second*30)
366
+ listenChan := dht.listener.Listen(pmes.GetId(), len(seq), time.Second*30)
367
368
for _, ps := range seq {
369
mes := swarm.NewMessage(ps, pmes)
@@ -499,7 +409,7 @@ out:
409
func (dht *IpfsDHT) getValueOrPeers(p *peer.Peer, key u.Key, timeout time.Duration, level int) ([]byte, []*peer.Peer, error) {
410
pmes, err := dht.getValueSingle(p, key, timeout, level)
411
if err != nil {
502
- return nil, nil, u.WrapError(err, "getValue Error")
412
+ return nil, nil, err
413
}
414
415
if pmes.GetSuccess() {
@@ -517,6 +427,9 @@ func (dht *IpfsDHT) getValueOrPeers(p *peer.Peer, key u.Key, timeout time.Durati
427
// We were given a closer node
428
var peers []*peer.Peer
429
for _, pb := range pmes.GetPeers() {
430
+ if peer.ID(pb.GetId()).Equal(dht.self.ID) {
431
+ continue
432
+ }
433
addr, err := ma.NewMultiaddr(pb.GetAddr())
434
if err != nil {
435
u.PErr(err.Error())
@@ -543,7 +456,7 @@ func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duratio
456
Value: []byte{byte(level)},
457
Id: GenerateMessageID(),
458
}
546
- response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
459
+ response_chan := dht.listener.Listen(pmes.Id, 1, time.Minute)
460
461
mes := swarm.NewMessage(p, pmes.ToProtobuf())
462
t := time.Now()
@@ -553,7 +466,7 @@ func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duratio
466
timeup := time.After(timeout)
467
select {
468
case <-timeup:
556
- dht.Unlisten(pmes.Id)
469
+ dht.listener.Unlisten(pmes.Id)
470
return nil, u.ErrTimeout
471
case resp, ok := <-response_chan:
472
if !ok {
@@ -658,13 +571,13 @@ func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Durati
571
}
572
573
mes := swarm.NewMessage(p, pmes.ToProtobuf())
661
- listenChan := dht.ListenFor(pmes.Id, 1, time.Minute)
574
+ listenChan := dht.listener.Listen(pmes.Id, 1, time.Minute)
575
t := time.Now()
576
dht.network.Send(mes)
577
after := time.After(timeout)
578
select {
579
case <-after:
667
- dht.Unlisten(pmes.Id)
580
+ dht.listener.Unlisten(pmes.Id)
581
return nil, u.ErrTimeout
582
case resp := <-listenChan:
583
roundtrip := time.Since(t)
@@ -695,12 +608,12 @@ func (dht *IpfsDHT) findProvidersSingle(p *peer.Peer, key u.Key, level int, time
608
609
mes := swarm.NewMessage(p, pmes.ToProtobuf())
610
698
- listenChan := dht.ListenFor(pmes.Id, 1, time.Minute)
611
+ listenChan := dht.listener.Listen(pmes.Id, 1, time.Minute)
612
dht.network.Send(mes)
613
after := time.After(timeout)
614
select {
615
case <-after:
703
- dht.Unlisten(pmes.Id)
616
+ dht.listener.Unlisten(pmes.Id)
617
return nil, u.ErrTimeout
618
case resp := <-listenChan:
619
u.DOut("FindProviders: got response.")
routing/dht/routing.go
+42
-9
@@ -81,6 +81,36 @@ func (c *counter) Size() int {
81
return c.n
82
}
83
84
+type peerSet struct {
85
+ ps map[string]bool
86
+ lk sync.RWMutex
87
+}
88
+
89
+func newPeerSet() *peerSet {
90
+ ps := new(peerSet)
91
+ ps.ps = make(map[string]bool)
92
+ return ps
93
+}
94
+
95
+func (ps *peerSet) Add(p *peer.Peer) {
96
+ ps.lk.Lock()
97
+ ps.ps[string(p.ID)] = true
98
+ ps.lk.Unlock()
99
+}
100
+
101
+func (ps *peerSet) Contains(p *peer.Peer) bool {
102
+ ps.lk.RLock()
103
+ _, ok := ps.ps[string(p.ID)]
104
+ ps.lk.RUnlock()
105
+ return ok
106
+}
107
+
108
+func (ps *peerSet) Size() int {
109
+ ps.lk.RLock()
110
+ defer ps.lk.RUnlock()
111
+ return len(ps.ps)
112
+}
113
+
114
// GetValue searches for the value corresponding to given Key.
115
// If the search does not succeed, a multiaddr string of a closer peer is
116
// returned along with util.ErrSearchIncomplete
@@ -111,8 +141,10 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
141
proc_peer := make(chan *peer.Peer, 30)
142
err_chan := make(chan error)
143
after := time.After(timeout)
144
+ pset := newPeerSet()
145
146
for _, p := range closest {
147
+ pset.Add(p)
148
npeer_chan <- p
149
}
150
@@ -130,6 +162,7 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
162
break
163
}
164
c.Increment()
165
+
166
proc_peer <- p
167
default:
168
if c.Size() == 0 {
@@ -161,7 +194,10 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
194
195
for _, np := range peers {
196
// TODO: filter out peers that arent closer
164
- npeer_chan <- np
197
+ if !pset.Contains(np) && pset.Size() < limit {
198
+ pset.Add(np) //This is racey... make a single function to do operation
199
+ npeer_chan <- np
200
+ }
201
}
202
c.Decrement()
203
}
@@ -175,13 +211,10 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
211
212
select {
213
case val := <-val_chan:
178
- close(npeer_chan)
214
return val, nil
215
case err := <-err_chan:
181
- close(npeer_chan)
216
return nil, err
217
case <-after:
184
- close(npeer_chan)
218
return nil, u.ErrTimeout
219
}
220
}
@@ -288,12 +321,12 @@ func (s *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, error
321
322
addr, err := ma.NewMultiaddr(found.GetAddr())
323
if err != nil {
291
- return nil, u.WrapError(err, "FindPeer received bad info")
324
+ return nil, err
325
}
326
327
nxtPeer, err := s.network.GetConnection(peer.ID(found.GetId()), addr)
328
if err != nil {
296
- return nil, u.WrapError(err, "FindPeer failed to connect to new peer.")
329
+ return nil, err
330
}
331
if pmes.GetSuccess() {
332
if !id.Equal(nxtPeer.ID) {
@@ -316,7 +349,7 @@ func (dht *IpfsDHT) Ping(p *peer.Peer, timeout time.Duration) error {
349
mes := swarm.NewMessage(p, pmes.ToProtobuf())
350
351
before := time.Now()
319
- response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
352
+ response_chan := dht.listener.Listen(pmes.Id, 1, time.Minute)
353
dht.network.Send(mes)
354
355
tout := time.After(timeout)
@@ -329,7 +362,7 @@ func (dht *IpfsDHT) Ping(p *peer.Peer, timeout time.Duration) error {
362
case <-tout:
363
// Timed out, think about removing peer from network
364
u.DOut("Ping peer timed out.")
332
- dht.Unlisten(pmes.Id)
365
+ dht.listener.Unlisten(pmes.Id)
366
return u.ErrTimeout
367
}
368
}
@@ -345,7 +378,7 @@ func (dht *IpfsDHT) GetDiagnostic(timeout time.Duration) ([]*diagInfo, error) {
378
Id: GenerateMessageID(),
379
}
380
348
- listenChan := dht.ListenFor(pmes.Id, len(targets), time.Minute*2)
381
+ listenChan := dht.listener.Listen(pmes.Id, len(targets), time.Minute*2)
382
383
pbmes := pmes.ToProtobuf()
384
for _, p := range targets {
util/util.go
-26
@@ -1,12 +1,10 @@
1
package util
2
3
import (
4
- "bytes"
4
"errors"
5
"fmt"
6
"os"
7
"os/user"
9
- "runtime"
8
"strings"
9
10
b58 "github.com/jbenet/go-base58"
@@ -36,30 +34,6 @@ func (k Key) Pretty() string {
34
return b58.Encode([]byte(k))
35
}
36
39
-type IpfsError struct {
40
- Inner error
41
- Note string
42
- Stack string
43
-}
44
-
45
-func (ie *IpfsError) Error() string {
46
- buf := new(bytes.Buffer)
47
- fmt.Fprintln(buf, ie.Inner)
48
- fmt.Fprintln(buf, ie.Note)
49
- fmt.Fprintln(buf, ie.Stack)
50
- return buf.String()
51
-}
52
-
53
-func WrapError(err error, note string) error {
54
- ie := new(IpfsError)
55
- ie.Inner = err
56
- ie.Note = note
57
- stack := make([]byte, 2048)
58
- n := runtime.Stack(stack, false)
59
- ie.Stack = string(stack[:n])
60
- return ie
61
-}
62
-
37
// Hash is the global IPFS hash function. uses multihash SHA2_256, 256 bits
38
func Hash(data []byte) (mh.Multihash, error) {
39
return mh.Sum(data, mh.SHA2_256, -1)