diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs index 57cf1c411a..0c0f3d6398 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs @@ -6,23 +6,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http { public partial class Frame { - private const long flagIHttpRequestFeature = 1; - private const long flagIHttpResponseFeature = 2; - private const long flagIHttpRequestIdentifierFeature = 4; - private const long flagIHttpSendFileFeature = 8; - private const long flagIServiceProvidersFeature = 16; - private const long flagIHttpAuthenticationFeature = 32; - private const long flagIHttpRequestLifetimeFeature = 64; - private const long flagIQueryFeature = 128; - private const long flagIFormFeature = 256; - private const long flagIResponseCookiesFeature = 512; - private const long flagIItemsFeature = 1024; - private const long flagIHttpConnectionFeature = 2048; - private const long flagITlsConnectionFeature = 4096; - private const long flagIHttpUpgradeFeature = 8192; - private const long flagIHttpWebSocketFeature = 16384; - private const long flagISessionFeature = 32768; - private static readonly Type IHttpRequestFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature); private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature); private static readonly Type IHttpRequestIdentifierFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature); @@ -40,7 +23,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature); private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature); private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature); + private static readonly Type IHttpUpgradeFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature); + private object _currentIHttpRequestFeature; + private object _currentIHttpResponseFeature; private object _currentIHttpRequestIdentifierFeature; private object _currentIServiceProvidersFeature; private object _currentIHttpRequestLifetimeFeature; @@ -48,41 +34,35 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private object _currentIHttpAuthenticationFeature; private object _currentIQueryFeature; private object _currentIFormFeature; - - private long _featureOverridenFlags = 0L; + private object _currentIHttpUpgradeFeature; private void FastReset() { - _featureOverridenFlags = 0L; + _currentIHttpRequestFeature = this; + _currentIHttpResponseFeature = this; + _currentIHttpUpgradeFeature = this; + + _currentIHttpRequestIdentifierFeature = null; + _currentIServiceProvidersFeature = null; + _currentIHttpRequestLifetimeFeature = null; + _currentIHttpConnectionFeature = null; + _currentIHttpAuthenticationFeature = null; + _currentIQueryFeature = null; + _currentIFormFeature = null; } private object FastFeatureGet(Type key) { if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature)) { - if ((_featureOverridenFlags & flagIHttpRequestFeature) == 0L) - { - return this; - } - return SlowFeatureGet(key); + + return _currentIHttpRequestFeature; } if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature)) { - if ((_featureOverridenFlags & flagIHttpResponseFeature) == 0L) - { - return this; - } - return SlowFeatureGet(key); + return _currentIHttpResponseFeature; } - if (key == IHttpRequestIdentifierFeatureType) - { - if ((_featureOverridenFlags & flagIHttpRequestIdentifierFeature) == 0L) - { - return this; - } - return SlowFeatureGet(key); - } - if (key == IHttpSendFileFeatureType) + if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature)) { if ((_featureOverridenFlags & flagIHttpSendFileFeature) == 0L) { @@ -146,7 +126,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http } return SlowFeatureGet(key); } - if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature)) + if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature)) + { + return _currentIHttpUpgradeFeature; + } + return SlowFeatureGet(key); + } + + private object SlowFeatureGet(Type key) + { + if (MaybeExtra == null) { if ((_featureOverridenFlags & flagIHttpConnectionFeature) == 0L) { @@ -189,53 +178,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http return SlowFeatureGet(key); } - private object SlowFeatureGet(Type key) - { - object feature = null; - if (MaybeExtra?.TryGetValue(key, out feature) ?? false) - { - return feature; - } - return null; - } - - private void FastFeatureSetInner(long flag, Type key, object feature) - { - Extra[key] = feature; - - // Altering only an individual bit of the long - // so need to make sure other concurrent bit changes are not overridden - // in an atomic yet lock-free manner - - long currentFeatureFlags; - long updatedFeatureFlags; - do - { - currentFeatureFlags = _featureOverridenFlags; - updatedFeatureFlags = currentFeatureFlags | flag; - } while (System.Threading.Interlocked.CompareExchange(ref _featureOverridenFlags, updatedFeatureFlags, currentFeatureFlags) != currentFeatureFlags); - - System.Threading.Interlocked.Increment(ref _featureRevision); - } private void FastFeatureSet(Type key, object feature) { if (key == IHttpRequestFeatureType) { - FastFeatureSetInner(flagIHttpRequestFeature, key, feature); + _currentIHttpRequestFeature = feature; return; } if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature)) { - FastFeatureSetInner(flagIHttpResponseFeature, key, feature); + _currentIHttpResponseFeature = feature; return; } - if (key == IHttpRequestIdentifierFeatureType) - { - FastFeatureSetInner(flagIHttpRequestIdentifierFeature, key, feature); - return; - } - if (key == IHttpSendFileFeatureType) + if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature)) { FastFeatureSetInner(flagIHttpSendFileFeature, key, feature); return; @@ -300,24 +256,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http FastFeatureSetInner(flagISessionFeature, key, feature); return; } - Extra[key] = feature; + if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature)) + { + _currentIHttpUpgradeFeature = feature; + return; + }; + SetExtra(key, feature); } private IEnumerable> FastEnumerable() { - if ((_featureOverridenFlags & flagIHttpRequestFeature) == 0L) + if (_currentIHttpRequestFeature != null) { - yield return new KeyValuePair(IHttpRequestFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature); + yield return new KeyValuePair(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature); } - if ((_featureOverridenFlags & flagIHttpResponseFeature) == 0L) + if (_currentIHttpResponseFeature != null) { - yield return new KeyValuePair(IHttpResponseFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature); + yield return new KeyValuePair(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature); } - if ((_featureOverridenFlags & flagIHttpRequestIdentifierFeature) == 0L) - { - yield return new KeyValuePair(IHttpRequestIdentifierFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature); - } - if ((_featureOverridenFlags & flagIHttpSendFileFeature) == 0L) + if (_currentIHttpRequestIdentifierFeature != null) { yield return new KeyValuePair(IHttpSendFileFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature); } @@ -369,6 +326,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http { yield return new KeyValuePair(ISessionFeatureType, this as global::Microsoft.AspNet.Http.Features.ISessionFeature); } + if (_currentIHttpUpgradeFeature != null) + { + yield return new KeyValuePair(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature); + } + if (MaybeExtra != null) { foreach(var item in MaybeExtra) diff --git a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs index ff7e2b46f4..9ee9b3ced8 100644 --- a/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs +++ b/tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs @@ -54,6 +54,10 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode typeof(IHttpUpgradeFeature), }; + // Only the always, common and implmented features will have backed objects + // the sometimes, rare and user-defined features will use the MaybeExtra collection + var cachedFeatures = alwaysFeatures.Concat(commonFeatures).Union(implementedFeatures); + return $@" using System; using System.Collections.Generic; @@ -61,31 +65,18 @@ using System.Collections.Generic; namespace Microsoft.AspNet.Server.Kestrel.Http {{ public partial class Frame - {{ - {Each(commonFeatures.Select((feature, index) => new { feature, index }), entry => $@" - private const long flag{entry.feature.Name} = {1 << entry.index};")} - - {Each(commonFeatures, feature => $@" + {{{Each(cachedFeatures, feature => $@" private static readonly Type {feature.Name}Type = typeof(global::{feature.FullName});")} - private long _featureOverridenFlags = 0L; - private void FastReset() - {{ - _featureOverridenFlags = 0L; + {{{Each(implementedFeatures, feature => $@" + _current{feature.Name} = this;")} + {Each(cachedFeatures.Where( f => !implementedFeatures.Contains(f)), feature => $@" + _current{feature.Name} = null;")} }} private object FastFeatureGet(Type key) - {{{Each(commonFeatures, feature => $@" - if (key == {feature.Name}Type) - {{ - if ((_featureOverridenFlags & flag{feature.Name}) == 0L) - {{ - return this; - }} - return SlowFeatureGet(key); - }}")} - {Each(cachedFeatures, feature => $@" + {{{Each(cachedFeatures, feature => $@" if (key == typeof(global::{feature.FullName})) {{ return _current{feature.Name}; @@ -119,18 +110,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http updatedFeatureFlags = currentFeatureFlags | flag; }} while (System.Threading.Interlocked.CompareExchange(ref _featureOverridenFlags, updatedFeatureFlags, currentFeatureFlags) != currentFeatureFlags); - System.Threading.Interlocked.Increment(ref _featureRevision); - }} - private void FastFeatureSet(Type key, object feature) {{ _featureRevision++; - {Each(implementedFeatures, feature => $@" - if (key == typeof(global::{feature.FullName})) - {{ - FastFeatureSetInner(flag{feature.Name}, key, feature); - return; - }}")}; {Each(cachedFeatures, feature => $@" if (key == typeof(global::{feature.FullName})) {{ @@ -141,10 +123,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http }} private IEnumerable> FastEnumerable() - {{{Each(commonFeatures, feature => $@" - if ((_featureOverridenFlags & flag{feature.Name}) == 0L) + {{{Each(cachedFeatures, feature => $@" + if (_current{feature.Name} != null) {{ - yield return new KeyValuePair({feature.Name}Type, this as global::{feature.FullName}); + yield return new KeyValuePair({feature.Name}Type, _current{feature.Name} as global::{feature.FullName}); }}")} if (MaybeExtra != null) {{