Remove bitfield for locally implemented interface items

Only generate type statics for cached features
This commit is contained in:
Ben Adams 2015-10-08 00:05:27 -04:00 committed by Louis DeJardin
parent 3c20053d9a
commit 8f41e47eca
2 changed files with 61 additions and 117 deletions

View File

@ -6,23 +6,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
public partial class Frame 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 IHttpRequestFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature);
private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature); private static readonly Type IHttpResponseFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature);
private static readonly Type IHttpRequestIdentifierFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature); 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 IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature);
private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature); 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 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 _currentIHttpRequestIdentifierFeature;
private object _currentIServiceProvidersFeature; private object _currentIServiceProvidersFeature;
private object _currentIHttpRequestLifetimeFeature; private object _currentIHttpRequestLifetimeFeature;
@ -48,41 +34,35 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private object _currentIHttpAuthenticationFeature; private object _currentIHttpAuthenticationFeature;
private object _currentIQueryFeature; private object _currentIQueryFeature;
private object _currentIFormFeature; private object _currentIFormFeature;
private object _currentIHttpUpgradeFeature;
private long _featureOverridenFlags = 0L;
private void FastReset() 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) private object FastFeatureGet(Type key)
{ {
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature)) if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature))
{ {
if ((_featureOverridenFlags & flagIHttpRequestFeature) == 0L)
{ return _currentIHttpRequestFeature;
return this;
}
return SlowFeatureGet(key);
} }
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature)) if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{ {
if ((_featureOverridenFlags & flagIHttpResponseFeature) == 0L) return _currentIHttpResponseFeature;
{
return this;
}
return SlowFeatureGet(key);
} }
if (key == IHttpRequestIdentifierFeatureType) if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
if ((_featureOverridenFlags & flagIHttpRequestIdentifierFeature) == 0L)
{
return this;
}
return SlowFeatureGet(key);
}
if (key == IHttpSendFileFeatureType)
{ {
if ((_featureOverridenFlags & flagIHttpSendFileFeature) == 0L) if ((_featureOverridenFlags & flagIHttpSendFileFeature) == 0L)
{ {
@ -146,7 +126,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
} }
return SlowFeatureGet(key); 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) if ((_featureOverridenFlags & flagIHttpConnectionFeature) == 0L)
{ {
@ -189,53 +178,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return SlowFeatureGet(key); 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) private void FastFeatureSet(Type key, object feature)
{ {
if (key == IHttpRequestFeatureType) if (key == IHttpRequestFeatureType)
{ {
FastFeatureSetInner(flagIHttpRequestFeature, key, feature); _currentIHttpRequestFeature = feature;
return; return;
} }
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature)) if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{ {
FastFeatureSetInner(flagIHttpResponseFeature, key, feature); _currentIHttpResponseFeature = feature;
return; return;
} }
if (key == IHttpRequestIdentifierFeatureType) if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
FastFeatureSetInner(flagIHttpRequestIdentifierFeature, key, feature);
return;
}
if (key == IHttpSendFileFeatureType)
{ {
FastFeatureSetInner(flagIHttpSendFileFeature, key, feature); FastFeatureSetInner(flagIHttpSendFileFeature, key, feature);
return; return;
@ -300,24 +256,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
FastFeatureSetInner(flagISessionFeature, key, feature); FastFeatureSetInner(flagISessionFeature, key, feature);
return; return;
} }
Extra[key] = feature; if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature))
{
_currentIHttpUpgradeFeature = feature;
return;
};
SetExtra(key, feature);
} }
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable() private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{ {
if ((_featureOverridenFlags & flagIHttpRequestFeature) == 0L) if (_currentIHttpRequestFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature); yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature);
} }
if ((_featureOverridenFlags & flagIHttpResponseFeature) == 0L) if (_currentIHttpResponseFeature != null)
{ {
yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature); yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature);
} }
if ((_featureOverridenFlags & flagIHttpRequestIdentifierFeature) == 0L) if (_currentIHttpRequestIdentifierFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature);
}
if ((_featureOverridenFlags & flagIHttpSendFileFeature) == 0L)
{ {
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature); yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, this as global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature);
} }
@ -369,6 +326,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{ {
yield return new KeyValuePair<Type, object>(ISessionFeatureType, this as global::Microsoft.AspNet.Http.Features.ISessionFeature); yield return new KeyValuePair<Type, object>(ISessionFeatureType, this as global::Microsoft.AspNet.Http.Features.ISessionFeature);
} }
if (_currentIHttpUpgradeFeature != null)
{
yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature as global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature);
}
if (MaybeExtra != null) if (MaybeExtra != null)
{ {
foreach(var item in MaybeExtra) foreach(var item in MaybeExtra)

View File

@ -54,6 +54,10 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
typeof(IHttpUpgradeFeature), 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 $@" return $@"
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -61,31 +65,18 @@ using System.Collections.Generic;
namespace Microsoft.AspNet.Server.Kestrel.Http namespace Microsoft.AspNet.Server.Kestrel.Http
{{ {{
public partial class Frame public partial class Frame
{{ {{{Each(cachedFeatures, feature => $@"
{Each(commonFeatures.Select((feature, index) => new { feature, index }), entry => $@"
private const long flag{entry.feature.Name} = {1 << entry.index};")}
{Each(commonFeatures, feature => $@"
private static readonly Type {feature.Name}Type = typeof(global::{feature.FullName});")} private static readonly Type {feature.Name}Type = typeof(global::{feature.FullName});")}
private long _featureOverridenFlags = 0L;
private void FastReset() private void FastReset()
{{ {{{Each(implementedFeatures, feature => $@"
_featureOverridenFlags = 0L; _current{feature.Name} = this;")}
{Each(cachedFeatures.Where( f => !implementedFeatures.Contains(f)), feature => $@"
_current{feature.Name} = null;")}
}} }}
private object FastFeatureGet(Type key) private object FastFeatureGet(Type key)
{{{Each(commonFeatures, feature => $@" {{{Each(cachedFeatures, feature => $@"
if (key == {feature.Name}Type)
{{
if ((_featureOverridenFlags & flag{feature.Name}) == 0L)
{{
return this;
}}
return SlowFeatureGet(key);
}}")}
{Each(cachedFeatures, feature => $@"
if (key == typeof(global::{feature.FullName})) if (key == typeof(global::{feature.FullName}))
{{ {{
return _current{feature.Name}; return _current{feature.Name};
@ -119,18 +110,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
updatedFeatureFlags = currentFeatureFlags | flag; updatedFeatureFlags = currentFeatureFlags | flag;
}} while (System.Threading.Interlocked.CompareExchange(ref _featureOverridenFlags, updatedFeatureFlags, currentFeatureFlags) != currentFeatureFlags); }} while (System.Threading.Interlocked.CompareExchange(ref _featureOverridenFlags, updatedFeatureFlags, currentFeatureFlags) != currentFeatureFlags);
System.Threading.Interlocked.Increment(ref _featureRevision);
}}
private void FastFeatureSet(Type key, object feature) private void FastFeatureSet(Type key, object feature)
{{ {{
_featureRevision++; _featureRevision++;
{Each(implementedFeatures, feature => $@"
if (key == typeof(global::{feature.FullName}))
{{
FastFeatureSetInner(flag{feature.Name}, key, feature);
return;
}}")};
{Each(cachedFeatures, feature => $@" {Each(cachedFeatures, feature => $@"
if (key == typeof(global::{feature.FullName})) if (key == typeof(global::{feature.FullName}))
{{ {{
@ -141,10 +123,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}} }}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable() private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(commonFeatures, feature => $@" {{{Each(cachedFeatures, feature => $@"
if ((_featureOverridenFlags & flag{feature.Name}) == 0L) if (_current{feature.Name} != null)
{{ {{
yield return new KeyValuePair<Type, object>({feature.Name}Type, this as global::{feature.FullName}); yield return new KeyValuePair<Type, object>({feature.Name}Type, _current{feature.Name} as global::{feature.FullName});
}}")} }}")}
if (MaybeExtra != null) if (MaybeExtra != null)
{{ {{