@@ -40,6 +40,7 @@ import (
40
40
"time"
41
41
42
42
"golang.org/x/tools/gopls/internal/bug"
43
+ "golang.org/x/tools/gopls/internal/lsp/lru"
43
44
"golang.org/x/tools/internal/lockedfile"
44
45
)
45
46
@@ -51,11 +52,28 @@ func Start() {
51
52
go getCacheDir ()
52
53
}
53
54
55
+ // As an optimization, use a 100MB in-memory LRU cache in front of filecache
56
+ // operations. This reduces I/O for operations such as diagnostics or
57
+ // implementations that repeatedly access the same cache entries.
58
+ var memCache = lru .New (100 * 1e6 )
59
+
60
+ type memKey struct {
61
+ kind string
62
+ key [32 ]byte
63
+ }
64
+
54
65
// Get retrieves from the cache and returns a newly allocated
55
66
// copy of the value most recently supplied to Set(kind, key),
56
67
// possibly by another process.
57
68
// Get returns ErrNotFound if the value was not found.
58
69
func Get (kind string , key [32 ]byte ) ([]byte , error ) {
70
+ // First consult the read-through memory cache.
71
+ // Note that memory cache hits do not update the times
72
+ // used for LRU eviction of the file-based cache.
73
+ if value := memCache .Get (memKey {kind , key }); value != nil {
74
+ return value .([]byte ), nil
75
+ }
76
+
59
77
iolimit <- struct {}{} // acquire a token
60
78
defer func () { <- iolimit }() // release a token
61
79
@@ -112,6 +130,7 @@ func Get(kind string, key [32]byte) ([]byte, error) {
112
130
return nil , fmt .Errorf ("failed to update access time: %w" , err )
113
131
}
114
132
133
+ memCache .Set (memKey {kind , key }, value , len (value ))
115
134
return value , nil
116
135
}
117
136
@@ -121,6 +140,8 @@ var ErrNotFound = fmt.Errorf("not found")
121
140
122
141
// Set updates the value in the cache.
123
142
func Set (kind string , key [32 ]byte , value []byte ) error {
143
+ memCache .Set (memKey {kind , key }, value , len (value ))
144
+
124
145
iolimit <- struct {}{} // acquire a token
125
146
defer func () { <- iolimit }() // release a token
126
147
0 commit comments