Commit 891400d2 authored by Jeromy's avatar Jeromy

more tests and add in table filtering by peer latency

parent 653841f2
......@@ -74,8 +74,12 @@ func NewDHT(p *peer.Peer, net swarm.Network) *IpfsDHT {
dht.listeners = make(map[uint64]*listenInfo)
dht.providers = make(map[u.Key][]*providerInfo)
dht.shutdown = make(chan struct{})
dht.routes = make([]*kb.RoutingTable, 1)
dht.routes[0] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID))
dht.routes = make([]*kb.RoutingTable, 3)
dht.routes[0] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Millisecond*30)
dht.routes[1] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Millisecond*100)
dht.routes[2] = kb.NewRoutingTable(20, kb.ConvertPeerID(p.ID), time.Hour)
dht.birth = time.Now()
return dht
}
......@@ -253,7 +257,13 @@ func (dht *IpfsDHT) handleGetValue(p *peer.Peer, pmes *PBDHTMessage) {
// No providers?
// Find closest peer on given cluster to desired key and reply with that info
level := pmes.GetValue()[0] // Using value field to specify cluster level
level := 0
if len(pmes.GetValue()) < 1 {
// TODO: maybe return an error? Defaulting isnt a good idea IMO
u.PErr("handleGetValue: no routing level specified, assuming 0")
} else {
level = int(pmes.GetValue()[0]) // Using value field to specify cluster level
}
closer := dht.routes[level].NearestPeer(kb.ConvertKey(u.Key(pmes.GetKey())))
......@@ -477,6 +487,7 @@ func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duratio
response_chan := dht.ListenFor(pmes.Id, 1, time.Minute)
mes := swarm.NewMessage(p, pmes.ToProtobuf())
t := time.Now()
dht.network.Send(mes)
// Wait for either the response or a timeout
......@@ -490,6 +501,8 @@ func (dht *IpfsDHT) getValueSingle(p *peer.Peer, key u.Key, timeout time.Duratio
u.PErr("response channel closed before timeout, please investigate.")
return nil, u.ErrTimeout
}
roundtrip := time.Since(t)
resp.Peer.SetLatency(roundtrip)
pmes_out := new(PBDHTMessage)
err := proto.Unmarshal(resp.Data, pmes_out)
if err != nil {
......@@ -513,7 +526,8 @@ func (dht *IpfsDHT) getFromPeerList(key u.Key, timeout time.Duration,
u.PErr("getValue error: %s", err)
continue
}
p, err = dht.Connect(maddr)
p, err = dht.network.Connect(maddr)
if err != nil {
u.PErr("getValue error: %s", err)
continue
......@@ -547,9 +561,21 @@ func (dht *IpfsDHT) PutLocal(key u.Key, value []byte) error {
}
func (dht *IpfsDHT) Update(p *peer.Peer) {
removed := dht.routes[0].Update(p)
if removed != nil {
dht.network.Drop(removed)
for _, route := range dht.routes {
removed := route.Update(p)
// Only drop the connection if no tables refer to this peer
if removed != nil {
found := false
for _, r := range dht.routes {
if r.Find(removed.ID) != nil {
found = true
break
}
}
if !found {
dht.network.Drop(removed)
}
}
}
}
......@@ -574,6 +600,7 @@ func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Durati
mes := swarm.NewMessage(p, pmes.ToProtobuf())
listenChan := dht.ListenFor(pmes.Id, 1, time.Minute)
t := time.Now()
dht.network.Send(mes)
after := time.After(timeout)
select {
......@@ -581,6 +608,8 @@ func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Durati
dht.Unlisten(pmes.Id)
return nil, u.ErrTimeout
case resp := <-listenChan:
roundtrip := time.Since(t)
resp.Peer.SetLatency(roundtrip)
pmes_out := new(PBDHTMessage)
err := proto.Unmarshal(resp.Data, pmes_out)
if err != nil {
......@@ -590,3 +619,9 @@ func (dht *IpfsDHT) findPeerSingle(p *peer.Peer, id peer.ID, timeout time.Durati
return pmes_out, nil
}
}
func (dht *IpfsDHT) PrintTables() {
for _, route := range dht.routes {
route.Print()
}
}
......@@ -16,13 +16,16 @@ import (
// fauxNet is a standin for a swarm.Network in order to more easily recreate
// different testing scenarios
type fauxNet struct {
Chan *swarm.Chan
Chan *swarm.Chan
handlers []mesHandleFunc
swarm.Network
handlers []mesHandleFunc
}
// mesHandleFunc is a function that takes in outgoing messages
// and can respond to them, simulating other peers on the network.
// returning nil will chose not to respond and pass the message onto the
// next registered handler
type mesHandleFunc func(*swarm.Message) *swarm.Message
func newFauxNet() *fauxNet {
......@@ -32,6 +35,9 @@ func newFauxNet() *fauxNet {
return fn
}
// Instead of 'Listening' Start up a goroutine that will check
// all outgoing messages against registered message handlers,
// and reply if needed
func (f *fauxNet) Listen() error {
go func() {
for {
......@@ -95,6 +101,7 @@ func TestGetFailures(t *testing.T) {
t.Fatal("Did not get expected error!")
}
// Reply with failures to every message
fn.AddHandler(func(mes *swarm.Message) *swarm.Message {
pmes := new(PBDHTMessage)
err := proto.Unmarshal(mes.Data, pmes)
......@@ -120,4 +127,30 @@ func TestGetFailures(t *testing.T) {
} else {
t.Fatal("expected error, got none.")
}
success := make(chan struct{})
fn.handlers = nil
fn.AddHandler(func(mes *swarm.Message) *swarm.Message {
resp := new(PBDHTMessage)
err := proto.Unmarshal(mes.Data, resp)
if err != nil {
t.Fatal(err)
}
if resp.GetSuccess() {
t.Fatal("Get returned success when it shouldnt have.")
}
success <- struct{}{}
return nil
})
// Now we test this DHT's handleGetValue failure
req := DHTMessage{
Type: PBDHTMessage_GET_VALUE,
Key: "hello",
Id: GenerateMessageID(),
Value: []byte{0},
}
fn.Chan.Incoming <- swarm.NewMessage(other, req.ToProtobuf())
<-success
}
......@@ -89,9 +89,7 @@ func (s *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
panic("not yet implemented")
}
// TODO: dht.Connect has overhead due to an internal
// ping to the target. Use something else
p, err = s.Connect(maddr)
p, err = s.network.Connect(maddr)
if err != nil {
// Move up route level
panic("not yet implemented.")
......@@ -167,7 +165,7 @@ func (s *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Peer,
u.PErr("error connecting to new peer: %s", err)
continue
}
p, err = s.Connect(maddr)
p, err = s.network.Connect(maddr)
if err != nil {
u.PErr("error connecting to new peer: %s", err)
continue
......@@ -204,7 +202,7 @@ func (s *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, error
return nil, u.WrapError(err, "FindPeer received bad info")
}
nxtPeer, err := s.Connect(addr)
nxtPeer, err := s.network.Connect(addr)
if err != nil {
return nil, u.WrapError(err, "FindPeer failed to connect to new peer.")
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment