a06f331eb8
install-script / powershell-syntax (push) Waiting to run
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
install-script / install (macos-14) (push) Waiting to run
install-script / install (ubuntu-latest) (push) Waiting to run
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
132 lines
4.1 KiB
Go
132 lines
4.1 KiB
Go
package indexer
|
|
|
|
import (
|
|
"container/list"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// cppIncludeDirCacheT is a memory-bounded LRU over per-repo-root compile-DB
|
|
// include-dir sets. Unlike the resolver's per-pass maps (cleared between passes
|
|
// and intentionally uncapped — bounded by the pass work set), this cache is
|
|
// long-lived: one entry per tracked repo root, surviving across reindexes. It
|
|
// is bounded by GORTEX_RESOLVER_CACHE_MAX_MB; a zero / unset budget (the
|
|
// default) leaves it unbounded, preserving the prior plain-map behavior.
|
|
type cppIncludeDirCacheT struct {
|
|
mu sync.Mutex
|
|
ll *list.List // front = most-recently-used
|
|
m map[string]*list.Element
|
|
maxBytes int64 // 0 = unbounded
|
|
curBytes int64
|
|
}
|
|
|
|
type cppIncludeCacheEntry struct {
|
|
key string
|
|
tus map[string]cppTU
|
|
bytes int64
|
|
// mtime is the newest modtime (unix nanoseconds) across the compile_commands.json
|
|
// files this entry was built from. A lookup whose on-disk files are newer than
|
|
// this is treated as a miss, so an isolated edit to compile_commands.json is
|
|
// picked up on the next load without a full reindex.
|
|
mtime int64
|
|
}
|
|
|
|
// newCppIncludeDirCache builds the cache, reading GORTEX_RESOLVER_CACHE_MAX_MB
|
|
// (MiB; <= 0 / unset = unbounded) for its memory budget.
|
|
func newCppIncludeDirCache() *cppIncludeDirCacheT {
|
|
c := &cppIncludeDirCacheT{ll: list.New(), m: map[string]*list.Element{}}
|
|
if v := strings.TrimSpace(os.Getenv("GORTEX_RESOLVER_CACHE_MAX_MB")); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
|
c.maxBytes = int64(n) << 20
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// get returns the cached include-dir set for root, promoting it to
|
|
// most-recently-used. diskMtime is the newest modtime currently on disk across
|
|
// the compile_commands.json files for root; an entry whose recorded mtime is
|
|
// older is treated as stale (a miss) so an edited compile_commands.json is
|
|
// re-read on the next load without a full reindex. The second return is false on
|
|
// a miss.
|
|
func (c *cppIncludeDirCacheT) get(root string, diskMtime int64) (map[string]cppTU, bool) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
el, ok := c.m[root]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
e := el.Value.(*cppIncludeCacheEntry)
|
|
if diskMtime > e.mtime {
|
|
return nil, false
|
|
}
|
|
c.ll.MoveToFront(el)
|
|
return e.tus, true
|
|
}
|
|
|
|
// put stores the include-dir set for root along with the modtime it was built
|
|
// from, evicting least-recently-used entries until within the memory budget (at
|
|
// least the just-stored entry is retained).
|
|
func (c *cppIncludeDirCacheT) put(root string, tus map[string]cppTU, mtime int64) {
|
|
sz := cppTUMapBytes(tus)
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if el, ok := c.m[root]; ok {
|
|
e := el.Value.(*cppIncludeCacheEntry)
|
|
c.curBytes += sz - e.bytes
|
|
e.tus = tus
|
|
e.bytes = sz
|
|
e.mtime = mtime
|
|
c.ll.MoveToFront(el)
|
|
c.evictLocked()
|
|
return
|
|
}
|
|
el := c.ll.PushFront(&cppIncludeCacheEntry{key: root, tus: tus, bytes: sz, mtime: mtime})
|
|
c.m[root] = el
|
|
c.curBytes += sz
|
|
c.evictLocked()
|
|
}
|
|
|
|
// clear drops the cached include-dir set for root so the next load re-reads
|
|
// compile_commands.json.
|
|
func (c *cppIncludeDirCacheT) clear(root string) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if el, ok := c.m[root]; ok {
|
|
c.ll.Remove(el)
|
|
delete(c.m, root)
|
|
c.curBytes -= el.Value.(*cppIncludeCacheEntry).bytes
|
|
}
|
|
}
|
|
|
|
// evictLocked drops least-recently-used entries until within the byte budget,
|
|
// always retaining the most-recently-used entry (so a freshly-loaded set stays
|
|
// available to its caller). A zero budget disables eviction. Caller holds c.mu.
|
|
func (c *cppIncludeDirCacheT) evictLocked() {
|
|
if c.maxBytes <= 0 {
|
|
return
|
|
}
|
|
for c.curBytes > c.maxBytes && c.ll.Len() > 1 {
|
|
back := c.ll.Back()
|
|
e := back.Value.(*cppIncludeCacheEntry)
|
|
c.ll.Remove(back)
|
|
delete(c.m, e.key)
|
|
c.curBytes -= e.bytes
|
|
}
|
|
}
|
|
|
|
// cppTUMapBytes estimates the retained size of one repo's include-dir set for
|
|
// the cache's byte accounting (string content plus per-entry map overhead).
|
|
func cppTUMapBytes(tus map[string]cppTU) int64 {
|
|
var n int64
|
|
for k, tu := range tus {
|
|
n += int64(len(k)) + int64(len(tu.file)) + 64
|
|
for _, d := range tu.includeDirs {
|
|
n += int64(len(d)) + 16
|
|
}
|
|
}
|
|
return n
|
|
}
|