Skip to content

Commit a3cc702

Browse files
committed
fix race condition in symlinks
1 parent f1f86d5 commit a3cc702

File tree

3 files changed

+15
-13
lines changed

3 files changed

+15
-13
lines changed

internal/modulespecifiers/specifiers.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,15 +363,15 @@ func GetEachFileNameOfModule(
363363
}
364364
}
365365

366-
symlinkedDirectories := host.GetSymlinkCache().DirectoriesByRealpath()
366+
symlinkCache := host.GetSymlinkCache()
367367
fullImportedFileName := tspath.GetNormalizedAbsolutePath(importedFileName, cwd)
368-
if symlinkedDirectories != nil {
368+
if symlinkCache != nil {
369369
tspath.ForEachAncestorDirectoryStoppingAtGlobalCache(
370370
host.GetGlobalTypingsCacheLocation(),
371371
tspath.GetDirectoryPath(fullImportedFileName),
372372
func(realPathDirectory string) (bool, bool) {
373-
symlinkDirectories := symlinkedDirectories.Get(tspath.ToPath(realPathDirectory, cwd, host.UseCaseSensitiveFileNames()).EnsureTrailingDirectorySeparator())
374-
if symlinkDirectories == nil {
373+
symlinkSet, ok := symlinkCache.DirectoriesByRealpath().Load(tspath.ToPath(realPathDirectory, cwd, host.UseCaseSensitiveFileNames()).EnsureTrailingDirectorySeparator())
374+
if !ok {
375375
return false, false
376376
} // Continue to ancestor directory
377377

@@ -392,15 +392,16 @@ func GetEachFileNameOfModule(
392392
UseCaseSensitiveFileNames: host.UseCaseSensitiveFileNames(),
393393
CurrentDirectory: cwd,
394394
})
395-
for _, symlinkDirectory := range symlinkDirectories {
395+
symlinkSet.Range(func(symlinkDirectory string) bool {
396396
option := tspath.ResolvePath(symlinkDirectory, relative)
397397
results = append(results, ModulePath{
398398
FileName: option,
399399
IsInNodeModules: ContainsNodeModules(option),
400400
IsRedirect: target == referenceRedirect,
401401
})
402402
shouldFilterIgnoredPaths = true // We found a non-ignored path in symlinks, so we can reject ignored-path realpaths
403-
}
403+
return true
404+
})
404405
}
405406

406407
return false, false

internal/symlinks/knownsymlinks.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type KnownDirectoryLink struct {
2626

2727
type KnownSymlinks struct {
2828
directories collections.SyncMap[tspath.Path, *KnownDirectoryLink]
29-
directoriesByRealpath collections.MultiMap[tspath.Path, string]
29+
directoriesByRealpath collections.SyncMap[tspath.Path, *collections.SyncSet[string]]
3030
files collections.SyncMap[tspath.Path, string]
3131
HasProcessedResolutions bool
3232
populatedPackages collections.SyncMap[string, struct{}]
@@ -39,7 +39,7 @@ func (cache *KnownSymlinks) Directories() *collections.SyncMap[tspath.Path, *Kno
3939
return &cache.directories
4040
}
4141

42-
func (cache *KnownSymlinks) DirectoriesByRealpath() *collections.MultiMap[tspath.Path, string] {
42+
func (cache *KnownSymlinks) DirectoriesByRealpath() *collections.SyncMap[tspath.Path, *collections.SyncSet[string]] {
4343
return &cache.directoriesByRealpath
4444
}
4545

@@ -51,7 +51,8 @@ func (cache *KnownSymlinks) Files() *collections.SyncMap[tspath.Path, string] {
5151
func (cache *KnownSymlinks) SetDirectory(symlink string, symlinkPath tspath.Path, realDirectory *KnownDirectoryLink) {
5252
if realDirectory != nil {
5353
if _, ok := cache.directories.Load(symlinkPath); !ok {
54-
cache.directoriesByRealpath.Add(realDirectory.RealPath, symlink)
54+
set, _ := cache.directoriesByRealpath.LoadOrStore(realDirectory.RealPath, &collections.SyncSet[string]{})
55+
set.Add(symlink)
5556
}
5657
}
5758
cache.directories.Store(symlinkPath, realDirectory)

internal/symlinks/knownsymlinks_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ func TestSetDirectory(t *testing.T) {
5050
}
5151

5252
// Check that realpath mapping was created
53-
realpaths := cache.DirectoriesByRealpath().Get(realDirectory.RealPath)
54-
if len(realpaths) == 0 {
53+
set, ok := cache.DirectoriesByRealpath().Load(realDirectory.RealPath)
54+
if !ok || set.Size() == 0 {
5555
t.Fatal("Expected realpath mapping to be created")
5656
}
57-
if realpaths[0] != "/test/symlink" {
58-
t.Errorf("Expected symlink to be '/test/symlink', got '%s'", realpaths[0])
57+
if !set.Has("/test/symlink") {
58+
t.Error("Expected symlink '/test/symlink' to be in set")
5959
}
6060
}
6161

0 commit comments

Comments
 (0)