diff --git a/internal/project/extendedconfigcache.go b/internal/project/extendedconfigcache.go index 38654c55ae..3e6977272d 100644 --- a/internal/project/extendedconfigcache.go +++ b/internal/project/extendedconfigcache.go @@ -38,6 +38,17 @@ func (c *extendedConfigCache) Acquire(fh FileHandle, path tspath.Path, parse fun func (c *extendedConfigCache) Ref(path tspath.Path) { if entry, ok := c.entries.Load(path); ok { entry.mu.Lock() + if entry.refCount <= 0 { + // Entry was deleted while we were acquiring the lock + newEntry, loaded := c.loadOrStoreNewLockedEntry(path) + if !loaded { + newEntry.entry = entry.entry + newEntry.hash = entry.hash + } + entry.mu.Unlock() + newEntry.mu.Unlock() + return + } entry.refCount++ entry.mu.Unlock() } @@ -48,10 +59,10 @@ func (c *extendedConfigCache) Deref(path tspath.Path) { entry.mu.Lock() entry.refCount-- remove := entry.refCount <= 0 - entry.mu.Unlock() if remove { c.entries.Delete(path) } + entry.mu.Unlock() } } @@ -68,6 +79,11 @@ func (c *extendedConfigCache) loadOrStoreNewLockedEntry(path tspath.Path) (*exte entry.mu.Lock() if existing, loaded := c.entries.LoadOrStore(path, entry); loaded { existing.mu.Lock() + if existing.refCount <= 0 { + // Entry was deleted while we were acquiring the lock + existing.mu.Unlock() + return c.loadOrStoreNewLockedEntry(path) + } existing.refCount++ return existing, true } diff --git a/internal/project/parsecache.go b/internal/project/parsecache.go index caf8851584..48ccf8a9e7 100644 --- a/internal/project/parsecache.go +++ b/internal/project/parsecache.go @@ -63,6 +63,17 @@ func (c *ParseCache) Ref(file *ast.SourceFile) { key := newParseCacheKey(file.ParseOptions(), file.ScriptKind) if entry, ok := c.entries.Load(key); ok { entry.mu.Lock() + if entry.refCount <= 0 && !c.Options.DisableDeletion { + // Entry was deleted while we were acquiring the lock + newEntry, loaded := c.loadOrStoreNewLockedEntry(key) + if !loaded { + newEntry.sourceFile = entry.sourceFile + newEntry.hash = entry.hash + } + entry.mu.Unlock() + newEntry.mu.Unlock() + return + } entry.refCount++ entry.mu.Unlock() } else { @@ -76,10 +87,10 @@ func (c *ParseCache) Deref(file *ast.SourceFile) { entry.mu.Lock() entry.refCount-- remove := entry.refCount <= 0 - entry.mu.Unlock() if !c.Options.DisableDeletion && remove { c.entries.Delete(key) } + entry.mu.Unlock() } } @@ -92,6 +103,11 @@ func (c *ParseCache) loadOrStoreNewLockedEntry(key parseCacheKey) (*parseCacheEn existing, loaded := c.entries.LoadOrStore(key, entry) if loaded { existing.mu.Lock() + if existing.refCount <= 0 && !c.Options.DisableDeletion { + // Existing entry was deleted while we were acquiring the lock + existing.mu.Unlock() + return c.loadOrStoreNewLockedEntry(key) + } existing.refCount++ return existing, true }