Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions GVFS/GVFS.Common/FileSystem/PhysicalFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public virtual void DeleteDirectory(string path, bool recursive = true, bool ign
}
}

public virtual void MoveDirectory(string sourceDirName, string destDirName)
{
Directory.Move(sourceDirName, destDirName);
}

public virtual void CopyDirectoryRecursive(
string srcDirectoryPath,
string dstDirectoryPath,
Expand Down
11 changes: 7 additions & 4 deletions GVFS/GVFS.Common/NamedPipes/NamedPipeMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,21 +203,24 @@ public static class DehydrateFolders

public class Request
{
public Request(string folders)
public Request(string backupFolderPath, string folders)
{
this.Folders = folders;
this.BackupFolderPath = backupFolderPath;
}

public Request(Message message)
public static Request FromMessage(Message message)
{
this.Folders = message.Body;
return JsonConvert.DeserializeObject<Request>(message.Body);
}

public string Folders { get; }

public string BackupFolderPath { get; }

public Message CreateMessage()
{
return new Message(Dehydrate, this.Folders);
return new Message(Dehydrate, JsonConvert.SerializeObject(this));
}
}

Expand Down
98 changes: 78 additions & 20 deletions GVFS/GVFS.Mount/InProcessMount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ private void HandleRequest(ITracer tracer, string request, NamedPipeServer.Conne

private void HandleDehydrateFolders(NamedPipeMessages.Message message, NamedPipeServer.Connection connection)
{
NamedPipeMessages.DehydrateFolders.Request request = new NamedPipeMessages.DehydrateFolders.Request(message);
NamedPipeMessages.DehydrateFolders.Request request = NamedPipeMessages.DehydrateFolders.Request.FromMessage(message);

EventMetadata metadata = new EventMetadata();
metadata.Add(nameof(request.Folders), request.Folders);
Expand All @@ -308,7 +308,9 @@ private void HandleDehydrateFolders(NamedPipeMessages.Message message, NamedPipe
response = new NamedPipeMessages.DehydrateFolders.Response(NamedPipeMessages.DehydrateFolders.DehydratedResult);
string[] folders = request.Folders.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
StringBuilder resetFolderPaths = new StringBuilder();
foreach (string folder in folders)
List<string> movedFolders = BackupFoldersWhileUnmounted(request, response, folders);

foreach (string folder in movedFolders)
{
if (this.fileSystemCallbacks.TryDehydrateFolder(folder, out string errorMessage))
{
Expand Down Expand Up @@ -357,6 +359,50 @@ private void HandleDehydrateFolders(NamedPipeMessages.Message message, NamedPipe
connection.TrySendResponse(response.CreateMessage());
}

private List<string> BackupFoldersWhileUnmounted(NamedPipeMessages.DehydrateFolders.Request request, NamedPipeMessages.DehydrateFolders.Response response, string[] folders)
{
/* We can't move folders while the virtual file system is mounted, so unmount it first.
* After moving the folders, remount the virtual file system.
*/

var movedFolders = new List<string>();
try
{
/* Set to "Mounting" instead of "Unmounting" so that incoming requests
* that are rejected will know they can try again soon.
*/
this.currentState = MountState.Mounting;
this.UnmountAndStopWorkingDirectoryCallbacks(willRemountInSameProcess: true);
foreach (string folder in folders)
{
try
{
var source = Path.Combine(this.enlistment.WorkingDirectoryBackingRoot, folder);
var destination = Path.Combine(request.BackupFolderPath, folder);
var destinationParent = Path.GetDirectoryName(destination);
this.context.FileSystem.CreateDirectory(destinationParent);
if (this.context.FileSystem.DirectoryExists(source))
{
this.context.FileSystem.MoveDirectory(source, destination);
}
movedFolders.Add(folder);
}
catch (Exception ex)
{
response.FailedFolders.Add($"{folder}\0{ex.Message}");
continue;
}
}
}
finally
{
this.MountAndStartWorkingDirectoryCallbacks(this.cacheServer, alreadyInitialized: true);
this.currentState = MountState.Ready;
}

return movedFolders;
}

private void HandleLockRequest(string messageBody, NamedPipeServer.Connection connection)
{
NamedPipeMessages.AcquireLock.Response response;
Expand Down Expand Up @@ -551,9 +597,9 @@ private void HandleDownloadObjectRequest(NamedPipeMessages.Message message, Name
/* If a commit is downloaded, it wasn't prefetched.
* If any prefetch has been done, there is probably a commit in the prefetch packs that is close enough that
* loose object download of missing trees will be faster than downloading a pack of all the trees for the commit.
* Otherwise, the trees for the commit may be needed soon depending on the context.
* Otherwise, the trees for the commit may be needed soon depending on the context.
* e.g. git log (without a pathspec) doesn't need trees, but git checkout does.
*
*
* Save the tree/commit so if more trees are requested we can download all the trees for the commit in a batch.
*/
this.treesWithDownloadedCommits[treeSha] = objectSha;
Expand Down Expand Up @@ -596,7 +642,7 @@ private bool ShouldDownloadCommitPack(string objectSha, out string commitSha)
private void UpdateTreesForDownloadedCommits(string objectSha)
{
/* If we are downloading missing trees, we probably are missing more trees for the commit.
* Update our list of trees associated with the commit so we can use the # of missing trees
* Update our list of trees associated with the commit so we can use the # of missing trees
* as a heuristic to decide whether to batch download all the trees for the commit the
* next time a missing one is requested.
*/
Expand Down Expand Up @@ -723,12 +769,15 @@ private void HandleUnmountRequest(NamedPipeServer.Connection connection)
}
}

private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache)
private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache, bool alreadyInitialized = false)
{
string error;
if (!this.context.Enlistment.Authentication.TryInitialize(this.context.Tracer, this.context.Enlistment, out error))
if (!alreadyInitialized)
{
this.FailMountAndExit("Failed to obtain git credentials: " + 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);
Expand Down Expand Up @@ -763,19 +812,22 @@ private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache)
}, "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))
if (!alreadyInitialized)
{
this.FailMountAndExit("Error: {0}", error);
}
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);
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
Expand All @@ -794,7 +846,7 @@ private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache)
this.heartbeat.Start();
}

private void UnmountAndStopWorkingDirectoryCallbacks()
private void UnmountAndStopWorkingDirectoryCallbacks(bool willRemountInSameProcess = false)
{
if (this.maintenanceScheduler != null)
{
Expand All @@ -817,6 +869,12 @@ private void UnmountAndStopWorkingDirectoryCallbacks()

this.gvfsDatabase?.Dispose();
this.gvfsDatabase = null;

if (!willRemountInSameProcess)
{
this.context?.Dispose();
this.context = null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ protected void Dispose(bool disposing)
this.backgroundThread.Dispose();
this.backgroundThread = null;
}
if (this.backgroundTasks != null)
{
this.backgroundTasks.Dispose();
this.backgroundTasks = null;
}
}
}

Expand Down
6 changes: 0 additions & 6 deletions GVFS/GVFS.Virtualization/FileSystemCallbacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,6 @@ public void Dispose()
this.backgroundFileSystemTaskRunner.Dispose();
this.backgroundFileSystemTaskRunner = null;
}

if (this.context != null)
{
this.context.Dispose();
this.context = null;
}
}

public bool IsReadyForExternalAcquireLockRequests(NamedPipeMessages.LockData requester, out string denyMessage)
Expand Down
Loading
Loading