Skip to content
代码片段 群组 项目
提交 5cdfe292 编辑于 作者: Sean Reeser's avatar Sean Reeser
浏览文件

Merge commit 'bc25dd5d' into internal-merge-6.0-2023-10-10-1028

No related branches found
No related tags found
无相关合并请求
......@@ -4,11 +4,12 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-4bb6dc1" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-4bb6dc19/nuget/v3/index.json" />
<add key="darc-int-dotnet-runtime-e0f0de8" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-e0f0de87/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-runtime -->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-687fc8f" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-687fc8f9/nuget/v3/index.json" />
<add key="darc-int-dotnet-efcore-687fc8f-1" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-687fc8f9-1/nuget/v3/index.json" />
<add key="darc-int-dotnet-efcore-50a6896" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-50a6896c/nuget/v3/index.json" />
<add key="darc-int-dotnet-efcore-50a6896-2" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-50a6896c-2/nuget/v3/index.json" />
<add key="darc-int-dotnet-efcore-50a6896-1" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-50a6896c-1/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-efcore -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
......@@ -26,11 +27,12 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-687fc8f-1" value="true" />
<add key="darc-int-dotnet-efcore-687fc8f" value="true" />
<add key="darc-int-dotnet-efcore-50a6896-1" value="true" />
<add key="darc-int-dotnet-efcore-50a6896-2" value="true" />
<add key="darc-int-dotnet-efcore-50a6896" value="true" />
<!-- End: Package sources from dotnet-efcore -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-4bb6dc1" value="true" />
<add key="darc-int-dotnet-runtime-e0f0de8" value="true" />
<!-- End: Package sources from dotnet-runtime -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
</disabledPackageSources>
......
......@@ -9,37 +9,37 @@
-->
<Dependencies>
<ProductDependencies>
<Dependency Name="dotnet-ef" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="dotnet-ef" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="6.0.22">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
<Sha>687fc8f9a538592b2b1494f6353293aac5da74a5</Sha>
<Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="6.0.23">
<Uri>https://github.com/dotnet/efcore</Uri>
<Sha>50a6896cca24b06e154bdf652c2e7aefd0dfb7a1</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0">
<Uri>https://github.com/dotnet/runtime</Uri>
......@@ -177,9 +177,9 @@
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>4822e3c3aa77eb82b2fb33c9321f923cf11ddde6</Sha>
</Dependency>
<Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="6.0.22-servicing.23424.25">
<Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="6.0.23-servicing.23480.2">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<Dependency Name="System.Diagnostics.DiagnosticSource" Version="6.0.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
......@@ -245,33 +245,33 @@
<Uri>https://github.com/dotnet/runtime</Uri>
<Sha>4822e3c3aa77eb82b2fb33c9321f923cf11ddde6</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.App.Ref" Version="6.0.22">
<Dependency Name="Microsoft.NETCore.App.Ref" Version="6.0.23">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="6.0.22">
<Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="6.0.23">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="6.0.22">
<Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="6.0.23">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<!--
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="6.0.22">
<Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="6.0.23">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="6.0.22">
<Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="6.0.23">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="6.0.22-servicing.23424.25">
<Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="6.0.23-servicing.23480.2">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>4bb6dc195c0a3bc4c7e24ff54a8925b98db4fecd</Sha>
<Sha>e0f0de876a67755a2c6cd2dc730c13f5959bdea8</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
......
......@@ -63,12 +63,12 @@
<PropertyGroup Label="Automated">
<!-- Packages from dotnet/runtime -->
<MicrosoftExtensionsDependencyModelVersion>6.0.0</MicrosoftExtensionsDependencyModelVersion>
<MicrosoftNETCoreAppRefVersion>6.0.22</MicrosoftNETCoreAppRefVersion>
<MicrosoftNETCoreAppRuntimewinx64Version>6.0.22</MicrosoftNETCoreAppRuntimewinx64Version>
<MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>6.0.22</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>
<MicrosoftNETRuntimeWebAssemblySdkVersion>6.0.22</MicrosoftNETRuntimeWebAssemblySdkVersion>
<MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>6.0.22</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>
<MicrosoftNETCoreBrowserDebugHostTransportVersion>6.0.22-servicing.23424.25</MicrosoftNETCoreBrowserDebugHostTransportVersion>
<MicrosoftNETCoreAppRefVersion>6.0.23</MicrosoftNETCoreAppRefVersion>
<MicrosoftNETCoreAppRuntimewinx64Version>6.0.23</MicrosoftNETCoreAppRuntimewinx64Version>
<MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>6.0.23</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>
<MicrosoftNETRuntimeWebAssemblySdkVersion>6.0.23</MicrosoftNETRuntimeWebAssemblySdkVersion>
<MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>6.0.23</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>
<MicrosoftNETCoreBrowserDebugHostTransportVersion>6.0.23-servicing.23480.2</MicrosoftNETCoreBrowserDebugHostTransportVersion>
<MicrosoftExtensionsCachingAbstractionsVersion>6.0.0</MicrosoftExtensionsCachingAbstractionsVersion>
<MicrosoftExtensionsCachingMemoryVersion>6.0.1</MicrosoftExtensionsCachingMemoryVersion>
<MicrosoftExtensionsConfigurationAbstractionsVersion>6.0.0</MicrosoftExtensionsConfigurationAbstractionsVersion>
......@@ -103,7 +103,7 @@
<MicrosoftExtensionsOptionsDataAnnotationsVersion>6.0.0</MicrosoftExtensionsOptionsDataAnnotationsVersion>
<MicrosoftExtensionsOptionsVersion>6.0.0</MicrosoftExtensionsOptionsVersion>
<MicrosoftExtensionsPrimitivesVersion>6.0.0</MicrosoftExtensionsPrimitivesVersion>
<MicrosoftInternalRuntimeAspNetCoreTransportVersion>6.0.22-servicing.23424.25</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
<MicrosoftInternalRuntimeAspNetCoreTransportVersion>6.0.23-servicing.23480.2</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
<SystemDiagnosticsDiagnosticSourceVersion>6.0.1</SystemDiagnosticsDiagnosticSourceVersion>
<SystemDiagnosticsEventLogVersion>6.0.0</SystemDiagnosticsEventLogVersion>
<SystemDirectoryServicesProtocolsVersion>6.0.2</SystemDirectoryServicesProtocolsVersion>
......@@ -122,14 +122,14 @@
<!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
<MicrosoftNETCorePlatformsVersion>6.0.11</MicrosoftNETCorePlatformsVersion>
<!-- Packages from dotnet/efcore -->
<dotnetefVersion>6.0.22</dotnetefVersion>
<MicrosoftEntityFrameworkCoreInMemoryVersion>6.0.22</MicrosoftEntityFrameworkCoreInMemoryVersion>
<MicrosoftEntityFrameworkCoreRelationalVersion>6.0.22</MicrosoftEntityFrameworkCoreRelationalVersion>
<MicrosoftEntityFrameworkCoreSqliteVersion>6.0.22</MicrosoftEntityFrameworkCoreSqliteVersion>
<MicrosoftEntityFrameworkCoreSqlServerVersion>6.0.22</MicrosoftEntityFrameworkCoreSqlServerVersion>
<MicrosoftEntityFrameworkCoreToolsVersion>6.0.22</MicrosoftEntityFrameworkCoreToolsVersion>
<MicrosoftEntityFrameworkCoreVersion>6.0.22</MicrosoftEntityFrameworkCoreVersion>
<MicrosoftEntityFrameworkCoreDesignVersion>6.0.22</MicrosoftEntityFrameworkCoreDesignVersion>
<dotnetefVersion>6.0.23</dotnetefVersion>
<MicrosoftEntityFrameworkCoreInMemoryVersion>6.0.23</MicrosoftEntityFrameworkCoreInMemoryVersion>
<MicrosoftEntityFrameworkCoreRelationalVersion>6.0.23</MicrosoftEntityFrameworkCoreRelationalVersion>
<MicrosoftEntityFrameworkCoreSqliteVersion>6.0.23</MicrosoftEntityFrameworkCoreSqliteVersion>
<MicrosoftEntityFrameworkCoreSqlServerVersion>6.0.23</MicrosoftEntityFrameworkCoreSqlServerVersion>
<MicrosoftEntityFrameworkCoreToolsVersion>6.0.23</MicrosoftEntityFrameworkCoreToolsVersion>
<MicrosoftEntityFrameworkCoreVersion>6.0.23</MicrosoftEntityFrameworkCoreVersion>
<MicrosoftEntityFrameworkCoreDesignVersion>6.0.23</MicrosoftEntityFrameworkCoreDesignVersion>
<!-- Packages from dotnet/arcade -->
<MicrosoftDotNetBuildTasksInstallersVersion>6.0.0-beta.23408.5</MicrosoftDotNetBuildTasksInstallersVersion>
<MicrosoftDotNetBuildTasksTemplatingVersion>6.0.0-beta.23408.5</MicrosoftDotNetBuildTasksTemplatingVersion>
......
......@@ -33,6 +33,55 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private const PseudoHeaderFields _mandatoryRequestPseudoHeaderFields =
PseudoHeaderFields.Method | PseudoHeaderFields.Path | PseudoHeaderFields.Scheme;
private const string MaximumEnhanceYourCalmCountProperty = "Microsoft.AspNetCore.Server.Kestrel.Http2.MaxEnhanceYourCalmCount";
private const string MaximumFlowControlQueueSizeProperty = "Microsoft.AspNetCore.Server.Kestrel.Http2.MaxConnectionFlowControlQueueSize";
private static readonly int _enhanceYourCalmMaximumCount = GetMaximumEnhanceYourCalmCount();
private static int GetMaximumEnhanceYourCalmCount()
{
var data = AppContext.GetData(MaximumEnhanceYourCalmCountProperty);
if (data is int count)
{
return count;
}
if (data is string countStr && int.TryParse(countStr, out var parsed))
{
return parsed;
}
return 20; // Empirically derived
}
// Accumulate _enhanceYourCalmCount over the course of EnhanceYourCalmTickWindowCount ticks.
// This should make bursts less likely to trigger disconnects.
private const int EnhanceYourCalmTickWindowCount = 5;
private static bool IsEnhanceYourCalmEnabled => _enhanceYourCalmMaximumCount > 0;
private static readonly int? ConfiguredMaximumFlowControlQueueSize = GetConfiguredMaximumFlowControlQueueSize();
private static int? GetConfiguredMaximumFlowControlQueueSize()
{
var data = AppContext.GetData(MaximumFlowControlQueueSizeProperty);
if (data is int count)
{
return count;
}
if (data is string countStr && int.TryParse(countStr, out var parsed))
{
return parsed;
}
return null;
}
private readonly int _maximumFlowControlQueueSize;
private bool IsMaximumFlowControlQueueSizeEnabled => _maximumFlowControlQueueSize > 0;
private readonly HttpConnectionContext _context;
private readonly Http2FrameWriter _frameWriter;
private readonly Pipe _input;
......@@ -40,7 +89,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private readonly int _minAllocBufferSize;
private readonly HPackDecoder _hpackDecoder;
private readonly InputFlowControl _inputFlowControl;
private readonly OutputFlowControl _outputFlowControl = new OutputFlowControl(new MultipleAwaitableProvider(), Http2PeerSettings.DefaultInitialWindowSize);
private readonly OutputFlowControl _outputFlowControl;
private readonly AwaitableProvider _outputFlowControlAwaitableProvider; // Keep our own reference so we can track queue size
private readonly Http2PeerSettings _serverSettings = new Http2PeerSettings();
private readonly Http2PeerSettings _clientSettings = new Http2PeerSettings();
......@@ -59,6 +109,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
private int _clientActiveStreamCount;
private int _serverActiveStreamCount;
private int _enhanceYourCalmCount;
private int _tickCount;
// The following are the only fields that can be modified outside of the ProcessRequestsAsync loop.
private readonly ConcurrentQueue<Http2Stream> _completedStreams = new ConcurrentQueue<Http2Stream>();
private readonly StreamCloseAwaitable _streamCompletionAwaitable = new StreamCloseAwaitable();
......@@ -88,6 +141,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
// Capture the ExecutionContext before dispatching HTTP/2 middleware. Will be restored by streams when processing request
_context.InitialExecutionContext = ExecutionContext.Capture();
_outputFlowControlAwaitableProvider = new MultipleAwaitableProvider();
_outputFlowControl = new OutputFlowControl(_outputFlowControlAwaitableProvider, Http2PeerSettings.DefaultInitialWindowSize);
_frameWriter = new Http2FrameWriter(
context.Transport.Output,
context.ConnectionContext,
......@@ -129,6 +185,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
_serverSettings.MaxHeaderListSize = (uint)httpLimits.MaxRequestHeadersTotalSize;
_serverSettings.InitialWindowSize = (uint)http2Limits.InitialStreamWindowSize;
_maximumFlowControlQueueSize = ConfiguredMaximumFlowControlQueueSize is null
? 4 * http2Limits.MaxStreamsPerConnection // 4 is a magic number to give us some padding above the expected maximum size
: (int)ConfiguredMaximumFlowControlQueueSize;
var minimumMaximumFlowControlQueueSize = 2 * http2Limits.MaxStreamsPerConnection; // Double to match 7.0 and 8.0
if (IsMaximumFlowControlQueueSizeEnabled && _maximumFlowControlQueueSize < minimumMaximumFlowControlQueueSize)
{
Log.Http2FlowControlQueueMaximumTooLow(context.ConnectionId, minimumMaximumFlowControlQueueSize, _maximumFlowControlQueueSize);
_maximumFlowControlQueueSize = minimumMaximumFlowControlQueueSize;
}
// Start pool off at a smaller size if the max number of streams is less than the InitialStreamPoolSize
StreamPool = new PooledStreamStack<Http2Stream>(Math.Min(InitialStreamPoolSize, http2Limits.MaxStreamsPerConnection));
......@@ -352,13 +419,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
stream.Abort(new IOException(CoreStrings.Http2StreamAborted, connectionError));
}
// Use the server _serverActiveStreamCount to drain all requests on the server side.
// Can't use _clientActiveStreamCount now as we now decrement that count earlier/
// Can't use _streams.Count as we wait for RST/END_STREAM before removing the stream from the dictionary
while (_serverActiveStreamCount > 0)
// For some reason, this loop doesn't terminate when we're trying to abort.
// Since we're making a narrow fix for a patch, we'll bypass it in such scenarios.
// TODO: This is probably a bug - something in here should probably detect aborted
// connections and short-circuit.
if (!(IsEnhanceYourCalmEnabled || IsMaximumFlowControlQueueSizeEnabled) || error is not Http2ConnectionErrorException)
{
await _streamCompletionAwaitable;
UpdateCompletedStreams();
// Use the server _serverActiveStreamCount to drain all requests on the server side.
// Can't use _clientActiveStreamCount now as we now decrement that count earlier/
// Can't use _streams.Count as we wait for RST/END_STREAM before removing the stream from the dictionary
while (_serverActiveStreamCount > 0)
{
await _streamCompletionAwaitable;
UpdateCompletedStreams();
}
}
while (StreamPool.TryPop(out var pooledStream))
......@@ -1053,6 +1127,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2ErrorMaxStreams, Http2ErrorCode.REFUSED_STREAM);
}
if (IsMaximumFlowControlQueueSizeEnabled && _outputFlowControlAwaitableProvider.ActiveCount > _maximumFlowControlQueueSize)
{
Log.Http2FlowControlQueueOperationsExceeded(_context.ConnectionId, _maximumFlowControlQueueSize);
// Now that we've logged a useful message, we can put vague text in the exception
// messages in case they somehow make it back to the client (not expected)
// This will close the socket - we want to do that right away
Abort(new ConnectionAbortedException("HTTP/2 connection exceeded the outgoing flow control maximum queue size."));
// Throwing an exception as well will help us clean up on our end more quickly by (e.g.) skipping processing of already-buffered input
throw new Http2ConnectionErrorException(CoreStrings.Http2ConnectionFaulted, Http2ErrorCode.INTERNAL_ERROR);
}
// We don't use the _serverActiveRequestCount here as during shutdown, it and the dictionary counts get out of sync.
// The streams still exist in the dictionary until the client responds with a RST or END_STREAM.
// Also, we care about the dictionary size for too much memory consumption.
......@@ -1061,6 +1149,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
// Server is getting hit hard with connection resets.
// Tell client to calm down.
// TODO consider making when to send ENHANCE_YOUR_CALM configurable?
if (IsEnhanceYourCalmEnabled && Interlocked.Increment(ref _enhanceYourCalmCount) > EnhanceYourCalmTickWindowCount * _enhanceYourCalmMaximumCount)
{
Log.Http2TooManyEnhanceYourCalms(_context.ConnectionId, _enhanceYourCalmMaximumCount);
// Now that we've logged a useful message, we can put vague text in the exception
// messages in case they somehow make it back to the client (not expected)
// This will close the socket - we want to do that right away
Abort(new ConnectionAbortedException(CoreStrings.Http2ConnectionFaulted));
// Throwing an exception as well will help us clean up on our end more quickly by (e.g.) skipping processing of already-buffered input
throw new Http2ConnectionErrorException(CoreStrings.Http2ConnectionFaulted, Http2ErrorCode.ENHANCE_YOUR_CALM);
}
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2TellClientToCalmDown, Http2ErrorCode.ENHANCE_YOUR_CALM);
}
}
......@@ -1123,6 +1225,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
void IRequestProcessor.Tick(DateTimeOffset now)
{
Input.CancelPendingRead();
// We count EYCs over a window of a given length to avoid flagging short-lived bursts.
// At the end of each window, reset the count.
if (IsEnhanceYourCalmEnabled && ++_tickCount % EnhanceYourCalmTickWindowCount == 0)
{
Interlocked.Exchange(ref _enhanceYourCalmCount, 0);
}
}
void IHttp2StreamLifetimeHandler.OnStreamCompleted(Http2Stream stream)
......
......@@ -78,8 +78,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
void Http2FrameSending(string connectionId, Http2Frame frame);
void Http2TooManyEnhanceYourCalms(string connectionId, int count);
void Http2MaxConcurrentStreamsReached(string connectionId);
void Http2FlowControlQueueOperationsExceeded(string connectionId, int count);
void Http2FlowControlQueueMaximumTooLow(string connectionId, int expected, int actual);
void InvalidResponseHeaderRemoved();
void Http3ConnectionError(string connectionId, Http3ConnectionErrorException ex);
......
......@@ -395,6 +395,30 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
Http3GoAwayStreamId(_http3Logger, connectionId, goAwayStreamId);
}
[LoggerMessage(54, LogLevel.Debug, @"Connection id ""{ConnectionId}"" aborted since at least {Count} ENHANCE_YOUR_CALM responses were recorded per second.", EventName = "Http2TooManyEnhanceYourCalms")]
private static partial void Http2TooManyEnhanceYourCalms(ILogger logger, string connectionId, int count);
public void Http2TooManyEnhanceYourCalms(string connectionId, int count)
{
Http2TooManyEnhanceYourCalms(_http2Logger, connectionId, count);
}
[LoggerMessage(55, LogLevel.Debug, @"Connection id ""{ConnectionId}"" exceeded the output flow control maximum queue size of {Count}.", EventName = "Http2FlowControlQueueOperationsExceeded")]
private static partial void Http2FlowControlQueueOperationsExceeded(ILogger logger, string connectionId, int count);
public void Http2FlowControlQueueOperationsExceeded(string connectionId, int count)
{
Http2FlowControlQueueOperationsExceeded(_http3Logger, connectionId, count);
}
[LoggerMessage(56, LogLevel.Debug, @"Connection id ""{ConnectionId}"" configured maximum flow control queue size {Actual} is less than double the maximum streams per connection {Expected}. Increasing configured value to {Expected}.", EventName = "Http2FlowControlQueueMaximumTooLow")]
private static partial void Http2FlowControlQueueMaximumTooLow(ILogger logger, string connectionId, int expected, int actual);
public void Http2FlowControlQueueMaximumTooLow(string connectionId, int expected, int actual)
{
Http2FlowControlQueueMaximumTooLow(_http3Logger, connectionId, expected, actual);
}
public virtual void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
=> _generalLogger.Log(logLevel, eventId, state, exception, formatter);
......
......@@ -59,7 +59,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks
public void Http2ConnectionClosed(string connectionId, int highestOpenedStreamId) { }
public void Http2FrameReceived(string connectionId, Http2Frame frame) { }
public void Http2FrameSending(string connectionId, Http2Frame frame) { }
public void Http2TooManyEnhanceYourCalms(string connectionId, int count) { }
public void Http2MaxConcurrentStreamsReached(string connectionId) { }
public void Http2FlowControlQueueOperationsExceeded(string connectionId, int count) { }
public void Http2FlowControlQueueMaximumTooLow(string connectionId, int expected, int actual) { }
public void InvalidResponseHeaderRemoved() { }
public void Http3ConnectionError(string connectionId, Http3ConnectionErrorException ex) { }
public void Http3ConnectionClosing(string connectionId) { }
......
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
......
......@@ -234,12 +234,30 @@ namespace Microsoft.AspNetCore.Testing
_trace2.Http2FrameSending(connectionId, frame);
}
public void Http2TooManyEnhanceYourCalms(string connectionId, int count)
{
_trace1.Http2TooManyEnhanceYourCalms(connectionId, count);
_trace2.Http2TooManyEnhanceYourCalms(connectionId, count);
}
public void Http2MaxConcurrentStreamsReached(string connectionId)
{
_trace1.Http2MaxConcurrentStreamsReached(connectionId);
_trace2.Http2MaxConcurrentStreamsReached(connectionId);
}
public void Http2FlowControlQueueOperationsExceeded(string connectionId, int count)
{
_trace1.Http2FlowControlQueueOperationsExceeded(connectionId, count);
_trace2.Http2FlowControlQueueOperationsExceeded(connectionId, count);
}
public void Http2FlowControlQueueMaximumTooLow(string connectionId, int expected, int actual)
{
_trace1.Http2FlowControlQueueMaximumTooLow(connectionId, expected, actual);
_trace2.Http2FlowControlQueueMaximumTooLow(connectionId, expected, actual);
}
public void InvalidResponseHeaderRemoved()
{
_trace1.InvalidResponseHeaderRemoved();
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册