When a file is locked during hash calculation, if retries fails then do not throw exception out but rather return null hash
ci / build_linux (push) Has been cancelled
ci / build_linux (pull_request) Has been cancelled

This commit is contained in:
2025-12-13 10:38:43 +10:30
parent 169cf9ecf9
commit dd53bc547f
+29 -6
View File
@@ -221,8 +221,23 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
_watchers.Remove(fileSystemWatchers); _watchers.Remove(fileSystemWatchers);
} }
private void OnChanged(object? _, FileSystemEventArgs e) => ThrottleSnapshotUpdate(e); private void OnChanged(object? _, FileSystemEventArgs e)
private void OnRenamed(object? _, RenamedEventArgs e) => ThrottleSnapshotUpdate(e); {
var fileInfo = new FileInfo(e.FullPath);
if (_options.ArchiveExtensions.Contains(fileInfo.Extension) || _options.RomExtensions.Contains(fileInfo.Extension))
{
ThrottleSnapshotUpdate(e);
}
}
private void OnRenamed(object? _, RenamedEventArgs e)
{
var fileInfo = new FileInfo(e.FullPath);
if (_options.ArchiveExtensions.Contains(fileInfo.Extension) || _options.RomExtensions.Contains(fileInfo.Extension))
{
ThrottleSnapshotUpdate(e);
}
}
/// <summary> /// <summary>
/// Rebuild the snapshot, if rebuild in process, cancel it and restart /// Rebuild the snapshot, if rebuild in process, cancel it and restart
@@ -421,7 +436,7 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
return fileInfo.LastWriteTimeUtc; return fileInfo.LastWriteTimeUtc;
})) }))
{ {
string hash; string? hash;
var ext = Path.GetExtension(file).ToLowerInvariant(); var ext = Path.GetExtension(file).ToLowerInvariant();
if (!(_options.ArchiveExtensions.Contains(ext) || _options.RomExtensions.Contains(ext))) if (!(_options.ArchiveExtensions.Contains(ext) || _options.RomExtensions.Contains(ext)))
@@ -474,6 +489,8 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
Stopwatch stopwatch = Stopwatch.StartNew(); Stopwatch stopwatch = Stopwatch.StartNew();
hash = ComputeFirstStreamHashAsync(file, cancellationToken).Result; hash = ComputeFirstStreamHashAsync(file, cancellationToken).Result;
stopwatch.Stop(); stopwatch.Stop();
if (!string.IsNullOrEmpty(hash))
{
_logger.LogDebug("Computed hash for {File} in {Time}ms", file, stopwatch.ElapsedMilliseconds); _logger.LogDebug("Computed hash for {File} in {Time}ms", file, stopwatch.ElapsedMilliseconds);
if (_hashCache.TryGetValue(hash, out var value) && file == _cache[value].Path) if (_hashCache.TryGetValue(hash, out var value) && file == _cache[value].Path)
{ {
@@ -481,6 +498,7 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
yield return null; yield return null;
continue; continue;
} }
}
IEnumerable<(string, long, NcaMetadataWithHash)>? titlesEnumerable = null; IEnumerable<(string, long, NcaMetadataWithHash)>? titlesEnumerable = null;
try try
@@ -572,7 +590,7 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
{ {
if (_debouncerCache.TryGetValue(_jsonPath, out _)) if (_debouncerCache.TryGetValue(_jsonPath, out _))
{ {
_logger.LogInformation("Sliding debounce in progress, skipping snapshot persistence"); _logger.LogDebug("Sliding debounce in progress, skipping snapshot persistence");
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -821,7 +839,7 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
// File: TinfoilVibeServer/Services/SnapshotService.cs (inside SnapshotService class) // File: TinfoilVibeServer/Services/SnapshotService.cs (inside SnapshotService class)
private async Task<string> ComputeFirstStreamHashAsync(string filePath, CancellationToken cancellationToken = default) private async Task<string?> ComputeFirstStreamHashAsync(string filePath, CancellationToken cancellationToken = default)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
for (var attempt = 0; attempt < _options.MaxRetryCount; attempt++) for (var attempt = 0; attempt < _options.MaxRetryCount; attempt++)
@@ -868,11 +886,16 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
} }
catch (IOException ex) when (attempt < _options.MaxRetryCount - 1) catch (IOException ex) when (attempt < _options.MaxRetryCount - 1)
{ {
var delay = (int)((attempt+1) * _options.DebounceTimeoutMs * _options.RetryMultiplier); var delay = (int)((attempt + 1) * _options.DebounceTimeoutMs * _options.RetryMultiplier);
_logger.LogWarning(ex, "Attempt {Attempt} failed for {Path}. Retrying after {Delay}.", _logger.LogWarning(ex, "Attempt {Attempt} failed for {Path}. Retrying after {Delay}.",
attempt + 1, filePath, delay); attempt + 1, filePath, delay);
await Task.Delay(delay, cancellationToken); await Task.Delay(delay, cancellationToken);
} }
catch (IOException)
{
_logger.LogWarning("Attempt to load {Path} failed after {retries}", filePath, attempt + 1);
return null;
}
} }
return string.Empty; return string.Empty;