From 5e3921a98c76777e81fcdb72f54bc4c39d7d870c Mon Sep 17 00:00:00 2001 From: Jack Edwards Date: Tue, 17 Sep 2024 21:41:13 -0500 Subject: [PATCH] Simple algorithm to target 1 second multipart upload request times --- .../Transfer/Handlers/UploadFileHandler.cs | 17 +++++++++++++++-- .../Transfer/Models/ClientTransferSettings.cs | 5 +++++ Crypter.Web/wwwroot/appsettings.json | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Crypter.Common.Client/Transfer/Handlers/UploadFileHandler.cs b/Crypter.Common.Client/Transfer/Handlers/UploadFileHandler.cs index 6c7d169f..5d031e35 100644 --- a/Crypter.Common.Client/Transfer/Handlers/UploadFileHandler.cs +++ b/Crypter.Common.Client/Transfer/Handlers/UploadFileHandler.cs @@ -27,6 +27,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -159,13 +160,16 @@ await Parallel.ForEachAsync(asyncEnumerable, parallelOptions, async (streamOpene async IAsyncEnumerable> SplitEncryptionStreamAsync(EncryptionStream encryptionStream) { bool endOfStream = false; + Stopwatch loopStopwatch = new Stopwatch(); + short blocksPerRequest = ClientTransferSettings.InitialMultipartReadBlocks; do { - int bufferSize = ClientTransferSettings.MaximumMultipartReadBlocks * encryptionStream.MinimumBufferSize; + loopStopwatch.Restart(); + int bufferSize = blocksPerRequest * encryptionStream.MinimumBufferSize; byte[] buffer = ArrayPool.Shared.Rent(bufferSize); int totalBytesRead = 0; - for (int i = 0; i < ClientTransferSettings.MaximumMultipartReadBlocks; i++) + for (int i = 0; i < blocksPerRequest; i++) { int bytesRead = await encryptionStream.ReadAsync(buffer.AsMemory(totalBytesRead, encryptionStream.MinimumBufferSize)); totalBytesRead += bytesRead; @@ -187,6 +191,15 @@ async IAsyncEnumerable> SplitEncryptionStreamAsync(Encryption ArrayPool.Shared.Return(buffer, clearArray: true); } } + + if (loopStopwatch.Elapsed < TimeSpan.FromSeconds(1) && blocksPerRequest < ClientTransferSettings.MaximumMultipartReadBlocks) + { + blocksPerRequest += 5; + } + else if (loopStopwatch.Elapsed > TimeSpan.FromSeconds(1) && blocksPerRequest > ClientTransferSettings.InitialMultipartReadBlocks) + { + blocksPerRequest -= 5; + } } while (!endOfStream); } } diff --git a/Crypter.Common.Client/Transfer/Models/ClientTransferSettings.cs b/Crypter.Common.Client/Transfer/Models/ClientTransferSettings.cs index 6f1f6998..c322bfce 100644 --- a/Crypter.Common.Client/Transfer/Models/ClientTransferSettings.cs +++ b/Crypter.Common.Client/Transfer/Models/ClientTransferSettings.cs @@ -48,6 +48,11 @@ public class ClientTransferSettings /// public short MaximumMultipartReadBlocks { get; init; } + /// + /// Set the initial number of read blocks in a single multipart request body. + /// + public short InitialMultipartReadBlocks { get; init; } + /// /// Set the maximum degrees of parallelism for multipart uploads. /// diff --git a/Crypter.Web/wwwroot/appsettings.json b/Crypter.Web/wwwroot/appsettings.json index 9becaf31..6efee96f 100644 --- a/Crypter.Web/wwwroot/appsettings.json +++ b/Crypter.Web/wwwroot/appsettings.json @@ -7,6 +7,7 @@ "MaximumUploadStreamSizeMB": 250, "MaximumMultipartUploadSizeMB": 250, "MaximumMultipartReadBlocks": 120, + "InitialMultipartReadBlocks": 10, "MaximumMultipartParallelism": 1, "MaxReadSize": 32704, "PadSize": 64