Skip to content

Commit a917f38

Browse files
tyrielvCopilot
andcommitted
Parallelize pre-mount validations with network operations
Start auth + config query immediately on entry to Mount(), before repo metadata loading. This overlaps network latency with all local I/O: metadata, git version/hooks/filesystem checks, and git config writes. The network task (auth + config) and local task (validations + git config) run concurrently via Task.WhenAll. RepoMetadata loading runs on the main thread between task launch and local task start, overlapping with the initial anonymous auth probe. Measured improvement on os.2020 (2.4M index entries): Production: ~29s wall clock Sequential: ~22s (prior commit moved work to mount.exe) Parallel: ~19s (this commit) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9d3a09b commit a917f38

1 file changed

Lines changed: 61 additions & 21 deletions

File tree

GVFS/GVFS.Mount/InProcessMount.cs

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Security;
1919
using System.Text;
2020
using System.Threading;
21+
using System.Threading.Tasks;
2122
using static GVFS.Common.Git.LibGit2Repo;
2223

2324
namespace GVFS.Mount
@@ -84,6 +85,27 @@ public void Mount(EventLevel verbosity, Keywords keywords)
8485
{
8586
this.currentState = MountState.Mounting;
8687

88+
// Start auth + config query immediately — these are network-bound and don't
89+
// depend on repo metadata or cache paths. Every millisecond of network latency
90+
// we can overlap with local I/O is a win.
91+
Stopwatch parallelTimer = Stopwatch.StartNew();
92+
93+
var networkTask = Task.Run(() =>
94+
{
95+
Stopwatch sw = Stopwatch.StartNew();
96+
string authError;
97+
if (!this.enlistment.Authentication.TryInitialize(this.tracer, this.enlistment, out authError))
98+
{
99+
this.tracer.RelatedWarning("Mount will proceed, but new files cannot be accessed until GVFS can authenticate: " + authError);
100+
}
101+
102+
this.tracer.RelatedInfo("ParallelMount: Auth completed in {0}ms", sw.ElapsedMilliseconds);
103+
104+
ServerGVFSConfig config = this.QueryAndValidateGVFSConfig();
105+
this.tracer.RelatedInfo("ParallelMount: Auth + config query completed in {0}ms", sw.ElapsedMilliseconds);
106+
return config;
107+
});
108+
87109
// We must initialize repo metadata before starting the pipe server so it
88110
// can immediately handle status requests
89111
string error;
@@ -122,39 +144,57 @@ public void Mount(EventLevel verbosity, Keywords keywords)
122144

123145
this.enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot, blobSizesRoot);
124146

125-
if (!this.enlistment.Authentication.TryInitialize(this.tracer, this.enlistment, out error))
147+
// Local validations and git config run while we wait for the network
148+
var localTask = Task.Run(() =>
126149
{
127-
this.tracer.RelatedWarning("Mount will proceed, but new files cannot be accessed until GVFS can authenticate: " + error);
128-
}
150+
Stopwatch sw = Stopwatch.StartNew();
129151

130-
this.ValidateGitVersion();
131-
this.ValidateHooksVersion();
132-
this.ValidateFileSystemSupportsRequiredFeatures();
152+
this.ValidateGitVersion();
153+
this.tracer.RelatedInfo("ParallelMount: ValidateGitVersion completed in {0}ms", sw.ElapsedMilliseconds);
133154

134-
ServerGVFSConfig serverGVFSConfig = this.QueryAndValidateGVFSConfig();
155+
this.ValidateHooksVersion();
156+
this.ValidateFileSystemSupportsRequiredFeatures();
135157

136-
CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);
137-
this.cacheServer = cacheServerResolver.ResolveNameFromRemote(this.cacheServer.Url, serverGVFSConfig);
158+
GitProcess git = new GitProcess(this.enlistment);
159+
if (!git.IsValidRepo())
160+
{
161+
this.FailMountAndExit("The .git folder is missing or has invalid contents");
162+
}
138163

139-
this.EnsureLocalCacheIsHealthy(serverGVFSConfig);
164+
if (!GVFSPlatform.Instance.FileSystem.IsFileSystemSupported(this.enlistment.EnlistmentRoot, out string fsError))
165+
{
166+
this.FailMountAndExit("FileSystem unsupported: " + fsError);
167+
}
140168

141-
GitProcess git = new GitProcess(this.enlistment);
142-
if (!git.IsValidRepo())
143-
{
144-
this.FailMountAndExit("The .git folder is missing or has invalid contents");
145-
}
169+
this.tracer.RelatedInfo("ParallelMount: Local validations completed in {0}ms", sw.ElapsedMilliseconds);
170+
171+
if (!this.TrySetRequiredGitConfigSettings())
172+
{
173+
this.FailMountAndExit("Unable to configure git repo");
174+
}
146175

147-
if (!GVFSPlatform.Instance.FileSystem.IsFileSystemSupported(this.enlistment.EnlistmentRoot, out error))
176+
this.LogEnlistmentInfoAndSetConfigValues();
177+
this.tracer.RelatedInfo("ParallelMount: Local validations + git config completed in {0}ms", sw.ElapsedMilliseconds);
178+
});
179+
180+
try
148181
{
149-
this.FailMountAndExit("FileSystem unsupported: " + error);
182+
Task.WaitAll(networkTask, localTask);
150183
}
151-
152-
if (!this.TrySetRequiredGitConfigSettings())
184+
catch (AggregateException ae)
153185
{
154-
this.FailMountAndExit("Unable to configure git repo");
186+
this.FailMountAndExit(ae.Flatten().InnerExceptions[0].Message);
155187
}
156188

157-
this.LogEnlistmentInfoAndSetConfigValues();
189+
parallelTimer.Stop();
190+
this.tracer.RelatedInfo("ParallelMount: All parallel tasks completed in {0}ms", parallelTimer.ElapsedMilliseconds);
191+
192+
ServerGVFSConfig serverGVFSConfig = networkTask.Result;
193+
194+
CacheServerResolver cacheServerResolver = new CacheServerResolver(this.tracer, this.enlistment);
195+
this.cacheServer = cacheServerResolver.ResolveNameFromRemote(this.cacheServer.Url, serverGVFSConfig);
196+
197+
this.EnsureLocalCacheIsHealthy(serverGVFSConfig);
158198

159199
using (NamedPipeServer pipeServer = this.StartNamedPipe())
160200
{

0 commit comments

Comments
 (0)