private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache) { string error; if (!this.context.Enlistment.Authentication.TryInitialize(this.context.Tracer, this.context.Enlistment, out error)) { this.FailMountAndExit("Failed to obtain git credentials: " + error); } GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(this.context.Tracer, this.context.Enlistment, cache, this.retryConfig); this.gitObjects = new GVFSGitObjects(this.context, objectRequestor); FileSystemVirtualizer virtualizer = this.CreateOrReportAndExit(() => GVFSPlatformLoader.CreateFileSystemVirtualizer(this.context, this.gitObjects), "Failed to create src folder virtualizer"); GitStatusCache gitStatusCache = (!this.context.Unattended && GVFSPlatform.Instance.IsGitStatusCacheSupported()) ? new GitStatusCache(this.context, this.gitStatusCacheConfig) : null; if (gitStatusCache != null) { this.tracer.RelatedInfo("Git status cache enabled. Backoff time: {0}ms", this.gitStatusCacheConfig.BackoffTime.TotalMilliseconds); } else { this.tracer.RelatedInfo("Git status cache is not enabled"); } this.fileSystemCallbacks = this.CreateOrReportAndExit(() => new FileSystemCallbacks(this.context, this.gitObjects, RepoMetadata.Instance, virtualizer, gitStatusCache), "Failed to create src folder callback listener"); this.maintenanceScheduler = this.CreateOrReportAndExit(() => new GitMaintenanceScheduler(this.context, this.gitObjects), "Failed to start maintenance scheduler"); int majorVersion; int minorVersion; if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { this.FailMountAndExit("Error: {0}", error); } if (majorVersion != GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion) { this.FailMountAndExit( "Error: On disk version ({0}) does not match current version ({1})", majorVersion, GVFSPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion); } try { if (!this.fileSystemCallbacks.TryStart(out error)) { this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error); } } catch (Exception e) { this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString()); } this.heartbeat = new HeartbeatThread(this.tracer, this.fileSystemCallbacks); this.heartbeat.Start(); }
public MockFileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, FileSystemVirtualizer fileSystemVirtualizer) : base(context, gitObjects, repoMetadata, fileSystemVirtualizer, null) { }
public MockFileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer) : base(context, gitObjects, repoMetadata, blobSizes, gitIndexProjection, backgroundFileSystemTaskRunner, fileSystemVirtualizer) { }
private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache) { string error; if (!this.context.Enlistment.Authentication.TryRefreshCredentials(this.context.Tracer, out error)) { this.FailMountAndExit("Failed to obtain git credentials: " + error); } GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(this.context.Tracer, this.context.Enlistment, cache, this.retryConfig); this.gitObjects = new GVFSGitObjects(this.context, objectRequestor); FileSystemVirtualizer virtualizer = this.CreateOrReportAndExit(() => GVFSPlatformLoader.CreateFileSystemVirtualizer(this.context, this.gitObjects), "Failed to create src folder virtualizer"); this.fileSystemCallbacks = this.CreateOrReportAndExit(() => new FileSystemCallbacks(this.context, this.gitObjects, RepoMetadata.Instance, virtualizer), "Failed to create src folder callback listener"); if (!this.context.Unattended) { this.prefetcher = this.CreateOrReportAndExit(() => new BackgroundPrefetcher(this.tracer, this.enlistment, this.context.FileSystem, this.gitObjects), "Failed to start background prefetcher"); } int majorVersion; int minorVersion; if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { this.FailMountAndExit("Error: {0}", error); } if (majorVersion != RepoMetadata.DiskLayoutVersion.CurrentMajorVersion) { this.FailMountAndExit( "Error: On disk version ({0}) does not match current version ({1})", majorVersion, RepoMetadata.DiskLayoutVersion.CurrentMajorVersion); } try { if (!this.fileSystemCallbacks.TryStart(out error)) { this.FailMountAndExit("Error: {0}. \r\nPlease confirm that gvfs clone completed without error.", error); } } catch (Exception e) { this.FailMountAndExit("Failed to initialize src folder callbacks. {0}", e.ToString()); } this.heartbeat = new HeartbeatThread(this.tracer, this.fileSystemCallbacks); this.heartbeat.Start(); }
public MockFileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer, IPlaceholderCollection placeholderDatabase, ISparseCollection sparseCollection) : base(context, gitObjects, repoMetadata, blobSizes, gitIndexProjection, backgroundFileSystemTaskRunner, fileSystemVirtualizer, placeholderDatabase, sparseCollection) { }
public void OnGetFileStreamReturnsSuccessWhenFileStreamAvailable() { const string TestFileName = "test.txt"; Mock <IPlaceholderCollection> mockPlaceholderDb = new Mock <IPlaceholderCollection>(MockBehavior.Strict); mockPlaceholderDb.Setup(x => x.GetCount()).Returns(1); Mock <ISparseCollection> mockSparseDb = new Mock <ISparseCollection>(MockBehavior.Strict); using (MockBackgroundFileSystemTaskRunner backgroundTaskRunner = new MockBackgroundFileSystemTaskRunner()) using (MockVirtualizationInstance mockVirtualization = new MockVirtualizationInstance()) using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { TestFileName })) using (MacFileSystemVirtualizer virtualizer = new MacFileSystemVirtualizer(this.Repo.Context, this.Repo.GitObjects, mockVirtualization)) using (FileSystemCallbacks fileSystemCallbacks = new FileSystemCallbacks( this.Repo.Context, this.Repo.GitObjects, RepoMetadata.Instance, new MockBlobSizes(), gitIndexProjection, backgroundTaskRunner, virtualizer, mockPlaceholderDb.Object, mockSparseDb.Object)) { string error; fileSystemCallbacks.TryStart(out error).ShouldEqual(true); byte[] contentId = FileSystemVirtualizer.ConvertShaToContentId("0123456789012345678901234567890123456789"); byte[] placeholderVersion = MacFileSystemVirtualizer.PlaceholderVersionId; uint fileLength = 100; MockGVFSGitObjects mockGVFSGitObjects = this.Repo.GitObjects as MockGVFSGitObjects; mockGVFSGitObjects.FileLength = fileLength; mockVirtualization.WriteFileReturnResult = Result.Success; mockVirtualization.OnGetFileStream( commandId: 1, relativePath: TestFileName, providerId: placeholderVersion, contentId: contentId, triggeringProcessId: 2, triggeringProcessName: "UnitTest", fileHandle: IntPtr.Zero).ShouldEqual(Result.Success); mockVirtualization.BytesWritten.ShouldEqual(fileLength); fileSystemCallbacks.Stop(); } mockPlaceholderDb.VerifyAll(); mockSparseDb.VerifyAll(); }
private Result CreatePlaceholders(string directoryRelativePath, IEnumerable <ProjectedFileInfo> projectedItems, string triggeringProcessName) { foreach (ProjectedFileInfo fileInfo in projectedItems) { Result result; string sha = null; string childRelativePath = Path.Combine(directoryRelativePath, fileInfo.Name); if (fileInfo.IsFolder) { result = this.virtualizationInstance.WritePlaceholderDirectory(childRelativePath); } else { // TODO(Mac): Add functional tests that validate file mode is set correctly ushort fileMode = this.FileSystemCallbacks.GitIndexProjection.GetFilePathMode(childRelativePath); sha = fileInfo.Sha.ToString(); result = this.virtualizationInstance.WritePlaceholderFile( childRelativePath, PlaceholderVersionId, ToVersionIdByteArray(FileSystemVirtualizer.ConvertShaToContentId(sha)), (ulong)fileInfo.Size, fileMode); } if (result != Result.Success) { EventMetadata metadata = this.CreateEventMetadata(childRelativePath); metadata.Add("fileInfo.Name", fileInfo.Name); metadata.Add("fileInfo.Size", fileInfo.Size); metadata.Add("fileInfo.IsFolder", fileInfo.IsFolder); this.Context.Tracer.RelatedError(metadata, $"{nameof(this.CreatePlaceholders)}: Write placeholder failed"); return(result); } else { if (fileInfo.IsFolder) { this.FileSystemCallbacks.OnPlaceholderFolderCreated(childRelativePath); } else { this.FileSystemCallbacks.OnPlaceholderFileCreated(childRelativePath, sha, triggeringProcessName); } } } return(Result.Success); }
/// <summary> /// Writes a placeholder file. /// </summary> /// <param name="relativePath">Placeholder's path relative to the root of the repo</param> /// <param name="endOfFile">Length of the file (ignored on this platform)</param> /// <param name="sha">The SHA of the placeholder's contents, stored as the content ID in the placeholder</param> public override FileSystemResult WritePlaceholderFile( string relativePath, long endOfFile, string sha) { // TODO(#223): Add functional tests that validate file mode is set correctly GitIndexProjection.FileType fileType; ushort fileMode; this.FileSystemCallbacks.GitIndexProjection.GetFileTypeAndMode(relativePath, out fileType, out fileMode); if (fileType == GitIndexProjection.FileType.Regular) { Result result = this.virtualizationInstance.WritePlaceholderFile( relativePath, PlaceholderVersionId, ToVersionIdByteArray(FileSystemVirtualizer.ConvertShaToContentId(sha)), (ulong)endOfFile, fileMode); return(new FileSystemResult(ResultToFSResult(result), unchecked ((int)result))); } else if (fileType == GitIndexProjection.FileType.SymLink) { string symLinkTarget; if (this.TryGetSymLinkTarget(sha, out symLinkTarget)) { Result result = this.virtualizationInstance.WriteSymLink(relativePath, symLinkTarget); this.FileSystemCallbacks.OnFileSymLinkCreated(relativePath); return(new FileSystemResult(ResultToFSResult(result), unchecked ((int)result))); } EventMetadata metadata = this.CreateEventMetadata(relativePath); metadata.Add(nameof(sha), sha); this.Context.Tracer.RelatedError(metadata, $"{nameof(this.WritePlaceholderFile)}: Failed to read contents of symlink object"); return(new FileSystemResult(FSResult.IOError, 0)); } else { EventMetadata metadata = this.CreateEventMetadata(relativePath); metadata.Add(nameof(fileType), fileType); metadata.Add(nameof(fileMode), fileMode); this.Context.Tracer.RelatedError(metadata, $"{nameof(this.WritePlaceholderFile)}: Unsupported fileType"); return(new FileSystemResult(FSResult.IOError, 0)); } }
public override FileSystemResult WritePlaceholderFile( string relativePath, long endOfFile, string sha) { // TODO(Mac): Add functional tests that validate file mode is set correctly ushort fileMode = this.FileSystemCallbacks.GitIndexProjection.GetFilePathMode(relativePath); Result result = this.virtualizationInstance.WritePlaceholderFile( relativePath, PlaceholderVersionId, ToVersionIdByteArray(FileSystemVirtualizer.ConvertShaToContentId(sha)), (ulong)endOfFile, fileMode); return(new FileSystemResult(ResultToFSResult(result), unchecked ((int)result))); }
public void Dispose() { if (this.BlobSizes != null) { this.BlobSizes.Dispose(); this.BlobSizes = null; } if (this.fileSystemVirtualizer != null) { this.fileSystemVirtualizer.Dispose(); this.fileSystemVirtualizer = null; } if (this.GitIndexProjection != null) { this.GitIndexProjection.Dispose(); this.GitIndexProjection = null; } if (this.modifiedPaths != null) { this.modifiedPaths.Dispose(); this.modifiedPaths = null; } if (this.gitStatusCache != null) { this.gitStatusCache.Dispose(); this.gitStatusCache = null; } if (this.backgroundFileSystemTaskRunner != null) { this.backgroundFileSystemTaskRunner.Dispose(); this.backgroundFileSystemTaskRunner = null; } if (this.context != null) { this.context.Dispose(); this.context = null; } }
public void OnGetFileStreamReturnsErrorWhenWriteFileContentsFails() { const string TestFileName = "test.txt"; using (MockBackgroundFileSystemTaskRunner backgroundTaskRunner = new MockBackgroundFileSystemTaskRunner()) using (MockVirtualizationInstance mockVirtualization = new MockVirtualizationInstance()) using (MockGitIndexProjection gitIndexProjection = new MockGitIndexProjection(new[] { TestFileName })) using (MacFileSystemVirtualizer virtualizer = new MacFileSystemVirtualizer(this.Repo.Context, this.Repo.GitObjects, mockVirtualization)) using (FileSystemCallbacks fileSystemCallbacks = new FileSystemCallbacks( this.Repo.Context, this.Repo.GitObjects, RepoMetadata.Instance, new MockBlobSizes(), gitIndexProjection, backgroundFileSystemTaskRunner: backgroundTaskRunner, fileSystemVirtualizer: virtualizer)) { string error; fileSystemCallbacks.TryStart(out error).ShouldEqual(true); byte[] contentId = FileSystemVirtualizer.ConvertShaToContentId("0123456789012345678901234567890123456789"); byte[] placeholderVersion = MacFileSystemVirtualizer.PlaceholderVersionId; uint fileLength = 100; MockGVFSGitObjects mockGVFSGitObjects = this.Repo.GitObjects as MockGVFSGitObjects; mockGVFSGitObjects.FileLength = fileLength; mockVirtualization.WriteFileReturnResult = Result.EIOError; mockVirtualization.OnGetFileStream( commandId: 1, relativePath: TestFileName, providerId: placeholderVersion, contentId: contentId, triggeringProcessId: 2, triggeringProcessName: "UnitTest", fileHandle: IntPtr.Zero).ShouldEqual(Result.EIOError); fileSystemCallbacks.Stop(); } }
public FileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer, GitStatusCache gitStatusCache = null) { this.logsHeadFileProperties = null; this.postFetchJobLock = new object(); this.context = context; this.gitObjects = gitObjects; this.fileSystemVirtualizer = fileSystemVirtualizer; this.placeHolderCreationCount = new ConcurrentDictionary <string, PlaceHolderCreateCounter>(StringComparer.OrdinalIgnoreCase); this.newlyCreatedFileAndFolderPaths = new ConcurrentHashSet <string>(StringComparer.OrdinalIgnoreCase); string error; if (!ModifiedPathsDatabase.TryLoadOrCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.ModifiedPaths), this.context.FileSystem, out this.modifiedPaths, out error)) { throw new InvalidRepoException(error); } this.BlobSizes = blobSizes; this.BlobSizes.Initialize(); PlaceholderListDatabase placeholders; if (!PlaceholderListDatabase.TryCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.PlaceholderList), this.context.FileSystem, out placeholders, out error)) { throw new InvalidRepoException(error); } this.GitIndexProjection = gitIndexProjection ?? new GitIndexProjection( context, gitObjects, this.BlobSizes, repoMetadata, fileSystemVirtualizer, placeholders, this.modifiedPaths); if (backgroundFileSystemTaskRunner != null) { this.backgroundFileSystemTaskRunner = backgroundFileSystemTaskRunner; this.backgroundFileSystemTaskRunner.SetCallbacks( this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation); } else { this.backgroundFileSystemTaskRunner = new BackgroundFileSystemTaskRunner( this.context, this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation, Path.Combine(context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.BackgroundFileSystemTasks)); } this.enableGitStatusCache = gitStatusCache != null; // If the status cache is not enabled, create a dummy GitStatusCache that will never be initialized // This lets us from having to add null checks to callsites into GitStatusCache. this.gitStatusCache = gitStatusCache ?? new GitStatusCache(context, TimeSpan.Zero); this.logsHeadPath = Path.Combine(this.context.Enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Logs.Head); EventMetadata metadata = new EventMetadata(); metadata.Add("placeholders.Count", placeholders.EstimatedCount); metadata.Add("background.Count", this.backgroundFileSystemTaskRunner.Count); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(FileSystemCallbacks)} created"); this.context.Tracer.RelatedEvent(EventLevel.Informational, $"{nameof(FileSystemCallbacks)}_Constructor", metadata); }
public FileSystemCallbacks(GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, FileSystemVirtualizer fileSystemVirtualizer, GitStatusCache gitStatusCache) : this( context, gitObjects, repoMetadata, new BlobSizes(context.Enlistment.BlobSizesRoot, context.FileSystem, context.Tracer), gitIndexProjection : null, backgroundFileSystemTaskRunner : null, fileSystemVirtualizer : fileSystemVirtualizer, gitStatusCache : gitStatusCache) { }
public FileSystemCallbacks( GVFSContext context, GVFSGitObjects gitObjects, RepoMetadata repoMetadata, BlobSizes blobSizes, GitIndexProjection gitIndexProjection, BackgroundFileSystemTaskRunner backgroundFileSystemTaskRunner, FileSystemVirtualizer fileSystemVirtualizer) { this.logsHeadFileProperties = null; this.postFetchJobLock = new object(); this.context = context; this.gitObjects = gitObjects; this.fileSystemVirtualizer = fileSystemVirtualizer; this.placeHolderCreationCount = new ConcurrentDictionary <string, PlaceHolderCreateCounter>(StringComparer.OrdinalIgnoreCase); string error; if (!ModifiedPathsDatabase.TryLoadOrCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.ModifiedPaths), this.context.FileSystem, out this.modifiedPaths, out error)) { throw new InvalidRepoException(error); } this.BlobSizes = blobSizes; this.BlobSizes.Initialize(); PlaceholderListDatabase placeholders; if (!PlaceholderListDatabase.TryCreate( this.context.Tracer, Path.Combine(this.context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.PlaceholderList), this.context.FileSystem, out placeholders, out error)) { throw new InvalidRepoException(error); } this.GitIndexProjection = gitIndexProjection ?? new GitIndexProjection( context, gitObjects, this.BlobSizes, repoMetadata, fileSystemVirtualizer, placeholders, this.modifiedPaths); this.backgroundFileSystemTaskRunner = backgroundFileSystemTaskRunner ?? new BackgroundFileSystemTaskRunner( this.context, this.PreBackgroundOperation, this.ExecuteBackgroundOperation, this.PostBackgroundOperation, Path.Combine(context.Enlistment.DotGVFSRoot, GVFSConstants.DotGVFS.Databases.BackgroundFileSystemTasks)); this.logsHeadPath = Path.Combine(this.context.Enlistment.WorkingDirectoryRoot, GVFSConstants.DotGit.Logs.Head); EventMetadata metadata = new EventMetadata(); metadata.Add("placeholders.Count", placeholders.EstimatedCount); metadata.Add("background.Count", this.backgroundFileSystemTaskRunner.Count); metadata.Add(TracingConstants.MessageKey.InfoMessage, $"{nameof(FileSystemCallbacks)} created"); this.context.Tracer.RelatedEvent(EventLevel.Informational, $"{nameof(FileSystemCallbacks)}_Constructor", metadata); }