1
0

feat: Add overlay commit mode.

This commit is contained in:
Ca2didi 2025-05-19 18:44:50 +08:00
parent 33d1a4bf49
commit c0d22d3959

View File

@ -1221,11 +1221,13 @@ public class RepositoryService : BaseService<RepositoryService>
var localDb = GetRepositoryLocalDatabase(repo);
var manifestList = CreateCommitManifestByCurrentBaselineAndChanges(localDb.LocalAccessor, changes);
var (manifestList, miniManifestList) = CreateCommitManifestByCurrentBaselineAndChanges(localDb.LocalAccessor, changes);
var snapshot = manifestList.Select(l => $"{l.ModifyTime.ToBinary()}${l.WorkPath}");
Guid commitId;
try
{
// Renew for once.
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
{
@ -1234,38 +1236,63 @@ public class RepositoryService : BaseService<RepositoryService>
}
// Decide create new depot, create full depot or create addon depot.
var changesSize = localDb.LocalAccessor.Changes.Values.Sum(x => (long) x.File.Size);
var hasAddOrModify = localDb.LocalAccessor.Changes.Any(x =>
x.Value.Type == ChangeInfoType.Add || x.Value.Type == ChangeInfoType.Modify);
var newDepot = forceBaseline || hasAddOrModify || localDb.RepoAccessor == null;
// Generate depot
var tempDepotPath = await CreateDepotIntoTempFileAsync(repo, manifestList);
if (tempDepotPath == null) return null;
// Upload and create commit
await using var str = File.OpenRead(tempDepotPath);
var snapshot = manifestList.Select(l => $"{l.ModifyTime.ToBinary()}${l.WorkPath}");
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
if (newDepot)
{
api.ClearGateway();
return null;
var changesSize = localDb.LocalAccessor.Changes.Values.Sum(x => (long) x.File.Size);
var baselineSize = localDb.RepoAccessor?.Sum(x => (long) x.Size) ?? 0;
var changesRatio = changesSize / (double) baselineSize;
var isBaseline = forceBaseline || localDb.CurrentCommit == null || changesRatio > 0.8f;
var depotFiles = isBaseline ? manifestList : miniManifestList;
// Generate depot
var tempDepotPath = await CreateDepotIntoTempFileAsync(repo, depotFiles);
if (tempDepotPath == null) return null;
Console.WriteLine($"Create new {(isBaseline ? "baseline" : "overlay")} depot at \"{tempDepotPath}\"");
// Upload and create commit
await using var str = File.OpenRead(tempDepotPath);
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
{
api.ClearGateway();
return null;
}
var requireDepot = isBaseline ? [] : new[] {localDb.CurrentCommit.ToString()!};
var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name,
new StreamPart(str, Path.GetFileName(tempDepotPath)), message, snapshot, requireDepot, "");
commitId = rsp.CommitId;
// Move depot file to destination
var depotsPath = PathUtility.GetWorkspaceDepotCachePath(Api.Current.Username.Value!, repo.OwnerName, repo.Name);
var finalPath = Path.Combine(depotsPath, rsp.MainDepotId.ToString());
Directory.CreateDirectory(depotsPath);
File.Move(tempDepotPath, finalPath, true);
}
else
{
// Upload and create commit
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
{
api.ClearGateway();
return null;
}
var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name, null!,
message, snapshot, [], localDb.CurrentCommit?.ToString() ?? "");
commitId = rsp.CommitId;
}
var rsp = await api.Gateway.CreateCommit(repo.OwnerName, repo.Name,
new StreamPart(str, Path.GetFileName(tempDepotPath)), message, snapshot, [], string.Empty);
// Move depot file to destination
var depotsPath = PathUtility.GetWorkspaceDepotCachePath(Api.Current.Username.Value!, repo.OwnerName, repo.Name);
var finalPath = Path.Combine(depotsPath, rsp.MainDepotId.ToString());
Directory.CreateDirectory(depotsPath);
File.Move(tempDepotPath, finalPath, true);
// Fetch mapped manifest
var manifest = await DownloadManifestFromServerAsync(repo, rsp.CommitId);
var manifest = await DownloadManifestFromServerAsync(repo, commitId);
if (manifest == null) return null;
var accessor = await DownloadDepotsAndUseLocalCachesToGenerateRepositoryFileTreeAccessorFromServerAsync(repo, rsp.CommitId);
var accessor = await DownloadDepotsAndUseLocalCachesToGenerateRepositoryFileTreeAccessorFromServerAsync(repo, commitId);
if (accessor == null) return null; //todo this is a really fatal issue...
if (localDb.RepoAccessor != null)
{
@ -1282,10 +1309,11 @@ public class RepositoryService : BaseService<RepositoryService>
// Point to latest state.
localDb.RepoAccessor = accessor;
localDb.CurrentCommit = rsp.CommitId;
localDb.CurrentCommit = commitId;
localDb.LocalAccessor.SetBaseline(accessor);
SaveRepositoryLocalDatabaseChanges(repo);
Console.WriteLine($"Successful create commit as {commitId}");
return manifest;
}
catch (Exception e)
@ -1296,11 +1324,12 @@ public class RepositoryService : BaseService<RepositoryService>
}
}
public List<WorkspaceFile> CreateCommitManifestByCurrentBaselineAndChanges
private (List<WorkspaceFile>, List<WorkspaceFile>) CreateCommitManifestByCurrentBaselineAndChanges
(LocalFileTreeAccessor accessor, IEnumerable<ChangeInfo> changes, bool hard = false)
{
// Create a new depot file manifest.
var files = accessor.BaselineFiles.Values.ToList();
var overlayFsStatus = new List<WorkspaceFile>();
foreach (var c in changes)
{
switch (c.Type)
@ -1325,6 +1354,7 @@ public class RepositoryService : BaseService<RepositoryService>
}
files.Add(c.File);
overlayFsStatus.Add(c.File);
break;
}
case ChangeInfoType.Remove:
@ -1355,12 +1385,13 @@ public class RepositoryService : BaseService<RepositoryService>
}
files[idx] = c.File;
overlayFsStatus.Add(c.File);
break;
}
}
}
return files;
return (files, overlayFsStatus);
}
public async ValueTask<string?> CreateDepotIntoTempFileAsync(RepositoryModel repo, IEnumerable<WorkspaceFile> depotFiles)