From 36e14568e7cfcb12bcf7bcc04f7a7bfb7c071030 Mon Sep 17 00:00:00 2001
From: Stephen Halter <halter73@gmail.com>
Date: Fri, 17 Jun 2022 16:03:35 -0700
Subject: [PATCH] Partition more ConcurrentQueues in Kestrel (#42237)

---
 .../src/SocketConnectionContextFactory.cs     | 35 ++++++++++---------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionContextFactory.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionContextFactory.cs
index cd43cb1e7de..11e3aca3125 100644
--- a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionContextFactory.cs
+++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionContextFactory.cs
@@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
 /// </summary>
 public sealed class SocketConnectionContextFactory : IDisposable
 {
-    private readonly MemoryPool<byte> _memoryPool;
     private readonly SocketConnectionFactoryOptions _options;
     private readonly ILogger _logger;
     private readonly int _settingsCount;
@@ -43,7 +42,6 @@ public sealed class SocketConnectionContextFactory : IDisposable
 
         _options = options;
         _logger = logger;
-        _memoryPool = _options.MemoryPoolFactory();
         _settingsCount = _options.IOQueueCount;
 
         var maxReadBufferSize = _options.MaxReadBufferSize ?? 0;
@@ -56,6 +54,7 @@ public sealed class SocketConnectionContextFactory : IDisposable
 
             for (var i = 0; i < _settingsCount; i++)
             {
+                var memoryPool = _options.MemoryPoolFactory();
                 var transportScheduler = options.UnsafePreferInlineScheduling ? PipeScheduler.Inline : new IOQueue();
                 // https://github.com/aspnet/KestrelHttpServer/issues/2573
                 var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;
@@ -63,26 +62,29 @@ public sealed class SocketConnectionContextFactory : IDisposable
                 _settings[i] = new QueueSettings()
                 {
                     Scheduler = transportScheduler,
-                    InputOptions = new PipeOptions(_memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
-                    OutputOptions = new PipeOptions(_memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
-                    SocketSenderPool = new SocketSenderPool(awaiterScheduler)
+                    InputOptions = new PipeOptions(memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
+                    OutputOptions = new PipeOptions(memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
+                    SocketSenderPool = new SocketSenderPool(awaiterScheduler),
+                    MemoryPool = memoryPool,
                 };
             }
         }
         else
         {
+            var memoryPool = _options.MemoryPoolFactory();
             var transportScheduler = options.UnsafePreferInlineScheduling ? PipeScheduler.Inline : PipeScheduler.ThreadPool;
             // https://github.com/aspnet/KestrelHttpServer/issues/2573
             var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;
             _settings = new QueueSettings[]
             {
-                    new QueueSettings()
-                    {
-                        Scheduler = transportScheduler,
-                        InputOptions = new PipeOptions(_memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
-                        OutputOptions = new PipeOptions(_memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
-                        SocketSenderPool = new SocketSenderPool(awaiterScheduler)
-                    }
+                new QueueSettings()
+                {
+                    Scheduler = transportScheduler,
+                    InputOptions = new PipeOptions(memoryPool, applicationScheduler, transportScheduler, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false),
+                    OutputOptions = new PipeOptions(memoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false),
+                    SocketSenderPool = new SocketSenderPool(awaiterScheduler),
+                    MemoryPool = memoryPool,
+                }
             };
             _settingsCount = 1;
         }
@@ -98,7 +100,7 @@ public sealed class SocketConnectionContextFactory : IDisposable
         var setting = _settings[Interlocked.Increment(ref _settingsIndex) % _settingsCount];
 
         var connection = new SocketConnection(socket,
-            _memoryPool,
+            setting.MemoryPool,
             setting.Scheduler,
             _logger,
             setting.SocketSenderPool,
@@ -113,13 +115,11 @@ public sealed class SocketConnectionContextFactory : IDisposable
     /// <inheritdoc />
     public void Dispose()
     {
-        // Dispose the memory pool
-        _memoryPool.Dispose();
-
-        // Dispose any pooled senders
+        // Dispose any pooled senders and memory pools
         foreach (var setting in _settings)
         {
             setting.SocketSenderPool.Dispose();
+            setting.MemoryPool.Dispose();
         }
     }
 
@@ -129,5 +129,6 @@ public sealed class SocketConnectionContextFactory : IDisposable
         public PipeOptions InputOptions { get; init; } = default!;
         public PipeOptions OutputOptions { get; init; } = default!;
         public SocketSenderPool SocketSenderPool { get; init; } = default!;
+        public MemoryPool<byte> MemoryPool { get; init; } = default!;
     }
 }
-- 
GitLab