Skip to content

Commit bd9cd25

Browse files
committed
stash
1 parent 206542e commit bd9cd25

File tree

11 files changed

+182
-16
lines changed

11 files changed

+182
-16
lines changed

src/Servers/HttpSys/src/HttpSysListener.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Buffers;
55
using System.Diagnostics;
66
using System.Diagnostics.Metrics;
7+
using Microsoft.AspNetCore.Connections;
78
using Microsoft.AspNetCore.Http;
89
using Microsoft.AspNetCore.HttpSys.Internal;
910
using Microsoft.AspNetCore.WebUtilities;
@@ -34,14 +35,14 @@ internal sealed partial class HttpSysListener : IDisposable
3435
// 0.5 seconds per request. Respond with a 400 Bad Request.
3536
private const int UnknownHeaderLimit = 1000;
3637

37-
internal sealed class DummyMeterFactory : IMeterFactory
38+
internal sealed class NoopMeterFactory : IMeterFactory
3839
{
3940
public Meter Create(MeterOptions options) => new Meter(options);
4041

4142
public void Dispose() { }
4243
}
4344

44-
internal MemoryPool<byte> MemoryPool { get; } = PinnedBlockMemoryPoolFactory.Create(new DummyMeterFactory());
45+
internal MemoryPool<byte> MemoryPool { get; }
4546

4647
private volatile State _state; // m_State is set only within lock blocks, but often read outside locks.
4748

@@ -52,7 +53,7 @@ public void Dispose() { }
5253

5354
private readonly object _internalLock;
5455

55-
public HttpSysListener(HttpSysOptions options, ILoggerFactory loggerFactory)
56+
public HttpSysListener(HttpSysOptions options, IMemoryPoolFactory<byte> memoryPoolFactory, ILoggerFactory loggerFactory)
5657
{
5758
ArgumentNullException.ThrowIfNull(options);
5859
ArgumentNullException.ThrowIfNull(loggerFactory);
@@ -62,6 +63,8 @@ public HttpSysListener(HttpSysOptions options, ILoggerFactory loggerFactory)
6263
throw new PlatformNotSupportedException();
6364
}
6465

66+
MemoryPool = memoryPoolFactory.Create();
67+
6568
Options = options;
6669

6770
Logger = loggerFactory.CreateLogger<HttpSysListener>();

src/Servers/HttpSys/src/MessagePump.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Diagnostics;
55
using System.Linq;
66
using Microsoft.AspNetCore.Authentication;
7+
using Microsoft.AspNetCore.Connections;
78
using Microsoft.AspNetCore.Hosting.Server;
89
using Microsoft.AspNetCore.Hosting.Server.Features;
910
using Microsoft.AspNetCore.Http.Features;
@@ -27,12 +28,13 @@ internal sealed partial class MessagePump : IServer, IServerDelegationFeature
2728

2829
private readonly ServerAddressesFeature _serverAddresses;
2930

30-
public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication)
31+
public MessagePump(IOptions<HttpSysOptions> options, IMemoryPoolFactory<byte> memoryPoolFactory,
32+
ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication)
3133
{
3234
ArgumentNullException.ThrowIfNull(options);
3335
ArgumentNullException.ThrowIfNull(loggerFactory);
3436
_options = options.Value;
35-
Listener = new HttpSysListener(_options, loggerFactory);
37+
Listener = new HttpSysListener(_options, memoryPoolFactory, loggerFactory);
3638
_logger = loggerFactory.CreateLogger<MessagePump>();
3739

3840
if (_options.Authentication.Schemes != AuthenticationSchemes.None)

src/Servers/HttpSys/src/WebHostBuilderHttpSysExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Buffers;
45
using System.Runtime.Versioning;
6+
using Microsoft.AspNetCore.Connections;
57
using Microsoft.AspNetCore.Hosting.Server;
68
using Microsoft.AspNetCore.Server.HttpSys;
79
using Microsoft.Extensions.DependencyInjection;
10+
using Microsoft.Extensions.DependencyInjection.Extensions;
811
using Microsoft.Extensions.Options;
912

1013
namespace Microsoft.AspNetCore.Hosting;
@@ -45,6 +48,8 @@ public static IWebHostBuilder UseHttpSys(this IWebHostBuilder hostBuilder)
4548
};
4649
});
4750
services.AddAuthenticationCore();
51+
52+
services.TryAddSingleton<IMemoryPoolFactory<byte>, DefaultMemoryPoolFactory>();
4853
});
4954
}
5055

