-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathcache.go
More file actions
72 lines (61 loc) · 2.09 KB
/
cache.go
File metadata and controls
72 lines (61 loc) · 2.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: MIT
package main
import (
"sort"
"strings"
"time"
"github.com/boyter/simplecache"
)
// SearchCache caches file locations (paths) keyed by query string so that
// progressive refinements of a query can skip the full filesystem walk
// and re-evaluate only the files that matched a shorter prefix of the query.
type SearchCache struct {
cache *simplecache.Cache[[]string]
}
// NewSearchCache creates a SearchCache with LRU eviction, 100 items max, 60s TTL.
func NewSearchCache() *SearchCache {
maxItems := 100
evictionPolicy := simplecache.LRU
evictionSamples := 5
maxAge := 60 * time.Second
return &SearchCache{
cache: simplecache.New[[]string](simplecache.Option{
MaxItems: &maxItems,
EvictionPolicy: &evictionPolicy,
EvictionSamples: &evictionSamples,
MaxAge: &maxAge,
}),
}
}
// FindPrefixFiles tries progressively shorter prefixes of the query to find
// cached file locations from a previous search. Returns the cached locations
// and true on hit, or nil and false on miss.
func (sc *SearchCache) FindPrefixFiles(extensions []string, query string) ([]string, bool) {
prefix := cacheKeyPrefix(extensions)
// Try the full query first, then progressively shorter prefixes.
// We split on spaces and try removing the last word each time.
words := strings.Fields(query)
for i := len(words); i >= 1; i-- {
key := prefix + strings.Join(words[:i], " ")
if files, ok := sc.cache.Get(key); ok {
return files, true
}
}
return nil, false
}
// Store saves the matched file locations under the full query key.
func (sc *SearchCache) Store(extensions []string, query string, locations []string) {
key := cacheKeyPrefix(extensions) + query
_ = sc.cache.Set(key, locations)
}
// cacheKeyPrefix builds a deterministic prefix from the extension filter
// so that searches with different ext= params don't share cache entries.
func cacheKeyPrefix(extensions []string) string {
if len(extensions) == 0 {
return ""
}
sorted := make([]string, len(extensions))
copy(sorted, extensions)
sort.Strings(sorted)
return strings.Join(sorted, ",") + ":"
}