kittenipc/kitcom/internal/tsgo/project/extendedconfigcache.go
2025-10-15 10:12:44 +03:00

76 lines
2.0 KiB
Go

package project
import (
"sync"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
"github.com/zeebo/xxh3"
)
type extendedConfigCache struct {
entries collections.SyncMap[tspath.Path, *extendedConfigCacheEntry]
}
type extendedConfigCacheEntry struct {
mu sync.Mutex
entry *tsoptions.ExtendedConfigCacheEntry
hash xxh3.Uint128
refCount int
}
func (c *extendedConfigCache) Acquire(fh FileHandle, path tspath.Path, parse func() *tsoptions.ExtendedConfigCacheEntry) *tsoptions.ExtendedConfigCacheEntry {
entry, loaded := c.loadOrStoreNewLockedEntry(path)
defer entry.mu.Unlock()
var hash xxh3.Uint128
if fh != nil {
hash = fh.Hash()
}
if !loaded || entry.hash != hash {
// Reparse the config if the hash has changed, or parse for the first time.
entry.entry = parse()
entry.hash = hash
}
return entry.entry
}
func (c *extendedConfigCache) Ref(path tspath.Path) {
if entry, ok := c.entries.Load(path); ok {
entry.mu.Lock()
entry.refCount++
entry.mu.Unlock()
}
}
func (c *extendedConfigCache) Deref(path tspath.Path) {
if entry, ok := c.entries.Load(path); ok {
entry.mu.Lock()
entry.refCount--
remove := entry.refCount <= 0
entry.mu.Unlock()
if remove {
c.entries.Delete(path)
}
}
}
func (c *extendedConfigCache) Has(path tspath.Path) bool {
_, ok := c.entries.Load(path)
return ok
}
// loadOrStoreNewLockedEntry loads an existing entry or creates a new one. The returned
// entry's mutex is locked and its refCount is incremented (or initialized to 1
// in the case of a new entry).
func (c *extendedConfigCache) loadOrStoreNewLockedEntry(path tspath.Path) (*extendedConfigCacheEntry, bool) {
entry := &extendedConfigCacheEntry{refCount: 1}
entry.mu.Lock()
if existing, loaded := c.entries.LoadOrStore(path, entry); loaded {
existing.mu.Lock()
existing.refCount++
return existing, true
}
return entry, false
}