From 73a37363e1a44e221f070c530a5b987e118cc7a7 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 13 Nov 2017 15:04:54 -0800 Subject: [PATCH] Migrate to new pipe APIs (#2124) --- ...Http1ConnectionParsingOverheadBenchmark.cs | 7 +- .../Http1WritingBenchmark.cs | 46 ++++--- .../HttpProtocolFeatureCollection.cs | 7 +- .../PipeThroughputBenchmark.cs | 7 +- .../RequestParsingBenchmark.cs | 11 +- .../ResponseHeaderCollectionBenchmark.cs | 7 +- .../ResponseHeadersWritingBenchmark.cs | 24 ++-- build/dependencies.props | 11 +- korebuild-lock.txt | 4 +- .../Internal/ConnectionHandler.cs | 38 +++--- .../Internal/Http/Http1Connection.cs | 3 + .../Internal/Http/Http1ConnectionContext.cs | 3 +- .../Internal/Http/Http1OutputProducer.cs | 9 +- .../Internal/Http/HttpProtocol.cs | 19 +-- .../Internal/Http/IHttpProtocolContext.cs | 3 +- .../Internal/Http/PipelineExtensions.cs | 10 +- .../Internal/Http2/Http2Connection.cs | 2 +- .../Internal/Http2/Http2ConnectionContext.cs | 3 +- .../Internal/Http2/Http2StreamContext.cs | 3 +- src/Kestrel.Core/Internal/HttpConnection.cs | 37 +++--- .../Internal/HttpConnectionContext.cs | 3 +- .../Internal/HttpConnectionMiddleware.cs | 2 +- .../Internal/TransportConnection.Features.cs | 3 +- .../Internal/TransportConnection.cs | 4 +- .../Internal/LibuvConnection.cs | 4 +- .../Internal/LibuvConnectionContext.cs | 6 +- .../Internal/LibuvThread.cs | 7 +- .../Internal/Networking/UvWriteReq.cs | 10 +- .../Internal/BufferExtensions.cs | 4 +- .../Internal/SocketConnection.cs | 11 +- .../Internal/SocketReceiver.cs | 4 +- .../Internal/SocketSender.cs | 4 +- .../SocketTransport.cs | 7 +- .../ConnectionContext.cs | 3 +- .../DefaultConnectionContext.cs | 5 +- .../Features/IConnectionTransportFeature.cs | 6 +- .../PipeFactoryExtensions.cs | 16 ++- .../ConnectionHandlerTests.cs | 4 +- .../Http1ConnectionTests.cs | 9 +- .../Http2ConnectionTests.cs | 9 +- .../Kestrel.Core.Tests/HttpConnectionTests.cs | 11 +- .../HttpResponseHeadersTests.cs | 33 ++--- .../Kestrel.Core.Tests.csproj | 1 + .../Kestrel.Core.Tests/OutputProducerTests.cs | 17 ++- test/Kestrel.Core.Tests/PipeOptionsTests.cs | 6 +- .../PipelineExtensionTests.cs | 19 +-- test/Kestrel.Core.Tests/TestInput.cs | 10 +- .../LibuvConnectionTests.cs | 24 +++- .../LibuvOutputConsumerTests.cs | 121 ++++++++++-------- .../TestHelpers/MockConnectionHandler.cs | 9 +- 50 files changed, 352 insertions(+), 274 deletions(-) diff --git a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs index 208d9eca15..28413ab08b 100644 --- a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Http.Features; @@ -22,8 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance [IterationSetup] public void Setup() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); + var bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(bufferPool); var serviceContext = new ServiceContext { @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ServiceContext = serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, + BufferPool = bufferPool, TimeoutControl = new MockTimeoutControl(), Application = pair.Application, Transport = pair.Transport diff --git a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs index c216433f50..91f42667ae 100644 --- a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Text; using System.Threading; @@ -93,31 +94,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private TestHttp1Connection MakeHttp1Connection() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); - _pair = pair; - - var serviceContext = new ServiceContext + using (var memoryPool = new MemoryPool()) { - DateHeaderValueManager = new DateHeaderValueManager(), - ServerOptions = new KestrelServerOptions(), - Log = new MockTrace(), - HttpParserFactory = f => new HttpParser() - }; + var pair = PipeFactory.CreateConnectionPair(memoryPool); + _pair = pair; - var http1Connection = new TestHttp1Connection(application: null, context: new Http1ConnectionContext - { - ServiceContext = serviceContext, - ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, - Application = pair.Application, - Transport = pair.Transport - }); + var serviceContext = new ServiceContext + { + DateHeaderValueManager = new DateHeaderValueManager(), + ServerOptions = new KestrelServerOptions(), + Log = new MockTrace(), + HttpParserFactory = f => new HttpParser() + }; - http1Connection.Reset(); - http1Connection.InitializeStreams(MessageBody.ZeroContentLengthKeepAlive); + var http1Connection = new TestHttp1Connection( + application: null, context: new Http1ConnectionContext + { + ServiceContext = serviceContext, + ConnectionFeatures = new FeatureCollection(), + BufferPool = memoryPool, + Application = pair.Application, + Transport = pair.Transport + }); - return http1Connection; + http1Connection.Reset(); + http1Connection.InitializeStreams(MessageBody.ZeroContentLengthKeepAlive); + + return http1Connection; + } } [IterationCleanup] diff --git a/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs b/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs index f461fe470b..d55644d976 100644 --- a/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs +++ b/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Http.Features; @@ -77,8 +78,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public HttpProtocolFeatureCollection() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); + var bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(bufferPool); var serviceContext = new ServiceContext { @@ -92,7 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ServiceContext = serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, + BufferPool = bufferPool, Application = pair.Application, Transport = pair.Transport }); diff --git a/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs b/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs index 15ea0c4cae..973a63708d 100644 --- a/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs +++ b/benchmarks/Kestrel.Performance/PipeThroughputBenchmark.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; @@ -14,13 +15,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private const int InnerLoopCount = 512; private IPipe _pipe; - private PipeFactory _pipelineFactory; + private BufferPool _bufferPool; [IterationSetup] public void Setup() { - _pipelineFactory = new PipeFactory(); - _pipe = _pipelineFactory.Create(); + _bufferPool = new MemoryPool(); + _pipe = new Pipe(new PipeOptions(_bufferPool)); } [Benchmark(OperationsPerInvoke = InnerLoopCount)] diff --git a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs index 7f5c44c437..5837b5f5a1 100644 --- a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Http.Features; @@ -18,13 +19,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public Http1Connection Http1Connection { get; set; } - public PipeFactory PipeFactory { get; set; } - [IterationSetup] public void Setup() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); + var bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(bufferPool); var serviceContext = new ServiceContext { @@ -38,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ServiceContext = serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, + BufferPool = bufferPool, Application = pair.Application, Transport = pair.Transport, TimeoutControl = new MockTimeoutControl() @@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance http1Connection.Reset(); Http1Connection = http1Connection; - Pipe = pipeFactory.Create(); + Pipe = new Pipe(new PipeOptions(bufferPool)); } [Benchmark(Baseline = true, OperationsPerInvoke = RequestParsingData.InnerLoopCount)] diff --git a/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs b/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs index 36207e4296..cbd2fd5e79 100644 --- a/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs +++ b/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Runtime.CompilerServices; using System.Text; @@ -170,8 +171,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance [IterationSetup] public void Setup() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); + var bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(bufferPool); var serviceContext = new ServiceContext { @@ -185,7 +186,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { ServiceContext = serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, + BufferPool = bufferPool, Application = pair.Application, Transport = pair.Transport }); diff --git a/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs b/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs index 8443e13a5b..4940aa4326 100644 --- a/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Text; using System.Threading; @@ -110,8 +111,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance [IterationSetup] public void Setup() { - var pipeFactory = new PipeFactory(); - var pair = pipeFactory.CreateConnectionPair(); + var bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(bufferPool); var serviceContext = new ServiceContext { @@ -121,15 +122,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance HttpParserFactory = f => new HttpParser() }; - var http1Connection = new TestHttp1Connection(application: null, context: new Http1ConnectionContext - { - ServiceContext = serviceContext, - ConnectionFeatures = new FeatureCollection(), - PipeFactory = pipeFactory, - TimeoutControl = new MockTimeoutControl(), - Application = pair.Application, - Transport = pair.Transport - }); + var http1Connection = new TestHttp1Connection( + application: null, context: new Http1ConnectionContext + { + ServiceContext = serviceContext, + ConnectionFeatures = new FeatureCollection(), + BufferPool = bufferPool, + TimeoutControl = new MockTimeoutControl(), + Application = pair.Application, + Transport = pair.Transport + }); http1Connection.Reset(); diff --git a/build/dependencies.props b/build/dependencies.props index b8ba66b1f4..243bff93f3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -28,12 +28,13 @@ 4.7.49 10.0.1 4.4.0 - 0.1.0-e170811-6 - 4.4.0-preview3-25519-03 - 4.4.0 - 4.4.0 + 0.1.0-alpha-002 + 0.1.0-alpha-002 + 4.5.0-preview1-25902-08 + 4.5.0-preview1-25902-08 + 4.5.0-preview1-25902-08 4.4.0 - 0.1.0-e170811-6 + 0.1.0-alpha-002 4.4.0 0.7.0 2.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 45463cc71e..86352477bb 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15549 -commithash:f570e08585fec510dd60cd4bfe8795388b757a95 +version:2.1.0-preview1-15551 +commithash:8fad9553b48533fddbb16a423ea55b9710ea2e63 diff --git a/src/Kestrel.Core/Internal/ConnectionHandler.cs b/src/Kestrel.Core/Internal/ConnectionHandler.cs index 5e3513b5ac..fd9dc68746 100644 --- a/src/Kestrel.Core/Internal/ConnectionHandler.cs +++ b/src/Kestrel.Core/Internal/ConnectionHandler.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Protocols; @@ -34,10 +36,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal // REVIEW: Unfortunately, we still need to use the service context to create the pipes since the settings // for the scheduler and limits are specified here - var inputOptions = GetInputPipeOptions(_serviceContext, transportFeature.InputWriterScheduler); - var outputOptions = GetOutputPipeOptions(_serviceContext, transportFeature.OutputReaderScheduler); + var inputOptions = GetInputPipeOptions(_serviceContext, connectionContext.BufferPool, transportFeature.InputWriterScheduler); + var outputOptions = GetOutputPipeOptions(_serviceContext, connectionContext.BufferPool, transportFeature.OutputReaderScheduler); - var pair = connectionContext.PipeFactory.CreateConnectionPair(inputOptions, outputOptions); + var pair = PipeFactory.CreateConnectionPair(inputOptions, outputOptions); // Set the transport and connection id connectionContext.ConnectionId = CorrelationIdGenerator.GetNextId(); @@ -81,21 +83,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal } // Internal for testing - internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, IScheduler writerScheduler) => new PipeOptions - { - ReaderScheduler = serviceContext.ThreadPool, - WriterScheduler = writerScheduler, - MaximumSizeHigh = serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - MaximumSizeLow = serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 - }; + internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, BufferPool bufferPool, IScheduler writerScheduler) => new PipeOptions + ( + bufferPool: bufferPool, + readerScheduler: serviceContext.ThreadPool, + writerScheduler: writerScheduler, + maximumSizeHigh: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, + maximumSizeLow: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + ); - internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, IScheduler readerScheduler) => new PipeOptions - { - ReaderScheduler = readerScheduler, - WriterScheduler = serviceContext.ThreadPool, - MaximumSizeHigh = GetOutputResponseBufferSize(serviceContext), - MaximumSizeLow = GetOutputResponseBufferSize(serviceContext) - }; + internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, BufferPool bufferPool, IScheduler readerScheduler) => new PipeOptions + ( + bufferPool: bufferPool, + readerScheduler: readerScheduler, + writerScheduler: serviceContext.ThreadPool, + maximumSizeHigh: GetOutputResponseBufferSize(serviceContext), + maximumSizeLow: GetOutputResponseBufferSize(serviceContext) + ); private static long GetOutputResponseBufferSize(ServiceContext serviceContext) { diff --git a/src/Kestrel.Core/Internal/Http/Http1Connection.cs b/src/Kestrel.Core/Internal/Http/Http1Connection.cs index b5d9c0235a..cb073a0724 100644 --- a/src/Kestrel.Core/Internal/Http/Http1Connection.cs +++ b/src/Kestrel.Core/Internal/Http/Http1Connection.cs @@ -209,7 +209,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (pathEncoded) { // URI was encoded, unescape and then parse as UTF-8 + // Disabling warning temporary +#pragma warning disable 618 var pathLength = UrlEncoder.Decode(path, path); +#pragma warning restore 618 // Removing dot segments must be done after unescaping. From RFC 3986: // diff --git a/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs b/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs index 2b15279564..de529ea372 100644 --- a/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs +++ b/src/Kestrel.Core/Internal/Http/Http1ConnectionContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Net; using Microsoft.AspNetCore.Http.Features; @@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public string ConnectionId { get; set; } public ServiceContext ServiceContext { get; set; } public IFeatureCollection ConnectionFeatures { get; set; } - public PipeFactory PipeFactory { get; set; } + public BufferPool BufferPool { get; set; } public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; } public ITimeoutControl TimeoutControl { get; set; } diff --git a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs index 6ff341bb71..34c74f23d1 100644 --- a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http CancellationToken cancellationToken) { var writableBuffer = default(WritableBuffer); - + long bytesWritten = 0; lock (_contextLock) { if (_completed) @@ -181,17 +181,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (buffer.Count > 0) { writer.Write(buffer.Array, buffer.Offset, buffer.Count); + bytesWritten += buffer.Count; } writableBuffer.Commit(); } - return FlushAsync(writableBuffer, cancellationToken); + return FlushAsync(writableBuffer, bytesWritten, cancellationToken); } // Single caller, at end of method - so inline [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Task FlushAsync(WritableBuffer writableBuffer, CancellationToken cancellationToken) + private Task FlushAsync(WritableBuffer writableBuffer, long bytesWritten, CancellationToken cancellationToken) { var awaitable = writableBuffer.FlushAsync(cancellationToken); if (awaitable.IsCompleted) @@ -199,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // The flush task can't fail today return Task.CompletedTask; } - return FlushAsyncAwaited(awaitable, writableBuffer.BytesWritten, cancellationToken); + return FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken); } private async Task FlushAsyncAwaited(WritableBufferAwaitable awaitable, long count, CancellationToken cancellationToken) diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs index 9f6c11740d..0cadbce735 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public IHttpResponseControl HttpResponseControl { get; set; } - public IPipe RequestBodyPipe { get; } + public Pipe RequestBodyPipe { get; } public ServiceContext ServiceContext => _context.ServiceContext; private IPEndPoint LocalEndPoint => _context.LocalEndPoint; @@ -1301,13 +1301,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http Log.ApplicationError(ConnectionId, TraceIdentifier, ex); } - private IPipe CreateRequestBodyPipe() - => _context.PipeFactory.Create(new PipeOptions - { - ReaderScheduler = ServiceContext.ThreadPool, - WriterScheduler = InlineScheduler.Default, - MaximumSizeHigh = 1, - MaximumSizeLow = 1 - }); + private Pipe CreateRequestBodyPipe() + => new Pipe(new PipeOptions + ( + bufferPool: _context.BufferPool, + readerScheduler: ServiceContext.ThreadPool, + writerScheduler: InlineScheduler.Default, + maximumSizeHigh: 1, + maximumSizeLow: 1 + )); } } diff --git a/src/Kestrel.Core/Internal/Http/IHttpProtocolContext.cs b/src/Kestrel.Core/Internal/Http/IHttpProtocolContext.cs index fe1d5fa363..44abe5160f 100644 --- a/src/Kestrel.Core/Internal/Http/IHttpProtocolContext.cs +++ b/src/Kestrel.Core/Internal/Http/IHttpProtocolContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Net; using Microsoft.AspNetCore.Http.Features; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http string ConnectionId { get; set; } ServiceContext ServiceContext { get; set; } IFeatureCollection ConnectionFeatures { get; set; } - PipeFactory PipeFactory { get; set; } + BufferPool BufferPool { get; set; } IPEndPoint RemoteEndPoint { get; set; } IPEndPoint LocalEndPoint { get; set; } } diff --git a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs index 0f53b2783a..e12b588bb4 100644 --- a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs +++ b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return buffer.ToArray(); } - public static ArraySegment GetArray(this Buffer buffer) + public static ArraySegment GetArray(this Memory buffer) { ArraySegment result; if (!buffer.TryGetArray(out result)) @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return result; } - public unsafe static void WriteAsciiNoValidation(ref WritableBufferWriter buffer, string data) + public unsafe static void WriteAsciiNoValidation(ref this WritableBufferWriter buffer, string data) { if (string.IsNullOrEmpty(data)) { @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe static void WriteNumeric(ref WritableBufferWriter buffer, ulong number) + public unsafe static void WriteNumeric(ref this WritableBufferWriter buffer, ulong number) { const byte AsciiDigitStart = (byte)'0'; @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.NoInlining)] - private static void WriteNumericMultiWrite(ref WritableBufferWriter buffer, ulong number) + private static void WriteNumericMultiWrite(ref this WritableBufferWriter buffer, ulong number) { const byte AsciiDigitStart = (byte)'0'; @@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } [MethodImpl(MethodImplOptions.NoInlining)] - private unsafe static void WriteAsciiMultiWrite(ref WritableBufferWriter buffer, string data) + private unsafe static void WriteAsciiMultiWrite(ref this WritableBufferWriter buffer, string data) { var remaining = data.Length; diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs index 82637d51c1..83ec0d64f6 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs @@ -397,7 +397,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 StreamId = _incomingFrame.StreamId, ServiceContext = _context.ServiceContext, ConnectionFeatures = _context.ConnectionFeatures, - PipeFactory = _context.PipeFactory, + BufferPool = _context.BufferPool, LocalEndPoint = _context.LocalEndPoint, RemoteEndPoint = _context.RemoteEndPoint, StreamLifetimeHandler = this, diff --git a/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs b/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs index 1c089cc5b0..c4766a7b15 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2ConnectionContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Net; using Microsoft.AspNetCore.Http.Features; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 public string ConnectionId { get; set; } public ServiceContext ServiceContext { get; set; } public IFeatureCollection ConnectionFeatures { get; set; } - public PipeFactory PipeFactory { get; set; } + public BufferPool BufferPool { get; set; } public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; } diff --git a/src/Kestrel.Core/Internal/Http2/Http2StreamContext.cs b/src/Kestrel.Core/Internal/Http2/Http2StreamContext.cs index 68ea22533e..6bc9fc8b82 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2StreamContext.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2StreamContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.IO.Pipelines; using System.Net; using Microsoft.AspNetCore.Http.Features; @@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 public int StreamId { get; set; } public ServiceContext ServiceContext { get; set; } public IFeatureCollection ConnectionFeatures { get; set; } - public PipeFactory PipeFactory { get; set; } + public BufferPool BufferPool { get; set; } public IPEndPoint RemoteEndPoint { get; set; } public IPEndPoint LocalEndPoint { get; set; } public IHttp2StreamLifetimeHandler StreamLifetimeHandler { get; set; } diff --git a/src/Kestrel.Core/Internal/HttpConnection.cs b/src/Kestrel.Core/Internal/HttpConnection.cs index 099446058b..2ecc65d253 100644 --- a/src/Kestrel.Core/Internal/HttpConnection.cs +++ b/src/Kestrel.Core/Internal/HttpConnection.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -65,24 +66,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal public IPEndPoint LocalEndPoint => _context.LocalEndPoint; public IPEndPoint RemoteEndPoint => _context.RemoteEndPoint; - private PipeFactory PipeFactory => _context.PipeFactory; + private BufferPool BufferPool => _context.BufferPool; // Internal for testing internal PipeOptions AdaptedInputPipeOptions => new PipeOptions - { - ReaderScheduler = _context.ServiceContext.ThreadPool, - WriterScheduler = InlineScheduler.Default, - MaximumSizeHigh = _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - MaximumSizeLow = _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 - }; + ( + bufferPool: BufferPool, + readerScheduler: _context.ServiceContext.ThreadPool, + writerScheduler: InlineScheduler.Default, + maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, + maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + ); internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions - { - ReaderScheduler = InlineScheduler.Default, - WriterScheduler = InlineScheduler.Default, - MaximumSizeHigh = _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, - MaximumSizeLow = _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 - }; + ( + bufferPool: BufferPool, + readerScheduler: InlineScheduler.Default, + writerScheduler: InlineScheduler.Default, + maximumSizeHigh: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, + maximumSizeLow: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 + ); private IKestrelTrace Log => _context.ServiceContext.Log; @@ -107,8 +110,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal { adaptedPipeline = new AdaptedPipeline(transport, application, - PipeFactory.Create(AdaptedInputPipeOptions), - PipeFactory.Create(AdaptedOutputPipeOptions)); + new Pipe(AdaptedInputPipeOptions), + new Pipe(AdaptedOutputPipeOptions)); transport = adaptedPipeline; } @@ -180,7 +183,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal { ConnectionId = _context.ConnectionId, ConnectionFeatures = _context.ConnectionFeatures, - PipeFactory = PipeFactory, + BufferPool = BufferPool, LocalEndPoint = LocalEndPoint, RemoteEndPoint = RemoteEndPoint, ServiceContext = _context.ServiceContext, @@ -197,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal ConnectionId = _context.ConnectionId, ServiceContext = _context.ServiceContext, ConnectionFeatures = _context.ConnectionFeatures, - PipeFactory = PipeFactory, + BufferPool = BufferPool, LocalEndPoint = LocalEndPoint, RemoteEndPoint = RemoteEndPoint, Application = application, diff --git a/src/Kestrel.Core/Internal/HttpConnectionContext.cs b/src/Kestrel.Core/Internal/HttpConnectionContext.cs index 67298c0544..c2862b170b 100644 --- a/src/Kestrel.Core/Internal/HttpConnectionContext.cs +++ b/src/Kestrel.Core/Internal/HttpConnectionContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; using System.Net; @@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal public ServiceContext ServiceContext { get; set; } public IFeatureCollection ConnectionFeatures { get; set; } public IList ConnectionAdapters { get; set; } - public PipeFactory PipeFactory { get; set; } + public BufferPool BufferPool { get; set; } public IPEndPoint LocalEndPoint { get; set; } public IPEndPoint RemoteEndPoint { get; set; } public IPipeConnection Transport { get; set; } diff --git a/src/Kestrel.Core/Internal/HttpConnectionMiddleware.cs b/src/Kestrel.Core/Internal/HttpConnectionMiddleware.cs index d2b0757fcb..e6686cfd7c 100644 --- a/src/Kestrel.Core/Internal/HttpConnectionMiddleware.cs +++ b/src/Kestrel.Core/Internal/HttpConnectionMiddleware.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal Protocols = _protocols, ServiceContext = _serviceContext, ConnectionFeatures = connectionContext.Features, - PipeFactory = connectionContext.PipeFactory, + BufferPool = connectionContext.BufferPool, ConnectionAdapters = _connectionAdapters, Transport = connectionContext.Transport, Application = transportFeature.Application diff --git a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs index 2ac096eb24..7da585aeec 100644 --- a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs +++ b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.Features.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.IO.Pipelines; @@ -95,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal set => LocalPort = value; } - PipeFactory IConnectionTransportFeature.PipeFactory => PipeFactory; + BufferPool IConnectionTransportFeature.BufferPool => BufferPool; IPipeConnection IConnectionTransportFeature.Transport { diff --git a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs index c269a8f928..df8247aa09 100644 --- a/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs +++ b/src/Kestrel.Transport.Abstractions/Internal/TransportConnection.cs @@ -1,6 +1,8 @@ using System; +using System.Buffers; using System.IO.Pipelines; using System.Net; +using System.Threading; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal { @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal public string ConnectionId { get; set; } - public virtual PipeFactory PipeFactory { get; } + public virtual BufferPool BufferPool { get; } public virtual IScheduler InputWriterScheduler { get; } public virtual IScheduler OutputReaderScheduler { get; } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs index 670503dbda..60b7849e26 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal private readonly UvStreamHandle _socket; private WritableBuffer? _currentWritableBuffer; - private BufferHandle _bufferHandle; + private MemoryHandle _bufferHandle; public LibuvConnection(ListenerContext context, UvStreamHandle socket) : base(context) { @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal _bufferHandle = currentWritableBuffer.Buffer.Retain(true); - return handle.Libuv.buf_init((IntPtr)_bufferHandle.PinnedPointer, currentWritableBuffer.Buffer.Length); + return handle.Libuv.buf_init((IntPtr)_bufferHandle.Pointer, currentWritableBuffer.Buffer.Length); } private static void ReadCallback(UvStreamHandle handle, int status, object state) diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs index e1319c8317..2f052becab 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnectionContext.cs @@ -1,8 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.Net; using System.IO.Pipelines; +using System.Threading; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal @@ -15,8 +17,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal } public ListenerContext ListenerContext { get; set; } - - public override PipeFactory PipeFactory => ListenerContext.Thread.PipeFactory; + + public override BufferPool BufferPool => ListenerContext.Thread.BufferPool; public override IScheduler InputWriterScheduler => ListenerContext.Thread; public override IScheduler OutputReaderScheduler => ListenerContext.Thread; } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs index 726f3bfb6a..acab590fdc 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO.Pipelines; @@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal #endif QueueCloseHandle = PostCloseHandle; QueueCloseAsyncHandle = EnqueueCloseHandle; - PipeFactory = new PipeFactory(); + BufferPool = new MemoryPool(); WriteReqPool = new WriteReqPool(this, _log); } @@ -68,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal public UvLoopHandle Loop { get { return _loop; } } - public PipeFactory PipeFactory { get; } + public BufferPool BufferPool { get; } public WriteReqPool WriteReqPool { get; } @@ -295,7 +296,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal } finally { - PipeFactory.Dispose(); + BufferPool.Dispose(); WriteReqPool.Dispose(); _threadTcs.SetResult(null); diff --git a/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs b/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs index 857e98ea75..9eac9c1a39 100644 --- a/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs +++ b/src/Kestrel.Transport.Libuv/Internal/Networking/UvWriteReq.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin private LibuvAwaitable _awaitable = new LibuvAwaitable(); private List _pins = new List(BUFFER_COUNT + 1); - private List _handles = new List(BUFFER_COUNT + 1); + private List _handles = new List(BUFFER_COUNT + 1); public UvWriteReq(ILibuvTrace logger) : base(logger) { @@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin // Fast path for single buffer pBuffers[0] = Libuv.buf_init( - (IntPtr)memoryHandle.PinnedPointer, + (IntPtr)memoryHandle.Pointer, memory.Length); } else @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin // create and pin each segment being written pBuffers[index] = Libuv.buf_init( - (IntPtr)memoryHandle.PinnedPointer, + (IntPtr)memoryHandle.Pointer, memory.Length); index++; } @@ -206,7 +206,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin } // Safe handle has instance method called Unpin - // so using UnpinGcHandles to avoid conflict + // so using UnpinGcHandles to avoid conflict private void UnpinGcHandles() { var pinList = _pins; @@ -254,4 +254,4 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin } } } -} \ No newline at end of file +} diff --git a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs index cadf97f0d0..8edfb997b2 100644 --- a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs +++ b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal { public static class BufferExtensions { - public static ArraySegment GetArray(this Buffer buffer) + public static ArraySegment GetArray(this Memory buffer) { ArraySegment result; if (!buffer.TryGetArray(out result)) @@ -17,4 +17,4 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return result; } } -} \ No newline at end of file +} diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs index ac9ef9a8e2..27f5807a1b 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Pipelines; @@ -9,6 +11,7 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using Microsoft.AspNetCore.Protocols; +using System.Threading; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.Extensions.Logging; @@ -25,14 +28,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal private volatile bool _aborted; - internal SocketConnection(Socket socket, PipeFactory pipeFactory, ISocketsTrace trace) + internal SocketConnection(Socket socket, BufferPool bufferPool, ISocketsTrace trace) { Debug.Assert(socket != null); - Debug.Assert(pipeFactory != null); + Debug.Assert(bufferPool != null); Debug.Assert(trace != null); _socket = socket; - PipeFactory = pipeFactory; + BufferPool = bufferPool; _trace = trace; var localEndPoint = (IPEndPoint)_socket.LocalEndPoint; @@ -48,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal _sender = new SocketSender(_socket); } - public override PipeFactory PipeFactory { get; } + public override BufferPool BufferPool { get; } public override IScheduler InputWriterScheduler => InlineScheduler.Default; public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default; diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketReceiver.cs b/src/Kestrel.Transport.Sockets/Internal/SocketReceiver.cs index bb9f85a56b..ad3a99a0b0 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketReceiver.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketReceiver.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal _eventArgs.Completed += (_, e) => ((SocketAwaitable)e.UserToken).Complete(e.BytesTransferred, e.SocketError); } - public SocketAwaitable ReceiveAsync(Buffer buffer) + public SocketAwaitable ReceiveAsync(Memory buffer) { var segment = buffer.GetArray(); @@ -33,4 +33,4 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return _awaitable; } } -} \ No newline at end of file +} diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs index 04f680f42d..0b3b998c6b 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketSender.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal return _awaitable; } - private SocketAwaitable SendAsync(Buffer buffer) + private SocketAwaitable SendAsync(Memory buffer) { var segment = buffer.GetArray(); @@ -95,4 +95,4 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal awaitable.Complete(e.BytesTransferred, e.SocketError); } } -} \ No newline at end of file +} diff --git a/src/Kestrel.Transport.Sockets/SocketTransport.cs b/src/Kestrel.Transport.Sockets/SocketTransport.cs index fe6601253e..d4f056829f 100644 --- a/src/Kestrel.Transport.Sockets/SocketTransport.cs +++ b/src/Kestrel.Transport.Sockets/SocketTransport.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Diagnostics; using System.IO.Pipelines; using System.Net; @@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets { internal sealed class SocketTransport : ITransport { - private readonly PipeFactory _pipeFactory = new PipeFactory(); + private readonly BufferPool _bufferPool = new MemoryPool(); private readonly IEndPointInformation _endPointInformation; private readonly IConnectionHandler _handler; private readonly IApplicationLifetime _appLifetime; @@ -115,7 +116,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets public Task StopAsync() { - _pipeFactory.Dispose(); + _bufferPool.Dispose(); return Task.CompletedTask; } @@ -130,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets var acceptSocket = await _listenSocket.AcceptAsync(); acceptSocket.NoDelay = _endPointInformation.NoDelay; - var connection = new SocketConnection(acceptSocket, _pipeFactory, _trace); + var connection = new SocketConnection(acceptSocket, _bufferPool, _trace); _ = connection.StartAsync(_handler); } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset) diff --git a/src/Protocols.Abstractions/ConnectionContext.cs b/src/Protocols.Abstractions/ConnectionContext.cs index f2ddc754ae..586a2ae19b 100644 --- a/src/Protocols.Abstractions/ConnectionContext.cs +++ b/src/Protocols.Abstractions/ConnectionContext.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO.Pipelines; using System.Threading; using System.Threading.Tasks; @@ -14,6 +15,6 @@ namespace Microsoft.AspNetCore.Protocols public abstract IPipeConnection Transport { get; set; } - public abstract PipeFactory PipeFactory { get; } + public abstract BufferPool BufferPool { get; } } } diff --git a/src/Protocols.Abstractions/DefaultConnectionContext.cs b/src/Protocols.Abstractions/DefaultConnectionContext.cs index b81fc16f06..0c34637735 100644 --- a/src/Protocols.Abstractions/DefaultConnectionContext.cs +++ b/src/Protocols.Abstractions/DefaultConnectionContext.cs @@ -1,4 +1,5 @@ -using System.IO.Pipelines; +using System.Buffers; +using System.IO.Pipelines; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Protocols.Features; @@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Protocols public override IFeatureCollection Features => _features.Collection; - public override PipeFactory PipeFactory => ConnectionTransportFeature.PipeFactory; + public override BufferPool BufferPool => ConnectionTransportFeature.BufferPool; public override IPipeConnection Transport { diff --git a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs index 8f27924126..3fc8d86224 100644 --- a/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs +++ b/src/Protocols.Abstractions/Features/IConnectionTransportFeature.cs @@ -1,10 +1,12 @@ -using System.IO.Pipelines; +using System.Buffers; +using System.IO.Pipelines; +using System.Threading; namespace Microsoft.AspNetCore.Protocols.Features { public interface IConnectionTransportFeature { - PipeFactory PipeFactory { get; } + BufferPool BufferPool { get; } IPipeConnection Transport { get; set; } diff --git a/src/Protocols.Abstractions/PipeFactoryExtensions.cs b/src/Protocols.Abstractions/PipeFactoryExtensions.cs index 9ded8a8f9d..f28207db59 100644 --- a/src/Protocols.Abstractions/PipeFactoryExtensions.cs +++ b/src/Protocols.Abstractions/PipeFactoryExtensions.cs @@ -1,16 +1,18 @@ -namespace System.IO.Pipelines +using System.Buffers; + +namespace System.IO.Pipelines { - public static class PipeFactoryExtensions + public static class PipeFactory { - public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(this PipeFactory pipeFactory) + public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(BufferPool memoryPool) { - return pipeFactory.CreateConnectionPair(new PipeOptions(), new PipeOptions()); + return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool)); } - public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(this PipeFactory pipeFactory, PipeOptions inputOptions, PipeOptions outputOptions) + public static (IPipeConnection Transport, IPipeConnection Application) CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions) { - var input = pipeFactory.Create(inputOptions); - var output = pipeFactory.Create(outputOptions); + var input = new Pipe(inputOptions); + var output = new Pipe(outputOptions); var transportToApplication = new PipeConnection(output.Reader, input.Writer); var applicationToTransport = new PipeConnection(input.Reader, output.Writer); diff --git a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs index 45450bf9bd..e1ff59b297 100644 --- a/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs +++ b/test/Kestrel.Core.Tests/ConnectionHandlerTests.cs @@ -1,8 +1,10 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Protocols.Features; @@ -51,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Set(this); } - public PipeFactory PipeFactory { get; } = new PipeFactory(); + public BufferPool BufferPool { get; } = new MemoryPool(); public IPipeConnection Transport { get; set; } public IPipeConnection Application { get; set; } diff --git a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs index 2cfd2ed2f8..0601a12763 100644 --- a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.IO; @@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private readonly TestHttp1Connection _http1Connection; private readonly ServiceContext _serviceContext; private readonly Http1ConnectionContext _http1ConnectionContext; - private readonly PipeFactory _pipelineFactory; + private readonly BufferPool _pipelineFactory; private ReadCursor _consumed; private ReadCursor _examined; private Mock _timeoutControl; @@ -52,8 +53,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public Http1ConnectionTests() { - _pipelineFactory = new PipeFactory(); - var pair = _pipelineFactory.CreateConnectionPair(); + _pipelineFactory = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(_pipelineFactory); _transport = pair.Transport; _application = pair.Application; @@ -64,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { ServiceContext = _serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = _pipelineFactory, + BufferPool = _pipelineFactory, TimeoutControl = _timeoutControl.Object, Application = pair.Application, Transport = pair.Transport diff --git a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs index e4a875da58..69a7807ab0 100644 --- a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -92,7 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private static readonly byte[] _noData = new byte[0]; private static readonly byte[] _maxData = Encoding.ASCII.GetBytes(new string('a', Http2Frame.MinAllowedMaxFrameSize)); - private readonly PipeFactory _pipeFactory = new PipeFactory(); + private readonly BufferPool _bufferPool = new MemoryPool(); private readonly (IPipeConnection Transport, IPipeConnection Application) _pair; private readonly TestApplicationErrorLogger _logger; private readonly Http2ConnectionContext _connectionContext; @@ -121,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public Http2ConnectionTests() { - _pair = _pipeFactory.CreateConnectionPair(); + _pair = PipeFactory.CreateConnectionPair(_bufferPool); _noopApplication = context => Task.CompletedTask; @@ -256,7 +257,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { Log = new TestKestrelTrace(_logger) }, - PipeFactory = _pipeFactory, + BufferPool = _bufferPool, Application = _pair.Application, Transport = _pair.Transport }; @@ -265,7 +266,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void Dispose() { - _pipeFactory.Dispose(); + _bufferPool.Dispose(); } void IHttpHeadersHandler.OnHeader(Span name, Span value) diff --git a/test/Kestrel.Core.Tests/HttpConnectionTests.cs b/test/Kestrel.Core.Tests/HttpConnectionTests.cs index a5c53eafde..3a4e43cc44 100644 --- a/test/Kestrel.Core.Tests/HttpConnectionTests.cs +++ b/test/Kestrel.Core.Tests/HttpConnectionTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; using System.Threading; @@ -17,21 +18,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { public class HttpConnectionTests : IDisposable { - private readonly PipeFactory _pipeFactory; + private readonly BufferPool _bufferPool; private readonly HttpConnectionContext _httpConnectionContext; private readonly HttpConnection _httpConnection; public HttpConnectionTests() { - _pipeFactory = new PipeFactory(); - var pair = _pipeFactory.CreateConnectionPair(); + _bufferPool = new MemoryPool(); + var pair = PipeFactory.CreateConnectionPair(_bufferPool); _httpConnectionContext = new HttpConnectionContext { ConnectionId = "0123456789", ConnectionAdapters = new List(), ConnectionFeatures = new FeatureCollection(), - PipeFactory = _pipeFactory, + BufferPool = _bufferPool, HttpConnectionId = long.MinValue, Application = pair.Application, Transport = pair.Transport, @@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void Dispose() { - _pipeFactory.Dispose(); + _bufferPool.Dispose(); } [Fact] diff --git a/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs b/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs index 8ed1d70602..46c28a3633 100644 --- a/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs +++ b/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Generic; using System.Globalization; using System.IO.Pipelines; @@ -19,26 +20,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [Fact] public void InitialDictionaryIsEmpty() { - var factory = new PipeFactory(); - var pair = factory.CreateConnectionPair(); - var http1ConnectionContext = new Http1ConnectionContext + using (var memoryPool = new MemoryPool()) { - ServiceContext = new TestServiceContext(), - ConnectionFeatures = new FeatureCollection(), - PipeFactory = factory, - Application = pair.Application, - Transport = pair.Transport, - TimeoutControl = null - }; + var pair = PipeFactory.CreateConnectionPair(memoryPool); + var http1ConnectionContext = new Http1ConnectionContext + { + ServiceContext = new TestServiceContext(), + ConnectionFeatures = new FeatureCollection(), + BufferPool = memoryPool, + Application = pair.Application, + Transport = pair.Transport, + TimeoutControl = null + }; - var http1Connection = new Http1Connection(application: null, context: http1ConnectionContext); + var http1Connection = new Http1Connection(application: null, context: http1ConnectionContext); - http1Connection.Reset(); + http1Connection.Reset(); - IDictionary headers = http1Connection.ResponseHeaders; + IDictionary headers = http1Connection.ResponseHeaders; - Assert.Equal(0, headers.Count); - Assert.False(headers.IsReadOnly); + Assert.Equal(0, headers.Count); + Assert.False(headers.IsReadOnly); + } } [Theory] diff --git a/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj b/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj index 38f15bc983..de9645ced9 100644 --- a/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj +++ b/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/test/Kestrel.Core.Tests/OutputProducerTests.cs b/test/Kestrel.Core.Tests/OutputProducerTests.cs index 2beb0fcda6..ccfb164bad 100644 --- a/test/Kestrel.Core.Tests/OutputProducerTests.cs +++ b/test/Kestrel.Core.Tests/OutputProducerTests.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; +using System.Threading; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Testing; @@ -13,25 +15,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { public class OutputProducerTests : IDisposable { - private readonly PipeFactory _pipeFactory; + private readonly BufferPool _bufferPool; public OutputProducerTests() { - _pipeFactory = new PipeFactory(); + _bufferPool = new MemoryPool(); } public void Dispose() { - _pipeFactory.Dispose(); + _bufferPool.Dispose(); } [Fact] public void WritesNoopAfterConnectionCloses() { var pipeOptions = new PipeOptions - { - ReaderScheduler = Mock.Of(), - }; + ( + bufferPool:_bufferPool, + readerScheduler: Mock.Of() + ); using (var socketOutput = CreateOutputProducer(pipeOptions)) { @@ -52,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private Http1OutputProducer CreateOutputProducer(PipeOptions pipeOptions) { - var pipe = _pipeFactory.Create(pipeOptions); + var pipe = new Pipe(pipeOptions); var serviceContext = new TestServiceContext(); var socketOutput = new Http1OutputProducer( pipe.Reader, diff --git a/test/Kestrel.Core.Tests/PipeOptionsTests.cs b/test/Kestrel.Core.Tests/PipeOptionsTests.cs index 530d2698d6..19ac6a1592 100644 --- a/test/Kestrel.Core.Tests/PipeOptionsTests.cs +++ b/test/Kestrel.Core.Tests/PipeOptionsTests.cs @@ -1,8 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; +using System.Threading; using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; @@ -25,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests serviceContext.ThreadPool = new LoggingThreadPool(null); var mockScheduler = Mock.Of(); - var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, readerScheduler: mockScheduler); + var outputPipeOptions = ConnectionHandler.GetOutputPipeOptions(serviceContext, new MemoryPool(), readerScheduler: mockScheduler); Assert.Equal(expectedMaximumSizeLow, outputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeHigh, outputPipeOptions.MaximumSizeHigh); @@ -43,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests serviceContext.ThreadPool = new LoggingThreadPool(null); var mockScheduler = Mock.Of(); - var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, writerScheduler: mockScheduler); + var inputPipeOptions = ConnectionHandler.GetInputPipeOptions(serviceContext, new MemoryPool(), writerScheduler: mockScheduler); Assert.Equal(expectedMaximumSizeLow, inputPipeOptions.MaximumSizeLow); Assert.Equal(expectedMaximumSizeHigh, inputPipeOptions.MaximumSizeHigh); diff --git a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs index b79bb20a75..954122f369 100644 --- a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs +++ b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Text; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; @@ -15,16 +16,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private const int _ulongMaxValueLength = 20; private readonly IPipe _pipe; - private readonly PipeFactory _pipeFactory = new PipeFactory(); + private readonly BufferPool _bufferPool = new MemoryPool(); public PipelineExtensionTests() { - _pipe = _pipeFactory.Create(); + _pipe = new Pipe(new PipeOptions(_bufferPool)); } public void Dispose() { - _pipeFactory.Dispose(); + _bufferPool.Dispose(); } [Theory] @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { var writerBuffer = _pipe.Writer.Alloc(); var writer = new WritableBufferWriter(writerBuffer); - PipelineExtensions.WriteNumeric(ref writer, number); + writer.WriteNumeric(number); writerBuffer.FlushAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); @@ -57,7 +58,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests writer.Write(spacer); var bufferLength = writer.Span.Length; - PipelineExtensions.WriteNumeric(ref writer, ulong.MaxValue); + writer.WriteNumeric(ulong.MaxValue); Assert.NotEqual(bufferLength, writer.Span.Length); writerBuffer.FlushAsync().GetAwaiter().GetResult(); @@ -83,7 +84,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { var writerBuffer = _pipe.Writer.Alloc(); var writer = new WritableBufferWriter(writerBuffer); - PipelineExtensions.WriteAsciiNoValidation(ref writer, input); + writer.WriteAsciiNoValidation(input); writerBuffer.FlushAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); @@ -110,7 +111,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests // but it shouldn't produce more than one byte per character var writerBuffer = _pipe.Writer.Alloc(); var writer = new WritableBufferWriter(writerBuffer); - PipelineExtensions.WriteAsciiNoValidation(ref writer, input); + writer.WriteAsciiNoValidation(input); writerBuffer.FlushAsync().GetAwaiter().GetResult(); var reader = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); @@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var writer = new WritableBufferWriter(writerBuffer); for (var i = 0; i < maxAscii; i++) { - PipelineExtensions.WriteAsciiNoValidation(ref writer, new string((char)i, 1)); + writer.WriteAsciiNoValidation(new string((char)i, 1)); } writerBuffer.FlushAsync().GetAwaiter().GetResult(); @@ -158,7 +159,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.Equal(gapSize, writer.Span.Length); var bufferLength = writer.Span.Length; - PipelineExtensions.WriteAsciiNoValidation(ref writer, testString); + writer.WriteAsciiNoValidation(testString); Assert.NotEqual(bufferLength, writer.Span.Length); writerBuffer.FlushAsync().GetAwaiter().GetResult(); diff --git a/test/Kestrel.Core.Tests/TestInput.cs b/test/Kestrel.Core.Tests/TestInput.cs index 9905a4a965..e9c2cdf701 100644 --- a/test/Kestrel.Core.Tests/TestInput.cs +++ b/test/Kestrel.Core.Tests/TestInput.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Text; using Microsoft.AspNetCore.Http.Features; @@ -15,13 +16,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests class TestInput : IDisposable { private MemoryPool _memoryPool; - private PipeFactory _pipelineFactory; public TestInput() { _memoryPool = new MemoryPool(); - _pipelineFactory = new PipeFactory(); - var pair = _pipelineFactory.CreateConnectionPair(); + var pair = PipeFactory.CreateConnectionPair(_memoryPool); Transport = pair.Transport; Application = pair.Application; @@ -31,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests ConnectionFeatures = new FeatureCollection(), Application = Application, Transport = Transport, - PipeFactory = _pipelineFactory, + BufferPool = _memoryPool, TimeoutControl = Mock.Of() }; @@ -43,8 +42,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public IPipeConnection Application { get; } - public PipeFactory PipeFactory => _pipelineFactory; - public Http1ConnectionContext Http1ConnectionContext { get; } public Http1Connection Http1Connection { get; set; } @@ -67,7 +64,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public void Dispose() { - _pipelineFactory.Dispose(); _memoryPool.Dispose(); } } diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs index 5f6e341d74..061dfcebf7 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs @@ -55,13 +55,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests public async Task ConnectionDoesNotResumeAfterSocketCloseIfBackpressureIsApplied() { var mockConnectionHandler = new MockConnectionHandler(); - mockConnectionHandler.InputOptions.MaximumSizeHigh = 3; var mockLibuv = new MockLibuv(); var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler }; var transport = new LibuvTransport(mockLibuv, transportContext, null); var thread = new LibuvThread(transport); + mockConnectionHandler.InputOptions = pool => + new PipeOptions( + bufferPool: pool, + maximumSizeHigh: 3); + // We don't set the output writer scheduler here since we want to run the callback inline - mockConnectionHandler.OutputOptions.ReaderScheduler = thread; + + mockConnectionHandler.OutputOptions = pool => new PipeOptions(bufferPool: pool, readerScheduler: thread); + + Task connectionTask = null; try { @@ -106,8 +113,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests public async Task ConnectionDoesNotResumeAfterReadCallbackScheduledAndSocketCloseIfBackpressureIsApplied() { var mockConnectionHandler = new MockConnectionHandler(); - mockConnectionHandler.InputOptions.MaximumSizeHigh = 3; - mockConnectionHandler.InputOptions.MaximumSizeLow = 3; var mockLibuv = new MockLibuv(); var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler }; var transport = new LibuvTransport(mockLibuv, transportContext, null); @@ -118,8 +123,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests { backPressure = () => a(o); }); - mockConnectionHandler.InputOptions.WriterScheduler = mockScheduler.Object; - mockConnectionHandler.OutputOptions.ReaderScheduler = thread; + mockConnectionHandler.InputOptions = pool => + new PipeOptions( + bufferPool: pool, + maximumSizeHigh: 3, + maximumSizeLow: 3, + writerScheduler: mockScheduler.Object); + + mockConnectionHandler.OutputOptions = pool => new PipeOptions(bufferPool: pool, readerScheduler:thread ); + Task connectionTask = null; try { diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs index be256e30d0..2a7b0ee4c1 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.Collections.Concurrent; using System.IO.Pipelines; using System.Threading; @@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests { public class LibuvOutputConsumerTests : IDisposable { - private readonly PipeFactory _pipeFactory; + private readonly BufferPool _bufferPool; private readonly MockLibuv _mockLibuv; private readonly LibuvThread _libuvThread; @@ -37,7 +38,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests public LibuvOutputConsumerTests() { - _pipeFactory = new PipeFactory(); + _bufferPool = new MemoryPool(); _mockLibuv = new MockLibuv(); var libuvTransport = new LibuvTransport(_mockLibuv, new TestLibuvTransportContext(), new ListenOptions(0)); @@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests public void Dispose() { _libuvThread.StopAsync(TimeSpan.FromSeconds(1)).Wait(); - _pipeFactory.Dispose(); + _bufferPool.Dispose(); } [Theory] @@ -62,11 +63,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests // ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize ?? 0, - MaximumSizeLow = maxResponseBufferSize ?? 0, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize ?? 0, + maximumSizeLow: maxResponseBufferSize ?? 0 + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -97,11 +99,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests // ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = 0, - MaximumSizeLow = 0, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: 0, + maximumSizeLow: 0 + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -144,11 +147,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests // ConnectionHandler will set MaximumSizeHigh/Low to 1 when MaxResponseBufferSize is zero. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = 1, - MaximumSizeLow = 1, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: 1, + maximumSizeLow: 1 + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -199,11 +203,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests }; var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -262,11 +267,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests }; var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -331,11 +337,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests var abortedSource = new CancellationTokenSource(); var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource)) { @@ -423,11 +430,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests var abortedSource = new CancellationTokenSource(); var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -506,11 +514,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests var abortedSource = new CancellationTokenSource(); var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -587,11 +596,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests }; var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize, - MaximumSizeLow = maxResponseBufferSize, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize, + maximumSizeLow: maxResponseBufferSize + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -647,11 +657,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests // ConnectionHandler will set MaximumSizeHigh/Low to zero when MaxResponseBufferSize is null. // This is verified in PipeOptionsTests.OutputPipeOptionsConfiguredCorrectly. var pipeOptions = new PipeOptions - { - ReaderScheduler = _libuvThread, - MaximumSizeHigh = maxResponseBufferSize ?? 0, - MaximumSizeLow = maxResponseBufferSize ?? 0, - }; + ( + bufferPool: _bufferPool, + readerScheduler: _libuvThread, + maximumSizeHigh: maxResponseBufferSize ?? 0, + maximumSizeLow: maxResponseBufferSize ?? 0 + ); using (var outputProducer = CreateOutputProducer(pipeOptions)) { @@ -684,7 +695,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests private Http1OutputProducer CreateOutputProducer(PipeOptions pipeOptions, CancellationTokenSource cts = null) { - var pair = _pipeFactory.CreateConnectionPair(pipeOptions, pipeOptions); + var pair = PipeFactory.CreateConnectionPair(pipeOptions, pipeOptions); var logger = new TestApplicationErrorLogger(); var serviceContext = new TestServiceContext @@ -701,7 +712,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests { ServiceContext = serviceContext, ConnectionFeatures = new FeatureCollection(), - PipeFactory = _pipeFactory, + BufferPool = _bufferPool, TimeoutControl = Mock.Of(), Application = pair.Application, Transport = pair.Transport diff --git a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs index f1615378ee..5ae8289792 100644 --- a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs +++ b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Buffers; using System.IO.Pipelines; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; @@ -13,15 +14,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers { public class MockConnectionHandler : IConnectionHandler { - public PipeOptions InputOptions { get; set; } = new PipeOptions(); - public PipeOptions OutputOptions { get; set; } = new PipeOptions(); + public Func InputOptions { get; set; } = pool => new PipeOptions(pool); + public Func OutputOptions { get; set; } = pool => new PipeOptions(pool); public void OnConnection(IFeatureCollection features) { var connectionContext = new DefaultConnectionContext(features); - Input = connectionContext.PipeFactory.Create(InputOptions ?? new PipeOptions()); - Output = connectionContext.PipeFactory.Create(OutputOptions ?? new PipeOptions()); + Input = new Pipe(InputOptions(connectionContext.BufferPool)); + Output = new Pipe(InputOptions(connectionContext.BufferPool)); var feature = connectionContext.Features.Get();