optimise generation of the initial PEX
This commit is contained in:
parent
94055287b0
commit
0c1a506e04
33
pex.go
33
pex.go
|
@ -2,6 +2,7 @@ package torrent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/anacrolix/dht/v2/krpc"
|
"github.com/anacrolix/dht/v2/krpc"
|
||||||
pp "github.com/anacrolix/torrent/peer_protocol"
|
pp "github.com/anacrolix/torrent/peer_protocol"
|
||||||
|
@ -140,15 +141,23 @@ func shortestIP(ip net.IP) net.IP {
|
||||||
|
|
||||||
// Per-torrent PEX state
|
// Per-torrent PEX state
|
||||||
type pexState struct {
|
type pexState struct {
|
||||||
ev []pexEvent // event feed, append-only
|
ev []pexEvent // event feed, append-only
|
||||||
hold []pexEvent // delayed drops
|
hold []pexEvent // delayed drops
|
||||||
nc int // net number of alive conns
|
nc int // net number of alive conns
|
||||||
|
initCache pexMsgFactory // last generated initial message
|
||||||
|
initSeq int // number of events which went into initCache
|
||||||
|
initLock sync.RWMutex // serialise access to initCache and initSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset wipes the state clean, releasing resources. Called from Torrent.Close().
|
||||||
func (s *pexState) Reset() {
|
func (s *pexState) Reset() {
|
||||||
s.ev = nil
|
s.ev = nil
|
||||||
s.hold = nil
|
s.hold = nil
|
||||||
s.nc = 0
|
s.nc = 0
|
||||||
|
s.initLock.Lock()
|
||||||
|
s.initCache = pexMsgFactory{}
|
||||||
|
s.initSeq = 0
|
||||||
|
s.initLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pexState) Add(c *PeerConn) {
|
func (s *pexState) Add(c *PeerConn) {
|
||||||
|
@ -179,6 +188,10 @@ func (s *pexState) Drop(c *PeerConn) {
|
||||||
// Generate a PEX message based on the event feed. Also returns an index to pass to the subsequent
|
// Generate a PEX message based on the event feed. Also returns an index to pass to the subsequent
|
||||||
// calls, producing incremental deltas.
|
// calls, producing incremental deltas.
|
||||||
func (s *pexState) Genmsg(start int) (pp.PexMsg, int) {
|
func (s *pexState) Genmsg(start int) (pp.PexMsg, int) {
|
||||||
|
if start == 0 {
|
||||||
|
return s.genmsg0()
|
||||||
|
}
|
||||||
|
|
||||||
var factory pexMsgFactory
|
var factory pexMsgFactory
|
||||||
n := start
|
n := start
|
||||||
for _, e := range s.ev[start:] {
|
for _, e := range s.ev[start:] {
|
||||||
|
@ -190,3 +203,17 @@ func (s *pexState) Genmsg(start int) (pp.PexMsg, int) {
|
||||||
}
|
}
|
||||||
return factory.PexMsg(), n
|
return factory.PexMsg(), n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *pexState) genmsg0() (pp.PexMsg, int) {
|
||||||
|
s.initLock.Lock()
|
||||||
|
for _, e := range s.ev[s.initSeq:] {
|
||||||
|
s.initCache.addEvent(e)
|
||||||
|
s.initSeq++
|
||||||
|
}
|
||||||
|
s.initLock.Unlock()
|
||||||
|
s.initLock.RLock()
|
||||||
|
n := s.initSeq
|
||||||
|
msg := s.initCache.PexMsg()
|
||||||
|
s.initLock.RUnlock()
|
||||||
|
return msg, n
|
||||||
|
}
|
||||||
|
|
20
pex_test.go
20
pex_test.go
|
@ -307,11 +307,11 @@ func TestPexGenmsg(t *testing.T) {
|
||||||
func addrgen(n int) chan net.Addr {
|
func addrgen(n int) chan net.Addr {
|
||||||
c := make(chan net.Addr)
|
c := make(chan net.Addr)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer close(c)
|
||||||
for i := 4747; i < 65535 && n > 0; i++ {
|
for i := 4747; i < 65535 && n > 0; i++ {
|
||||||
c <- &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: i}
|
c <- &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: i}
|
||||||
n--
|
n--
|
||||||
}
|
}
|
||||||
close(c)
|
|
||||||
}()
|
}()
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -335,6 +335,24 @@ func TestPexInitialNoCutoff(t *testing.T) {
|
||||||
require.EqualValues(t, 0, len(m.Dropped6))
|
require.EqualValues(t, 0, len(m.Dropped6))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkPexInitialN(b *testing.B, npeers int) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
var s pexState
|
||||||
|
c := addrgen(npeers)
|
||||||
|
for addr := range c {
|
||||||
|
s.Add(&PeerConn{peer: peer{RemoteAddr: addr}})
|
||||||
|
s.Genmsg(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain at least 5 points, e.g. to plot a graph
|
||||||
|
func BenchmarkPexInitial4(b *testing.B) { benchmarkPexInitialN(b, 4) }
|
||||||
|
func BenchmarkPexInitial50(b *testing.B) { benchmarkPexInitialN(b, 50) }
|
||||||
|
func BenchmarkPexInitial100(b *testing.B) { benchmarkPexInitialN(b, 100) }
|
||||||
|
func BenchmarkPexInitial200(b *testing.B) { benchmarkPexInitialN(b, 200) }
|
||||||
|
func BenchmarkPexInitial400(b *testing.B) { benchmarkPexInitialN(b, 400) }
|
||||||
|
|
||||||
func TestPexAdd(t *testing.T) {
|
func TestPexAdd(t *testing.T) {
|
||||||
t.Run("ipv4", func(t *testing.T) {
|
t.Run("ipv4", func(t *testing.T) {
|
||||||
addrs := addrs4
|
addrs := addrs4
|
||||||
|
|
Loading…
Reference in New Issue