dht: Limit the size of peer discovery backlog

This commit is contained in:
Matt Joiner 2014-12-08 21:57:53 -06:00
parent a081ad63d9
commit fa501ed06a
2 changed files with 28 additions and 10 deletions

View File

@ -156,7 +156,7 @@ func (n *Node) DefinitelyGood() bool {
if len(n.id) != 20 { if len(n.id) != 20 {
return false return false
} }
// No reason to think ill of them if they've never responded. // No reason to think ill of them if they've never been queried.
if n.lastSentQuery.IsZero() { if n.lastSentQuery.IsZero() {
return true return true
} }

View File

@ -17,7 +17,10 @@ type peerDiscovery struct {
infoHash string infoHash string
} }
const parallelQueries = 100 const (
parallelQueries = 100
backlogMaxLen = 10000
)
func (me *peerDiscovery) Close() { func (me *peerDiscovery) Close() {
me.peerStream.Close() me.peerStream.Close()
@ -43,12 +46,29 @@ func (s *Server) GetPeers(infoHash string) (*peerStream, error) {
peerStream: &peerStream{ peerStream: &peerStream{
Values: make(chan peerStreamValue), Values: make(chan peerStreamValue),
stop: make(chan struct{}), stop: make(chan struct{}),
values: make(chan peerStreamValue),
}, },
triedAddrs: make(map[string]struct{}, 500), triedAddrs: make(map[string]struct{}, 500),
backlog: make(map[string]net.Addr, parallelQueries), backlog: make(map[string]net.Addr, parallelQueries),
server: s, server: s,
infoHash: infoHash, infoHash: infoHash,
} }
// Function ferries from values to Values until discovery is halted.
go func() {
defer close(disc.Values)
for {
select {
case psv := <-disc.values:
select {
case disc.Values <- psv:
case <-disc.stop:
return
}
case <-disc.stop:
return
}
}
}()
disc.mu.Lock() disc.mu.Lock()
for _, addr := range startAddrs { for _, addr := range startAddrs {
disc.contact(addr) disc.contact(addr)
@ -72,7 +92,9 @@ func (me *peerDiscovery) gotNodeAddr(addr net.Addr) {
return return
} }
if me.pending >= parallelQueries { if me.pending >= parallelQueries {
me.backlog[addr.String()] = addr if len(me.backlog) < backlogMaxLen {
me.backlog[addr.String()] = addr
}
} else { } else {
me.contact(addr) me.contact(addr)
} }
@ -89,7 +111,6 @@ func (me *peerDiscovery) contact(addr net.Addr) {
func (me *peerDiscovery) transactionClosed() { func (me *peerDiscovery) transactionClosed() {
me.pending-- me.pending--
// log.Printf("pending: %d", me.pending)
for key, addr := range me.backlog { for key, addr := range me.backlog {
if me.pending >= parallelQueries { if me.pending >= parallelQueries {
break break
@ -140,7 +161,7 @@ func (me *peerDiscovery) getPeers(addr net.Addr) error {
}() }()
copy(nodeInfo.ID[:], id) copy(nodeInfo.ID[:], id)
select { select {
case me.peerStream.Values <- peerStreamValue{ case me.peerStream.values <- peerStreamValue{
Peers: vs, Peers: vs,
NodeInfo: nodeInfo, NodeInfo: nodeInfo,
}: }:
@ -157,10 +178,6 @@ func (me *peerDiscovery) getPeers(addr net.Addr) error {
return nil return nil
} }
func (me *peerDiscovery) streamValue(psv peerStreamValue) {
me.peerStream.Values <- psv
}
type peerStreamValue struct { type peerStreamValue struct {
Peers []util.CompactPeer // Peers given in get_peers response. Peers []util.CompactPeer // Peers given in get_peers response.
NodeInfo // The node that gave the response. NodeInfo // The node that gave the response.
@ -169,6 +186,8 @@ type peerStreamValue struct {
type peerStream struct { type peerStream struct {
mu sync.Mutex mu sync.Mutex
Values chan peerStreamValue Values chan peerStreamValue
// Inner chan is set to nil when on close.
values chan peerStreamValue
stop chan struct{} stop chan struct{}
} }
@ -179,6 +198,5 @@ func (ps *peerStream) Close() {
case <-ps.stop: case <-ps.stop:
default: default:
close(ps.stop) close(ps.stop)
close(ps.Values)
} }
} }