Skip to content

Commit 2d17f9d

Browse files
committed
Fix bad merge: prefetch cache args and noop-cache update
The merge of #2002 (prefetch-offload-to-mount) on top of #2004 (expand-prefetch-cache) left three issues: 1. PrefetchVerb.cs hydration-fallback path passed the removed lastPrefetchArgs variable instead of prefetchCache + prefetchCacheSize. 2. InProcessMount.cs HandlePrefetchBlobsRequest passed the removed lastPrefetchArgs variable. The mount-side handler is a one-shot download with no persistent noop cache, so it correctly receives null + 0. 3. When prefetch succeeds via mount offload, the verb-side noop cache was never updated — SavePrefetchArgs only runs inside BlobPrefetcher.PrefetchWithStats, which is skipped on the offload path. This caused NoopPrefetch to re-download on the second run instead of printing 'Nothing new to prefetch.' Fix: add BlobPrefetcher.UpdateNoopCache() static method (extracted from SavePrefetchArgs logic) and call it from PrefetchVerb after successful mount offload. Update PrefetchBlobsMountedAfterRemount test to expect the noop message since the file was already cached by a prior test in the same fixture. Assisted-by: Claude Opus 4.6 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
1 parent fa0c3c5 commit 2d17f9d

4 files changed

Lines changed: 55 additions & 7 deletions

File tree

GVFS/GVFS.Common/Prefetch/BlobPrefetcher.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,42 @@ private void SavePrefetchArgs(string targetCommit, bool hydrate)
688688
}
689689
}
690690

691+
/// <summary>
692+
/// Updates the noop prefetch cache after a successful prefetch that was
693+
/// handled externally (e.g. offloaded to the mount process). This mirrors
694+
/// the logic in <see cref="SavePrefetchArgs"/> but is callable without a
695+
/// BlobPrefetcher instance.
696+
/// </summary>
697+
public static void UpdateNoopCache(
698+
FileBasedDictionary<string, string> prefetchCache,
699+
int maxCacheSize,
700+
string commitId,
701+
List<string> files,
702+
List<string> folders,
703+
bool hydrate)
704+
{
705+
if (prefetchCache == null || maxCacheSize <= 0)
706+
{
707+
return;
708+
}
709+
710+
string cacheKey = ComputeCacheKey(files, folders, hydrate);
711+
712+
Dictionary<string, string> allEntries = prefetchCache.GetAllKeysAndValues();
713+
if (allEntries.Count >= maxCacheSize && !allEntries.ContainsKey(cacheKey))
714+
{
715+
using (Dictionary<string, string>.Enumerator enumerator = allEntries.GetEnumerator())
716+
{
717+
if (enumerator.MoveNext())
718+
{
719+
prefetchCache.RemoveAndFlush(enumerator.Current.Key);
720+
}
721+
}
722+
}
723+
724+
prefetchCache.SetValueAndFlush(cacheKey, commitId);
725+
}
726+
691727
internal static string ComputeCacheKey(List<string> files, List<string> folders, bool hydrate)
692728
{
693729
List<string> sortedFiles = new List<string>(files);

GVFS/GVFS.FunctionalTests/Tests/EnlistmentPerFixture/PrefetchBlobsOffloadTests.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ public void PrefetchBlobsMountedReportsStats()
4242
public void PrefetchBlobsUnmountedFallsBackToDirectAuth()
4343
{
4444
// Unmount, then blob prefetch should fall back to direct auth
45-
// and still succeed.
45+
// and still succeed. Use a file not prefetched by earlier tests
46+
// so the noop cache doesn't short-circuit.
4647
this.Enlistment.UnmountGVFS();
4748

4849
try
4950
{
50-
string output = this.Enlistment.Prefetch($"--files {Path.Combine("GVFS", "GVFS", "Program.cs")}");
51+
string output = this.Enlistment.Prefetch($"--files {Path.Combine("GVFS", "GVFS.Common", "GVFSEnlistment.cs")}");
5152
output.ShouldContain("Matched blobs:");
5253
output.ShouldContain("Downloaded:");
5354
}
@@ -69,12 +70,14 @@ public void PrefetchBlobsMountedWithFolders()
6970
public void PrefetchBlobsMountedAfterRemount()
7071
{
7172
// After unmount + remount, blob prefetch should work via
72-
// the mount process again.
73+
// the mount process again. Since this file was already
74+
// prefetched in Order(1), the noop cache correctly detects
75+
// there's nothing new to download.
7376
this.Enlistment.UnmountGVFS();
7477
this.Enlistment.MountGVFS();
7578

7679
string output = this.Enlistment.Prefetch($"--files {Path.Combine("GVFS", "GVFS", "Program.cs")}");
77-
output.ShouldContain("Matched blobs:");
80+
output.ShouldContain("Nothing new to prefetch.");
7881
}
7982
}
8083
}

GVFS/GVFS.Mount/InProcessMount.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,8 @@ private void HandlePrefetchBlobsRequest(NamedPipeMessages.Message message, Named
11231123
objectRequestor,
11241124
request.Files,
11251125
request.Folders,
1126-
lastPrefetchArgs,
1126+
prefetchCache: null,
1127+
maxCacheSize: 0,
11271128
chunkSize: 4000,
11281129
searchThreadCount: maxThreads,
11291130
downloadThreadCount: downloadThreads,

GVFS/GVFS/CommandLine/PrefetchVerb.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,15 @@ protected override void Execute(GVFSEnlistment enlistment)
231231
cacheServerFromConfig,
232232
out objectRequestor,
233233
out resolvedCacheServer);
234-
this.PrefetchBlobs(tracer, enlistment, headCommitId, filesList, foldersList, lastPrefetchArgs, objectRequestor, resolvedCacheServer);
234+
this.PrefetchBlobs(tracer, enlistment, headCommitId, filesList, foldersList, prefetchCache, prefetchCacheSize, objectRequestor, resolvedCacheServer);
235235
}
236236
else
237237
{
238-
// Mount handled download — now hydrate locally
238+
// Mount handled download — hydrate locally, then update noop
239+
// cache. Cache update is after hydration so a hydration failure
240+
// doesn't suppress the retry on the next run.
239241
this.HydrateMatchingFiles(tracer, enlistment, filesList, foldersList);
242+
BlobPrefetcher.UpdateNoopCache(prefetchCache, prefetchCacheSize, headCommitId, filesList, foldersList, this.HydrateFiles);
240243
}
241244
}
242245
else if (!this.TryPrefetchBlobsViaMountProcess(tracer, enlistment, filesList, foldersList, headCommitId))
@@ -251,6 +254,11 @@ protected override void Execute(GVFSEnlistment enlistment)
251254
out resolvedCacheServer);
252255
this.PrefetchBlobs(tracer, enlistment, headCommitId, filesList, foldersList, prefetchCache, prefetchCacheSize, objectRequestor, resolvedCacheServer);
253256
}
257+
else
258+
{
259+
// Mount handled download — update noop cache so repeat runs are skipped
260+
BlobPrefetcher.UpdateNoopCache(prefetchCache, prefetchCacheSize, headCommitId, filesList, foldersList, hydrate: false);
261+
}
254262
}
255263
}
256264
catch (VerbAbortedException)

0 commit comments

Comments
 (0)