src/Servers/HttpSys/test/FunctionalTests/Listener/ServerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Buffers;
56
using System.IO;
67
using System.Net;
78
using System.Net.Http;
@@ -132,7 +133,7 @@ public void Server_RegisterUnavailablePrefix_ThrowsActionableHttpSysException()
132133

133134
var options = new HttpSysOptions();
134135
options.UrlPrefixes.Add(address1);
135-
using var listener = new HttpSysListener(options, new LoggerFactory());
136+
using var listener = new HttpSysListener(options, new DefaultMemoryPoolFactory(), new LoggerFactory());
136137

137138
var exception = Assert.Throws<HttpSysException>(() => listener.Start());
138139

src/Servers/HttpSys/test/FunctionalTests/Listener/Utilities.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Buffers;
56
using System.Threading.Tasks;
67
using Microsoft.AspNetCore.HttpSys.Internal;
78
using Microsoft.Extensions.Logging;
@@ -47,7 +48,7 @@ internal static HttpSysListener CreateDynamicHttpServer(string basePath, out str
4748
var options = new HttpSysOptions();
4849
options.UrlPrefixes.Add(prefix);
4950
options.RequestQueueName = prefix.Port; // Convention for use with CreateServerOnExistingQueue
50-
var listener = new HttpSysListener(options, new LoggerFactory());
51+
var listener = new HttpSysListener(options, new DefaultMemoryPoolFactory(), new LoggerFactory());
5152
try
5253
{
5354
listener.Start();
@@ -76,7 +77,7 @@ internal static HttpSysListener CreateHttpsServer()
7677

7778
internal static HttpSysListener CreateServer(string scheme, string host, int port, string path)
7879
{
79-
var listener = new HttpSysListener(new HttpSysOptions(), new LoggerFactory());
80+
var listener = new HttpSysListener(new HttpSysOptions(), new DefaultMemoryPoolFactory(), new LoggerFactory());
8081
listener.Options.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path));
8182
listener.Start();
8283
return listener;
@@ -86,7 +87,7 @@ internal static HttpSysListener CreateServer(Action<HttpSysOptions> configureOpt
8687
{
8788
var options = new HttpSysOptions();
8889
configureOptions(options);
89-
var listener = new HttpSysListener(options, new LoggerFactory());
90+
var listener = new HttpSysListener(options, new DefaultMemoryPoolFactory(), new LoggerFactory());
9091
listener.Start();
9192
return listener;
9293
}

src/Servers/HttpSys/test/FunctionalTests/Utilities.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Buffers;
56
using System.Linq;
67
using System.Threading;
78
using System.Threading.Tasks;
@@ -112,13 +113,13 @@ internal static IHost CreateDynamicHost(string basePath, out string root, out st
112113
}
113114

114115
internal static MessagePump CreatePump(ILoggerFactory loggerFactory)
115-
=> new MessagePump(Options.Create(new HttpSysOptions()), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
116+
=> new MessagePump(Options.Create(new HttpSysOptions()), new DefaultMemoryPoolFactory(), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
116117

117118
internal static MessagePump CreatePump(Action<HttpSysOptions> configureOptions, ILoggerFactory loggerFactory)
118119
{
119120
var options = new HttpSysOptions();
120121
configureOptions(options);
121-
return new MessagePump(Options.Create(options), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
122+
return new MessagePump(Options.Create(options), new DefaultMemoryPoolFactory(), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
122123
}
123124

124125
internal static IServer CreateDynamicHttpServer(string basePath, out string root, out string baseAddress, Action<HttpSysOptions> configureOptions, RequestDelegate app, ILoggerFactory loggerFactory)

src/Servers/HttpSys/test/NonHelixTests/Utilities.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Buffers;
45
using Microsoft.AspNetCore.Authentication;
56
using Microsoft.AspNetCore.Hosting.Server;
67
using Microsoft.AspNetCore.Hosting.Server.Features;
@@ -31,13 +32,13 @@ internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate
3132
}
3233

3334
internal static MessagePump CreatePump(ILoggerFactory loggerFactory = null)
34-
=> new MessagePump(Options.Create(new HttpSysOptions()), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
35+
=> new MessagePump(Options.Create(new HttpSysOptions()), new DefaultMemoryPoolFactory(), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
3536

3637
internal static MessagePump CreatePump(Action<HttpSysOptions> configureOptions, ILoggerFactory loggerFactory = null)
3738
{
3839
var options = new HttpSysOptions();
3940
configureOptions(options);
40-
return new MessagePump(Options.Create(options), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
41+
return new MessagePump(Options.Create(options), new DefaultMemoryPoolFactory(), loggerFactory ?? new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
4142
}
4243

4344
internal static IServer CreateDynamicHttpServer(string basePath, out string root, out string baseAddress, Action<HttpSysOptions> configureOptions, RequestDelegate app)

src/Servers/Kestrel/Kestrel/test/Microsoft.AspNetCore.Server.Kestrel.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<Content Include="$(KestrelRoot)Core\src\Internal\Infrastructure\HttpUtilities.Generated.cs" LinkBase="shared\GeneratedContent" CopyToOutputDirectory="PreserveNewest" />
1919
<Content Include="$(KestrelSharedSourceRoot)\TransportConnection.Generated.cs" LinkBase="shared\GeneratedContent" CopyToOutputDirectory="PreserveNewest" />
2020
<Content Include="$(KestrelSharedSourceRoot)\TransportMultiplexedConnection.Generated.cs" LinkBase="shared\GeneratedContent" CopyToOutputDirectory="PreserveNewest" />
21+
<Compile Include="$(KestrelSharedSourceRoot)test\TransportTestHelpers\NamedPipesSupportedAttribute.cs" Link="shared\TransportTestHelpers\NamedPipesSupportedAttribute.cs" />
2122

2223
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
2324
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />

src/Servers/Kestrel/Kestrel/test/WebHostBuilderKestrelExtensionsTests.cs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.IO.Pipelines;
6+
using System.Reflection;
57
using Microsoft.AspNetCore.Connections;
68
using Microsoft.AspNetCore.Hosting;
79
using Microsoft.AspNetCore.Hosting.Server;
10+
using Microsoft.AspNetCore.InternalTesting;
811
using Microsoft.AspNetCore.Server.Kestrel.Core;
912
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
13+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
1014
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
15+
using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;
1116
using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Internal;
1217
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
1318
using Microsoft.Extensions.DependencyInjection;
@@ -115,10 +120,25 @@ public void ServerIsKestrelServerImpl()
115120
Assert.IsType<KestrelMetrics>(server.ServiceContext.Metrics);
116121
Assert.Equal(PipeScheduler.ThreadPool, server.ServiceContext.Scheduler);
117122
Assert.Equal(TimeProvider.System, server.ServiceContext.TimeProvider);
123+
124+
var handlers = (IHeartbeatHandler[])typeof(Heartbeat).GetField("_callbacks", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(server.ServiceContext.Heartbeat);
125+
Assert.Collection(handlers,
126+
handler =>
127+
{
128+
Assert.Equal(typeof(DateHeaderValueManager), handler.GetType());
129+
},
130+
handler =>
131+
{
132+
Assert.Equal(typeof(ConnectionManager), handler.GetType());
133+
},
134+
handler =>
135+
{
136+
Assert.Equal(typeof(PinnedBlockMemoryPoolFactory), handler.GetType());
137+
});
118138
}
119139

120140
[Fact]
121-
public void MemoryPoolFactorySetCorrectly()
141+
public void MemoryPoolFactorySetCorrectlyWithSockets()
122142
{
123143
var hostBuilder = new WebHostBuilder()
124144
.UseSockets()
@@ -145,4 +165,67 @@ public void MemoryPoolFactorySetCorrectly()
145165

146166
Assert.Same(memoryPoolFactory, host.Services.GetRequiredService<IOptions<SocketTransportOptions>>().Value.MemoryPoolFactory);
147167
}
168+
169+
[Fact]
170+
public void SocketsHasDefaultMemoryPool()
171+
{
172+
var hostBuilder = new WebHostBuilder()
173+
.UseSockets()
174+
.Configure(app => { });
175+
176+
var host = hostBuilder.Build();
177+
178+
var memoryPoolFactory = host.Services.GetRequiredService<IMemoryPoolFactory<byte>>();
179+
Assert.IsNotType<PinnedBlockMemoryPoolFactory>(memoryPoolFactory);
180+
Assert.Null(host.Services.GetService<IMemoryPoolFactory<int>>());
181+
182+
Assert.Same(memoryPoolFactory, host.Services.GetRequiredService<IOptions<SocketTransportOptions>>().Value.MemoryPoolFactory);
183+
}
184+
185+
[ConditionalFact]
186+
[NamedPipesSupported]
187+
public void MemoryPoolFactorySetCorrectlyWithNamedPipes()
188+
{
189+
var hostBuilder = new WebHostBuilder()
190+
.UseNamedPipes()
191+
.UseKestrel()
192+
.Configure(app => { });
193+
194+
var host = hostBuilder.Build();
195+
196+
var memoryPoolFactory = Assert.IsType<PinnedBlockMemoryPoolFactory>(host.Services.GetRequiredService<IMemoryPoolFactory<byte>>());
197+
Assert.Null(host.Services.GetService<IMemoryPoolFactory<int>>());
198+
199+
Assert.Same(memoryPoolFactory, host.Services.GetRequiredService<IOptions<NamedPipeTransportOptions>>().Value.MemoryPoolFactory);
200+
201+
// Swap order of UseKestrel and UseNamedPipes
202+
hostBuilder = new WebHostBuilder()
203+
.UseKestrel()
204+
.UseNamedPipes()
205+
.Configure(app => { });
206+
207+
host = hostBuilder.Build();
208+
209+
memoryPoolFactory = Assert.IsType<PinnedBlockMemoryPoolFactory>(host.Services.GetRequiredService<IMemoryPoolFactory<byte>>());
210+
Assert.Null(host.Services.GetService<IMemoryPoolFactory<int>>());
211+
212+
Assert.Same(memoryPoolFactory, host.Services.GetRequiredService<IOptions<NamedPipeTransportOptions>>().Value.MemoryPoolFactory);
213+
}
214+
215+
[ConditionalFact]
216+
[NamedPipesSupported]
217+
public void NamedPipesHasDefaultMemoryPool()
218+
{
219+
var hostBuilder = new WebHostBuilder()
220+
.UseNamedPipes()
221+
.Configure(app => { });
222+
223+
var host = hostBuilder.Build();
224+
225+
var memoryPoolFactory = host.Services.GetRequiredService<IMemoryPoolFactory<byte>>();
226+
Assert.IsNotType<PinnedBlockMemoryPoolFactory>(memoryPoolFactory);
227+
Assert.Null(host.Services.GetService<IMemoryPoolFactory<int>>());
228+
229+
Assert.Same(memoryPoolFactory, host.Services.GetRequiredService<IOptions<NamedPipeTransportOptions>>().Value.MemoryPoolFactory);
230+
}
148231
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Concurrent;
5+
using System.Diagnostics;
6+
using System.Diagnostics.Metrics;
7+
using Microsoft.AspNetCore.Connections;
8+
9+
namespace System.Buffers;
10+
11+
internal sealed class DefaultMemoryPoolFactory : IMemoryPoolFactory<byte>, IDisposable
12+
{
13+
private readonly IMeterFactory _meterFactory;
14+
private readonly ConcurrentDictionary<PinnedBlockMemoryPool, PinnedBlockMemoryPool> _pools = new();
15+
private readonly PeriodicTimer _timer;
16+
17+
public DefaultMemoryPoolFactory(IMeterFactory? meterFactory = null)
18+
{
19+
_meterFactory = meterFactory ?? NoopMeterFactory.Instance;
20+
_timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
21+
_ = Task.Run(async () =>
22+
{
23+
try
24+
{
25+
while (await _timer.WaitForNextTickAsync())
26+
{
27+
foreach (var pool in _pools.Keys)
28+
{
29+
pool.PerformEviction();
30+
}
31+
}
32+
}
33+
catch (Exception ex)
34+
{
35+
Debug.WriteLine(ex);
36+
}
37+
});
38+
}
39+
40+
public MemoryPool<byte> Create()
41+
{
42+
var pool = new PinnedBlockMemoryPool(_meterFactory);
43+
pool.DisposeCallback = (self) =>
44+
{
45+
_pools.TryRemove(self, out _);
46+
};
47+
48+
_pools.TryAdd(pool, pool);
49+
50+
return pool;
51+
}
52+
53+
public void Dispose()
54+
{
55+
_timer.Dispose();
56+
}
57+
58+
private sealed class NoopMeterFactory : IMeterFactory
59+
{
60+
public static NoopMeterFactory Instance = new NoopMeterFactory();
61+
62+
public Meter Create(MeterOptions options) => new Meter(options);
63+
64+
public void Dispose()
65+
{
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)