Commit 9f9dd240 authored by Jakub Sztandera's avatar Jakub Sztandera

feat: cache interface addresses for 1 minute

This can be quite an overhead in cases of high connection rates.
The main overhead is thread blocking syscall causing a lot of context
switching.

License: MIT
Signed-off-by: default avatarJakub Sztandera <kubuxu@protonmail.ch>
parent 99831444
......@@ -20,6 +20,7 @@ import (
goprocessctx "github.com/jbenet/goprocess/context"
filter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
mafilter "github.com/whyrusleeping/multiaddr-filter"
)
......@@ -58,6 +59,10 @@ type Swarm struct {
listeners struct {
sync.RWMutex
ifaceAddresses []ma.Multiaddr
cacheEOL time.Time
m map[transport.Listener]struct{}
}
......
package swarm
import (
"time"
addrutil "github.com/libp2p/go-addr-util"
ma "github.com/multiformats/go-multiaddr"
)
......@@ -9,6 +11,10 @@ import (
func (s *Swarm) ListenAddresses() []ma.Multiaddr {
s.listeners.RLock()
defer s.listeners.RUnlock()
return s.listenAddressesNoLock()
}
func (s *Swarm) listenAddressesNoLock() []ma.Multiaddr {
addrs := make([]ma.Multiaddr, 0, len(s.listeners.m))
for l := range s.listeners.m {
addrs = append(addrs, l.Multiaddr())
......@@ -16,9 +22,47 @@ func (s *Swarm) ListenAddresses() []ma.Multiaddr {
return addrs
}
const ifaceAddrsCacheDuration = 1 * time.Minute
// InterfaceListenAddresses returns a list of addresses at which this swarm
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
func (s *Swarm) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
return addrutil.ResolveUnspecifiedAddresses(s.ListenAddresses(), nil)
s.listeners.RLock() // RLock start
listenAddrs := s.listenAddressesNoLock()
ifaceAddrs := s.listeners.ifaceAddresses
isEOL := time.Now().After(s.listeners.cacheEOL)
s.listeners.RUnlock() // RLock end
if listenAddrs != nil && !isEOL {
// Cache is valid
return addrutil.ResolveUnspecifiedAddresses(listenAddrs, ifaceAddrs)
}
// Cache is not valid
// Perfrom double checked locking
s.listeners.Lock() // Lock start
listenAddrs = s.listenAddressesNoLock()
ifaceAddrs = s.listeners.ifaceAddresses
isEOL = time.Now().After(s.listeners.cacheEOL)
if listenAddrs == nil || isEOL {
// Cache is still invalid
var err error
ifaceAddrs, err = addrutil.InterfaceAddresses()
if err != nil {
s.listeners.Unlock() // Lock early exit
return nil, err
}
s.listeners.ifaceAddresses = ifaceAddrs
s.listeners.cacheEOL = time.Now().Add(ifaceAddrsCacheDuration)
}
s.listeners.Unlock() // Lock end
return addrutil.ResolveUnspecifiedAddresses(listenAddrs, ifaceAddrs)
}
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