mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-10 19:17:25 +02:00
types: avoid NodeView clone in CanAccess
NodeView.CanAccess called node2.AsStruct() on every check. In peer-map construction we run CanAccess in O(n^2) pair scans (often twice per pair), so that per-call clone multiplied into large heap churn
This commit is contained in:
@@ -800,11 +800,11 @@ func (nv NodeView) InIPSet(set *netipx.IPSet) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (nv NodeView) CanAccess(matchers []matcher.Match, node2 NodeView) bool {
|
func (nv NodeView) CanAccess(matchers []matcher.Match, node2 NodeView) bool {
|
||||||
if !nv.Valid() {
|
if !nv.Valid() || !node2.Valid() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return nv.ж.CanAccess(matchers, node2.AsStruct())
|
return nv.ж.CanAccess(matchers, node2.ж)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nv NodeView) CanAccessRoute(matchers []matcher.Match, route netip.Prefix) bool {
|
func (nv NodeView) CanAccessRoute(matchers []matcher.Match, route netip.Prefix) bool {
|
||||||
|
|||||||
73
hscontrol/types/node_benchmark_test.go
Normal file
73
hscontrol/types/node_benchmark_test.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/juanfont/headscale/hscontrol/policy/matcher"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkNodeViewCanAccess(b *testing.B) {
|
||||||
|
addr := func(ip string) *netip.Addr {
|
||||||
|
parsed := netip.MustParseAddr(ip)
|
||||||
|
return &parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
rules := []tailcfg.FilterRule{
|
||||||
|
{
|
||||||
|
SrcIPs: []string{"100.64.0.1/32"},
|
||||||
|
DstPorts: []tailcfg.NetPortRange{
|
||||||
|
{
|
||||||
|
IP: "100.64.0.2/32",
|
||||||
|
Ports: tailcfg.PortRangeAny,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
matchers := matcher.MatchesFromFilterRules(rules)
|
||||||
|
|
||||||
|
derpLatency := make(map[string]float64, 256)
|
||||||
|
for i := range 128 {
|
||||||
|
derpLatency[fmt.Sprintf("%d-v4", i)] = float64(i) / 10
|
||||||
|
derpLatency[fmt.Sprintf("%d-v6", i)] = float64(i) / 10
|
||||||
|
}
|
||||||
|
|
||||||
|
src := Node{
|
||||||
|
IPv4: addr("100.64.0.1"),
|
||||||
|
}
|
||||||
|
dst := Node{
|
||||||
|
IPv4: addr("100.64.0.2"),
|
||||||
|
Hostinfo: &tailcfg.Hostinfo{
|
||||||
|
NetInfo: &tailcfg.NetInfo{
|
||||||
|
DERPLatency: derpLatency,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
srcView := src.View()
|
||||||
|
dstView := dst.View()
|
||||||
|
|
||||||
|
if !srcView.CanAccess(matchers, dstView) {
|
||||||
|
b.Fatal("benchmark setup error: expected source to access destination")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("pointer", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for b.Loop() {
|
||||||
|
srcView.CanAccess(matchers, dstView)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("struct clone", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for b.Loop() {
|
||||||
|
src.CanAccess(matchers, dstView.AsStruct())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user