diff --git a/Module/PSMinIO/bin/PSMinIO.dll b/Module/PSMinIO/bin/PSMinIO.dll
index 4e7190b..ee00d05 100644
Binary files a/Module/PSMinIO/bin/PSMinIO.dll and b/Module/PSMinIO/bin/PSMinIO.dll differ
diff --git a/src/Core/S3/MultipartUploadManager.cs b/src/Core/S3/MultipartUploadManager.cs
index d4f475d..5afebc9 100644
--- a/src/Core/S3/MultipartUploadManager.cs
+++ b/src/Core/S3/MultipartUploadManager.cs
@@ -60,7 +60,7 @@ namespace PSMinIO.Core.S3
// Layer 2: File Progress
_progressCollector.QueueProgressUpdate(2, "File Upload",
- $"Uploading {fileInfo.Name} ({SizeFormatter.FormatBytes(totalSize)})", 0, 1);
+ $"Uploading {fileInfo.Name} - {SizeFormatter.FormatBytesIntelligent(0, totalSize)}", 0, 1);
// Process initial progress updates
_progressCollector.ProcessQueuedUpdates();
@@ -161,9 +161,10 @@ namespace PSMinIO.Core.S3
var elapsed = DateTime.UtcNow - operationStartTime;
var speed = elapsed.TotalSeconds > 0 ? currentUploaded / elapsed.TotalSeconds : 0;
- // Update file progress (Layer 2)
+ // Update file progress (Layer 2) with intelligent size formatting
+ var sizeDisplay = SizeFormatter.FormatBytesIntelligent(currentUploaded, totalSize);
_progressCollector.QueueProgressUpdate(2, "File Upload",
- $"Part {partNum}/{totalParts} - {SizeFormatter.FormatBytes(currentUploaded)}/{SizeFormatter.FormatBytes(totalSize)} at {SizeFormatter.FormatSpeed(speed)}",
+ $"Uploading {fileInfo.Name} - {sizeDisplay} (Part {partNum}/{totalParts}) at {SizeFormatter.FormatSpeed(speed)}",
(int)fileProgress, 1);
// Log completion for larger chunks or milestone parts
@@ -319,11 +320,13 @@ namespace PSMinIO.Core.S3
fileStream.Seek(offset, SeekOrigin.Begin);
// Create progress-tracking stream for chunk upload (Layer 3)
+ // Use unique activity ID for each chunk: 100 + partNumber (allows up to 900 concurrent chunks)
+ var chunkActivityId = 100 + partNumber;
var progressStream = new ProgressTrackingStream(fileStream, size,
(bytesRead, totalBytes) =>
{
var chunkProgress = (double)bytesRead / totalBytes * 100;
- _progressCollector.QueueProgressUpdate(3, "Uploading Chunk",
+ _progressCollector.QueueProgressUpdate(chunkActivityId, "Uploading Chunk",
$"Part {partNumber}: {SizeFormatter.FormatBytes(bytesRead)}/{SizeFormatter.FormatBytes(totalBytes)}",
(int)chunkProgress, 2); // Parent: File Upload (Layer 2)
});
@@ -356,8 +359,8 @@ namespace PSMinIO.Core.S3
var etag = response.Headers.ETag?.Tag?.Trim('"') ?? "";
- // Complete chunk progress (Layer 3)
- _progressCollector.QueueProgressCompletion(3, "Uploading Chunk", 2);
+ // Complete chunk progress (Layer 3) - use same unique activity ID
+ _progressCollector.QueueProgressCompletion(chunkActivityId, "Uploading Chunk", 2);
return new PartInfo
{
diff --git a/src/Utils/SizeFormatter.cs b/src/Utils/SizeFormatter.cs
index 4228f2e..ef87278 100644
--- a/src/Utils/SizeFormatter.cs
+++ b/src/Utils/SizeFormatter.cs
@@ -160,5 +160,34 @@ namespace PSMinIO.Utils
return FormatDuration(TimeSpan.FromSeconds(remainingSeconds));
}
+
+ ///
+ /// Formats two byte values using the same unit based on the larger value
+ /// Example: FormatBytesIntelligent(1536MB, 4.57GB) returns "1.50 GB/4.57 GB"
+ ///
+ /// Current byte count
+ /// Total byte count
+ /// Number of decimal places to show (default: 2)
+ /// Formatted size string with consistent units
+ public static string FormatBytesIntelligent(long currentBytes, long totalBytes, int decimalPlaces = 2)
+ {
+ if (totalBytes == 0) return $"{FormatBytes(currentBytes, decimalPlaces)}/0 B";
+
+ // Determine the unit based on the total size (larger value)
+ int unitIndex = 0;
+ double totalSize = Math.Abs(totalBytes);
+
+ while (totalSize >= 1024 && unitIndex < SizeUnits.Length - 1)
+ {
+ totalSize /= 1024;
+ unitIndex++;
+ }
+
+ // Format both values using the same unit
+ double currentSize = currentBytes / Math.Pow(1024, unitIndex);
+ double totalSizeFormatted = totalBytes / Math.Pow(1024, unitIndex);
+
+ return $"{currentSize.ToString($"F{decimalPlaces}")} {SizeUnits[unitIndex]}/{totalSizeFormatted.ToString($"F{decimalPlaces}")} {SizeUnits[unitIndex]}";
+ }
}
}