@cryptotaxi247 / kubo / commits / 8a1fdbb83

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)