public FileSystemTreeSnapshot Compute( IFileSystemNameFactory fileNameFactory, FileSystemTreeSnapshot oldSnapshot, FullPathChanges pathChanges /* may be null */, List <FullPath> rootFiles, int version) { using (var progress = _progressTrackerFactory.CreateIndeterminateTracker()) { var projectRoots = rootFiles .Select(filename => _projectDiscovery.GetProject(filename)) .Where(project => project != null) .Distinct(new ProjectPathComparer()) .Select(project => { var data = new ProjectProcessingData { FileSystemNameFactory = fileNameFactory, Project = project, Progress = progress, OldSnapshot = oldSnapshot, PathChanges = (pathChanges == null ? null : new ProjectPathChanges(project.RootPath, pathChanges.Entries)), }; var rootSnapshot = ProcessProject(data); return(new ProjectRootSnapshot(project, rootSnapshot)); }) .OrderBy(projectRoot => projectRoot.Directory.DirectoryName) .ToReadOnlyCollection(); return(new FileSystemTreeSnapshot(version, projectRoots)); } }
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 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); }
private FileSystemTreeSnapshot ComputeNewSnapshot(FileSystemTreeSnapshot oldSnapshot, FullPathChanges pathChanges) { using (new TimeElapsedLogger("Computing snapshot delta from list of file changes")) { // Get list of currently registered files. var rootFiles = new List<FullPath>(); lock (_lock) { ValidateKnownFiles(); rootFiles.AddRange(_registeredFiles); } // file name factory var fileNameFactory = _fileSystemNameFactory; if (ReuseFileNameInstances) { if (_fileSystemSnapshot.ProjectRoots.Count > 0) { fileNameFactory = new FileSystemTreeSnapshotNameFactory(_fileSystemSnapshot, fileNameFactory); } } // Compute new snapshot var newSnapshot = _fileSystemSnapshotBuilder.Compute( fileNameFactory, oldSnapshot, pathChanges, rootFiles, Interlocked.Increment(ref _version)); // Monitor all the Chromium directories for changes. var newRoots = newSnapshot.ProjectRoots .Select(entry => entry.Directory.DirectoryName.FullPath); _directoryChangeWatcher.WatchDirectories(newRoots); return newSnapshot; } }
private void RecomputeGraph(FullPathChanges pathChanges) { _operationProcessor.Execute(new OperationHandlers { OnBeforeExecute = info => OnSnapshotComputing(info), OnError = (info, error) => OnSnapshotComputed(new SnapshotComputedResult { OperationInfo = info, Error = error }), Execute = info => { // Compute and assign new snapshot var oldSnapshot = _fileSystemSnapshot; var newSnapshot = ComputeNewSnapshot(oldSnapshot, pathChanges); // Update of new tree (assert calls are serialized). Debug.Assert(ReferenceEquals(oldSnapshot, _fileSystemSnapshot)); _fileSystemSnapshot = newSnapshot; if (Logger.Info) { Logger.LogInfo("+++++++++++ Collected {0:n0} files in {1:n0} directories", newSnapshot.ProjectRoots.Aggregate(0, (acc, x) => acc + CountFileEntries(x.Directory)), newSnapshot.ProjectRoots.Aggregate(0, (acc, x) => acc + CountDirectoryEntries(x.Directory))); } // Post event OnSnapshotComputed(new SnapshotComputedResult { OperationInfo = info, PreviousSnapshot = oldSnapshot, FullPathChanges = pathChanges, NewSnapshot = newSnapshot }); } }); }
private void FlushFileRegistrationQueueTask() { var entries = _fileRegistrationQueue.DequeueAll(); if (!entries.Any()) return; Logger.LogInfo("FlushFileRegistrationQueueTask:"); foreach (var entry in entries) { Logger.LogInfo(" Path=\"{0}\", Kind={1}", entry.Path, entry.Kind); } bool recompute = ValidateKnownFiles(); lock (_lock) { // Take a snapshot of all known project paths before applying changes var projectPaths1 = CollectKnownProjectPathsSorted(_registeredFiles); // Apply changes foreach (var entry in entries) { switch (entry.Kind) { case FileRegistrationKind.Register: _registeredFiles.Add(entry.Path); break; case FileRegistrationKind.Unregister: _registeredFiles.Remove(entry.Path); break; default: throw new ArgumentOutOfRangeException(); } } // Take a snapshot after applying changes, and compare var projectPaths2 = CollectKnownProjectPathsSorted(_registeredFiles); if (!projectPaths1.SequenceEqual(projectPaths2)) { recompute = true; } } // TODO(rpaquay): Be smarter here, don't recompute directory roots // that have not been affected. if (recompute) { // Pass empty changes, as we don't know of any file system changes for // existing entries. For new entries, they don't exist in the snapshot, // so they will be read form disk var emptyChanges = new FullPathChanges(ArrayUtilities.EmptyList<PathChangeEntry>.Instance); RecomputeGraph(emptyChanges); } }