diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..522b1d1 --- /dev/null +++ b/cache.go @@ -0,0 +1,66 @@ +// Copyright (C) 2017 Marius Schellenberger + +package filter + +import ( + "math/rand" + "sync" +) + +// QueryCache can be used to cache queries +type QueryCache struct { + // protects m + sync.RWMutex + + m map[string]Query + max int +} + +// NewQueryCache returns a new QueryCache +func NewQueryCache(max int) *QueryCache { + return &QueryCache{ + m: make(map[string]Query), + max: max, + } +} + +// NewQuery looks for the given query in the cache and returns it. +// If the query is not found it will be generated and inserted in the cache.. +func (qc *QueryCache) NewQuery(s string) (q *Query, err error) { + q = qc.lookup(s) + if q != nil { + return + } + q, err = NewQuery(s) + if err != nil { + return + } + qc.Lock() + defer qc.Unlock() + if len(qc.m) == qc.max { + qc.clean() + } + qc.m[s] = *q + return +} + +func (qc *QueryCache) lookup(s string) *Query { + qc.RLock() + defer qc.RUnlock() + if q, ok := qc.m[s]; ok { + return &q + } + return nil +} + +func (qc *QueryCache) clean() { + i := rand.Intn(len(qc.m)) + var k string + for k = range qc.m { + if i == 0 { + break + } + i-- + } + delete(qc.m, k) +} diff --git a/filter_test.go b/filter_test.go index b257805..fbb81aa 100644 --- a/filter_test.go +++ b/filter_test.go @@ -275,6 +275,14 @@ func BenchmarkNewQueryComplexOr(b *testing.B) { } } +func BenchmarkNewQueryCacheComplexOr(b *testing.B) { + c := NewQueryCache(1) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + c.NewQuery(compOr) + } +} + func BenchmarkNewQuerySort(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { @@ -303,6 +311,14 @@ func BenchmarkNewQuerySortComplexOr(b *testing.B) { } } +func BenchmarkNewQueryCacheSortComplexOr(b *testing.B) { + c := NewQueryCache(1) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + c.NewQuery(compOrSort) + } +} + func BenchmarkFilterSimple(b *testing.B) { b.ReportAllocs() q, err := NewQuery(simple)