private bool IsFileContentsUpToDate(FileSystemEntities entities, FullPathChanges fullPathChanges, FileWithContents existingFileWithContents) { Debug.Assert(existingFileWithContents.Contents != null); var fullPath = existingFileWithContents.FileName.FullPath; if (fullPathChanges != null) { // We don't get file change events for file in symlinks, so we can't // rely on fullPathChanges contents for our heuristic of avoiding file // system access. if (!FileDatabaseSnapshot.IsContainedInSymLinkHelper(entities.Directories, existingFileWithContents.FileName)) { return(fullPathChanges.ShouldSkipLoadFileContents(fullPath)); } } // Do the "expensive" check by going to the file system. var fi = _fileSystem.GetFileInfoSnapshot(fullPath); return ((fi.Exists) && (fi.IsFile) && (fi.LastWriteTimeUtc == existingFileWithContents.Contents.UtcLastModified)); }
public FileSystemSnapshot Compute(IFileSystemNameFactory fileNameFactory, FileSystemSnapshot oldSnapshot, FullPathChanges pathChanges /* may be null */, IList <IProject> projects, int version, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // cancellation using (var progress = _progressTrackerFactory.CreateIndeterminateTracker()) { var projectRoots = projects .Distinct(new ProjectPathComparer()) .Select(project => { cancellationToken.ThrowIfCancellationRequested(); // cancellation var projectSnapshotBuilder = new ProjectRootSnapshotBuilder( _fileSystem, fileNameFactory, oldSnapshot, project, progress, (pathChanges == null ? null : new ProjectPathChanges(project.RootPath, pathChanges.Entries)), cancellationToken); var rootSnapshot = projectSnapshotBuilder.Build(); return(new ProjectRootSnapshot(project, rootSnapshot)); }) .OrderBy(projectRoot => projectRoot.Directory.DirectoryName) .ToReadOnlyCollection(); return(new FileSystemSnapshot(version, projectRoots)); } }
private void ComputeNewStateLongTask(FileSystemSnapshot previousSnapshot, FileSystemSnapshot newSnapshot, FullPathChanges fullPathChanges, CancellationToken cancellationToken) { Invariants.Assert(_inTaskQueueTask); UpdateFileDatabase(newSnapshot, options => { // We only allow incremental updates if the last update was successfully completed // and if the file system snapshot version we are based on is the same as the // new file system snapshot we are processing if (previousSnapshot.Version == _currentFileSystemSnapshotVersion && options.PreviousUpdateCompleted && fullPathChanges != null) { return(CreateWithFileSystemChanges(newSnapshot, fullPathChanges, options, cancellationToken)); } else { Logger.LogInfo($"Starting a full database update: " + $"CurrentSnapshotVersion={_currentFileSystemSnapshotVersion}, " + $"PreviousUpdateCompleted={options.PreviousUpdateCompleted}, " + $"PreviousSnapshotVersion={previousSnapshot.Version}, " + $"FullPathChanges={fullPathChanges?.Entries.Count ?? -1}."); return(CreateFullScan(newSnapshot, options, cancellationToken)); } }); }
private bool IsFileContentsUpToDate(FileSystemEntities entities, FullPathChanges fullPathChanges, FileWithContents existingFileWithContents) { Invariants.Assert(existingFileWithContents.Contents != null); var fullPath = existingFileWithContents.FileName.FullPath; if (fullPathChanges != null) { // We don't get file change events for file in symlinks, so we can't // rely on fullPathChanges contents for our heuristic of avoiding file // system access. // Actually, since we cannot reliable detect changes in symlinks, we enable this // optimization anyways, as we rely on the user to manually refresh the index // (that results in a "null" value for fullPathChanges) //if (!FileDatabaseSnapshot.IsContainedInSymLinkHelper(entities.Directories, existingFileWithContents.FileName)) { return(fullPathChanges.ShouldSkipLoadFileContents(fullPath)); //} } // Do the "expensive" check by going to the file system. var fi = _fileSystem.GetFileInfoSnapshot(fullPath); return ((fi.Exists) && (fi.IsFile) && (fi.LastWriteTimeUtc == existingFileWithContents.Contents.UtcLastModified)); }
private bool IsFileContentsUpToDate(FullPathChanges fullPathChanges, FileData oldFileData) { Debug.Assert(oldFileData.Contents != null); var fullPath = oldFileData.FileName.FullPath; if (fullPathChanges != null) { // We don't get file change events for file in symlinks, so we can't // rely on fullPathChanges contents for our heuristic of avoiding file // system access. if (!FileDatabase.IsContainedInSymLinkHelper(_directories, oldFileData.FileName)) { return(fullPathChanges.GetPathChangeKind(fullPath) == PathChangeKind.None); } } // Do the "expensive" check by going to the file system. var fi = _fileSystem.GetFileInfoSnapshot(fullPath); return ((fi.Exists) && (fi.IsFile) && (fi.LastWriteTimeUtc == oldFileData.Contents.UtcLastModified)); }
public IFileDatabaseSnapshot Build(IFileDatabaseSnapshot previousDatabase, FileSystemSnapshot newSnapshot, FullPathChanges fullPathChanges, Action onLoading, Action onLoaded, Action <IFileDatabaseSnapshot> onIntermadiateResult, CancellationToken cancellationToken) { using (new TimeElapsedLogger("Building file database from previous one and file system tree snapshot", cancellationToken, InfoLogger.Instance)) { using (var progress = _progressTrackerFactory.CreateIndeterminateTracker()) { onLoading(); progress.DisplayProgress((i, n) => "Preparing list of files to load from disk"); var fileDatabase = (FileDatabaseSnapshot)previousDatabase; // Compute list of files from tree var entities = ComputeFileSystemEntities(newSnapshot, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); var unchangedProjects = newSnapshot .ProjectRoots.Where(x => fileDatabase.ProjectHashes.ContainsKey(x.Project.RootPath) && fileDatabase.ProjectHashes[x.Project.RootPath] == x.Project.VersionHash) .Select(x => x.Project); cancellationToken.ThrowIfCancellationRequested(); var unchangedProjectSet = new HashSet <IProject>(unchangedProjects, // Use reference equality for IProject is safe, as we keep this // dictionary only for the duration of this "Build" call. new ReferenceEqualityComparer <IProject>()); cancellationToken.ThrowIfCancellationRequested(); var loadingContext = new FileContentsLoadingContext { FullPathChanges = fullPathChanges, LoadedTextFileCount = 0, OldFileDatabaseSnapshot = fileDatabase, UnchangedProjects = unchangedProjectSet, PartialProgressReporter = new PartialProgressReporter( TimeSpan.FromSeconds(5.0), () => { Logger.LogInfo("Creating intermedidate file database for partial progress reporting"); var database = CreateFileDatabase(entities, false, cancellationToken); onIntermadiateResult(database); }) }; // Merge old state in new state and load all missing files LoadFileContents(entities, loadingContext, cancellationToken); var result = CreateFileDatabase(entities, true, cancellationToken); onLoaded(); return(result); } } }
public IFileDatabase CreateIncremental( IFileDatabase previousFileDatabase, FileSystemTreeSnapshot previousSnapshot, FileSystemTreeSnapshot newSnapshot, FullPathChanges fullPathChanges, Action <IFileDatabase> onIntermadiateResult) { return(new FileDatabaseBuilder(_fileSystem, _fileContentsFactory, _progressTrackerFactory) .Build(previousFileDatabase, newSnapshot, fullPathChanges, onIntermadiateResult)); }
public IFileDatabase Build( IFileDatabase previousFileDatabase, FileSystemTreeSnapshot newSnapshot, FullPathChanges fullPathChanges, Action <IFileDatabase> onIntermadiateResult) { using (var logger = new TimeElapsedLogger("Building file database from previous one and file system tree snapshot")) { var fileDatabase = (FileDatabase)previousFileDatabase; // Compute list of files from tree ComputeFileCollection(newSnapshot); var unchangedProjects = newSnapshot .ProjectRoots.Where(x => fileDatabase.ProjectHashes.ContainsKey(x.Project.RootPath) && fileDatabase.ProjectHashes[x.Project.RootPath] == x.Project.VersionHash) .Select(x => x.Project); var unchangedProjectSet = new HashSet <IProject>(unchangedProjects, // Use reference equality for IProject is safe, as we keep this // dictionary only for the duration of this "Build" call. new ReferenceEqualityComparer <IProject>()); // Don't use file memoization for now, as benefit is dubvious. //IFileContentsMemoization fileContentsMemoization = new FileContentsMemoization(); IFileContentsMemoization fileContentsMemoization = new NullFileContentsMemoization(); var loadingInfo = new FileContentsLoadingInfo { FileContentsMemoization = fileContentsMemoization, FullPathChanges = fullPathChanges, LoadedTextFileCount = 0, OldFileDatabase = fileDatabase, UnchangedProjects = unchangedProjectSet, PartialProgressReporter = new PartialProgressReporter( TimeSpan.FromSeconds(5.0), () => { Logger.LogInfo("Creating intermedidate file database"); var database = this.CreateFileDatabse(); onIntermadiateResult(database); }) }; // Merge old state in new state and load all missing files LoadFileContents(loadingInfo); return(CreateFileDatabse()); } }
private void ComputeNewState( FileSystemTreeSnapshot previousSnapshot, FileSystemTreeSnapshot newSnapshot, FullPathChanges fullPathChanges) { _operationProcessor.Execute(new OperationHandlers { OnBeforeExecute = info => OnFilesLoading(info), OnError = (info, error) => { _currentTreeVersion = newSnapshot.Version; OnFilesLoaded(new FilesLoadedResult { OperationInfo = info, Error = error, TreeVersion = newSnapshot.Version }); }, Execute = info => { using (new TimeElapsedLogger("Computing new state of file database")) { var oldState = _currentFileDatabase; var newState = _fileDatabaseFactory.CreateIncremental( oldState, previousSnapshot, newSnapshot, fullPathChanges, fileDatabase => { // Store and activate intermediate new state (atomic operation). _currentFileDatabase = fileDatabase; OnFilesLoadingProgress(info); }); // Store and activate final new state (atomic operation). _currentFileDatabase = newState; } _currentTreeVersion = newSnapshot.Version; OnFilesLoaded(new FilesLoadedResult { OperationInfo = info, TreeVersion = newSnapshot.Version }); } }); }
public FileSystemSnapshot Compute(IFileSystemNameFactory fileNameFactory, FileSystemSnapshot oldSnapshot, FullPathChanges pathChanges /* may be null */, IList <IProject> projects, int version, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // cancellation using (var progress = _progressTrackerFactory.CreateIndeterminateTracker()) { // Clear file name factory intern tables if no projects. We could be // more aggressive at the expense of decreasing string interning. if (projects.Count == 0) { fileNameFactory.ClearInternedStrings(); } var projectRoots = projects .Distinct(new ProjectPathComparer()) .Select(project => { cancellationToken.ThrowIfCancellationRequested(); // cancellation var projectSnapshotBuilder = new ProjectRootSnapshotBuilder( _fileSystem, fileNameFactory, oldSnapshot, project, progress, (pathChanges == null ? null : new ProjectPathChanges(project.RootPath, pathChanges.Entries)), cancellationToken); var rootSnapshot = projectSnapshotBuilder.Build(); return(new ProjectRootSnapshot(project, rootSnapshot)); }) .OrderBy(projectRoot => projectRoot.Directory.DirectoryName) .ToReadOnlyCollection(); return(new FileSystemSnapshot(version, projectRoots)); } }
private IFileDatabaseSnapshot CreateIncrementalWorker(IFileDatabaseSnapshot previousDatabase, FileSystemSnapshot newFileSystemSnapshot, FullPathChanges fullPathChanges, Action onLoading, Action onLoaded, Action <IFileDatabaseSnapshot> onIntermadiateResult, CancellationToken cancellationToken) { return(new FileDatabaseBuilder(_fileSystem, _fileContentsFactory, _progressTrackerFactory) .Build(previousDatabase, newFileSystemSnapshot, fullPathChanges, onLoading, onLoaded, onIntermadiateResult, cancellationToken)); }
public IFileDatabaseSnapshot CreateIncrementalWithFileSystemUpdates(IFileDatabaseSnapshot previousDatabase, FileSystemSnapshot newFileSystemSnapshot, FullPathChanges fullPathChanges, Action onLoading, Action onLoaded, Action <IFileDatabaseSnapshot> onIntermadiateResult, CancellationToken cancellationToken) { return(CreateIncrementalWorker(previousDatabase, newFileSystemSnapshot, fullPathChanges, onLoading, onLoaded, onIntermadiateResult, cancellationToken)); }
private IFileDatabaseSnapshot CreateWithFileSystemChanges(FileSystemSnapshot newSnapshot, FullPathChanges fullPathChanges, UpdateFileDatabaseOptions options, CancellationToken cancellationToken) { Invariants.Assert(_inTaskQueueTask); return(_fileDatabaseSnapshotFactory.CreateIncrementalWithFileSystemUpdates( options.CurrentFileDatabase, newSnapshot, fullPathChanges, onIntermadiateResult: fileDatabase => { ActivateCurrentDatabase(newSnapshot, fileDatabase, false); OnFilesLoadingProgress(options.OperationInfo); }, onLoading: () => OnFilesLoading(options.OperationInfo), onLoaded: () => OnFilesLoaded(new FilesLoadedResult { OperationInfo = options.OperationInfo, TreeVersion = _currentFileSystemSnapshotVersion, }), cancellationToken: cancellationToken)); }