Added reported statistics
This commit is contained in:
@@ -579,8 +579,64 @@ namespace Duplicati.Library.Interface
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Results of a sync operation.
|
||||
/// </summary>
|
||||
public interface ISyncResults : IBasicResults
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of folders created on the remote destination.
|
||||
/// </summary>
|
||||
long FoldersCreated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of folders deleted from the remote destination.
|
||||
/// </summary>
|
||||
long FoldersDeleted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of files uploaded to the remote destination (new files plus
|
||||
/// updated files whose content changed).
|
||||
/// </summary>
|
||||
long FilesUploaded { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of files that were examined but left unchanged because the
|
||||
/// local and remote content already matched (size/mtime, or hash when
|
||||
/// <c>--sync-verify-hash</c> is set).
|
||||
/// </summary>
|
||||
long UnchangedFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of files deleted from the remote destination (unknown remote
|
||||
/// files removed when <c>--sync-then-delete</c> is set).
|
||||
/// </summary>
|
||||
long FilesDeleted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of local source files encountered during enumeration
|
||||
/// across all folders, regardless of whether they were uploaded, unchanged,
|
||||
/// or skipped.
|
||||
/// </summary>
|
||||
long SourceFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size in bytes of all local source files encountered during
|
||||
/// enumeration, regardless of whether they were uploaded or left unchanged.
|
||||
/// </summary>
|
||||
long SizeOfSourceFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size in bytes of the files uploaded to the remote destination
|
||||
/// (new files plus updated files whose content changed).
|
||||
/// </summary>
|
||||
long SizeOfUploadedFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size in bytes of the files deleted from the remote destination
|
||||
/// (unknown remote files removed when <c>--sync-then-delete</c> is set).
|
||||
/// </summary>
|
||||
long SizeOfDeletedFiles { get; }
|
||||
}
|
||||
|
||||
public interface ISetLockResults : IBasicResults
|
||||
|
||||
@@ -266,6 +266,16 @@ public class VacuumResultsDto : BasicResultsDto
|
||||
[Serializable]
|
||||
public class SyncResultsDto : BasicResultsDto
|
||||
{
|
||||
public long FoldersCreated { get; set; }
|
||||
public long FoldersDeleted { get; set; }
|
||||
public long FilesUploaded { get; set; }
|
||||
public long UnchangedFiles { get; set; }
|
||||
public long FilesDeleted { get; set; }
|
||||
public long SourceFiles { get; set; }
|
||||
public long SizeOfSourceFiles { get; set; }
|
||||
public long SizeOfUploadedFiles { get; set; }
|
||||
public long SizeOfDeletedFiles { get; set; }
|
||||
|
||||
public static SyncResultsDto FromResults(ISyncResults results)
|
||||
{
|
||||
if (results == null) return null;
|
||||
@@ -278,7 +288,16 @@ public class SyncResultsDto : BasicResultsDto
|
||||
Warnings = results.Warnings?.ToList() ?? new List<string>(),
|
||||
Messages = results.Messages?.ToList() ?? new List<string>(),
|
||||
ParsedResult = results.ParsedResult,
|
||||
Interrupted = results.Interrupted
|
||||
Interrupted = results.Interrupted,
|
||||
FoldersCreated = results.FoldersCreated,
|
||||
FoldersDeleted = results.FoldersDeleted,
|
||||
FilesUploaded = results.FilesUploaded,
|
||||
UnchangedFiles = results.UnchangedFiles,
|
||||
FilesDeleted = results.FilesDeleted,
|
||||
SourceFiles = results.SourceFiles,
|
||||
SizeOfSourceFiles = results.SizeOfSourceFiles,
|
||||
SizeOfUploadedFiles = results.SizeOfUploadedFiles,
|
||||
SizeOfDeletedFiles = results.SizeOfDeletedFiles
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,18 @@ public class VacuumResultsWrapper : BasicResultsWrapper, IVacuumResults
|
||||
public class SyncResultsWrapper : BasicResultsWrapper, ISyncResults
|
||||
{
|
||||
public SyncResultsWrapper(SyncResultsDto dto) : base(dto) { }
|
||||
|
||||
protected new SyncResultsDto _dto => (SyncResultsDto)base._dto;
|
||||
|
||||
public long FoldersCreated => _dto.FoldersCreated;
|
||||
public long FoldersDeleted => _dto.FoldersDeleted;
|
||||
public long FilesUploaded => _dto.FilesUploaded;
|
||||
public long UnchangedFiles => _dto.UnchangedFiles;
|
||||
public long FilesDeleted => _dto.FilesDeleted;
|
||||
public long SourceFiles => _dto.SourceFiles;
|
||||
public long SizeOfSourceFiles => _dto.SizeOfSourceFiles;
|
||||
public long SizeOfUploadedFiles => _dto.SizeOfUploadedFiles;
|
||||
public long SizeOfDeletedFiles => _dto.SizeOfDeletedFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -168,6 +168,24 @@ internal class SyncHandler
|
||||
}
|
||||
|
||||
Logging.Log.WriteInformationMessage(LOGTAG, "SyncPlan", "Plan: Upload {0}, Update {1}, Delete {2}", planSummary.Upload, planSummary.Update, planSummary.Delete);
|
||||
|
||||
// Flush the running counters into the results so callers (CLI, IPC, web UI)
|
||||
// see folders created, files uploaded/unchanged/deleted, and the total
|
||||
// files/size encountered. Upload+Update is the combined "files uploaded"
|
||||
// count; Delete maps to files deleted from the remote.
|
||||
m_results.FoldersCreated = planSummary.FoldersCreated;
|
||||
// The handler deletes unknown remote files only, never remote folders, so
|
||||
// the folders-deleted count is always zero today; the field is exposed for
|
||||
// completeness and future folder-deletion support.
|
||||
m_results.FoldersDeleted = 0;
|
||||
m_results.FilesUploaded = planSummary.Upload + planSummary.Update;
|
||||
m_results.UnchangedFiles = planSummary.UnchangedFiles;
|
||||
m_results.FilesDeleted = planSummary.Delete;
|
||||
m_results.SourceFiles = planSummary.SourceFiles;
|
||||
m_results.SizeOfSourceFiles = planSummary.SizeOfSourceFiles;
|
||||
m_results.SizeOfUploadedFiles = planSummary.SizeOfUploadedFiles;
|
||||
m_results.SizeOfDeletedFiles = planSummary.SizeOfDeletedFiles;
|
||||
|
||||
Logging.Log.WriteInformationMessage(LOGTAG, "SyncFinished", "Sync completed successfully.");
|
||||
}
|
||||
|
||||
@@ -241,6 +259,12 @@ internal class SyncHandler
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count every local source file encountered (regardless of whether it
|
||||
// ends up uploaded, unchanged, or de-duplicated) so SourceFiles and
|
||||
// SizeOfSourceFiles reflect the full local inventory scanned this run.
|
||||
planSummary.SourceFiles++;
|
||||
planSummary.SizeOfSourceFiles += Math.Max(child.Size, 0);
|
||||
|
||||
// INSERT OR IGNORE semantics: the first entry seen for a path wins, so a
|
||||
// later duplicate in the same folder is ignored (paths are unique within
|
||||
// a single folder in practice).
|
||||
@@ -403,6 +427,7 @@ internal class SyncHandler
|
||||
Logging.Log.WriteDryrunMessage(LOGTAG, "DryRun", "Would create folder: {0}", subRelPath);
|
||||
else
|
||||
await backendManager.EnsureFolderAsync(subRelPath, ct).ConfigureAwait(false);
|
||||
planSummary.FoldersCreated++;
|
||||
}
|
||||
|
||||
folderQueue.Enqueue(new FolderWorkItem(subEntry, subRelPath));
|
||||
@@ -416,8 +441,14 @@ internal class SyncHandler
|
||||
// either already has files (so it exists) or is brand new, in which case the
|
||||
// sub-folder ensure above created it when it was enqueued as a child. The
|
||||
// backend root (folderRelPath == "") is assumed to exist for all modes.
|
||||
if (stateMode == SyncRemoteState.BlindlyUpload && !string.IsNullOrEmpty(folderRelPath) && !isDryRun)
|
||||
await backendManager.EnsureFolderAsync(folderRelPath, ct).ConfigureAwait(false);
|
||||
// BlindlyUpload always treats the current folder as new (we have no listing
|
||||
// to prove it exists), so it counts as a created folder when not a dry run.
|
||||
if (stateMode == SyncRemoteState.BlindlyUpload && !string.IsNullOrEmpty(folderRelPath))
|
||||
{
|
||||
if (!isDryRun)
|
||||
await backendManager.EnsureFolderAsync(folderRelPath, ct).ConfigureAwait(false);
|
||||
planSummary.FoldersCreated++;
|
||||
}
|
||||
|
||||
// 5. Upload all new or changed files in this folder. The caller guarantees the
|
||||
// current folder exists, so UploadOrUpdateAsync does not call EnsureFolderAsync.
|
||||
@@ -459,7 +490,10 @@ internal class SyncHandler
|
||||
}
|
||||
|
||||
if (!needsUpload)
|
||||
{
|
||||
planSummary.UnchangedFiles++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hashRecheck)
|
||||
{
|
||||
@@ -470,7 +504,10 @@ internal class SyncHandler
|
||||
{
|
||||
var hash = Convert.ToBase64String(hasher.ComputeHash(s));
|
||||
if (hash == remoteHash)
|
||||
{
|
||||
planSummary.UnchangedFiles++;
|
||||
continue; // Content unchanged; no upload needed.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -530,6 +567,7 @@ internal class SyncHandler
|
||||
{
|
||||
Logging.Log.WriteDryrunMessage(LOGTAG, "DryRun", "Would delete: {0}", relPath);
|
||||
planSummary.Delete++;
|
||||
planSummary.SizeOfDeletedFiles += Math.Max(rc.Size, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -542,6 +580,7 @@ internal class SyncHandler
|
||||
await backendManager.DeleteAsync(relPath, 0, true, ct).ConfigureAwait(false);
|
||||
deletedPaths.Add(relPath);
|
||||
planSummary.Delete++;
|
||||
planSummary.SizeOfDeletedFiles += Math.Max(rc.Size, 0);
|
||||
}
|
||||
|
||||
// Commit the inventory removals and intent clearances for all files deleted
|
||||
@@ -613,6 +652,7 @@ internal class SyncHandler
|
||||
planSummary.Upload++;
|
||||
else
|
||||
planSummary.Update++;
|
||||
planSummary.SizeOfUploadedFiles += Math.Max(lf.Size, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -655,6 +695,7 @@ internal class SyncHandler
|
||||
planSummary.Upload++;
|
||||
else
|
||||
planSummary.Update++;
|
||||
planSummary.SizeOfUploadedFiles += Math.Max(lf.Size, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -759,12 +800,19 @@ internal class SyncHandler
|
||||
|
||||
/// <summary>
|
||||
/// Running counters for the plan summary log, bumped per operation as it is
|
||||
/// planned/performed so the final log line reflects the whole run.
|
||||
/// planned/performed so the final log line reflects the whole run. The same
|
||||
/// counters are flushed into <see cref="SyncResults"/> at the end of the run.
|
||||
/// </summary>
|
||||
private sealed class PlanSummary
|
||||
{
|
||||
public long Upload;
|
||||
public long Update;
|
||||
public long Delete;
|
||||
public long FoldersCreated;
|
||||
public long UnchangedFiles;
|
||||
public long SourceFiles;
|
||||
public long SizeOfSourceFiles;
|
||||
public long SizeOfUploadedFiles;
|
||||
public long SizeOfDeletedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,5 +1058,24 @@ namespace Duplicati.Library.Main
|
||||
public SyncResults(BasicResults p) : base(p) { }
|
||||
|
||||
public override OperationMode MainOperation { get { return OperationMode.Sync; } }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long FoldersCreated { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long FoldersDeleted { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long FilesUploaded { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long UnchangedFiles { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long FilesDeleted { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long SourceFiles { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long SizeOfSourceFiles { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long SizeOfUploadedFiles { get; internal set; }
|
||||
/// <inheritdoc/>
|
||||
public long SizeOfDeletedFiles { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user