in GVFS/GVFS/CommandLine/GVFSVerb.cs [1142:1319]
private void EnsureLocalCacheIsHealthy(
ITracer tracer,
GVFSEnlistment enlistment,
RetryConfig retryConfig,
ServerGVFSConfig serverGVFSConfig,
CacheServerInfo cacheServer)
{
if (!Directory.Exists(enlistment.LocalCacheRoot))
{
try
{
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Local cache root: {enlistment.LocalCacheRoot} missing, recreating it");
Directory.CreateDirectory(enlistment.LocalCacheRoot);
}
catch (Exception e)
{
EventMetadata metadata = new EventMetadata();
metadata.Add("Exception", e.ToString());
metadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot);
tracer.RelatedError(metadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to create local cache root");
this.ReportErrorAndExit(tracer, "Failed to create local cache: " + enlistment.LocalCacheRoot);
}
}
// Validate that the GitObjectsRoot directory is on disk, and that the GVFS repo is configured to use it.
// If the directory is missing (and cannot be found in the mapping file) a new key for the repo will be added
// to the mapping file and used for BOTH the GitObjectsRoot and BlobSizesRoot
PhysicalFileSystem fileSystem = new PhysicalFileSystem();
if (Directory.Exists(enlistment.GitObjectsRoot))
{
bool gitObjectsRootInAlternates = false;
string alternatesFilePath = this.GetAlternatesPath(enlistment);
if (File.Exists(alternatesFilePath))
{
try
{
using (Stream stream = fileSystem.OpenFileStream(
alternatesFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
callFlushFileBuffers: false))
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string alternatesLine = reader.ReadLine();
if (string.Equals(alternatesLine, enlistment.GitObjectsRoot, GVFSPlatform.Instance.Constants.PathComparison))
{
gitObjectsRootInAlternates = true;
}
}
}
}
}
catch (Exception e)
{
EventMetadata exceptionMetadata = new EventMetadata();
exceptionMetadata.Add("Exception", e.ToString());
tracer.RelatedError(exceptionMetadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to validate alternates file");
this.ReportErrorAndExit(tracer, $"Failed to validate that alternates file includes git objects root: {e.Message}");
}
}
else
{
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Alternates file not found");
}
if (!gitObjectsRootInAlternates)
{
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing from alternates files, recreating alternates");
string error;
if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error))
{
this.ReportErrorAndExit(tracer, $"Failed to update alternates file to include git objects root: {error}");
}
}
}
else
{
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing, determining new root");
if (cacheServer == null)
{
cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);
}
string error;
if (serverGVFSConfig == null)
{
if (retryConfig == null)
{
if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
{
this.ReportErrorAndExit(tracer, "Failed to determine GVFS timeout and max retries: " + error);
}
}
serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
}
string localCacheKey;
LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers(
tracer,
serverGVFSConfig,
cacheServer,
enlistment.LocalCacheRoot,
localCacheKey: out localCacheKey,
errorMessage: out error))
{
this.ReportErrorAndExit(tracer, $"Previous git objects root ({enlistment.GitObjectsRoot}) not found, and failed to determine new local cache key: {error}");
}
EventMetadata metadata = new EventMetadata();
metadata.Add("localCacheRoot", enlistment.LocalCacheRoot);
metadata.Add("localCacheKey", localCacheKey);
metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing and persisting updated paths");
tracer.RelatedEvent(EventLevel.Informational, "GVFSVerb_EnsureLocalCacheIsHealthy_InitializePathsFromKey", metadata);
enlistment.InitializeCachePathsFromKey(enlistment.LocalCacheRoot, localCacheKey);
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating GitObjectsRoot ({enlistment.GitObjectsRoot}), GitPackRoot ({enlistment.GitPackRoot}), and BlobSizesRoot ({enlistment.BlobSizesRoot})");
try
{
Directory.CreateDirectory(enlistment.GitObjectsRoot);
Directory.CreateDirectory(enlistment.GitPackRoot);
}
catch (Exception e)
{
EventMetadata exceptionMetadata = new EventMetadata();
exceptionMetadata.Add("Exception", e.ToString());
exceptionMetadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot);
exceptionMetadata.Add("enlistment.GitObjectsRoot", enlistment.GitObjectsRoot);
exceptionMetadata.Add("enlistment.GitPackRoot", enlistment.GitPackRoot);
exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot);
tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create objects, pack, and sizes folders");
this.ReportErrorAndExit(tracer, "Failed to create objects, pack, and sizes folders");
}
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating new alternates file");
if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error))
{
this.ReportErrorAndExit(tracer, $"Failed to update alterates file with new objects path: {error}");
}
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving git objects root ({enlistment.GitObjectsRoot}) in repo metadata");
RepoMetadata.Instance.SetGitObjectsRoot(enlistment.GitObjectsRoot);
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving blob sizes root ({enlistment.BlobSizesRoot}) in repo metadata");
RepoMetadata.Instance.SetBlobSizesRoot(enlistment.BlobSizesRoot);
}
// Validate that the BlobSizesRoot folder is on disk.
// Note that if a user performed an action that resulted in the entire .gvfscache being deleted, the code above
// for validating GitObjectsRoot will have already taken care of generating a new key and setting a new enlistment.BlobSizesRoot path
if (!Directory.Exists(enlistment.BlobSizesRoot))
{
tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: BlobSizesRoot ({enlistment.BlobSizesRoot}) not found, re-creating");
try
{
Directory.CreateDirectory(enlistment.BlobSizesRoot);
}
catch (Exception e)
{
EventMetadata exceptionMetadata = new EventMetadata();
exceptionMetadata.Add("Exception", e.ToString());
exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot);
tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create blob sizes folder");
this.ReportErrorAndExit(tracer, "Failed to create blob sizes folder");
}
}
}