Пример #1
0
        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();
        }
Пример #2
0
 public MockFileSystemCallbacks(
     GVFSContext context,
     GVFSGitObjects gitObjects,
     RepoMetadata repoMetadata,
     FileSystemVirtualizer fileSystemVirtualizer)
     : base(context, gitObjects, repoMetadata, fileSystemVirtualizer, null)
 {
 }
Пример #3
0
 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();
        }
Пример #7
0
        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)));
        }
Пример #10
0
        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;
            }
        }
Пример #11
0
        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();
                            }
        }
Пример #12
0
        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);
        }
Пример #13
0
 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)
 {
 }
Пример #14
0
        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);
        }