Skip to content

Commit

Permalink
ScalarVerb: Remove EnsureLocalCacheIsHealthy
Browse files Browse the repository at this point in the history
With the deprecating of the mount process (and verb)
EnsureLocalCacheIsHealthy is no longer needed.

In VFS4G, EnsureLocalCacheIsHealthy is needed because:

- A mapping file is used in the .gvfsCache directory that
  may need to be regenerated if the user deletes it.
- The decision was made that the mount verb should ensure
  that the alternates file is properly configured to use
  the cache directory.

However, in Scalar:

- A mapping file will not be used (Scalar will rely on
  repository IDs and stable hashes.
- There will be no 'mount' verb run by users
- Scalar will not be responsible for automatically fixing
  up modifications made by users that would remove the
  .scalarCache directory from the alternates files

And so EnsureLocalCacheIsHealthy is being removed.
  • Loading branch information
wilbaker committed Oct 4, 2019
1 parent a8b0b08 commit ad64ba6
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,55 +159,17 @@ public void MountReusesLocalCacheKeyWhenGitObjectsRootDeleted()
string mappingFileContents = this.fileSystem.ReadAllText(mappingFilePath);
mappingFileContents.Length.ShouldNotEqual(0, "mapping.dat should not be empty");

// Delete the git objects root folder, mount should re-create it and the mapping.dat file should not change
RepositoryHelpers.DeleteTestDirectory(objectsRoot);

enlistment.MountScalar();

ScalarHelpers.GetGitObjectsRoot(enlistment.RepoRoot).ShouldEqual(objectsRoot);
objectsRoot.ShouldBeADirectory(this.fileSystem);
mappingFilePath.ShouldBeAFile(this.fileSystem).WithContents(mappingFileContents);

this.AlternatesFileShouldHaveGitObjectsRoot(enlistment);
}
// Downloading objects should recreate the objects directory
this.LoadBlobsViaGit(enlistment);

[TestCase]
public void MountUsesNewLocalCacheKeyWhenLocalCacheDeleted()
{
ScalarFunctionalTestEnlistment enlistment = this.CloneAndMountEnlistment();

enlistment.UnmountScalar();

// Find the current git objects root and ensure it's on disk
string objectsRoot = ScalarHelpers.GetGitObjectsRoot(enlistment.RepoRoot);
objectsRoot.ShouldBeADirectory(this.fileSystem);

string mappingFilePath = Path.Combine(enlistment.LocalCacheRoot, "mapping.dat");
string mappingFileContents = this.fileSystem.ReadAllText(mappingFilePath);
mappingFileContents.Length.ShouldNotEqual(0, "mapping.dat should not be empty");

// Delete the local cache folder, mount should re-create it and generate a new mapping file and local cache key
RepositoryHelpers.DeleteTestDirectory(enlistment.LocalCacheRoot);

enlistment.MountScalar();

// Mount should recreate the local cache root
enlistment.LocalCacheRoot.ShouldBeADirectory(this.fileSystem);

// Determine the new local cache key
string newMappingFileContents = mappingFilePath.ShouldBeAFile(this.fileSystem).WithContents();
const int GuidStringLength = 32;
string mappingFileKey = "A {\"Key\":\"https://gvfs.visualstudio.com/ci/_git/fortests\",\"Value\":\"";
int localKeyIndex = newMappingFileContents.IndexOf(mappingFileKey);
string newCacheKey = newMappingFileContents.Substring(localKeyIndex + mappingFileKey.Length, GuidStringLength);

// Validate the new objects root is on disk and uses the new key
objectsRoot.ShouldNotExistOnDisk(this.fileSystem);
string newObjectsRoot = ScalarHelpers.GetGitObjectsRoot(enlistment.RepoRoot);
newObjectsRoot.ShouldNotEqual(objectsRoot);
newObjectsRoot.ShouldContain(newCacheKey);
newObjectsRoot.ShouldBeADirectory(this.fileSystem);

// The alternates file shouldn't have changed
this.AlternatesFileShouldHaveGitObjectsRoot(enlistment);
}

Expand Down
151 changes: 0 additions & 151 deletions Scalar/CommandLine/ScalarVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ protected void InitializeLocalCacheAndObjectsPaths(
}

this.InitializeCachePaths(tracer, enlistment);
this.EnsureLocalCacheIsHealthy(tracer, enlistment, retryConfig, serverScalarConfig, cacheServer);

RepoMetadata.Shutdown();
}
Expand Down Expand Up @@ -840,156 +839,6 @@ private void InitializeCachePaths(
enlistment.InitializeCachePaths(localCacheRoot, gitObjectsRoot);
}

private void EnsureLocalCacheIsHealthy(
ITracer tracer,
ScalarEnlistment enlistment,
RetryConfig retryConfig,
ServerScalarConfig serverScalarConfig,
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 Scalar 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, StringComparison.OrdinalIgnoreCase))
{
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.TrySetObjectCacheLocation(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 (serverScalarConfig == null)
{
if (retryConfig == null)
{
if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
{
this.ReportErrorAndExit(tracer, "Failed to determine Scalar timeout and max retries: " + error);
}
}

serverScalarConfig = this.QueryScalarConfig(tracer, enlistment, retryConfig);
}

string localCacheKey;
LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers(
tracer,
serverScalarConfig,
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, "ScalarVerb_EnsureLocalCacheIsHealthy_InitializePathsFromKey", metadata);
enlistment.InitializeCachePathsFromKey(enlistment.LocalCacheRoot, localCacheKey);

tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating GitObjectsRoot ({enlistment.GitObjectsRoot}), and GitPackRoot ({enlistment.GitPackRoot})");
try
{
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);
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 and setting object cache in git config");
if (!this.TrySetObjectCacheLocation(fileSystem, enlistment, out error))
{
this.ReportErrorAndExit(tracer, $"Failed to update alterates file with new objects path: {error}");
}
}
}

private ScalarEnlistment CreateEnlistment(string enlistmentRootPath, GitAuthentication authentication)
{
string gitBinPath = ScalarPlatform.Instance.GitInstallation.GetInstalledGitBinPath();
Expand Down

0 comments on commit ad64ba6

Please sign in to comment.