diff --git a/common/strmatcher/benchmark_test.go b/common/strmatcher/benchmark_test.go index 6eb7f0eba..d92ec70c6 100644 --- a/common/strmatcher/benchmark_test.go +++ b/common/strmatcher/benchmark_test.go @@ -34,3 +34,20 @@ func BenchmarkMarchGroup(b *testing.B) { _ = g.Match("0.v2ray.com") } } + +func BenchmarkCachedMarchGroup(b *testing.B) { + g := NewMatcherGroup() + for i := 1; i <= 1024; i++ { + m, err := Domain.New(strconv.Itoa(i) + ".v2ray.com") + common.Must(err) + g.Add(m) + } + + cg := NewCachedMatcherGroup(g) + _ = cg.Match("0.v2ray.com") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = cg.Match("0.v2ray.com") + } +} diff --git a/common/strmatcher/strmatcher.go b/common/strmatcher/strmatcher.go index 15219a0f7..a65a68d8c 100644 --- a/common/strmatcher/strmatcher.go +++ b/common/strmatcher/strmatcher.go @@ -112,7 +112,7 @@ type cacheEntry struct { } type CachedMatcherGroup struct { - sync.Mutex + sync.RWMutex group *MatcherGroup cache map[string]cacheEntry cleanup *task.Periodic @@ -129,7 +129,7 @@ func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup { r.Lock() defer r.Unlock() - expire := time.Now().Add(-1 * time.Second * 60) + expire := time.Now().Add(-1 * time.Second * 120) for p, e := range r.cache { if e.timestamp.Before(expire) { delete(r.cache, p) @@ -143,22 +143,21 @@ func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup { } func (g *CachedMatcherGroup) Match(pattern string) uint32 { - g.Lock() - defer g.Unlock() - + g.RLock() r, f := g.cache[pattern] + g.RUnlock() if f { - r.timestamp = time.Now() - g.cache[pattern] = r return r.result } mr := g.group.Match(pattern) + g.Lock() g.cache[pattern] = cacheEntry{ result: mr, timestamp: time.Now(), } + g.Unlock() return mr }