Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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