Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to just using paths as keys for file watching #74877

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal sealed class FileWatchedReferenceFactory<TReference>
/// are only created once we are actually applying a batch because we don't determine until the batch is applied if
/// the file reference will actually be a file reference or it'll be a converted project reference.
/// </summary>
private readonly Dictionary<TReference, (IWatchedFile Token, int RefCount)> _referenceFileWatchingTokens = [];
private readonly Dictionary<string, (IWatchedFile Token, int RefCount)> _referenceFileWatchingTokens = [];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the crux of the change. it keeps the token/ref-count assocaited with the path, not the reerence identity anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dumb question: Could _previousDisposalLocations key on the path too?


/// <summary>
/// Stores the caller for a previous disposal of a reference produced by this class, to track down a double-dispose
Expand Down Expand Up @@ -113,17 +113,17 @@ static ImmutableArray<WatchedDirectory> GetAdditionalWatchedDirectories()
/// watched , the reference count will be incremented. This is *not* safe to attempt to call multiple times for the
/// same project and reference (e.g. in applying workspace updates)
/// </summary>
public void StartWatchingReference(TReference reference, string fullFilePath)
public void StartWatchingReference(string fullFilePath)
{
lock (_gate)
{
var (token, count) = _referenceFileWatchingTokens.GetOrAdd(reference, _ =>
var (token, count) = _referenceFileWatchingTokens.GetOrAdd(fullFilePath, _ =>
{
var fileToken = _fileReferenceChangeContext.Value.EnqueueWatchingFile(fullFilePath);
return (fileToken, RefCount: 0);
});

_referenceFileWatchingTokens[reference] = (token, RefCount: count + 1);
_referenceFileWatchingTokens[fullFilePath] = (token, RefCount: count + 1);
}
}

Expand All @@ -132,12 +132,12 @@ public void StartWatchingReference(TReference reference, string fullFilePath)
/// 0, the file watcher will be stopped. This is *not* safe to attempt to call multiple times for the same project
/// and reference (e.g. in applying workspace updates)
/// </summary>
public void StopWatchingReference(TReference reference, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0)
public void StopWatchingReference(TReference reference, string fullFilePath, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0)
{
lock (_gate)
{
var disposalLocation = callerFilePath + ", line " + callerLineNumber;
if (!_referenceFileWatchingTokens.TryGetValue(reference, out var watchedFileReference))
if (!_referenceFileWatchingTokens.TryGetValue(fullFilePath, out var watchedFileReference))
{
// We're attempting to stop watching a file that we never started watching. This is a bug.
var existingDisposalStackTrace = _previousDisposalLocations.TryGetValue(reference, out var previousDisposalLocation);
Expand All @@ -150,14 +150,14 @@ public void StopWatchingReference(TReference reference, [CallerFilePath] string
{
// No one else is watching this file, so stop watching it and remove from our map.
watchedFileReference.Token.Dispose();
_referenceFileWatchingTokens.Remove(reference);
_referenceFileWatchingTokens.Remove(fullFilePath);

_previousDisposalLocations.Remove(reference);
_previousDisposalLocations.Add(reference, disposalLocation);
}
else
{
_referenceFileWatchingTokens[reference] = (watchedFileReference.Token, newRefCount);
_referenceFileWatchingTokens[fullFilePath] = (watchedFileReference.Token, newRefCount);
}

// Note we still potentially have an outstanding change that we haven't raised a notification for due to the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ public void RemoveFromWorkspace()
Contract.ThrowIfNull(remainingMetadataReferences);

foreach (var reference in remainingMetadataReferences.OfType<PortableExecutableReference>())
_projectSystemProjectFactory.FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference);
_projectSystemProjectFactory.FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference, reference.FilePath!);
}

public void ReorderSourceFiles(ImmutableArray<string> filePaths)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,19 +418,19 @@ internal void ApplyProjectUpdateState(ProjectUpdateState projectUpdateState)

// Remove file watchers for any references we're no longer watching.
foreach (var reference in projectUpdateState.RemovedMetadataReferences)
FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference);
FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference, reference.FilePath!);

// Add file watchers for any references we are now watching.
foreach (var reference in projectUpdateState.AddedMetadataReferences)
FileWatchedPortableExecutableReferenceFactory.StartWatchingReference(reference, reference.FilePath!);
FileWatchedPortableExecutableReferenceFactory.StartWatchingReference(reference.FilePath!);

// Remove file watchers for any references we're no longer watching.
foreach (var reference in projectUpdateState.RemovedAnalyzerReferences)
FileWatchedAnalyzerReferenceFactory.StopWatchingReference(reference);
FileWatchedAnalyzerReferenceFactory.StopWatchingReference(reference, reference.FullPath);

// Add file watchers for any references we are now watching.
foreach (var reference in projectUpdateState.AddedAnalyzerReferences)
FileWatchedAnalyzerReferenceFactory.StartWatchingReference(reference, reference.FullPath);
FileWatchedAnalyzerReferenceFactory.StartWatchingReference(reference.FullPath);

// Clear the state from the this update in preparation for the next.
projectUpdateState = projectUpdateState.ClearIncrementalState();
Expand Down
Loading