Files
duplicati/Duplicati/Library/Main/Backend/BackendManager.ProgressHandler.cs
T
Kenneth Skovhede f393c00030 Fixed throttle support
This moves the throttle support to the StreamUtil throttled stream, which allows multiple streams to share a throttle value, such that the throttle setting is applied to the entire communication from Duplicati, and not for each connection.

This also cleans up a bit in the progress reporting, where the backend manager now keeps track of the "active" transfer and only emits progress on that. Once it finishes, a new transfer is promoted a "active".
2025-04-22 22:54:48 +02:00

131 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Duplicati.Library.Main.Operation.Common;
using Duplicati.Library.Utility;
namespace Duplicati.Library.Main.Backend;
#nullable enable
partial class BackendManager
{
/// <summary>
/// Represents a pending QuotaInfo operation
/// </summary>
private sealed record ProgressHandler(IBackendWriter Stats, ITaskReader TaskReader)
{
/// <summary>
/// A lock guarding for single-threaded access to the list of active transfers
/// </summary>
private readonly object _lock = new();
/// <summary>
/// The progress of the active transfers
/// </summary>
private Dictionary<string, long> _activeTransferProgress = new();
/// <summary>
/// Information about an active transfer
/// </summary>
/// <param name="Filename">The filename of the transfer</param>
/// <param name="Started">When the transfer started</param>
/// <param name="Type">The type of the transfer</param>
/// <param name="Size">The size of the transfer</param>
private sealed record TransferInfo(string Filename, DateTime Started, BackendActionType Type, long Size);
/// <summary>
/// The information for the active transfers
/// </summary>
private Dictionary<string, TransferInfo> _activeTransferInfo = new();
/// <summary>
/// The transfer that is currently reported in progress
/// </summary>
private TransferInfo? _currentTransfer;
/// <summary>
/// Handles the progress of a stream
/// </summary>
/// <param name="pg">The progress</param>
/// <param name="filename">The filename</param>
public void HandleProgress(long pg, string filename)
{
// This pauses and throws on cancellation, but ignores stop
TaskReader.TransferRendevouz().Await();
lock (_lock)
{
// Record the progress of the transfer
if (_activeTransferProgress.ContainsKey(filename))
_activeTransferProgress[filename] = pg;
// Only update the progress if the filename matches the current transfer
if (filename != _currentTransfer?.Filename)
return;
}
Stats.BackendProgressUpdater.UpdateProgress(pg);
}
/// <summary>
/// Begins the transfer of a file
/// </summary>
/// <param name="filename">The filename</param>
public void BeginTransfer(BackendActionType type, long size, string filename)
{
TransferInfo? info = null;
lock (_lock)
{
// Ignore the transfer if it is already in progress
if (_activeTransferProgress.ContainsKey(filename))
return;
_activeTransferProgress.Add(filename, 0);
info = new TransferInfo(filename, DateTime.UtcNow, type, size);
_activeTransferInfo.Add(filename, info);
// Don't process the event if it is not the current transfer
if (_currentTransfer != null)
return;
// This is now the current transfer
_currentTransfer = info;
}
Stats.BackendProgressUpdater.StartAction(info.Type, info.Filename, info.Size, info.Started);
}
/// <summary>
/// Ends the transfer of a file
/// </summary>
/// <param name="filename">The filename</param>
public void EndTransfer(string filename)
{
TransferInfo? info = null;
long progress = 0;
lock (_lock)
{
_activeTransferProgress.Remove(filename);
_activeTransferInfo.Remove(filename);
// If the current transfer is not the one that ended, ignore it
if (_currentTransfer?.Filename != filename)
return;
// Find the last started transfer, and report that as the current transfer
// We choose the last one, as it will most likely be in-progress for the longest time
info = _currentTransfer = _activeTransferInfo.Values.OrderBy(x => x.Started).LastOrDefault();
if (_currentTransfer != null)
_activeTransferProgress.TryGetValue(_currentTransfer.Filename, out progress);
}
if (info != null)
{
Stats.BackendProgressUpdater.StartAction(info.Type, info.Filename, info.Size, info.Started);
Stats.BackendProgressUpdater.UpdateProgress(progress);
}
}
}
}