From 8bd8cd393a6189e8c2852ecc6fed7f2c9fd970da Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Sat, 18 May 2024 12:54:27 +0200 Subject: [PATCH 1/3] Fix progress timing for `PutObject_Test9 ` test (fixes #1078) --- Minio.Functional.Tests/FunctionalTest.cs | 2 +- Minio/Helper/SyncProgress.cs | 29 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Minio/Helper/SyncProgress.cs diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index 95f35cee..b3518fd0 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -3495,7 +3495,7 @@ internal static async Task PutObject_Test9(IMinioClient minio) const string contentType = "application/octet-stream"; var percentage = 0; var totalBytesTransferred = 0L; - var progress = new Progress(progressReport => + var progress = new SyncProgress(progressReport => { percentage = progressReport.Percentage; totalBytesTransferred = progressReport.TotalBytesTransferred; diff --git a/Minio/Helper/SyncProgress.cs b/Minio/Helper/SyncProgress.cs new file mode 100644 index 00000000..ee37f2d7 --- /dev/null +++ b/Minio/Helper/SyncProgress.cs @@ -0,0 +1,29 @@ +namespace Minio.Helper; + +/// +/// SyncProgress is a thread-free alternative to +/// and should be used if progress needs be determined in real-time. +/// +/// +/// +/// The upload process uses asynchronous tasks to perform the upload, +/// so these events may be invoked on an arbitrary thread. Use the +/// regular if you need progress +/// to be reported on a fixed thread or provide your own thread +/// synchronization. Doing synchronous calls to other threads from +/// within this handler will degrade your upload performance. +/// +public class SyncProgress : IProgress +{ + private readonly Action handler; + + public SyncProgress(Action handler) + { + this.handler = handler; + } + + public void Report(T value) + { + handler(value); + } +} From 1db680814b383e02e61127b8408897713821920f Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Sat, 18 May 2024 13:27:06 +0200 Subject: [PATCH 2/3] Fix layout --- Minio/Helper/SyncProgress.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Minio/Helper/SyncProgress.cs b/Minio/Helper/SyncProgress.cs index ee37f2d7..3fa02daf 100644 --- a/Minio/Helper/SyncProgress.cs +++ b/Minio/Helper/SyncProgress.cs @@ -1,17 +1,17 @@ namespace Minio.Helper; /// -/// SyncProgress is a thread-free alternative to -/// and should be used if progress needs be determined in real-time. +/// SyncProgress is a thread-free alternative to +/// and should be used if progress needs be determined in real-time. /// /// /// -/// The upload process uses asynchronous tasks to perform the upload, -/// so these events may be invoked on an arbitrary thread. Use the -/// regular if you need progress -/// to be reported on a fixed thread or provide your own thread -/// synchronization. Doing synchronous calls to other threads from -/// within this handler will degrade your upload performance. +/// The upload process uses asynchronous tasks to perform the upload, +/// so these events may be invoked on an arbitrary thread. Use the +/// regular if you need progress +/// to be reported on a fixed thread or provide your own thread +/// synchronization. Doing synchronous calls to other threads from +/// within this handler will degrade your upload performance. /// public class SyncProgress : IProgress { @@ -21,7 +21,7 @@ public SyncProgress(Action handler) { this.handler = handler; } - + public void Report(T value) { handler(value); From a72991e76991489f10fbf7051cdbcc1161578bbd Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Sun, 19 May 2024 11:48:38 +0200 Subject: [PATCH 3/3] Process review comments --- Docs/API.md | 10 +++++++++- Minio.Examples/Program.cs | 3 ++- Minio.Functional.Tests/FunctionalTest.cs | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Docs/API.md b/Docs/API.md index 17c15c74..50dac319 100644 --- a/Docs/API.md +++ b/Docs/API.md @@ -1874,6 +1874,7 @@ try var ssec = new SSEC(aesEncryption.Key); var progress = new Progress(progressReport => { + // Progress events are delivered asynchronously (see remark below) Console.WriteLine( $"Percentage: {progressReport.Percentage}% TotalBytesTransferred: {progressReport.TotalBytesTransferred} bytes"); if (progressReport.Percentage != 100) @@ -1895,7 +1896,14 @@ catch(MinioException e) Console.WriteLine("Error occurred: " + e); } ``` - +**Remark:** +Note that the default [Progress class](https://learn.microsoft.com/en-us/dotnet/api/System.Progress-1) post progress +updates to the SynchronizationContext when the instance was constructed +([source](https://learn.microsoft.com/en-us/dotnet/api/system.progress-1#remarks)). This means that progress updates are +sent asynchronous. If you do want to receive the events synchronous, then use the `Minio.Helper.SyncProgress` instead, +but make sure you understand the implications. Progress events are sent synchronous, so they may be invoked on an +arbitrary thread (mostly a problem for UI applications) and performing long-running and/or blocking operations will +degrade upload performance. ### StatObjectAsync(StatObjectArgs args) diff --git a/Minio.Examples/Program.cs b/Minio.Examples/Program.cs index 817af18d..29ca57e3 100644 --- a/Minio.Examples/Program.cs +++ b/Minio.Examples/Program.cs @@ -24,6 +24,7 @@ using Minio.DataModel.Notification; using Minio.DataModel.ObjectLock; using Minio.Examples.Cases; +using Minio.Helper; namespace Minio.Examples; @@ -110,7 +111,7 @@ public static async Task Main() var destBucketName = GetRandomName(); var destObjectName = GetRandomName(); var lockBucketName = GetRandomName(); - var progress = new Progress(progressReport => + var progress = new SyncProgress(progressReport => { Console.WriteLine( $"Percentage: {progressReport.Percentage}% TotalBytesTransferred: {progressReport.TotalBytesTransferred} bytes"); diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index b3518fd0..af110324 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -3552,7 +3552,7 @@ internal static async Task PutObject_Test10(IMinioClient minio) var contentType = "binary/octet-stream"; var percentage = 0; var totalBytesTransferred = 0L; - var progress = new Progress(progressReport => + var progress = new SyncProgress(progressReport => { percentage = progressReport.Percentage; totalBytesTransferred = progressReport.TotalBytesTransferred;