diff --git a/route/process_cache.go b/route/process_cache.go new file mode 100644 index 00000000..691a4e8e --- /dev/null +++ b/route/process_cache.go @@ -0,0 +1,34 @@ +package route + +import ( + "context" + "net/netip" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/process" +) + +type processCacheKey struct { + Network string + Source netip.AddrPort + Destination netip.AddrPort +} + +type processCacheEntry struct { + result *adapter.ConnectionOwner + err error +} + +func (r *Router) findProcessInfoCached(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error) { + key := processCacheKey{ + Network: network, + Source: source, + Destination: destination, + } + if entry, ok := r.processCache.Get(key); ok { + return entry.result, entry.err + } + result, err := process.FindProcessInfo(r.processSearcher, ctx, network, source, destination) + r.processCache.Add(key, processCacheEntry{result: result, err: err}) + return result, err +} diff --git a/route/route.go b/route/route.go index 40a90e7d..7773ff3c 100644 --- a/route/route.go +++ b/route/route.go @@ -9,7 +9,6 @@ import ( "time" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/sniff" C "github.com/sagernet/sing-box/constant" R "github.com/sagernet/sing-box/route/rule" @@ -415,7 +414,7 @@ func (r *Router) matchRule( } else if metadata.Destination.IsIP() { originDestination = metadata.Destination.AddrPort() } - processInfo, fErr := process.FindProcessInfo(r.processSearcher, ctx, metadata.Network, metadata.Source.AddrPort(), originDestination) + processInfo, fErr := r.findProcessInfoCached(ctx, metadata.Network, metadata.Source.AddrPort(), originDestination) if fErr != nil { r.logger.InfoContext(ctx, "failed to search process: ", fErr) } else { diff --git a/route/router.go b/route/router.go index 5c73cb1c..9f8c343c 100644 --- a/route/router.go +++ b/route/router.go @@ -4,6 +4,7 @@ import ( "context" "os" "runtime" + "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/process" @@ -12,8 +13,11 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" R "github.com/sagernet/sing-box/route/rule" + "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/task" + "github.com/sagernet/sing/contrab/freelru" + "github.com/sagernet/sing/contrab/maphash" "github.com/sagernet/sing/service" "github.com/sagernet/sing/service/pause" ) @@ -34,6 +38,7 @@ type Router struct { ruleSets []adapter.RuleSet ruleSetMap map[string]adapter.RuleSet processSearcher process.Searcher + processCache freelru.Cache[processCacheKey, processCacheEntry] pauseManager pause.Manager trackers []adapter.ConnectionTracker platformInterface adapter.PlatformInterface @@ -141,6 +146,11 @@ func (r *Router) Start(stage adapter.StartStage) error { } } } + if r.processSearcher != nil { + processCache := common.Must1(freelru.NewSharded[processCacheKey, processCacheEntry](256, maphash.NewHasher[processCacheKey]().Hash32)) + processCache.SetLifetime(200 * time.Millisecond) + r.processCache = processCache + } case adapter.StartStatePostStart: for i, rule := range r.rules { monitor.Start("initialize rule[", i, "]")