From 15da77e5ca240776ff51786bc57176f13923dbe4 Mon Sep 17 00:00:00 2001 From: mytelegram Date: Thu, 17 Jul 2025 19:32:26 +0800 Subject: [PATCH 1/3] perf: Use MemoryPool to reduce memory allocations. --- Minio/ApiEndpoints/ObjectOperations.cs | 32 ++++++++++---------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Minio/ApiEndpoints/ObjectOperations.cs b/Minio/ApiEndpoints/ObjectOperations.cs index b695f0c65..dcc528391 100644 --- a/Minio/ApiEndpoints/ObjectOperations.cs +++ b/Minio/ApiEndpoints/ObjectOperations.cs @@ -15,6 +15,7 @@ * limitations under the License. */ +using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Net; @@ -576,8 +577,10 @@ public async Task PutObjectAsync(PutObjectArgs args, if ((args.ObjectSize < Constants.MinimumPartSize || isSnowball) && args.ObjectSize >= 0 && args.ObjectStreamData is not null) { - var bytes = await ReadFullAsync(args.ObjectStreamData, (int)args.ObjectSize).ConfigureAwait(false); - var bytesRead = bytes.Length; + using var tempMemory = MemoryPool.Shared.Rent((int)args.ObjectSize); + var bytesRead = await ReadFullAsync(args.ObjectStreamData, tempMemory.Memory) + .ConfigureAwait(false); + var bytes = tempMemory.Memory[..bytesRead]; if (bytesRead != (int)args.ObjectSize) throw new UnexpectedShortReadException( $"Data read {bytesRead.ToString(CultureInfo.InvariantCulture)} is shorter than the size {args.ObjectSize.ToString(CultureInfo.InvariantCulture)} of input buffer."); @@ -916,9 +919,11 @@ private async Task> PutObjectPartAsync(PutObjectPartArg var etags = new Dictionary(); var progressReport = new ProgressReport(); args.Progress?.Report(progressReport); + using var tempMemory = MemoryPool.Shared.Rent((int)partSize); for (partNumber = 1; partNumber <= partCount; partNumber++) { - var dataToCopy = await ReadFullAsync(args.ObjectStreamData, (int)partSize).ConfigureAwait(false); + var bytesRead = await ReadFullAsync(args.ObjectStreamData, tempMemory.Memory).ConfigureAwait(false); + var dataToCopy = tempMemory.Memory[..bytesRead]; if (dataToCopy.IsEmpty && numPartsUploaded > 0) break; if (partNumber == partCount) expectedReadSize = lastPartSize; var putObjectArgs = new PutObjectArgs(args) @@ -1140,23 +1145,10 @@ await this.ExecuteTaskAsync(requestMessageBuilder, /// Advances in the stream upto currentPartSize or End of Stream /// /// - /// - /// bytes read in a byte array - internal static async Task> ReadFullAsync(Stream data, int currentPartSize) + /// + /// bytes count read + internal static async Task ReadFullAsync(Stream data, Memory destination) { - Memory result = new byte[currentPartSize]; - var totalRead = 0; - while (totalRead < currentPartSize) - { - var curData = result[totalRead..currentPartSize]; - var curRead = await data.ReadAsync(curData).ConfigureAwait(false); - if (curRead == 0) break; - totalRead += curRead; - } - - if (totalRead == 0) return null; - - // Return only the valid portion without allocating a new buffer - return result[..totalRead]; + return await data.ReadAsync(destination).ConfigureAwait(false); } } From 8e8282ba8390ae6450f3bf50c75bebc0e156929f Mon Sep 17 00:00:00 2001 From: mytelegram Date: Thu, 17 Jul 2025 19:33:23 +0800 Subject: [PATCH 2/3] perf: Memory allocation optimization --- Minio/Helper/S3utils.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Minio/Helper/S3utils.cs b/Minio/Helper/S3utils.cs index eaae70026..a82395b24 100644 --- a/Minio/Helper/S3utils.cs +++ b/Minio/Helper/S3utils.cs @@ -22,13 +22,15 @@ internal static class S3utils { internal static readonly Regex TrimWhitespaceRegex = new("\\s+", RegexOptions.None, TimeSpan.FromHours(1)); + internal static readonly Regex AmazonEndpointRegex = new( + "^s3[.-]?(.*?)\\.amazonaws\\.com$", + RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant, + TimeSpan.FromHours(1) + ); + internal static bool IsAmazonEndPoint(string endpoint) { - if (IsAmazonChinaEndPoint(endpoint)) return true; - var rgx = new Regex("^s3[.-]?(.*?)\\.amazonaws\\.com$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture, - TimeSpan.FromHours(1)); - var matches = rgx.Matches(endpoint); - return matches.Count > 0; + return AmazonEndpointRegex.IsMatch(endpoint); } // IsAmazonChinaEndpoint - Match if it is exactly Amazon S3 China endpoint. From ab6532fc808d07317a560aaac0e1232b3508588b Mon Sep 17 00:00:00 2001 From: mytelegram Date: Thu, 31 Jul 2025 22:00:57 +0800 Subject: [PATCH 3/3] fix: Add missing IsAmazonChinaEndPoint check --- Minio/Helper/S3utils.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Minio/Helper/S3utils.cs b/Minio/Helper/S3utils.cs index a82395b24..cc1823b60 100644 --- a/Minio/Helper/S3utils.cs +++ b/Minio/Helper/S3utils.cs @@ -30,6 +30,7 @@ internal static class S3utils internal static bool IsAmazonEndPoint(string endpoint) { + if (IsAmazonChinaEndPoint(endpoint)) return true; return AmazonEndpointRegex.IsMatch(endpoint); }