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 ( ...@@ -20,6 +20,7 @@ import (
goprocessctx "github.com/jbenet/goprocess/context" goprocessctx "github.com/jbenet/goprocess/context"
filter "github.com/libp2p/go-maddr-filter" filter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
mafilter "github.com/whyrusleeping/multiaddr-filter" mafilter "github.com/whyrusleeping/multiaddr-filter"
) )
...@@ -58,6 +59,10 @@ type Swarm struct { ...@@ -58,6 +59,10 @@ type Swarm struct {
listeners struct { listeners struct {
sync.RWMutex sync.RWMutex
ifaceAddresses []ma.Multiaddr
cacheEOL time.Time
m map[transport.Listener]struct{} m map[transport.Listener]struct{}
} }
......
package swarm package swarm
import ( import (
"time"
addrutil "github.com/libp2p/go-addr-util" addrutil "github.com/libp2p/go-addr-util"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
...@@ -9,6 +11,10 @@ import ( ...@@ -9,6 +11,10 @@ import (
func (s *Swarm) ListenAddresses() []ma.Multiaddr { func (s *Swarm) ListenAddresses() []ma.Multiaddr {
s.listeners.RLock() s.listeners.RLock()
defer s.listeners.RUnlock() defer s.listeners.RUnlock()
return s.listenAddressesNoLock()
}
func (s *Swarm) listenAddressesNoLock() []ma.Multiaddr {
addrs := make([]ma.Multiaddr, 0, len(s.listeners.m)) addrs := make([]ma.Multiaddr, 0, len(s.listeners.m))
for l := range s.listeners.m { for l := range s.listeners.m {
addrs = append(addrs, l.Multiaddr()) addrs = append(addrs, l.Multiaddr())
...@@ -16,9 +22,47 @@ func (s *Swarm) ListenAddresses() []ma.Multiaddr { ...@@ -16,9 +22,47 @@ func (s *Swarm) ListenAddresses() []ma.Multiaddr {
return addrs return addrs
} }
const ifaceAddrsCacheDuration = 1 * time.Minute
// InterfaceListenAddresses returns a list of addresses at which this swarm // InterfaceListenAddresses returns a list of addresses at which this swarm
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces. // use the known local interfaces.
func (s *Swarm) InterfaceListenAddresses() ([]ma.Multiaddr, error) { 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